PageSourceSearch

https://client.rundles.org.uk/js/ie11CustomProperties.js

js rundles.org.uk collected 2026-10-08 13:26:38 UTC 21,831 bytes, 647 lines download raw bytes

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

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.