UNPKG

accordion

Version:

Silky-smooth accordion widgets with no external dependencies.

145 lines (116 loc) 4.1 kB
"use strict"; export const touchEnabled = "ontouchstart" in document.documentElement; export const pressEvent = touchEnabled ? "touchend" : "click"; /** * Name of the onTransitionEnd event supported by this browser. * @const {String} transitionEnd */ export const transitionEnd = (function(){ const names = "transitionend webkitTransitionEnd oTransitionEnd otransitionend".split(" "); for(let i = 0; i < 4; ++i) if("on" + names[i].toLowerCase() in window) return names[i]; return names[0]; }()); /** * Conditionally add or remove a token from a token-list. * * @param {DOMTokenList} list * @param {String} token * @param {Boolean} enabled */ export function setToken(list, token, enabled){ enabled ? list.add(token) : list.remove(token); } /** * Stop a function from firing too quickly. * * Returns a copy of the original function that runs only after the designated * number of milliseconds have elapsed. Useful for throttling onResize handlers. * * @param {Function} fn - Function to debounce * @param {Number} [limit=0] - Threshold to stall execution by, in milliseconds. * @param {Boolean} [asap=false] - Call function *before* threshold elapses, not after. * @return {Function} */ export function debounce(fn, limit = 0, asap = false){ let started, context, args, timing; const delayed = function(){ const timeSince = Date.now() - started; if(timeSince >= limit){ if(!asap) fn.apply(context, args); if(timing) clearTimeout(timing); timing = context = args = null; } else timing = setTimeout(delayed, limit - timeSince); }; // Debounced copy of original function return function(){ context = this, args = arguments; if(!limit) return fn.apply(context, args); started = Date.now(); if(!timing){ if(asap) fn.apply(context, args); timing = setTimeout(delayed, limit); } }; } export const uniqueID = (function(){ const IDs = {}; const indexes = {}; /** * Generate a unique ID for a DOM element. * * By default, minimalist IDs like "_1" or "_2" are generated using internally * tracked incrementation. Uglier, more collision-proof IDs can be generated by * passing a truthy value to the function's first argument. * * Irrespective of whether values are being generated simply or randomly, the * document tree is always consulted first to ensure a duplicate ID is never * returned. * * @param {String} prefix - Prefix prepended to result. Default: "_" * @param {Boolean} random - Generate collision-proof IDs using random symbols * @param {Number} length - Length of random passwords. Default: 6 * @return {String} */ function uniqueID(prefix, complex, length){ length = +(length || 6); let result = (prefix = prefix || "_"); // Simple IDs if(!complex){ // Set this prefix's starting index if it's not been used yet if(!indexes[prefix]) indexes[prefix] = 0; result += ++indexes[prefix]; } // Uglier, more collision-proof IDs else{ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; result += chars[ Math.round(Math.random() * 51) ]; while(result.length < length) result += chars[ Math.round(Math.random() * 61)]; } return IDs[result] || document.getElementById(result) ? uniqueID(prefix, complex) : (IDs[result] = true, result); } return uniqueID; }()); // Name of the CSSOM property used by this browser for CSS transforms export const cssTransform = (function(n){ s = document.documentElement.style; if((prop = n.toLowerCase()) in s) return prop; for(var prop, s, p = "Webkit Moz Ms O Khtml", p = (p.toLowerCase() + p).split(" "), i = 0; i < 10; ++i) if((prop = p[i]+n) in s) return prop; return ""; }("Transform")); // Whether 3D transforms are supported by this browser export const css3DSupported = (function(propName){ const e = document.createElement("div"), s = e.style; const v = [["translateY(", ")"], ["translate3d(0,", ",0)"]]; try{ s[propName] = v[1].join("1px"); } catch(e){} return v[+!!s[propName]] === v[1]; }(cssTransform));