Tried to rework type safety

This commit is contained in:
squidfunk
2017-02-19 23:33:52 +01:00
parent af4db15a27
commit 07e2eb4f85
24 changed files with 436 additions and 260 deletions

View File

@@ -27,6 +27,7 @@ import Material from "./components/Material"
* Application
* ------------------------------------------------------------------------- */
// TODO ./node_modules/.bin/gulp assets:javascripts:flow:annotate && ./node_modules/.bin/flow check
export const initialize = config => {
/* Initialize Modernizr and FastClick */
@@ -37,11 +38,6 @@ export const initialize = config => {
return !!navigator.userAgent.match(/(iPad|iPhone|iPod)/g)
})
/* Test for web application context */
Modernizr.addTest("standalone", () => {
return !!navigator.standalone
})
/* Attach FastClick to mitigate 300ms delay on touch devices */
FastClick.attach(document.body)
@@ -140,7 +136,7 @@ export const initialize = config => {
new Material.Event.Listener("[data-md-component=navigation] [href^='#']",
"click", () => {
const toggle = document.querySelector("[data-md-toggle=drawer]")
if (toggle.checked) {
if (toggle instanceof HTMLInputElement && toggle.checked) {
toggle.checked = false
toggle.dispatchEvent(new CustomEvent("change"))
}
@@ -150,7 +146,7 @@ export const initialize = config => {
new Material.Event.Listener("[data-md-toggle=search]", "change", ev => {
setTimeout(toggle => {
const query = document.forms.search.query
if (toggle.checked)
if (toggle instanceof HTMLInputElement && toggle.checked)
query.focus()
}, 400, ev.target)
}).listen()
@@ -159,7 +155,7 @@ export const initialize = config => {
new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Event.Listener(document.forms.search.query, "focus", () => {
const toggle = document.querySelector("[data-md-toggle=search]")
if (!toggle.checked) {
if (toggle instanceof HTMLInputElement && !toggle.checked) {
toggle.checked = true
toggle.dispatchEvent(new CustomEvent("change"))
}
@@ -169,7 +165,7 @@ export const initialize = config => {
new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Event.Listener(document.body, "click", () => {
const toggle = document.querySelector("[data-md-toggle=search]")
if (toggle.checked) {
if (toggle instanceof HTMLInputElement && toggle.checked) {
toggle.checked = false
toggle.dispatchEvent(new CustomEvent("change"))
}
@@ -180,7 +176,7 @@ export const initialize = config => {
const code = ev.keyCode || ev.which
if (code === 27) {
const toggle = document.querySelector("[data-md-toggle=search]")
if (toggle.checked) {
if (toggle instanceof HTMLInputElement && toggle.checked) {
toggle.checked = false
toggle.dispatchEvent(new CustomEvent("change"))
document.forms.search.query.blur()

View File

@@ -30,14 +30,22 @@ export default class Listener {
* Generic event listener
*
* @constructor
* @param {(string|NodeList<HTMLElement>)} els - Selector or HTML elements
* @param {Array.<string>} events - Event names
* @param {(object|function)} handler - Handler to be invoked
*
* @property {(Array<EventTarget>)} els_ - Event targets
* @property {Object} handler_- Event handlers
* @property {Array<string>} events_ - Event names
* @property {Function} update_ - Update handler
*
* @param {?(string|EventTarget|NodeList<EventTarget>)} els -
* Selector or Event targets
* @param {(string|Array<string>)} events - Event names
* @param {(Object|Function)} handler - Handler to be invoked
*/
constructor(els, events, handler) {
this.els_ = (typeof els === "string")
? document.querySelectorAll(els)
: [].concat(els)
this.els_ = Array.prototype.slice.call(
(typeof els === "string")
? document.querySelectorAll(els)
: [].concat(els))
/* Set handler as function or directly as object */
this.handler_ = typeof handler === "function"
@@ -53,7 +61,7 @@ export default class Listener {
* Register listener for all relevant events
*/
listen() {
Array.prototype.forEach.call(this.els_, el => {
this.els_.forEach(el => {
this.events_.forEach(event => {
el.addEventListener(event, this.update_, false)
})
@@ -68,7 +76,7 @@ export default class Listener {
* Unregister listener for all relevant events
*/
unlisten() {
Array.prototype.forEach.call(this.els_, el => {
this.els_.forEach(el => {
this.events_.forEach(event => {
el.removeEventListener(event, this.update_)
})

View File

@@ -20,6 +20,8 @@
* IN THE SOFTWARE.
*/
import Listener from "./Listener" // eslint-disable-line no-unused-vars
/* ----------------------------------------------------------------------------
* Class
* ------------------------------------------------------------------------- */
@@ -33,6 +35,9 @@ export default class MatchMedia {
* switches the given listeners on or off.
*
* @constructor
*
* @property {Function} handler_ - Media query event handler
*
* @param {string} query - Media query to test for
* @param {Listener} listener - Event listener
*/

View File

@@ -27,9 +27,16 @@
export default class Blur {
/**
* Blur anchors within the navigation above current page y-offset
* Blur links within the table of contents above current page y-offset
*
* @constructor
*
* @property {NodeList<HTMLElement>} els_ - Table of contents links
* @property {Array<HTMLElement>} anchors_ - Referenced anchor nodes
* @property {number} index_ - Current link index
* @property {number} offset_ - Current page y-offset
* @property {boolean} dir_ - Scroll direction change
*
* @param {(string|NodeList<HTMLElement>)} els - Selector or HTML elements
*/
constructor(els) {
@@ -45,20 +52,21 @@ export default class Blur {
this.dir_ = false
/* Index anchor node offsets for fast lookup */
this.anchors_ = [].map.call(this.els_, el => {
return document.getElementById(el.hash.substring(1))
})
this.anchors_ = [].reduce.call(this.els_, (anchors, el) => {
return anchors.concat(
document.getElementById(el.hash.substring(1)) || [])
}, [])
}
/**
* Initialize anchor states
* Initialize blur states
*/
setup() {
this.update()
}
/**
* Update anchor states
* Update blur states
*
* Deduct the static offset of the header (56px) and sidebar offset (24px),
* see _permalinks.scss for more information.
@@ -67,7 +75,7 @@ export default class Blur {
const offset = window.pageYOffset
const dir = this.offset_ - offset < 0
/* Hack: reset index if direction changed, to catch very fast scrolling,
/* Hack: reset index if direction changed to catch very fast scrolling,
because otherwise we would have to register a timer and that sucks */
if (this.dir_ !== dir)
this.index_ = dir
@@ -109,7 +117,7 @@ export default class Blur {
}
/**
* Reset anchor states
* Reset blur states
*/
reset() {
Array.prototype.forEach.call(this.els_, el => {

View File

@@ -30,6 +30,9 @@ export default class Collapse {
* Expand or collapse navigation on toggle
*
* @constructor
*
* @property {HTMLElement} el_ - Navigation list
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {
@@ -75,11 +78,16 @@ export default class Collapse {
/* Remove state on end of transition */
const end = ev => {
ev.target.removeAttribute("data-md-state")
ev.target.style.maxHeight = ""
const target = ev.target
if (!(target instanceof HTMLElement))
return
/* Reset height and state */
target.removeAttribute("data-md-state")
target.style.maxHeight = ""
/* Only fire once, so directly remove event listener */
ev.target.removeEventListener("transitionend", end)
target.removeEventListener("transitionend", end)
}
this.el_.addEventListener("transitionend", end, false)
}

View File

@@ -30,6 +30,9 @@ export default class Scrolling {
* Set overflow scrolling on the current active pane (for iOS)
*
* @constructor
*
* @property {HTMLElement} el_ - Navigation
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {

View File

@@ -30,6 +30,10 @@ export default class Lock {
* Lock body for full-screen search modal
*
* @constructor
*
* @property {HTMLInputElement} el_ - TODO
* @property {number} offset_ - TODO
*
* @param {(string|HTMLElement)} el - Selector or HTML element
*/
constructor(el) {

View File

@@ -32,8 +32,13 @@ export default class Result {
* Perform search and update results on keyboard events
*
* @constructor
*
* @property {HTMLElement} el_ - TODO
* @property {(Object|Array<Object>|Function)} data_ - TODO (very dirty)
* @property {React$Element|HTMLElement} meta_ - TODO
*
* @param {(string|HTMLElement)} el - Selector or HTML element
* @param {(Array.<object>|Function)} data - Promise or array providing data
* @param {(Array<Object>|Function)} data - Promise or array providing data // TODO ????
*/
constructor(el, data) {
this.el_ = (typeof el === "string")