1'use strict'; 2 3// js2016-10-25 4 5/** 6 * Part 1: 7 * Enable proper operation of <details> tags in unsupportive browsers (IE/Edge) 8 9 * based on details-shim.js from (c) 2013 Tyler Uebele, under the MIT license 10 */ 11 12var dbgShim={ 13 details: true 14 }; 15 16// utils ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 17 18function _tagname (e) { return e.tagName.toLowerCase(); } 19 20function _ins_css (id, stylestr) 21{ //var stylesheet=document.styleSheets[0]; 22 var stylesheet=document.getElementById(id); 23 if (!stylesheet) 24 { stylesheet=document.createElement('style'); 25 stylesheet.id=id; 26 stylesheet.type='text/css'; 27 // stylesheet.appendChild(document.createTextNode(stylestr)); 28 document.head.appendChild(stylesheet); 29 } 30 if (dbgShim.details) console.log(document.styleSheets); 31 if (dbgShim.details) console.log(stylesheet, stylestr); 32 //stylesheet.insertRule(stylestr, 0/*stylesheet.cssRules.length*/); 33 stylesheet.innerHTML=stylestr; 34} 35 36function _add_event (el,evname,fun, xtra) 37{ var args = Array.prototype.slice.call(arguments, 1); 38 el.addEventListener ? el.addEventListener.apply(el,args) 39 : el.attachEvent && el.attachEvent('on' + evname, fun) 40} 41 42function _foreach (es, fun) { return Array.prototype.forEach.call(es,fun) } 43 44// forward for namespace ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 45 46/** 47 * Enable proper operation of <details> tags in unsupportive browsers 48 * 49 * @param Details details element to shim 50 * @returns {boolean} false on error 51 */ 52function details_shim (Details) { return details_shim.shim(Details); } 53 54// helper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 55 56details_shim.test_native = function (e) // _test_native_support 57{ if ('boolean' == typeof details_shim.native_support) return details_shim.native_support; 58 var details=e || document.createElement('details'); 59 details_shim.native_support = 'boolean' == typeof details.open; 60 if (dbgShim.details) //console.log('details_shim.test_native:', details, details_shim.native_support); 61 return details_shim.native_support; 62} 63 64details_shim.ins_css = function () 65{ _ins_css('detailshim', 66 'details { display: block; }\ 67 details[data-shim] > summary { display: block; } /* list-item dont interfere */\ 68 details[data-shim="closed"] > * { display: none;}\ 69 details[data-shim="closed"] > summary { display: block; }\ 70 details[data-shim="open"] > summary { display: block; }\ 71 details[data-shim] > summary::before { display: inline-block; padding: 0; }\ 72 details[data-shim="closed"] > summary::before\ 73 { content: "\\25b6"; padding: 0 0.1em; margin-right: 0.4em; font-size: 0.9em;}\ 74 details[data-shim="open"] > summary::before { content: "\\25bc"; margin-right: 0.35em;}'); 75} 76 77// details shim ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 78 79details_shim.shim = function (Details) 80{ 81 // For backward compatibility, if no DOM Element is sent, call init() 82 if (!Details || !('nodeType' in Details) || !('tagName' in Details)) 83 return details_shim.init(); 84 85 var Summary; 86 // If we were passed a details tag, find its summary tag 87 if ('details' == _tagname(Details)) { 88 // Assume first found summary tag is the corresponding summary tag 89 Summary = Details.getElementsByTagName('summary')[0]; 90 91 // If we were passed a summary tag, find its details tag 92 } else if (!!Details.parentNode && 'summary' == _tagname(Details)) { 93 Summary = Details; 94 Details = Summary.parentNode; 95 } else { 96 // An invalid parameter was passed for Details 97 return false; 98 } 99 100 // If the details tag is natively supported or already shimmed 101 if (details_shim.test_native(Details) 102 || Details.getAttribute('data-shim') // ??? 103 ) return false; 104 105 // Set initial class according to `open` attribute 106 var state = Details.outerHTML; 107 // OR older firefox doesn't have .outerHTML 108 // || new XMLSerializer().serializeToString(Details); 109 state = state.substring(0, state.indexOf('>')); 110 // Read: There is an open attribute, and it's not explicitly empty 111 state = (-1 != state.indexOf('open') && -1 == state.indexOf('open=""')) 112 ? 'open' : 'closed'; 113 114 Details.setAttribute('data-shim', state); // TODO: last? 115 116 // make it focusable 117 if (!Summary.getAttribute('tabindex')) Summary.setAttribute('tabindex',0); 118
119 // Add onclick handler to toggle visibility class 120 _add_event(Summary,'click', function () { details_shim.toggle(Details); }); 121 _add_event(Summary,'keydown',function (ev) { 122 if (dbgShim.details) console.log('detailshim key-event:',ev); 123 if (ev.key=='Enter' || ev.keyCode==13 || ev.key==' ' || ev.charCode==32) 124 { details_shim.toggle(Details); ev.preventDefault(); } 125 }); 126 127 Object.defineProperty(Details, 'open', { 128 get: function() { 129 return 'open' == this.getAttribute('data-shim'); 130 }, 131 set: function(state) { 132 details_shim.toggle(this, state); 133 } 134 }); 135 136 // wrap text nodes in span to expose them to css 137 _foreach(Details.childNodes, function (n) { 138 if (n.nodeType == 3 && /[^\s]/.test(n.data)) // non-empty textnode 139 { var span = document.createElement('span'); 140 Details.insertBefore(span, n); 141 Details.removeChild(n); 142 span.appendChild(n); 143 } 144 }); 145} // end of details_shim() 146 147/** 148 * Toggle the open state of specified <details> tag 149 * @param Details The <details> tag to toggle 150 * @param state Optional override state 151 */
152details_shim.toggle = function(Details, state) { 153 var oldstate = Details.getAttribute('data-shim'); 154 // If state was not passed, seek current state 155 if ('undefined' === typeof state) { 156 // new state 157 state = oldstate=='open' ? 'closed' : 'open'; 158 } else { 159 // Sanitize the input, expect boolean, force string 160 // Expecting boolean means even 'closed' will result in an open 161 // This is the behavior of the natively supportive browsers 162 state = !!state ? 'open' : 'closed'; 163 } 164 165 // replace previous open/close state 166 if (state != oldstate) // 1st defense line against recurrent recall 167 { Details.setAttribute('data-shim', state); 168 try { 169 var ie8=!document.addEventListener; // 2nd defense line, more specific 170 if (state == 'open') 171 ie8 ? Details.setAttribute('OPEN', state, 1) : Details.setAttribute('open', state); 172 else ie8 ? Details.removeAttribute('OPEN', 1) : Details.removeAttribute('open'); 173 } catch (x) {} 174 } 175 if (dbgShim.details) console.log('details_shim.toggle: ', Details, state); 176 // TODO: Allow Links inside <summary> 177}; 178 179/** 180 * Run details_shim() on each details tag 181 */ 182details_shim.init = function() { 183 // untrue: Because <details> must include a <summary>, 184 // collecting <summary> tags collects *valid* <details> tags 185 // but: for our purpose we just assume every <details> has 186 // exactly one <summary>. 187 // also we ignore "future content", 188 // the possibility to inject DOM per JavaScript 189 if (details_shim.test_native()) return; 190 var Summaries = document.getElementsByTagName('summary'); 191 if (Summaries.length == 0) return; 192 details_shim.ins_css(); 193 for (var i=0; i<Summaries.length; ++i) { details_shim.shim(Summaries[i]); } 194}; 195 196// Run details_shim.init() when the page loads 197_add_event(window,'load',details_shim.init, false);
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.