1/** 2 * details-shim.js 3 * A pure JavaScript (no dependencies) solution to make HTML5 4 * Details/Summary tags work in unsupportive browsers 5 * 6 * Copyright (c) 2013 Tyler Uebele 7 * Released under the MIT license. See included LICENSE.txt 8 * or http://opensource.org/licenses/MIT 9 * 10 * latest version available at https://github.com/tyleruebele/details-shim 11 */ 12 13/** 14 * Enable proper operation of <details> tags in unsupportive browsers 15 * 16 * @param Details details element to shim 17 * @returns {boolean} false on error 18 */ 19function details_shim(Details) { 20 // For backward compatibility, if no DOM Element is sent, call init() 21 if (!Details || !('nodeType' in Details) || !('tagName' in Details)) { 22 return details_shim.init(); 23 } 24 25 var Summary; 26 // If we were passed a details tag, find its summary tag 27 if ('details' == Details.tagName.toLowerCase()) { 28 // Assume first found summary tag is the corresponding summary tag 29 Summary = Details.getElementsByTagName('summary')[0]; 30 31 // If we were passed a summary tag, find its details tag 32 } else if (!!Details.parentNode 33 && 'summary' == Details.tagName.toLowerCase() 34 ) { 35 Summary = Details; 36 Details = Summary.parentNode; 37 } else { 38 // An invalid parameter was passed for Details 39 return false; 40 } 41 42 // If the details tag is natively supported or already shimmed 43 if ('boolean' == typeof Details.open) { 44 // If native, remove custom classes 45 if (!Details.getAttribute('data-open')) { 46 Details.className = Details.className 47 .replace(/\bdetails_shim_open\b|\bdetails_shim_closed\b/g, ' '); 48 } 49 return false; 50 } 51 52 // Set initial class according to `open` attribute 53 var state = Details.outerHTML 54 // OR older firefox doesn't have .outerHTML 55 || new XMLSerializer().serializeToString(Details); 56 state = state.substring(0, state.indexOf('>')); 57 // Read: There is an open attribute, and it's not explicitly empty 58 state = (-1 != state.indexOf('open') && -1 == state.indexOf('open=""')) 59 ? 'open' 60 : 'closed' 61 ; 62 Details.setAttribute('data-open', state); 63 Details.className += ' details_shim_' + state; 64 65 // Add onclick handler to toggle visibility class 66 Summary.addEventListener 67 ? Summary.addEventListener('click', function() { details_shim.toggle(Details); }) 68 : Summary.attachEvent && Summary.attachEvent('onclick', function() { details_shim.toggle(Details); }) 69 ; 70 71 Object.defineProperty(Details, 'open', { 72 get: function() { 73 return 'open' == this.getAttribute('data-open'); 74 }, 75 set: function(state) { 76 details_shim.toggle(this, state); 77 } 78 }); 79 80 // wrap text nodes in span to expose them to css 81 for (var j = 0; j < Details.childNodes.length; j++) { 82 if (Details.childNodes[j].nodeType == 3 83 && /[^\s]/.test(Details.childNodes[j].data) 84 ) { 85 var span = document.createElement('span'); 86 var text = Details.childNodes[j]; 87 Details.insertBefore(span, text); 88 Details.removeChild(text); 89 span.appendChild(text); 90 } 91 } 92} // details_shim() 93 94/** 95 * Toggle the open state of specified <details> tag 96 * @param Details The <details> tag to toggle 97 * @param state Optional override state 98 */
99details_shim.toggle = function(Details, state) { 100 // If state was not passed, seek current state 101 if ('undefined' === typeof state) { 102 // new state 103 state = Details.getAttribute('data-open') == 'open' 104 ? 'closed' 105 : 'open' 106 ; 107 } else { 108 // Sanitize the input, expect boolean, force string 109 // Expecting boolean means even 'closed' will result in an open 110 // This is the behavior of the natively supportive browsers 111 state = !!state ? 'open' : 'closed'; 112 } 113 114 Details.setAttribute('data-open', state); 115 // replace previous open/close class 116 Details.className = Details.className 117 .replace(/\bdetails_shim_open\b|\bdetails_shim_closed\b/g, ' ') 118 + ' details_shim_' + state; 119}; 120 121/** 122 * Run details_shim() on each details tag 123 */ 124details_shim.init = function() { 125 // Because <details> must include a <summary>, 126 // collecting <summary> tags collects *valid* <details> tags 127 var Summaries = document.getElementsByTagName('summary'); 128 for (var i = 0; i < Summaries.length; i++) { 129 details_shim(Summaries[i]); 130 } 131}; 132 133// Run details_shim.init() when the page loads 134window.addEventListener 135 ? window.addEventListener('load', details_shim.init, false) 136 : window.attachEvent && window.attachEvent('onload', details_shim.init) 137;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.