mirror of
https://github.com/seigler/dash-docs
synced 2025-07-27 01:36:13 +00:00
207 lines
8.4 KiB
JavaScript
207 lines
8.4 KiB
JavaScript
// This file is licensed under the MIT License (MIT) available on
|
|
// http://opensource.org/licenses/MIT.
|
|
|
|
// This file should be used only for javascript code
|
|
// necessary for all pages to work properly.
|
|
|
|
"use strict";
|
|
|
|
function addEvent(a, b, c) {
|
|
// Attach event to a DOM node.
|
|
// Ex. addEvent(node,'click',function);
|
|
return (a.addEventListener) ? a.addEventListener(b, c, false) : (a.attachEvent) ? a.attachEvent('on' + b, c) : false;
|
|
}
|
|
|
|
function removeEvent(a, b, c) {
|
|
// Detach event from a DOM node.
|
|
// Ex. removeEvent(node,'click',function);
|
|
return (a.removeEventListener) ? a.removeEventListener(b, c, false) : (a.detachEvent) ? a.detachEvent('on' + b, c) : false;
|
|
}
|
|
|
|
function cancelEvent(e) {
|
|
// Cancel current event.
|
|
// Ex. cancelEvent(event);
|
|
e = e || window.event;
|
|
(e.preventDefault) ? e.preventDefault(): e.returnValue = false;
|
|
}
|
|
|
|
function getEvent(e, a) {
|
|
// Return requested event property.
|
|
// Ex. var target = getEvent(event, 'target');
|
|
e = (e) ? e : window.event;
|
|
switch (a) {
|
|
case 'type':
|
|
return e.type;
|
|
case 'target':
|
|
return (e.target && e.target.nodeType === 3) ? e.target.parentNode : (e.target) ? e.target : e.srcElement;
|
|
}
|
|
}
|
|
|
|
function getStyle(a, b) {
|
|
// Return the value of the computed style on a DOM node.
|
|
// Ex. getStyle(node,'padding-bottom');
|
|
if (window.getComputedStyle) return document.defaultView.getComputedStyle(a, null).getPropertyValue(b);
|
|
var n = b.indexOf('-');
|
|
if (n !== -1) b = b.substr(0, n) + b.substr(n + 1, 1).toUpperCase() + b.substr(n + 2);
|
|
return a.currentStyle[b];
|
|
}
|
|
|
|
function addClass(node, data) {
|
|
// Add class to node.
|
|
var cl = node.className.split(' ');
|
|
for (var i = 0, n = cl.length; i < n; i++) {
|
|
if (cl[i] === data) return;
|
|
}
|
|
cl.push(data);
|
|
node.className = cl.join(' ');
|
|
}
|
|
|
|
function removeClass(node, data) {
|
|
// Remove class from node.
|
|
var ocl = node.className.split(' ');
|
|
var ncl = [];
|
|
for (var i = 0, n = ocl.length; i < n; i++) {
|
|
if (ocl[i] !== data) ncl.push(ocl[i]);
|
|
}
|
|
node.className = ncl.join(' ');
|
|
}
|
|
|
|
function supportsSVG() {
|
|
// Return true if the browser supports SVG.
|
|
// Ex. if(!supportsSVG()){..apply png fallback..}
|
|
// Old FF 3.5 and Safari 3 versions have svg support, but a very poor one
|
|
// http://www.w3.org/TR/SVG11/feature#Image Defeat FF 3.5 only
|
|
// http://www.w3.org/TR/SVG11/feature#Animation Defeat Saf 3 but also returns false in IE9
|
|
// http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute Defeat Saf 3 but also returns false in Chrome and safari4
|
|
// http://www.w3.org/TR/SVG11/feature#Text Defeat Saf 3 but also returns false in FF and safari4
|
|
if (!document.createElementNS || !document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect) return false;
|
|
if (!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image", "1.1")) return false;
|
|
if (!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute", "1.1") && !document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Animation", "1.1") && !document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Text", "1.1")) return false;
|
|
return true;
|
|
}
|
|
|
|
function fallbackSVG() {
|
|
// Replace all images extensions from .svg to .png if browser doesn't support SVG files.
|
|
if (supportsSVG()) return;
|
|
for (var i = 0, nd = document.getElementsByTagName('*'), n = nd.length; i < n; i++) {
|
|
if (nd[i].nodeName === 'IMG' && /.*\.svg$/.test(nd[i].src)) nd[i].src = nd[i].src.slice(0, -3) + 'png';
|
|
if (/\.svg/.test(getStyle(nd[i], 'background-image'))) nd[i].style.backgroundImage = getStyle(nd[i], 'background-image').replace('.svg', '.png');
|
|
if (/\.svg/.test(getStyle(nd[i], 'background'))) nd[i].style.background = getStyle(nd[i], 'background').replace('.svg', '.png');
|
|
}
|
|
}
|
|
|
|
function onTouchClick(e, callback, callbackClick) {
|
|
// Detect and handle clicks using click and touch events while preventing accidental or ghost clicks.
|
|
var timeout = 1000,
|
|
srcEvent = e,
|
|
touchEndListener = function(e) {
|
|
// Call callback if touch events match the patterns of a click.
|
|
removeEvent(t, 'touchend', touchEndListener);
|
|
setClickTimeout();
|
|
if (Math.abs(e.changedTouches[0].pageX - x) > 20 || Math.abs(e.changedTouches[0].pageY - y) > 20) return;
|
|
callback(srcEvent);
|
|
},
|
|
wrongClickListener = function(e) {
|
|
// Cancel click events on different targets within timeframe.
|
|
// This avoids accidental clicks when the page is scrolled or updated due to the 300ms click event delay on mobiles.
|
|
removeEvent(document.body, 'click', wrongClickListener);
|
|
if (!clickReady() && getEvent(e, 'target') !== t) cancelEvent(e);
|
|
},
|
|
setClickTimeout = function() {
|
|
// Update timeout during which click events will be blocked.
|
|
document.body.setAttribute('data-touchtimeout', new Date().getTime() + timeout);
|
|
},
|
|
clickReady = function() {
|
|
// Check if timeout during click events are blocked has expired.
|
|
var ti = document.body.getAttribute('data-touchtimeout');
|
|
return (ti === null || ti === '' || parseInt(ti, 10) < new Date().getTime());
|
|
};
|
|
if (callbackClick === undefined) callbackClick = function() {};
|
|
// Apply appropriate actions according to each event type.
|
|
switch (getEvent(e, 'type')) {
|
|
case 'touchstart':
|
|
// Save initial touchstart coordinates and listen for touchend events and accidental click events.
|
|
var x = e.changedTouches[0].pageX,
|
|
y = e.changedTouches[0].pageY,
|
|
t = e.changedTouches[0].target;
|
|
setClickTimeout();
|
|
addEvent(t, 'touchend', touchEndListener);
|
|
addEvent(document.body, 'click', wrongClickListener);
|
|
setTimeout(function() {
|
|
removeEvent(document.body, 'click', wrongClickListener);
|
|
}, timeout);
|
|
break;
|
|
case 'click':
|
|
// Call callback on click in the absence of a recent touchstart event to prevent ghost clicks.
|
|
// Always call callbackClick to let it cancel click events on links.
|
|
callbackClick(srcEvent);
|
|
if (!clickReady()) return;
|
|
callback(srcEvent);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function mobileMenuShow(e) {
|
|
// Show the mobile menu when the visitors touch the menu icon.
|
|
var show = function() {
|
|
var mm = document.getElementById('menusimple');
|
|
var ml = document.getElementById('langselect');
|
|
mm.style.display = ml.style.display = (mm.style.display === 'block') ? '' : 'block';
|
|
addClass(mm, 'menutap');
|
|
cancelEvent(e);
|
|
};
|
|
onTouchClick(e, show);
|
|
}
|
|
|
|
function mobileMenuHover(e) {
|
|
// Prevent mobile menu to shrink on hover to prevent accidental clicks on other entries.
|
|
var t = getEvent(e, 'target'),
|
|
fn = (t.parentNode.className.indexOf('hover') === -1) ? addClass : removeClass,
|
|
initHover = function() {
|
|
if (t.nodeName !== 'A') return;
|
|
if (fn === removeClass && !hasSubItems(t)) return;
|
|
var p = t;
|
|
while (p.parentNode.nodeName === 'UL' || p.parentNode.nodeName === 'LI') p = p.parentNode;
|
|
for (var i = 0, nds = p.getElementsByTagName('LI'), n = nds.length; i < n; i++) {
|
|
if (nds[i] === t.parentNode) continue;
|
|
removeClass(nds[i], 'active');
|
|
if (hasSubItems(nds[i])) continue;
|
|
removeClass(nds[i], 'hover');
|
|
}
|
|
while (t !== p) {
|
|
if (t.nodeName === 'LI') {
|
|
fn(t, 'hover');
|
|
fn(t, 'active');
|
|
}
|
|
t = t.parentNode;
|
|
}
|
|
},
|
|
hasSubItems = function(t) {
|
|
while (t.nodeName !== 'LI') t = t.parentNode;
|
|
return (t.getElementsByTagName('UL').length > 0);
|
|
},
|
|
// Prevent clicks on parent element links in the menu.
|
|
filterClick = function(e) {
|
|
var t = getEvent(e, 'target');
|
|
if (t.nodeName !== 'A') return;
|
|
if (hasSubItems(t)) cancelEvent(e);
|
|
};
|
|
onTouchClick(e, initHover, filterClick);
|
|
}
|
|
|
|
function addAnchorLinks() {
|
|
// Apply anchor links icon on each title displayed on CSS hover.
|
|
var nodes = [];
|
|
var tags = ['H2', 'H3', 'H4', 'H5', 'H6'];
|
|
for (var i = 0, n = tags.length; i < n; i++) {
|
|
for (var ii = 0, t = document.getElementsByTagName(tags[i]), nn = t.length; ii < nn; ii++) nodes.push(t[ii]);
|
|
}
|
|
for (var i = 0, n = nodes.length; i < n; i++) {
|
|
if (!nodes[i].id) continue;
|
|
if (nodes[i].getElementsByTagName('A').length > 0 && nodes[i].getElementsByTagName('A')[0].innerHTML === '') return;
|
|
addClass(nodes[i], 'anchorAf');
|
|
var anc = document.createElement('A');
|
|
anc.href = '#' + nodes[i].id;
|
|
nodes[i].insertBefore(anc, nodes[i].firstChild);
|
|
}
|
|
}
|