2016-01-29 01:27:15 +03:00
|
|
|
/*
|
2017-01-06 21:11:18 +03:00
|
|
|
* Copyright (c) 2016-2017 Martin Donath <martin.donath@squidfunk.com>
|
2016-01-29 01:27:15 +03:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2017-11-21 23:32:25 +03:00
|
|
|
import "../images/icons/bitbucket.svg"
|
|
|
|
import "../images/icons/github.svg"
|
|
|
|
import "../images/icons/gitlab.svg"
|
|
|
|
|
|
|
|
import "../stylesheets/application.scss"
|
|
|
|
import "../stylesheets/application-palette.scss"
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
* Polyfills
|
|
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
import "custom-event-polyfill"
|
|
|
|
import "unfetch/polyfill"
|
|
|
|
|
|
|
|
import Promise from "promise-polyfill"
|
|
|
|
window.Promise = window.Promise || Promise
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
* Dependencies
|
|
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
|
2017-05-31 16:22:59 +03:00
|
|
|
import Clipboard from "clipboard"
|
2016-09-30 14:29:45 +03:00
|
|
|
import FastClick from "fastclick"
|
2017-05-31 16:22:59 +03:00
|
|
|
|
2016-10-06 13:14:33 +03:00
|
|
|
import Material from "./components/Material"
|
2016-09-30 14:29:45 +03:00
|
|
|
|
2017-10-18 21:40:12 +03:00
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
* Functions
|
|
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the meta tag value for the given key
|
|
|
|
*
|
|
|
|
* @param {string} key - Meta name
|
|
|
|
*
|
|
|
|
* @return {string} Meta content value
|
|
|
|
*/
|
2017-11-21 23:32:25 +03:00
|
|
|
const translate = key => {
|
2017-10-18 22:38:33 +03:00
|
|
|
const meta = document.getElementsByName(`lang:${key}`)[0]
|
2017-10-18 21:40:12 +03:00
|
|
|
if (!(meta instanceof HTMLMetaElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
return meta.content
|
|
|
|
}
|
|
|
|
|
2016-01-29 01:27:15 +03:00
|
|
|
/* ----------------------------------------------------------------------------
|
2016-08-07 19:01:56 +03:00
|
|
|
* Application
|
2016-01-29 01:27:15 +03:00
|
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
|
2017-02-25 16:49:49 +03:00
|
|
|
/**
|
2017-02-25 19:13:50 +03:00
|
|
|
* Initialize Material for MkDocs
|
2017-02-25 16:49:49 +03:00
|
|
|
*
|
2017-02-25 19:13:50 +03:00
|
|
|
* @param {Object} config - Configuration
|
2017-02-25 16:49:49 +03:00
|
|
|
*/
|
2017-02-25 19:13:50 +03:00
|
|
|
function initialize(config) { // eslint-disable-line func-style
|
2016-10-06 13:14:33 +03:00
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Initialize Modernizr and FastClick */
|
|
|
|
new Material.Event.Listener(document, "DOMContentLoaded", () => {
|
2017-02-25 16:49:49 +03:00
|
|
|
if (!(document.body instanceof HTMLElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Attach FastClick to mitigate 300ms delay on touch devices */
|
|
|
|
FastClick.attach(document.body)
|
2016-10-23 12:35:41 +03:00
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Test for iOS */
|
|
|
|
Modernizr.addTest("ios", () => {
|
|
|
|
return !!navigator.userAgent.match(/(iPad|iPhone|iPod)/g)
|
|
|
|
})
|
2016-11-02 21:21:14 +03:00
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Wrap all data tables for better overflow scrolling */
|
2017-05-31 17:22:00 +03:00
|
|
|
const tables = document.querySelectorAll("table:not([class])") // TODO: this is JSX, we should rename the file
|
2017-02-11 18:00:45 +03:00
|
|
|
Array.prototype.forEach.call(tables, table => {
|
2017-02-25 13:29:15 +03:00
|
|
|
const wrap = (
|
|
|
|
<div class="md-typeset__scrollwrap">
|
|
|
|
<div class="md-typeset__table"></div>
|
|
|
|
</div>
|
|
|
|
)
|
2017-02-11 18:00:45 +03:00
|
|
|
if (table.nextSibling) {
|
|
|
|
table.parentNode.insertBefore(wrap, table.nextSibling)
|
|
|
|
} else {
|
|
|
|
table.parentNode.appendChild(wrap)
|
2016-12-29 16:19:26 +03:00
|
|
|
}
|
2017-02-25 13:29:15 +03:00
|
|
|
wrap.children[0].appendChild(table)
|
2017-02-11 18:00:45 +03:00
|
|
|
})
|
2016-12-29 16:19:26 +03:00
|
|
|
|
2017-05-31 17:22:00 +03:00
|
|
|
/* Clipboard integration */
|
|
|
|
if (Clipboard.isSupported()) {
|
2017-11-08 10:34:55 +03:00
|
|
|
const blocks = document.querySelectorAll(".codehilite > pre, pre > code")
|
2017-05-31 17:22:00 +03:00
|
|
|
Array.prototype.forEach.call(blocks, (block, index) => {
|
|
|
|
const id = `__code_${index}`
|
|
|
|
|
|
|
|
/* Create button with message container */
|
|
|
|
const button = (
|
2017-10-18 22:38:33 +03:00
|
|
|
<button class="md-clipboard" title={translate("clipboard.copy")}
|
2017-06-13 16:05:51 +03:00
|
|
|
data-clipboard-target={`#${id} pre, #${id} code`}>
|
2017-05-31 17:22:00 +03:00
|
|
|
<span class="md-clipboard__message"></span>
|
|
|
|
</button>
|
|
|
|
)
|
|
|
|
|
|
|
|
/* Link to block and insert button */
|
|
|
|
const parent = block.parentNode
|
|
|
|
parent.id = id
|
|
|
|
parent.insertBefore(button, block)
|
|
|
|
})
|
|
|
|
|
|
|
|
/* Initialize Clipboard listener */
|
|
|
|
const copy = new Clipboard(".md-clipboard")
|
|
|
|
|
|
|
|
/* Success handler */
|
|
|
|
copy.on("success", action => {
|
|
|
|
const message = action.trigger.querySelector(".md-clipboard__message")
|
|
|
|
if (!(message instanceof HTMLElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
|
|
|
|
/* Clear selection and reset debounce logic */
|
|
|
|
action.clearSelection()
|
2017-06-06 22:51:25 +03:00
|
|
|
if (message.dataset.mdTimer)
|
|
|
|
clearTimeout(parseInt(message.dataset.mdTimer, 10))
|
2017-05-31 17:22:00 +03:00
|
|
|
|
|
|
|
/* Set message indicating success and show it */
|
|
|
|
message.classList.add("md-clipboard__message--active")
|
2017-10-18 22:38:33 +03:00
|
|
|
message.innerHTML = translate("clipboard.copied")
|
2017-05-31 17:22:00 +03:00
|
|
|
|
|
|
|
/* Hide message after two seconds */
|
2017-06-06 22:51:25 +03:00
|
|
|
message.dataset.mdTimer = setTimeout(() => {
|
2017-05-31 17:22:00 +03:00
|
|
|
message.classList.remove("md-clipboard__message--active")
|
2017-06-06 22:51:25 +03:00
|
|
|
message.dataset.mdTimer = ""
|
|
|
|
}, 2000).toString()
|
2017-05-31 17:22:00 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-08-29 17:17:16 +03:00
|
|
|
/* Polyfill details/summary functionality */
|
|
|
|
if (!Modernizr.details) {
|
|
|
|
const blocks = document.querySelectorAll("details > summary")
|
|
|
|
Array.prototype.forEach.call(blocks, summary => {
|
|
|
|
summary.addEventListener("click", ev => {
|
|
|
|
const details = ev.target.parentNode
|
|
|
|
if (details.hasAttribute("open")) {
|
|
|
|
details.removeAttribute("open")
|
|
|
|
} else {
|
|
|
|
details.setAttribute("open", "")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-11-05 17:17:23 +03:00
|
|
|
/* Open details after anchor jump */
|
|
|
|
const details = () => {
|
|
|
|
if (document.location.hash) {
|
2017-11-05 19:23:09 +03:00
|
|
|
const el = document.getElementById(document.location.hash.substring(1))
|
2017-11-05 17:17:23 +03:00
|
|
|
if (!el)
|
|
|
|
return
|
|
|
|
|
|
|
|
/* Walk up as long as we're not in a details tag */
|
|
|
|
let parent = el.parentNode
|
|
|
|
while (parent && !(parent instanceof HTMLDetailsElement))
|
|
|
|
parent = parent.parentNode
|
|
|
|
|
|
|
|
/* If there's a details tag, open it */
|
|
|
|
if (parent && !parent.open) {
|
|
|
|
parent.open = true
|
|
|
|
|
|
|
|
/* Force reload, so the viewport repositions */
|
|
|
|
const loc = location.hash
|
|
|
|
location.hash = " "
|
|
|
|
location.hash = loc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
window.addEventListener("hashchange", details)
|
|
|
|
details()
|
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Force 1px scroll offset to trigger overflow scrolling */
|
|
|
|
if (Modernizr.ios) {
|
|
|
|
const scrollable = document.querySelectorAll("[data-md-scrollfix]")
|
|
|
|
Array.prototype.forEach.call(scrollable, item => {
|
|
|
|
item.addEventListener("touchstart", () => {
|
|
|
|
const top = item.scrollTop
|
2016-12-29 16:19:26 +03:00
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* We're at the top of the container */
|
|
|
|
if (top === 0) {
|
|
|
|
item.scrollTop = 1
|
2016-12-29 16:19:26 +03:00
|
|
|
|
|
|
|
/* We're at the bottom of the container */
|
2017-02-11 18:00:45 +03:00
|
|
|
} else if (top + item.offsetHeight === item.scrollHeight) {
|
|
|
|
item.scrollTop = top - 1
|
2016-12-15 17:55:40 +03:00
|
|
|
}
|
2016-12-29 16:19:26 +03:00
|
|
|
})
|
2017-02-11 18:00:45 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}).listen()
|
2017-01-28 00:41:55 +03:00
|
|
|
|
2017-02-12 01:02:12 +03:00
|
|
|
/* Component: header shadow toggle */
|
2017-11-22 02:13:56 +03:00
|
|
|
new Material.Event.Listener(window, [
|
|
|
|
"scroll", "resize", "orientationchange"
|
|
|
|
], new Material.Header.Shadow(
|
|
|
|
"[data-md-component=container]",
|
|
|
|
"[data-md-component=header]")
|
|
|
|
).listen()
|
2017-01-28 00:41:55 +03:00
|
|
|
|
2017-11-19 18:46:01 +03:00
|
|
|
/* Component: header title toggle */
|
|
|
|
new Material.Event.Listener(window, [
|
|
|
|
"scroll", "resize", "orientationchange"
|
|
|
|
], new Material.Header.Title(
|
|
|
|
"[data-md-component=title]",
|
|
|
|
".md-typeset h1")
|
|
|
|
).listen()
|
2017-11-22 02:13:56 +03:00
|
|
|
|
|
|
|
/* Component: hero visibility toggle */
|
|
|
|
if (document.querySelector("[data-md-component=hero]"))
|
|
|
|
new Material.Event.Listener(window, [
|
|
|
|
"scroll", "resize", "orientationchange"
|
|
|
|
], new Material.Tabs.Toggle("[data-md-component=hero]")).listen()
|
2017-11-19 18:46:01 +03:00
|
|
|
|
2017-02-12 01:02:12 +03:00
|
|
|
/* Component: tabs visibility toggle */
|
2017-02-26 17:30:48 +03:00
|
|
|
if (document.querySelector("[data-md-component=tabs]"))
|
|
|
|
new Material.Event.Listener(window, [
|
|
|
|
"scroll", "resize", "orientationchange"
|
|
|
|
], new Material.Tabs.Toggle("[data-md-component=tabs]")).listen()
|
2016-12-15 17:55:40 +03:00
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Component: sidebar with navigation */
|
|
|
|
new Material.Event.MatchMedia("(min-width: 1220px)",
|
|
|
|
new Material.Event.Listener(window, [
|
|
|
|
"scroll", "resize", "orientationchange"
|
2017-03-03 23:57:15 +03:00
|
|
|
], new Material.Sidebar.Position(
|
2017-08-02 13:15:59 +03:00
|
|
|
"[data-md-component=navigation]",
|
|
|
|
"[data-md-component=header]")))
|
2016-12-15 17:55:40 +03:00
|
|
|
|
2017-04-06 13:49:37 +03:00
|
|
|
/* Component: sidebar with table of contents (missing on 404 page) */
|
|
|
|
if (document.querySelector("[data-md-component=toc]"))
|
|
|
|
new Material.Event.MatchMedia("(min-width: 960px)",
|
|
|
|
new Material.Event.Listener(window, [
|
|
|
|
"scroll", "resize", "orientationchange"
|
|
|
|
], new Material.Sidebar.Position(
|
2017-08-02 13:15:59 +03:00
|
|
|
"[data-md-component=toc]",
|
|
|
|
"[data-md-component=header]")))
|
2016-12-28 13:49:57 +03:00
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Component: link blurring for table of contents */
|
|
|
|
new Material.Event.MatchMedia("(min-width: 960px)",
|
|
|
|
new Material.Event.Listener(window, "scroll",
|
2017-02-12 01:02:12 +03:00
|
|
|
new Material.Nav.Blur("[data-md-component=toc] [href]")))
|
2016-12-15 17:55:40 +03:00
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Component: collapsible elements for navigation */
|
|
|
|
const collapsibles =
|
|
|
|
document.querySelectorAll("[data-md-component=collapsible]")
|
|
|
|
Array.prototype.forEach.call(collapsibles, collapse => {
|
|
|
|
new Material.Event.MatchMedia("(min-width: 1220px)",
|
|
|
|
new Material.Event.Listener(collapse.previousElementSibling, "click",
|
|
|
|
new Material.Nav.Collapse(collapse)))
|
|
|
|
})
|
|
|
|
|
|
|
|
/* Component: active pane monitor for iOS scrolling fixes */
|
|
|
|
new Material.Event.MatchMedia("(max-width: 1219px)",
|
|
|
|
new Material.Event.Listener(
|
|
|
|
"[data-md-component=navigation] [data-md-toggle]", "change",
|
2017-06-13 16:05:51 +03:00
|
|
|
new Material.Nav.Scrolling("[data-md-component=navigation] nav")))
|
2017-02-11 18:00:45 +03:00
|
|
|
|
|
|
|
/* Component: search body lock for mobile */
|
|
|
|
new Material.Event.MatchMedia("(max-width: 959px)",
|
|
|
|
new Material.Event.Listener("[data-md-toggle=search]", "change",
|
|
|
|
new Material.Search.Lock("[data-md-toggle=search]")))
|
|
|
|
|
|
|
|
/* Component: search results */
|
2017-02-25 19:13:50 +03:00
|
|
|
new Material.Event.Listener("[data-md-component=query]", [
|
2017-03-19 21:49:19 +03:00
|
|
|
"focus", "keyup", "change"
|
2017-02-11 18:00:45 +03:00
|
|
|
], new Material.Search.Result("[data-md-component=result]", () => {
|
2017-10-22 22:22:25 +03:00
|
|
|
return fetch(`${config.url.base}/${
|
|
|
|
config.version < "0.17" ? "mkdocs" : "search"
|
|
|
|
}/search_index.json`, {
|
2017-08-02 13:15:59 +03:00
|
|
|
credentials: "same-origin"
|
|
|
|
}).then(response => response.json())
|
|
|
|
.then(data => {
|
|
|
|
return data.docs.map(doc => {
|
|
|
|
doc.location = config.url.base + doc.location
|
|
|
|
return doc
|
2016-12-15 17:55:40 +03:00
|
|
|
})
|
2017-08-02 13:15:59 +03:00
|
|
|
})
|
|
|
|
})).listen()
|
2017-02-11 18:00:45 +03:00
|
|
|
|
|
|
|
/* Listener: close drawer when anchor links are clicked */
|
|
|
|
new Material.Event.MatchMedia("(max-width: 959px)",
|
|
|
|
new Material.Event.Listener("[data-md-component=navigation] [href^='#']",
|
|
|
|
"click", () => {
|
|
|
|
const toggle = document.querySelector("[data-md-toggle=drawer]")
|
2017-02-25 19:13:50 +03:00
|
|
|
if (!(toggle instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
2016-12-15 17:55:40 +03:00
|
|
|
if (toggle.checked) {
|
|
|
|
toggle.checked = false
|
2016-12-29 12:50:19 +03:00
|
|
|
toggle.dispatchEvent(new CustomEvent("change"))
|
2016-12-15 17:55:40 +03:00
|
|
|
}
|
|
|
|
}))
|
|
|
|
|
2017-03-21 17:27:45 +03:00
|
|
|
/* Listener: focus input after form reset */
|
|
|
|
new Material.Event.Listener("[data-md-component=reset]", "click", () => {
|
|
|
|
setTimeout(() => {
|
|
|
|
const query = document.querySelector("[data-md-component=query]")
|
|
|
|
if (!(query instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
query.focus()
|
|
|
|
}, 10)
|
|
|
|
}).listen()
|
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Listener: focus input after opening search */
|
|
|
|
new Material.Event.Listener("[data-md-toggle=search]", "change", ev => {
|
|
|
|
setTimeout(toggle => {
|
2017-02-25 19:13:50 +03:00
|
|
|
if (!(toggle instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
if (toggle.checked) {
|
|
|
|
const query = document.querySelector("[data-md-component=query]")
|
|
|
|
if (!(query instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
2017-02-11 18:00:45 +03:00
|
|
|
query.focus()
|
2017-02-25 19:13:50 +03:00
|
|
|
}
|
2017-02-11 18:00:45 +03:00
|
|
|
}, 400, ev.target)
|
|
|
|
}).listen()
|
|
|
|
|
|
|
|
/* Listener: open search on focus */
|
|
|
|
new Material.Event.MatchMedia("(min-width: 960px)",
|
2017-02-25 19:13:50 +03:00
|
|
|
new Material.Event.Listener("[data-md-component=query]", "focus", () => {
|
2017-02-11 18:00:45 +03:00
|
|
|
const toggle = document.querySelector("[data-md-toggle=search]")
|
2017-02-25 19:13:50 +03:00
|
|
|
if (!(toggle instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
2017-02-11 18:00:45 +03:00
|
|
|
if (!toggle.checked) {
|
|
|
|
toggle.checked = true
|
|
|
|
toggle.dispatchEvent(new CustomEvent("change"))
|
2016-12-28 19:32:56 +03:00
|
|
|
}
|
2017-02-11 18:00:45 +03:00
|
|
|
}))
|
|
|
|
|
2017-04-23 21:45:23 +03:00
|
|
|
/* Listener: keyboard handlers */ // eslint-disable-next-line complexity
|
|
|
|
new Material.Event.Listener(window, "keydown", ev => { // TODO: split up into component to reduce complexity
|
2017-03-24 00:41:08 +03:00
|
|
|
const toggle = document.querySelector("[data-md-toggle=search]")
|
|
|
|
if (!(toggle instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
const query = document.querySelector("[data-md-component=query]")
|
|
|
|
if (!(query instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
2017-03-23 00:38:42 +03:00
|
|
|
|
2017-04-20 19:28:28 +03:00
|
|
|
/* Abort if meta key (macOS) or ctrl key (Windows) is pressed */
|
|
|
|
if (ev.metaKey || ev.ctrlKey)
|
|
|
|
return
|
|
|
|
|
2017-03-24 00:41:08 +03:00
|
|
|
/* Search is open */
|
|
|
|
if (toggle.checked) {
|
2017-03-23 00:38:42 +03:00
|
|
|
|
2017-03-24 01:39:19 +03:00
|
|
|
/* Enter: prevent form submission */
|
2017-03-24 21:57:56 +03:00
|
|
|
if (ev.keyCode === 13) {
|
2017-04-23 21:45:23 +03:00
|
|
|
if (query === document.activeElement) {
|
2017-03-24 01:39:19 +03:00
|
|
|
ev.preventDefault()
|
|
|
|
|
2017-04-23 21:45:23 +03:00
|
|
|
/* Go to current active/focused link */
|
|
|
|
const focus = document.querySelector(
|
|
|
|
"[data-md-component=search] [href][data-md-state=active]")
|
2017-10-12 17:04:48 +03:00
|
|
|
if (focus instanceof HTMLLinkElement) {
|
2017-04-23 21:45:23 +03:00
|
|
|
window.location = focus.getAttribute("href")
|
|
|
|
|
2017-10-12 17:04:48 +03:00
|
|
|
/* Close search */
|
|
|
|
toggle.checked = false
|
|
|
|
toggle.dispatchEvent(new CustomEvent("change"))
|
|
|
|
query.blur()
|
|
|
|
}
|
2017-04-23 21:45:23 +03:00
|
|
|
}
|
|
|
|
|
2017-03-24 00:41:08 +03:00
|
|
|
/* Escape: close search */
|
2017-03-24 21:57:56 +03:00
|
|
|
} else if (ev.keyCode === 27) {
|
2017-03-24 00:41:08 +03:00
|
|
|
toggle.checked = false
|
|
|
|
toggle.dispatchEvent(new CustomEvent("change"))
|
|
|
|
query.blur()
|
|
|
|
|
|
|
|
/* Horizontal arrows and backspace: focus input */
|
2017-03-24 21:57:56 +03:00
|
|
|
} else if ([8, 37, 39].indexOf(ev.keyCode) !== -1) {
|
2017-03-24 00:41:08 +03:00
|
|
|
if (query !== document.activeElement)
|
|
|
|
query.focus()
|
|
|
|
|
|
|
|
/* Vertical arrows and tab: select previous or next search result */
|
2017-03-24 21:57:56 +03:00
|
|
|
} else if ([9, 38, 40].indexOf(ev.keyCode) !== -1) {
|
|
|
|
const map = ev.shiftKey ? 38 : 40
|
|
|
|
const key = ev.keyCode === 9 ? map : ev.keyCode
|
2017-03-24 00:41:08 +03:00
|
|
|
|
|
|
|
/* Retrieve all results */
|
2017-03-23 00:38:42 +03:00
|
|
|
const links = Array.prototype.slice.call(
|
2017-07-25 18:02:42 +03:00
|
|
|
document.querySelectorAll(
|
|
|
|
"[data-md-component=query], [data-md-component=search] [href]"))
|
2017-03-24 00:41:08 +03:00
|
|
|
|
|
|
|
/* Retrieve current active/focused result */
|
|
|
|
const focus = links.find(link => {
|
|
|
|
if (!(link instanceof HTMLElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
return link.dataset.mdState === "active"
|
|
|
|
})
|
|
|
|
if (focus)
|
|
|
|
focus.dataset.mdState = ""
|
|
|
|
|
|
|
|
/* Calculate index depending on direction, add length to form ring */
|
|
|
|
const index = Math.max(0, (
|
2017-03-24 21:57:56 +03:00
|
|
|
links.indexOf(focus) + links.length + (key === 38 ? -1 : +1)
|
2017-03-24 00:41:08 +03:00
|
|
|
) % links.length)
|
|
|
|
|
|
|
|
/* Set active state and focus */
|
2017-07-25 18:02:42 +03:00
|
|
|
if (links[index]) {
|
|
|
|
links[index].dataset.mdState = "active"
|
|
|
|
links[index].focus()
|
|
|
|
}
|
2017-03-24 00:41:08 +03:00
|
|
|
|
|
|
|
/* Prevent scrolling of page */
|
|
|
|
ev.preventDefault()
|
|
|
|
ev.stopPropagation()
|
|
|
|
|
|
|
|
/* Return false prevents the cursor position from changing */
|
|
|
|
return false
|
2017-03-23 00:38:42 +03:00
|
|
|
}
|
|
|
|
|
2017-07-25 17:08:05 +03:00
|
|
|
/* Search is closed and we're not inside a form */
|
|
|
|
} else if (document.activeElement && !document.activeElement.form) {
|
2017-03-24 00:41:08 +03:00
|
|
|
|
2017-03-24 21:57:56 +03:00
|
|
|
/* F/S: Open search if not in input field */
|
|
|
|
if (ev.keyCode === 70 || ev.keyCode === 83) {
|
2017-03-24 00:41:08 +03:00
|
|
|
query.focus()
|
|
|
|
ev.preventDefault()
|
2017-02-11 18:00:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}).listen()
|
|
|
|
|
2017-03-24 00:41:08 +03:00
|
|
|
/* Listener: focus query if in search is open and character is typed */
|
|
|
|
new Material.Event.Listener(window, "keypress", () => {
|
|
|
|
const toggle = document.querySelector("[data-md-toggle=search]")
|
|
|
|
if (!(toggle instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
if (toggle.checked) {
|
|
|
|
const query = document.querySelector("[data-md-component=query]")
|
|
|
|
if (!(query instanceof HTMLInputElement))
|
|
|
|
throw new ReferenceError
|
|
|
|
if (query !== document.activeElement)
|
|
|
|
query.focus()
|
|
|
|
}
|
|
|
|
}).listen()
|
|
|
|
|
2017-02-11 18:00:45 +03:00
|
|
|
/* Retrieve facts for the given repository type */
|
|
|
|
;(() => {
|
|
|
|
const el = document.querySelector("[data-md-source]")
|
2017-02-25 16:49:49 +03:00
|
|
|
if (!el)
|
|
|
|
return Promise.resolve([])
|
|
|
|
else if (!(el instanceof HTMLAnchorElement))
|
|
|
|
throw new ReferenceError
|
2017-02-11 18:00:45 +03:00
|
|
|
switch (el.dataset.mdSource) {
|
|
|
|
case "github": return new Material.Source.Adapter.GitHub(el).fetch()
|
|
|
|
default: return Promise.resolve([])
|
|
|
|
}
|
|
|
|
|
2017-02-25 19:13:50 +03:00
|
|
|
/* Render repository information */
|
2017-02-11 18:00:45 +03:00
|
|
|
})().then(facts => {
|
|
|
|
const sources = document.querySelectorAll("[data-md-source]")
|
|
|
|
Array.prototype.forEach.call(sources, source => {
|
|
|
|
new Material.Source.Repository(source)
|
|
|
|
.initialize(facts)
|
2016-12-15 17:55:40 +03:00
|
|
|
})
|
2017-02-11 18:00:45 +03:00
|
|
|
})
|
2016-10-06 13:14:33 +03:00
|
|
|
}
|
2017-02-25 19:13:50 +03:00
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
* Exports
|
|
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
|
2017-11-21 23:32:25 +03:00
|
|
|
/* Provide this for downward compatibility for now */
|
|
|
|
const app = {
|
2017-02-25 19:13:50 +03:00
|
|
|
initialize
|
|
|
|
}
|
2017-11-21 23:32:25 +03:00
|
|
|
|
|
|
|
export {
|
|
|
|
app
|
|
|
|
}
|