1/*! ie11CustomProperties.js v4.1.0 | MIT License | https://git.io/fjXMN */ 2!(function () { 3 'use strict' 4 5 // check for support 6 var testEl = document.createElement('i') 7 testEl.style.setProperty('--x', 'y') 8 if (testEl.style.getPropertyValue('--x') === 'y' || !testEl.msMatchesSelector) return 9 10 if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.msMatchesSelector 11 12 var listeners = [], 13 root = document, 14 Observer 15 16 function qsa(el, selector) { 17 try { 18 return el.querySelectorAll(selector) 19 } catch (e) { 20 // console.warn('the Selector '+selector+' can not be parsed'); 21 return [] 22 } 23 } 24 function onElement(selector, callback) { 25 var listener = { 26 selector: selector, 27 callback: callback, 28 elements: new WeakMap(), 29 } 30 var els = qsa(root, listener.selector), 31 i = 0, 32 el 33 while ((el = els[i++])) { 34 listener.elements.set(el, true) 35 listener.callback.call(el, el) 36 } 37 listeners.push(listener) 38 if (!Observer) { 39 Observer = new MutationObserver(checkMutations) 40 Observer.observe(root, { 41 childList: true, 42 subtree: true, 43 }) 44 } 45 checkListener(listener) 46 } 47 function checkListener(listener, target) { 48 var i = 0, 49 el, 50 els = [] 51 try { 52 target && target.matches(listener.selector) && els.push(target) 53 } catch (e) {} 54 if (loaded) { 55 // ok? check inside node on innerHTML - only when loaded 56 Array.prototype.push.apply(els, qsa(target || root, listener.selector)) 57 } 58 while ((el = els[i++])) { 59 if (listener.elements.has(el)) continue 60 listener.elements.set(el, true) 61 listener.callback.call(el, el) 62 } 63 } 64 function checkListeners(inside) { 65 var i = 0, 66 listener 67 while ((listener = listeners[i++])) checkListener(listener, inside) 68 } 69 function checkMutations(mutations) { 70 var j = 0, 71 i, 72 mutation, 73 nodes, 74 target 75 while ((mutation = mutations[j++])) { 76 ;(nodes = mutation.addedNodes), (i = 0) 77 while ((target = nodes[i++])) target.nodeType === 1 && checkListeners(target) 78 } 79 } 80 81 var loaded = false 82 document.addEventListener('DOMContentLoaded', function () { 83 loaded = true 84 }) 85 86 // svg polyfills 87 function copyProperty(prop, from, to) { 88 var desc = Object.getOwnPropertyDescriptor(from, prop) 89 Object.defineProperty(to, prop, desc) 90 } 91 if (!('classList' in Element.prototype)) { 92 copyProperty('classList', HTMLElement.prototype, Element.prototype) 93 } 94 if (!('innerHTML' in Element.prototype)) { 95 copyProperty('innerHTML', HTMLElement.prototype, Element.prototype) 96 } 97 if (!('runtimeStyle' in Element.prototype)) { 98 // new 99 copyProperty('runtimeStyle', HTMLElement.prototype, Element.prototype) 100 } 101 if (!('sheet' in SVGStyleElement.prototype)) { 102 Object.defineProperty(SVGStyleElement.prototype, 'sheet', { 103 get: function () { 104 var all = document.styleSheets, 105 i = 0, 106 sheet 107 while ((sheet = all[i++])) { 108 if (sheet.ownerNode === this) return sheet 109 } 110 }, 111 }) 112 } 113 114 // main logic 115 var styles_of_getter_properties = {} 116 var drawQueue = new Set() 117 var collecting = false 118 var drawing = false 119 120 // cached regexps, better performance 121 var regFindSetters = /([\s{;])(--([A-Za-z0-9-_]*)\s*:([^;!}{]+)(!important)?)(?=\s*([;}]|$))/g 122 var regFindGetters = /([{;]\s*)([A-Za-z0-9-_]+\s*:[^;}{]*var\([^!;}{]+)(!important)?(?=\s*([;}$]|$))/g 123 var regRuleIEGetters = /-ieVar-([^:]+):/g 124 var regRuleIESetters = /-ie-([^};]+)/g 125 //const regHasVar = /var\(/; 126 var regPseudos = /:(hover|active|focus|target|visited|link|:before|:after|:first-letter|:first-line)/ 127 128 function foundStyle(el) { 129 if (el.ieCP_polyfilled) return 130 if (el.ieCP_elementSheet) return 131 if (!el.sheet) return 132 if (el.href) { 133 return fetchCss(el.href, function (css) { 134 var newCss = rewriteCss(css) 135 if (css === newCss) return 136 activateStyleElement(el, newCss) 137 }) 138 } 139 140 var css = el.innerHTML 141 var newCss = rewriteCss(css) 142 if (css === newCss) return 143 activateStyleElement(el, newCss) 144 } 145 onElement('style', foundStyle) 146 onElement('link[rel="stylesheet"]', foundStyle) 147 // immediate, to pass w3c-tests, bud its a bad idea 148 // addEventListener('DOMNodeInserted',function(e){ e.target.tagName === 'STYLE' && foundStyle(e.target); }); 149 150 onElement('[ie-style]', function (el) { 151 var newCss = rewriteCss('{' + el.getAttribute('ie-style')).substr(1) 152 el.style.cssText += ';' + newCss 153 var found = parseRewrittenStyle(el.style) 154 if (found.getters) addGetterElement(el, found.getters, '%styleAttr') 155 if (found.setters) addSetterElement(el, found.setters) 156 }) 157 158 // ie has a bug, where unknown properties at pseudo-selectors are computed at the element 159 // #el::after { -content:'x'; } => getComputedStyle(el)['-content'] == 'x' 160 // should we add something like -ieVar-pseudo_after-content:'x'? 161 function rewriteCss(css) {
162 /* uncomment if spec finished and needed by someone 163 css = css.replace(/@property ([^{]+){([^}]+)}/, function($0, prop, body){ 164 prop = prop.trim(); 165 const declaration = {name:prop}; 166 body.split(';').forEach(function(pair){ 167 const x = pair.split(':'); 168 if (x[1]) declaration[ x[0].trim() ] = x[1]; 169 }); 170 declaration['inherits'] = declaration['inherits'].trim()==='true' ? true : false; 171 declaration['initialValue'] = declaration['initial-value']; 172 CSS.registerProperty(declaration) 173 return '/*\n @property ... removed \n*'+'/'; 174 }); 175 */ 176 return css 177 .replace(regFindSetters, function ($0, $1, $2, $3, $4, important) { 178 return $1 + '-ie-' + (important ? 'â' : '') + $3 + ':' + encodeValue($4) 179 }) 180 .replace(regFindGetters, function ($0, $1, $2, important) { 181 return $1 + '-ieVar-' + (important ? 'â' : '') + $2 + '; ' + $2 // keep the original, so chaining works "--x:var(--y)" 182 }) 183 } 184 function encodeValue(value) { 185 return value 186 return value.replace(/ /g, 'â£') 187 } 188 var keywords = { initial: 1, inherit: 1, revert: 1, unset: 1 } 189 function decodeValue(value) { 190 return value 191 if (value === undefined) return 192 value = value.replace(/â£/g, ' ') 193 const trimmed = value.trim() 194 if (keywords[trimmed]) return trimmed 195 return value 196 } 197 198 function parseRewrittenStyle(style) { 199 // less memory then parameter cssText? 200 201 // ie11 can access unknown properties in stylesheets only if accessed a dashed known property 202 style['z-index'] === style && x() // do something (compare and call) just for minifiers 203 204 const cssText = style.cssText 205 var matchesGetters = cssText.match(regRuleIEGetters), 206 j, 207 match 208 if (matchesGetters) { 209 var getters = [] // eg. [border,color] 210 for (j = 0; (match = matchesGetters[j++]); ) { 211 let propName = match.slice(7, -1) 212 if (propName[0] === 'â') propName = propName.substr(1) 213 getters.push(propName) 214 215 if (!styles_of_getter_properties[propName]) styles_of_getter_properties[propName] = [] 216 styles_of_getter_properties[propName].push(style) 217 } 218 } 219 var matchesSetters = cssText.match(regRuleIESetters) 220 if (matchesSetters) { 221 var setters = {} // eg. [--color:#fff, --padding:10px]; 222 for (j = 0; (match = matchesSetters[j++]); ) { 223 let x = match.substr(4).split(':') 224 let propName = x[0] 225 let propValue = x[1] 226 if (propName[0] === 'â') propName = propName.substr(1) 227 setters[propName] = propValue 228 } 229 } 230 return { getters: getters, setters: setters } 231 } 232 function activateStyleElement(style, css) { 233 style.sheet.cssText = css 234 style.ieCP_polyfilled = true 235 var rules = style.sheet.rules, 236 i = 0, 237 rule // cssRules = CSSRuleList, rules = MSCSSRuleList 238 while ((rule = rules[i++])) { 239 const found = parseRewrittenStyle(rule.style) 240 if (found.getters) addGettersSelector(rule.selectorText, found.getters) 241 if (found.setters) addSettersSelector(rule.selectorText, found.setters) 242 243 // mediaQueries: redraw the hole document 244 // better add events for each element? 245 const media = rule.parentRule && rule.parentRule.media && rule.parentRule.media.mediaText 246 if (media && (found.getters || found.setters)) { 247 matchMedia(media).addListener(function () { 248 drawTree(document.documentElement) 249 }) 250 } 251 } 252 redrawStyleSheets() 253 } 254 255 function addGettersSelector(selector, properties) { 256 selectorAddPseudoListeners(selector) 257 onElement(unPseudo(selector), function (el) { 258 addGetterElement(el, properties, selector) 259 drawElement(el) 260 }) 261 } 262 function addGetterElement(el, properties, selector) { 263 var i = 0, 264 prop, 265 j 266 const selectors = selector.split(',') // split grouped selectors 267 el.setAttribute('iecp-needed', true) 268 if (!el.ieCPSelectors) el.ieCPSelectors = {} 269 while ((prop = properties[i++])) { 270 for (j = 0; (selector = selectors[j++]); ) { 271 const parts = selector.trim().split('::') 272 if (!el.ieCPSelectors[prop]) el.ieCPSelectors[prop] = [] 273 el.ieCPSelectors[prop].push({ 274 selector: parts[0], 275 pseudo: parts[1] ? '::' + parts[1] : '', 276 }) 277 } 278 } 279 } 280 function addSettersSelector(selector, propVals) { 281 selectorAddPseudoListeners(selector) 282 onElement(unPseudo(selector), function (el) { 283 addSetterElement(el, propVals) 284 }) 285 } 286 function addSetterElement(el, propVals) { 287 if (!el.ieCP_setters) el.ieCP_setters = {} 288 for (var prop in propVals) { 289 // eg. {foo:#fff, bar:baz} 290 el.ieCP_setters['--' + prop] = 1 291 } 292 drawTree(el) 293 } 294 295 function redrawStyleSheets() { 296 for (var prop in styles_of_getter_properties) { 297 let styles = styles_of_getter_properties[prop] 298 for (var i = 0, style; (style = styles[i++]); ) { 299 if (style.owningElement) continue 300 var value = style['-ieVar-' + prop] 301 if (!value) continue 302 value = styleComputeValueWidthVars(getComputedStyle(document.documentElement), value) 303 if (value === '') continue 304 try { 305 style[prop] = value 306 } catch (e) {} 307 } 308 } 309 } 310 311 var pseudos = { 312 hover: { 313 on: 'mouseenter', 314 off: 'mouseleave', 315 }, 316 focus: { 317 on: 'focusin', 318 off: 'focusout', 319 }, 320 active: { 321 on: 'CSSActivate',
322 off: 'CSSDeactivate', 323 }, 324 } 325 function selectorAddPseudoListeners(selector) { 326 // ie11 has the strange behavoir, that groups of selectors are individual rules, but starting with the full selector: 327 // td, th, button { color:red } results in this rules: 328 // "td, th, button" | "th, th" | "th" 329 selector = selector.split(',')[0] 330 for (var pseudo in pseudos) { 331 var parts = selector.split(':' + pseudo) 332 if (parts.length > 1) { 333 var ending = parts[1].match(/^[^\s]*/) // ending elementpart of selector (used for not(:active)) 334 let sel = unPseudo(parts[0] + ending) 335 const listeners = pseudos[pseudo] 336 onElement(sel, function (el) { 337 el.addEventListener(listeners.on, drawTreeEvent) 338 el.addEventListener(listeners.off, drawTreeEvent) 339 }) 340 } 341 } 342 } 343 344 var CSSActive = null 345 document.addEventListener('mousedown', function (e) { 346 setTimeout(function () { 347 if (e.target === document.activeElement) { 348 var evt = document.createEvent('Event') 349 evt.initEvent('CSSActivate', true, true) 350 CSSActive = e.target 351 CSSActive.dispatchEvent(evt) 352 } 353 }) 354 }) 355 document.addEventListener('mouseup', function () { 356 if (CSSActive) { 357 var evt = document.createEvent('Event') 358 evt.initEvent('CSSDeactivate', true, true) 359 CSSActive.dispatchEvent(evt) 360 CSSActive = null 361 } 362 }) 363 364 function unPseudo(selector) { 365 return selector.replace(regPseudos, '').replace(':not()', '') 366 } 367 368 // draw queue 369 function drawElement(el) { 370 drawQueue.add(el) 371 if (collecting) return 372 collecting = true 373 requestAnimationFrame(function () { 374 //setImmediate(function(){ 375 collecting = false 376 drawing = true 377 drawQueue.forEach(_drawElement) 378 drawQueue.clear() 379 setTimeout(function () { 380 // mutationObserver will trigger delayed, requestAnimationFrame will miss some changes 381 drawing = false 382 }) 383 }) 384 } 385 386 var uniqueCounter = 0 387 function _drawElement(el) { 388 if (!el.ieCP_unique) { 389 // use el.uniqueNumber? but needs class for the css-selector => test performance 390 el.ieCP_unique = ++uniqueCounter 391 el.classList.add('iecp-u' + el.ieCP_unique) 392 } 393 var style = getComputedStyle(el) 394 let css = '' 395 396 el.runtimeStyle.cssText = '' // new 397 398 for (var prop in el.ieCPSelectors) { 399 var important = style['-ieVar-â' + prop] 400 let valueWithVar = important || style['-ieVar-' + prop] 401 if (!valueWithVar) continue // todo, what if '0' 402 var details = {} 403 var value = styleComputeValueWidthVars(style, valueWithVar, details) 404 //if (value==='initial') value = initials[prop]; 405 if (important) value += ' !important' 406 for (var i = 0, item; (item = el.ieCPSelectors[prop][i++]); ) { 407 // todo: split and use requestAnimationFrame? 408 if (item.selector === '%styleAttr') el.style[prop] = value // i dont know why but i initial have to set style also (seen in demo) 409 if (!important && details.allByRoot !== false) continue // dont have to draw root-properties 410 if (item.pseudo) { 411 css += item.selector + '.iecp-u' + el.ieCP_unique + item.pseudo + '{' + prop + ':' + value + '}\n' 412 } else { 413 el.runtimeStyle[prop] = value // new 414 } 415 } 416 } 417 elementSetCss(el, css) 418 } 419 function elementSetCss(el, css) { 420 if (!el.ieCP_styleEl && css) { 421 const styleEl = document.createElement('style') 422 styleEl.ieCP_elementSheet = 1 423 //el.appendChild(styleEl); // yes! self-closing tags can have style as children, but - if i set innerHTML, the stylesheet is lost 424 document.head.appendChild(styleEl) 425 el.ieCP_styleEl = styleEl 426 } 427 if (el.ieCP_styleEl) el.ieCP_styleEl.innerHTML = css 428 } 429 /* */ 430 431 function drawTree(target) { 432 if (!target) return 433 434 target === document.documentElement && redrawStyleSheets() // new 435 436 var els = target.querySelectorAll('[iecp-needed]') 437 if (target.hasAttribute && target.hasAttribute('iecp-needed')) drawElement(target) // self 438 for (var i = 0, el; (el = els[i++]); ) drawElement(el) // tree 439 } 440 function drawTreeEvent(e) { 441 drawTree(e.target) 442 } 443 444 function findVars(str, cb) { 445 // css value parser 446 let level = 0, 447 openedLevel = null, 448 lastPoint = 0, 449 newStr = '', 450 i = 0, 451 char, 452 insideCalc 453 while ((char = str[i++])) { 454 if (char === '(') { 455 ++level 456 if (openedLevel === null && str[i - 4] + str[i - 3] + str[i - 2] === 'var') { 457 openedLevel = level 458 newStr += str.substring(lastPoint, i - 4) 459 lastPoint = i 460 } 461 if (str[i - 5] + str[i - 4] + str[i - 3] + str[i - 2] === 'calc') { 462 insideCalc = level 463 } 464 } 465 if (char === ')' && openedLevel === level) { 466 let variable = str.substring(lastPoint, i - 1).trim(), 467 fallback
468 let x = variable.indexOf(',') 469 if (x !== -1) { 470 fallback = variable.slice(x + 1) 471 variable = variable.slice(0, x) 472 } 473 newStr += cb(variable, fallback, insideCalc) 474 lastPoint = i 475 openedLevel = null 476 } 477 if (char === ')') { 478 --level 479 if (insideCalc === level) insideCalc = null 480 } 481 } 482 newStr += str.substring(lastPoint) 483 return newStr 484 } 485 function styleComputeValueWidthVars(style, valueWithVars, details) { 486 return findVars(valueWithVars, function (variable, fallback, insideCalc) { 487 var value = style.getPropertyValue(variable) 488 if (insideCalc) value = value.replace(/^calc\(/, '(') // prevent nested calc 489 if (details && style.lastPropertyServedBy !== document.documentElement) details.allByRoot = false 490 if (value === '' && fallback) value = styleComputeValueWidthVars(style, fallback, details) 491 return value 492 }) 493 } 494 495 // mutation listener 496 var observer = new MutationObserver(function (mutations) { 497 if (drawing) return 498 for (var i = 0, mutation; (mutation = mutations[i++]); ) { 499 if (mutation.attributeName === 'iecp-needed') continue // why? 500 // recheck all selectors if it targets new elements? 501 drawTree(mutation.target) 502 } 503 }) 504 setTimeout(function () { 505 observer.observe(document, { attributes: true, subtree: true }) 506 }) 507 508 // :target listener 509 var oldHash = location.hash 510 addEventListener('hashchange', function (e) { 511 var newEl = document.getElementById(location.hash.substr(1)) 512 if (newEl) { 513 var oldEl = document.getElementById(oldHash.substr(1)) 514 drawTree(newEl) 515 drawTree(oldEl) 516 } else { 517 drawTree(document) 518 } 519 oldHash = location.hash 520 }) 521 522 // add owningElement to Element.style 523 var descriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'style') 524 var styleGetter = descriptor.get 525 descriptor.get = function () { 526 const style = styleGetter.call(this) 527 style.owningElement = this 528 return style 529 } 530 Object.defineProperty(HTMLElement.prototype, 'style', descriptor) 531 532 // add computedFor to computed style-objects 533 var originalGetComputed = getComputedStyle 534 window.getComputedStyle = function (el) { 535 var style = originalGetComputed.apply(this, arguments) 536 style.computedFor = el 537 //style.pseudoElt = pseudoElt; //not needed at the moment 538 return style 539 } 540 541 // getPropertyValue / setProperty hooks 542 var StyleProto = CSSStyleDeclaration.prototype 543 544 var oldGetP = StyleProto.getPropertyValue 545 StyleProto.getPropertyValue = function (property) { 546 this.lastPropertyServedBy = false 547 property = property.trim() 548 549 /* * 550 if (this.owningElement) { 551 const ieProperty = '-ieVar-'+property; 552 const iePropertyImportant = '-ieVar-â'+property; 553 let value = this[iePropertyImportant] || this[ieProperty]; 554 if (value !== undefined) { 555 // todo, test if syntax valid 556 return value; 557 } 558 } 559 /* */ 560 561 if (property[0] !== '-' || property[1] !== '-') return oldGetP.apply(this, arguments) 562 const undashed = property.substr(2) 563 const ieProperty = '-ie-' + undashed 564 const iePropertyImportant = '-ie-â' + undashed 565 let value = decodeValue(this[iePropertyImportant] || this[ieProperty]) 566 567 if (this.computedFor) { 568 // computedStyle 569 if (value !== undefined && !inheritingKeywords[value]) { 570 //if (regHasVar.test(value)) // todo: to i need this check?!!! i think its faster without 571 value = styleComputeValueWidthVars(this, value) 572 this.lastPropertyServedBy = this.computedFor 573 } else { 574 // inherited 575 if (inheritingKeywords[value] || !register[property] || register[property].inherits) { 576 //let el = this.pseudoElt ? this.computedFor : this.computedFor.parentNode; 577 let el = this.computedFor.parentNode 578 while (el.nodeType === 1) { 579 // how slower would it be to getComputedStyle for every element, not just with defined ieCP_setters 580 if (el.ieCP_setters && el.ieCP_setters[property]) { 581 // i could make 582 // value = el.nodeType ? getComputedStyle(this.computedFor.parentNode).getPropertyValue(property) 583 // but i fear performance, stupid? 584 var style = getComputedStyle(el) 585 var tmpVal = decodeValue(style[iePropertyImportant] || style[ieProperty]) 586 if (tmpVal !== undefined) { 587 // calculated style from current element not from the element the value was inherited from! (style, value) 588 //value = tmpVal; if (regHasVar.test(tmpVal)) // todo: to i need this check?!!!
588i think its faster without 589 value = styleComputeValueWidthVars(this, tmpVal) 590 this.lastPropertyServedBy = el 591 break 592 } 593 } 594 el = el.parentNode 595 } 596 } 597 } 598 if (value === 'initial') return '' 599 } 600 //if ((value === undefined || value === 'initial') && register[property]) value = register[property].initialValue; // todo? 601 if (value === undefined && register[property]) value = register[property].initialValue 602 if (value === undefined) return '' 603 return value 604 } 605 var inheritingKeywords = { inherit: 1, revert: 1, unset: 1 } 606 607 var oldSetP = StyleProto.setProperty 608 StyleProto.setProperty = function (property, value, prio) { 609 if (property[0] !== '-' || property[1] !== '-') return oldSetP.apply(this, arguments) 610 const el = this.owningElement 611 if (el) { 612 if (!el.ieCP_setters) el.ieCP_setters = {} 613 el.ieCP_setters[property] = 1 614 } 615 property = '-ie-' + (prio === 'important' ? 'â' : '') + property.substr(2) 616 this.cssText += '; ' + property + ':' + encodeValue(value) + ';' 617 //this[property] = value; 618 // el === document.documentElement && redrawStyleSheets(); new in drawTree 619 el && drawTree(el) // its delayed internal 620 } 621 622 /* 623 var descriptor = Object.getOwnPropertyDescriptor(StyleProto, 'cssText'); 624 var cssTextGetter = descriptor.get; 625 var cssTextSetter = descriptor.set; 626 // descriptor.get = function () { 627 // const style = styleGetter.call(this); 628 // style.owningElement = this; 629 // return style; 630 // } 631 descriptor.set = function (css) { 632 var el = this.owningElement; 633 if (el) { 634 css = rewriteCss('{'+css).substr(1); 635 cssTextSetter.call(this, css); 636 var found = parseRewrittenStyle(this); 637 if (found.getters) addGetterElement(el, found.getters, '%styleAttr'); 638 if (found.setters) addSetterElement(el, found.setters); 639 return; 640 } 641 return cssTextSetter.call(this, css); 642 } 643 Object.defineProperty(StyleProto, 'cssText', descriptor); 644 */ 645 646 if (!window.CSS) window.CSS = {} 647 var register = {} 648 CSS.registerProperty = function (options) { 649 register[options.name] = options 650 } 651 652 // fix "initial" keyword with generated custom properties, this is not supported ad all by ie, should i make a separate "inherit"-polyfill? 653 /* 654 const computed = getComputedStyle(document.documentElement) 655 const initials = {}; 656 for (let i in computed) { 657 initials[i.replace(/([A-Z])/, function(x){ return '-'+x.toLowerCase(x) })] = computed[i]; 658 } 659 initials['display'] = 'inline'; 660 */ 661 662 // utils 663 function fetchCss(url, callback) { 664 var request = new XMLHttpRequest() 665 request.open('GET', url) 666 request.overrideMimeType('text/css') 667 request.onload = function () { 668 if (request.status >= 200 && request.status < 400) { 669 callback(request.responseText) 670 } 671 } 672 request.send() 673 } 674})()
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.