Last active
March 8, 2016 16:04
-
-
Save sylvainpolletvillard/ea8868cb88081969605c to your computer and use it in GitHub Desktop.
<details> polyfill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* FORKED FROM: https://gist.githubusercontent.com/remy/370590/raw/0ade67d1b83b31c8eab1acc1f354ce425d290377/details.js | |
*/ | |
(function (window, document) { | |
if ('open' in document.createElement('details')) return; // no polyfill necessary | |
var addEvent = function (el, type, fn) { | |
if (el && el.nodeName || el === window) { | |
if (document.addEventListener) { | |
el.addEventListener(type, fn, false); | |
} else { | |
el.attachEvent('on' + type, function () { return fn.call(el, window.event); }); | |
} | |
} | |
} | |
// find the first /real/ node | |
function firstNode(source) { | |
if (source.firstChild.nodeName != "#text") { | |
return source.firstChild; | |
} else { | |
source = source.firstChild; | |
do { | |
source = source.nextSibling; | |
} while (source && source.nodeName == '#text'); | |
return source || null; | |
} | |
} | |
function isSummary(el) { | |
var nn = el.nodeName.toUpperCase(); | |
if (nn == 'DETAILS') { | |
return false; | |
} else if (nn == 'SUMMARY') { | |
return true; | |
} else { | |
return isSummary(el.parentNode); | |
} | |
} | |
function toggleDetails(event) { | |
// more sigh - need to check the clicked object | |
var keypress = event.type == 'keypress', | |
target = event.target || event.srcElement; | |
if (keypress || isSummary(target)) { | |
if (keypress) { | |
// if it's a keypress, make sure it was enter or space | |
keypress = event.which || event.keyCode; | |
if (keypress == 32 || keypress == 13) { | |
// all's good, go ahead and toggle | |
} else { | |
return; | |
} | |
} | |
var open = this.getAttribute('open'); | |
if (open === null) { | |
this.setAttribute('open', 'open'); | |
} else { | |
this.removeAttribute('open'); | |
} | |
// trigger reflow (required in IE - sometimes in Safari too) | |
setTimeout(function () { | |
document.body.className = document.body.className; | |
}, 13); | |
if (keypress) { | |
event.preventDefault && event.preventDefault(); | |
return false; | |
} | |
} | |
} | |
function addStyle() { | |
var style = document.createElement('style'), | |
head = document.getElementsByTagName('head')[0], | |
rules = ['details{display: block;}','details > *{display: none;}','details > summary:first-child{display: block;cursor: pointer;}','details[open],details[open] > *{display: block;}']; | |
style.innerHTML = rules.join("\n"); | |
head.insertBefore(style, head.firstChild); | |
} | |
function applyPolyfill(){ | |
var details = document.getElementsByTagName('details'), | |
wrapper, | |
i = details.length, | |
j, | |
first = null; | |
while (i--) { | |
if(details[i].polyfill === true){ continue; } // this element is already polyfilled | |
details[i].polyfill = true; | |
first = firstNode(details[i]); | |
if (first != null && first.nodeName.toUpperCase() == 'SUMMARY') { | |
// we've found that there's a details label already | |
} else { | |
first = document.createElement('summary'); | |
first.appendChild(document.createTextNode('Details')); | |
if (details[i].firstChild) { | |
details[i].insertBefore(first, details[i].firstChild); | |
} else { | |
details[i].appendChild(first); | |
} | |
} | |
// this feels *really* nasty, but we can't target details :text in css :( | |
j = details[i].childNodes.length; | |
while (j--) { | |
if (details[i].childNodes[j].nodeName === '#text' | |
&& (details[i].childNodes[j].nodeValue||'').replace(/\s/g, '').length) { | |
wrapper = document.createElement('text'); | |
wrapper.appendChild(details[i].childNodes[j]); | |
details[i].insertBefore(wrapper, details[i].childNodes[j]); | |
} | |
} | |
first.legend = true; | |
first.tabIndex = 0; | |
addEvent(details[i], 'click', toggleDetails); | |
addEvent(details[i], 'keypress', toggleDetails); | |
} | |
} | |
document.createElement('details'); | |
addStyle(); | |
applyPolyfill(); // apply polyfill for existing <detail> elements | |
setInterval(applyPolyfill, 200); // regularly check if new <details> have been appended | |
})(window, document); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment