├── LICENSE ├── README.md ├── htmlfills.js ├── htmlfills.old.js ├── mod.js ├── monkeyPatches ├── addEventListenerSignal.js ├── addEventListenerSignal.test.html ├── elContainsText.js ├── focusOptions.js ├── forceToggle.js └── test.html ├── polyfills ├── Array │ ├── from.js │ ├── of.js │ └── prototype │ │ ├── at.js │ │ ├── copyWithin.js │ │ ├── entries.js │ │ ├── fill.js │ │ ├── find.js │ │ ├── findIndex.js │ │ ├── findLast.js │ │ ├── findLastIndex.js │ │ ├── flat.js │ │ ├── flatMap.js │ │ ├── includes.js │ │ ├── item.js │ │ ├── keys.js │ │ └── values.js ├── CSS │ ├── escape.js │ ├── registerProperty.js │ └── supports.js ├── Element │ ├── aom.combo.js │ ├── aom.combo.test.html │ ├── combo.js │ └── prototype │ │ ├── isVisible.js │ │ ├── replaceChildren.js │ │ ├── scrollIntoViewIfNeeded.js │ │ ├── tests.html │ │ └── toggleAttribute.js ├── HTMLElement │ └── prototype │ │ └── inert.js ├── HTMLFormElement │ └── prototype │ │ ├── reportValidity.js │ │ └── requestSubmit.js ├── HTMLInputElement │ └── prototype │ │ ├── reportValidity.js │ │ └── showPicker.js ├── HTMLSlotElement │ └── prototype │ │ └── assignedElements.js ├── Math │ ├── sign.js │ └── trunc.js ├── Node │ └── prototype │ │ ├── contains.js │ │ ├── insertAfter.js │ │ ├── isConnected.js │ │ └── tests │ │ └── contains.html ├── Number │ └── isNumber.js ├── Object │ ├── assign.js │ ├── entries.js │ ├── fromEntries.js │ ├── hasOwn.js │ ├── is.js │ └── values.js ├── Promise │ ├── allSettled.js │ ├── any.js │ └── withResolvers.js ├── RegExp │ └── prototype │ │ └── flags.js ├── SVGStyleElement │ ├── combo.js │ └── prototype │ │ └── sheet.js ├── String │ ├── fromCodePoint.js │ └── prototype │ │ ├── at.js │ │ ├── codePointAt.js │ │ ├── endsWith.js │ │ ├── includes.js │ │ ├── padEnd.js │ │ ├── padStart.js │ │ ├── repeat.js │ │ ├── replaceAll.js │ │ └── startsWith.js ├── SubmitEvent │ └── prototype │ │ ├── submitter.js │ │ └── test.html ├── WeakRef.js ├── WeakSet.js ├── cancelIdleCallback.js ├── crypto │ ├── randomUUID.js │ └── randomUUID.original.js ├── document │ ├── caretRangeFromPoint.js │ └── currentScript.js ├── navigator │ ├── share.js │ └── share.test.html ├── requestIdleCallback.js └── tests │ ├── WeakRef.html │ └── structuredClone.html └── test.html /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tobias Buschor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 💊 lazyfill 2 | 3 | Polyfill Service - the lazy way 4 | 5 | 6 | Polyfills **are loaded on demand**, only when they are needed 😲 7 | Initial **3Kb** to polyfill a lot of Stuff! 8 | 9 | # Ussage 10 | 11 | Add this script on the top of your page: 12 | ```html 13 | 14 | ``` 15 | **done!** 16 | 17 | # Polyfills 18 | 19 | (Anything missing? Any suggestions?) 20 | 21 | 22 | 23 | 196 | 197 | 203 | 204 | 205 | # How it works 206 | 207 | To every polyfillable property, the scripts adds a getter which **synchronously** loads the corresponding polyfill. 208 | Of course, we all know that blocking xhr-requests is not nice. 209 | Therefore, the url to the script that should be added to the page is given in the console. 210 | Ideal for prototyping. 211 | 212 | Let's assume that your browser does not support the function "String.prototype.at". 213 | ```js 214 | > ['a','b','c'].at(-1); // accessing [].at immediately loads the polyfill 215 | > 'c' 216 | ``` 217 | 218 | 219 | # Help 220 | Any help is greatly appreciated. 221 | 222 | # Thanks / Resources 223 | 224 | https://github.com/es-shims 225 | 226 | https://github.com/behnammodi/polyfill 227 | 228 | https://polyfill.io/v3/ 229 | 230 | https://ungap.github.io/ 231 | 232 | https://github.com/Sylvain59650/all-polyfills 233 | 234 | https://vanillajstoolkit.com/polyfills/ 235 | -------------------------------------------------------------------------------- /htmlfills.js: -------------------------------------------------------------------------------- 1 | import {SelectorObserver} from 'https://cdn.jsdelivr.net/gh/u1ui/SelectorObserver.js@4.0.0/SelectorObserver.min.js' 2 | 3 | const scripts = {}; 4 | 5 | const polyfills = { 6 | dialog: { 7 | supports: 'HTMLDialogElement' in window, 8 | js: 'https://cdn.jsdelivr.net/gh/nuxodin/dialog-polyfill@1.4.1/dialog.min.js', 9 | }, 10 | "[focusgroup]": { // waiting for but to fix: https://github.com/MicrosoftEdge/MSEdgeExplainers/pull/581 11 | supports: 'focusgroup' in document.head, 12 | js: 'https://cdn.jsdelivr.net/gh/MicrosoftEdge/MSEdgeExplainers/Focusgroup/focusgroup_polyfill.js', 13 | }, 14 | "[inert]": { 15 | supports: Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'inert')?.enumerable === true, // hacky test, mod.js adds inert property support 16 | js: 'https://cdn.jsdelivr.net/npm/wicg-inert@3.1.2/dist/inert.min.js', 17 | //js: 'https://unpkg.com/wicg-inert@3.1.2/dist/inert.min.js', 18 | }, 19 | "search": { 20 | supports: window.HTMLSearchElement, 21 | js: (el)=> el.setAttribute('role', 'search'), 22 | }, 23 | } 24 | 25 | Object.keys(polyfills).forEach(selector => { 26 | const data = polyfills[selector]; 27 | if (data.supports) return; 28 | const obs = new SelectorObserver({ 29 | on: (el) => { 30 | if (data.js instanceof Function) { 31 | data.js(el); 32 | } 33 | else { 34 | onScript(data.js, () => { 35 | console.log('💊 lazyfill: "'+selector+'" polyfilled, you need the polyfill: '+data.js); 36 | //data.onfound && data.onfound(el) 37 | }); 38 | obs.disconnect(); 39 | } 40 | }, 41 | }) 42 | obs.observe(selector); 43 | }); 44 | 45 | 46 | function onScript(path, cb){ 47 | if (!scripts[path]) { 48 | scripts[path] = { 49 | callbacks:[cb] 50 | }; 51 | loadScript(path, function(){ 52 | scripts[path].callbacks.forEach(cb); 53 | scripts[path].loaded = true;; 54 | }); 55 | } 56 | if (scripts[path].loaded) cb(); 57 | else scripts[path].callbacks.push(cb); 58 | } 59 | function loadScript(path, cb, eb) { 60 | const elem = document.createElement('script'); 61 | elem.async = false; 62 | elem.src = path; 63 | elem.onload = cb; 64 | elem.onerror = eb; 65 | document.documentElement.firstChild.appendChild(elem); 66 | } -------------------------------------------------------------------------------- /htmlfills.old.js: -------------------------------------------------------------------------------- 1 | !function (window, document) { 'use strict'; 2 | 3 | 4 | /* onElement */ 5 | var listeners = [], 6 | root = document, 7 | Observer; 8 | 9 | function qsa(el, selector) { 10 | try { 11 | return el.querySelectorAll(selector); 12 | } catch (e) { 13 | return []; 14 | } 15 | } 16 | function onElement(selector, callback) { 17 | const listener = { 18 | selector: selector, 19 | callback: callback, 20 | elements: new WeakMap(), 21 | }; 22 | var els = qsa(root, listener.selector), i = 0, el; 23 | while (el = els[i++]) { 24 | listener.elements.set(el, true); 25 | listener.callback.call(el, el); 26 | } 27 | listeners.push(listener); 28 | if (!Observer) { 29 | Observer = new MutationObserver(checkMutations); 30 | Observer.observe(root, { 31 | childList: true, 32 | subtree: true 33 | }); 34 | } 35 | checkListener(listener); 36 | } 37 | function checkListener(listener, target) { 38 | var i = 0, el, els = []; 39 | try { 40 | target && target.matches(listener.selector) && els.push(target); 41 | } catch (e) { } 42 | if (loaded) { // ok? check inside node on innerHTML - only when loaded 43 | Array.prototype.push.apply(els, qsa(target || root, listener.selector)); 44 | } 45 | while (el = els[i++]) { 46 | if (listener.elements.has(el)) continue; 47 | listener.elements.set(el, true); 48 | listener.callback.call(el, el); 49 | } 50 | } 51 | function checkListeners(inside) { 52 | var i = 0, listener; 53 | while (listener = listeners[i++]) checkListener(listener, inside); 54 | } 55 | function checkMutations(mutations) { 56 | var j = 0, i, mutation, nodes, target; 57 | while (mutation = mutations[j++]) { 58 | nodes = mutation.addedNodes, i = 0; 59 | while (target = nodes[i++]) target.nodeType === 1 && checkListeners(target); 60 | } 61 | } 62 | let loaded = false; 63 | document.addEventListener('DOMContentLoaded', function () { 64 | loaded = true; 65 | }); 66 | /* /onElement */ 67 | 68 | 69 | const polyfills = { 70 | dialog: { 71 | supports: 'HTMLDialogElement' in window, 72 | js: 'https://cdn.jsdelivr.net/gh/nuxodin/dialog-polyfill@1.4.1/dist/dialog-polyfill.min.js', 73 | //js: 'https://cdn.jsdelivr.net/npm/dialog-polyfill@0.5.6/dist/dialog-polyfill.min.js', 74 | //css: 'https://cdn.jsdelivr.net/npm/dialog-polyfill@0.5.6/dialog-polyfill.css', 75 | //onfound: function(el){ 76 | // dialogPolyfill.registerDialog(el); 77 | //} 78 | }, 79 | "[focusgroup]": { // waiting for but to fix: https://github.com/MicrosoftEdge/MSEdgeExplainers/pull/581 80 | supports: 'focusgroup' in document.head, 81 | js: 'https://cdn.jsdelivr.net/gh/MicrosoftEdge/MSEdgeExplainers/Focusgroup/focusgroup_polyfill.js', 82 | }, 83 | "[inert]": { 84 | supports: Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'inert')?.enumerable === true, // hacky test, mod.js adds inert property support 85 | js: 'https://cdn.jsdelivr.net/npm/wicg-inert@3.1.2/dist/inert.min.js', 86 | }, 87 | } 88 | 89 | Object.keys(polyfills).forEach(function(selector){ 90 | const data = polyfills[selector]; 91 | if (data.supports) return; 92 | console.log(selector, data.supports) 93 | onElement(selector, function (el) { 94 | onScript(data.js, function(){ 95 | data.onfound && data.onfound(el) 96 | }); 97 | }); 98 | }); 99 | 100 | 101 | const scripts = {}; 102 | function onScript(path, cb){ 103 | if (!scripts[path]) { 104 | scripts[path] = { 105 | callbacks:[cb] 106 | }; 107 | loadScript(path, function(){ 108 | scripts[path].callbacks.forEach(cb); 109 | scripts[path].loaded = true;; 110 | }) 111 | } 112 | if (scripts[path].loaded) cb(); 113 | else scripts[path].callbacks.push(cb); 114 | } 115 | function loadScript(path, cb, eb) { 116 | const elem = document.createElement('script'); 117 | elem.async = false; 118 | elem.src = path; 119 | elem.onload = cb; 120 | elem.onerror = eb; 121 | document.documentElement.firstChild.appendChild(elem); 122 | } 123 | 124 | 125 | 126 | }(window, document); -------------------------------------------------------------------------------- /mod.js: -------------------------------------------------------------------------------- 1 | !function(window, document){ 'use strict'; 2 | // other libaries should check properties like so: if (prop in obj) { ... }; so the getter will not fire 3 | 4 | var root = 'cdn.jsdelivr.net/gh/nuxodin/lazyfill@1.7.14/'; 5 | var ending = '.min.js'; 6 | 7 | //var root = 'localhost/github/lazyfill/'; var ending = '.js'; 8 | 9 | /* very small polyfills, they are not worth adding to the service */ 10 | if (!NodeList.prototype.forEach) NodeList.prototype.forEach = Array.prototype.forEach; // ie11 11 | if (!document.scrollingElement) document.scrollingElement = document.documentElement; // ie11 12 | if (!window.crypto) window.crypto = window.msCrypto; // ie11 13 | if (!window.SubmitEvent) window.SubmitEvent = Event; // safari v? 14 | 15 | var urls = { 16 | 'cdn.jsdelivr.net/npm/cookie-store@3.0.0/index.min.js': { 17 | 'cookieStore': [window], 18 | }, 19 | 'cdn.jsdelivr.net/npm/whatwg-fetch@3.6.2/dist/fetch.umd.min.js':{ 20 | 'fetch':[window], 21 | //'Headers':[window], 'Request':[window], 'Response':[window], 22 | }, 23 | 'cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js':{ 24 | 'Promise':[window] 25 | }, 26 | 'polyfill.io/v3/polyfill.min.js?features=IntersectionObserver':{ 27 | 'IntersectionObserver':[window] 28 | }, 29 | 'cdn.jsdelivr.net/npm/@juggle/resize-observer@3.3.1/lib/exports/resize-observer.umd.js':{ // dit not work: 'polyfill.io/v3/polyfill.min.js?features=ResizeObserver' 30 | 'ResizeObserver':[window] 31 | }, 32 | 'polyfill.io/v3/polyfill.min.js?features=AbortController':{ 33 | 'AbortController':[window], 34 | //'AbortSignal': [window] 35 | }, 36 | 'polyfill.io/v3/polyfill.min.js?features=URL':{ 37 | //'URL':[window], // ie11: this will not work as it has "URL" but not as a constructor, what should we do? 38 | 'URLSearchParams':[window] 39 | }, 40 | /* not ready yet, exposes window.temportal.Temporal */ 41 | 'cdn.jsdelivr.net/npm/@js-temporal/polyfill@0.4.0/dist/index.umd.min.js':{ 42 | Temporal:[window], 43 | temporal:[window], 44 | }, 45 | 'unpkg.com/@ungap/custom-elements@0.1.15/es.js':{ 46 | 'customElements':[window], 47 | }, 48 | // 'cdn.jsdelivr.net/gh/nuxodin/structured-clone@2.4.0/index.min.js':{ // makes problems in safari 49 | // 'structuredClone':[window], 50 | // }, 51 | 'cdn.jsdelivr.net/npm/urlpattern-polyfill@1.0.0-rc5/dist/index.umd.js':{ 52 | 'URLPattern':[window], 53 | }, 54 | 'unpkg.com/web-streams-polyfill@3.2.1/dist/polyfill.min.js':{ 55 | 'ReadableStream':[window], 56 | }, 57 | //'raw.githubusercontent.com/mozilla/sanitizer-polyfill/main/dist/sanitizer-polyfill.min.js':{ 58 | 'mozilla.github.io/sanitizer-polyfill/dist/sanitizer-polyfill.min.js':{ 59 | 'Sanitizer':[window], 60 | 'setHTML':[Element.prototype], 61 | }, 62 | }; 63 | 64 | 65 | var path = 'cdn.jsdelivr.net/gh/tc39/proposal-change-array-by-copy@main/polyfill.min.js'; 66 | addCombo(path, { 67 | toReversed:1, 68 | toSorted:1, 69 | with:1, 70 | }, Object.getPrototypeOf(Int8Array.prototype)); 71 | addCombo(path, { 72 | toReversed:1, 73 | toSorted:1, 74 | with:1, 75 | toSpliced:1, 76 | }, Array.prototype); 77 | 78 | addCombo('polyfill.io/v3/polyfill.min.js?features=Intl', { 79 | DateTimeFormat:{ 80 | prototype:{ 81 | formatToParts:1 82 | } 83 | }, 84 | DisplayNames:1, 85 | ListFormat:1, 86 | Locale:1, 87 | PluralRules:1, 88 | RelativeTimeFormat:1, 89 | getCanonicalLocales:1, 90 | }, Intl); 91 | 92 | addCombo(root+'polyfills/Element/combo'+ending, { 93 | matches:1, 94 | closest:1, 95 | prepend:1, 96 | append:1, 97 | before:1, 98 | after:1, 99 | replaceWidth:1, 100 | remove:1, 101 | blur:1, // to use in SVGElement: 102 | focus:1, 103 | classList:1, 104 | getElementsByClassName:1, 105 | children:1, 106 | }, Element.prototype); 107 | 108 | 109 | /* set methods, stage 2 110 | addCombo('cdn.jsdelivr.net/npm/set-extensions@1.5.0/dist/index'+ending, { 111 | intersection:1, 112 | union:1, 113 | difference:1, 114 | symmetricDifference:1, 115 | isSubsetOf:1, 116 | isDisjointFrom:1, 117 | isSupersetOf:1, 118 | }, Set.prototype); 119 | */ 120 | 121 | /* iterator helpers, stage 2 122 | var getPrototypeOf = Object.getPrototypeOf; 123 | var AsyncIteratorPrototype = getPrototypeOf(getPrototypeOf(getPrototypeOf((async function* () {})()[Symbol.asyncIterator]()))); 124 | var IteratorPrototype = getPrototypeOf(getPrototypeOf([][Symbol.iterator]())); 125 | var props = { 126 | map:1, 127 | chain:1, 128 | count:1, 129 | cycle:1, 130 | drop:1, 131 | dropWhile:1, 132 | every:1, 133 | filter:1, 134 | find:1, 135 | findIndex:1, 136 | flatMap:1, 137 | forEach:1, 138 | fuse:1, 139 | join:1, 140 | map:1, 141 | max:1, 142 | min:1, 143 | partition:1, 144 | reduce:1, 145 | some:1, 146 | take:1, 147 | takeWhile:1, 148 | toArray:1, 149 | zip:1, 150 | } 151 | console.log(IteratorPrototype) 152 | path = 'cdn.jsdelivr.net/npm/iterator-polyfill@1.0.9/dist/index.min.js'; 153 | addCombo(path, props, IteratorPrototype); 154 | addCombo(path, props, AsyncIteratorPrototype); 155 | */ 156 | 157 | 158 | /* blank object "CSS" needed */ 159 | if (!window.CSS) window.CSS = {}; 160 | var lazyfills = { 161 | Array:{ 162 | from:1, 163 | of:1, 164 | prototype:{ 165 | at:1, 166 | copyWithin:1, 167 | entries:1, 168 | fill:1, 169 | find:1, 170 | findIndex:1, 171 | findLast:1, 172 | findLastIndex:1, 173 | flat:1, 174 | flatMap:1, 175 | includes:1, 176 | keys:1, 177 | values:1, 178 | } 179 | }, 180 | CSS:{ 181 | escape:1, 182 | registerProperty:1, 183 | supports:1, 184 | }, 185 | document:{ 186 | currentScript:1, 187 | caretRangeFromPoint:1, 188 | }, 189 | Node:{ 190 | prototype:{ 191 | contains:1, 192 | isConnected:1, 193 | //inserAfter:1, draft 194 | }, 195 | }, 196 | Element:{ 197 | prototype:{ 198 | toggleAttribute:1, 199 | isVisible:1, 200 | scrollIntoViewIfNeeded:1, 201 | replaceChildren:1, 202 | } 203 | }, 204 | HTMLElement:{ 205 | prototype:{ 206 | inert:1 207 | } 208 | }, 209 | HTMLFormElement:{ 210 | prototype:{ 211 | reportValidity:1, 212 | requestSubmit:1, 213 | } 214 | }, 215 | HTMLInputElement:{ 216 | prototype:{ 217 | reportValidity:1 218 | } 219 | }, 220 | HTMLSlotElement:{ 221 | prototype:{ 222 | assignedElements:1 223 | } 224 | }, 225 | Math:{ 226 | trunc:1, 227 | sign:1, 228 | }, 229 | navigator:{ 230 | share:1 231 | }, 232 | Number:{ 233 | isInteger:1 234 | }, 235 | Object:{ 236 | assign:1, 237 | entries:1, 238 | fromEntries:1, 239 | is:1, 240 | values:1, 241 | hasOwn:1, 242 | }, 243 | Promise:{ 244 | allSettled:1, 245 | any:1, 246 | withResolvers:1, 247 | }, 248 | RegExp:{ 249 | prototype:{ 250 | flags:1, 251 | } 252 | }, 253 | String:{ 254 | fromCodePoint:1, 255 | prototype:{ 256 | at:1, 257 | codePointAt:1, 258 | endsWith:1, 259 | includes:1, 260 | padEnd:1, 261 | padStart:1, 262 | repeat:1, 263 | startsWith:1, 264 | replaceAll:1, 265 | } 266 | }, 267 | SubmitEvent:{ 268 | prototype:{ 269 | submitter:1 270 | } 271 | }, 272 | SVGStyleElement:{ 273 | prototype:{ 274 | sheet:1 275 | } 276 | }, 277 | requestIdleCallback:1, 278 | cancelIdleCallback:1, 279 | WeakSet:1, 280 | crypto:{ 281 | randomUUID:1, 282 | }, 283 | }; 284 | function addFsStruct(obj, realObj, rootUrl){ 285 | var prop; 286 | for (prop in obj) { 287 | if (obj[prop] === 1) { 288 | var url = rootUrl + prop + ending 289 | if (!urls[url]) urls[url] = {}; 290 | if (!urls[url][prop]) urls[url][prop] = []; 291 | urls[url][prop].push(realObj); 292 | } else { 293 | if (realObj[prop]===undefined) { 294 | console.warn('💊 lazyfill: Object '+prop+' not defined to polyfill its properties!'); 295 | } else { 296 | addFsStruct(obj[prop], realObj[prop], rootUrl + prop + '/'); 297 | } 298 | 299 | } 300 | } 301 | } 302 | addFsStruct(lazyfills, window, root+'polyfills/'); 303 | 304 | 305 | for (let url in urls) addGetters(url, urls[url]); 306 | 307 | /* To list polyfills in the readme: * 308 | //IteratorPrototype.name = 'Iterator'; 309 | //AsyncIteratorPrototype.name = 'AsyncIterator'; 310 | CSS.name = 'CSS'; 311 | let supports = {}; 312 | Object.values(urls).forEach(function(props){ 313 | Object.entries(props).forEach(([prop, objects])=>{ 314 | objects.forEach(obj=>{ 315 | let name = obj[Symbol.toStringTag] || obj.name || obj.constructor.name 316 | if (!supports[name]) supports[name] = []; 317 | supports[name].push(prop) 318 | }) 319 | }) 320 | }); 321 | let output = '\n' 327 | console.log(output) 328 | /* */ 329 | 330 | console.log('💊 lazyfill: getters added, ready!'); 331 | 332 | function addCombo(url, obj, target) { 333 | var prop; 334 | if (!urls[url]) urls[url] = {}; 335 | for (prop in obj) { 336 | if (obj[prop] === 1) { 337 | if (!urls[url][prop]) urls[url][prop] = []; 338 | urls[url][prop].push(target); 339 | } else { 340 | addCombo(url, obj[prop], target[prop]); 341 | } 342 | } 343 | } 344 | 345 | function addGetters(url, props) { 346 | var prop, i, targets, target, propsNeeded = {}; 347 | for (prop in props) { 348 | targets = props[prop]; 349 | for (i=0; target=targets[i++] ;) { 350 | if (prop in target) continue; // not needed 351 | if (!propsNeeded[prop]) propsNeeded[prop] = []; 352 | propsNeeded[prop].push(target); 353 | //console.log('"'+prop+'" not supported, adding getter'); 354 | addGetter(target, prop, url); 355 | } 356 | } 357 | function addGetter(obj, prop, url) { 358 | Object.defineProperty(obj, prop, { 359 | configurable: true, 360 | get: function() { 361 | // try { throw new Error(); } catch (e) { console.log(e.stack) } // track where it has been added 362 | deleteGetters(); // we have to delete all assigned getters for a url, otherwise the script is parsed anew with every polyfill! 363 | console.log('💊 lazyfill: "'+prop+'" polyfilled (sync!), you need the polyfill '+url); 364 | 365 | // umd 366 | window.exports = {}; 367 | window.module = true; // todo: needed by umd but i dont know why? 368 | loadScriptSync('https://'+url); 369 | // if (!this[prop]) this[prop] = exports[prop]; // todo: loop exports? 370 | // new: polyfill the prototype, not the instance, ok? 371 | if (!obj[prop]) obj[prop] = exports[prop]; // todo: loop exports? 372 | return this[prop]; 373 | }, 374 | set: function(v) { 375 | //deleteGetters(); 376 | delete obj[prop]; // needed? the getter has already deleted the property!?? 377 | obj[prop] = v; 378 | } 379 | }); 380 | } 381 | function deleteGetters() { 382 | var prop, targets, target; 383 | for (prop in propsNeeded) { 384 | targets = props[prop]; 385 | for (i=0; target=targets[i++];) { 386 | delete target[prop]; 387 | } 388 | } 389 | } 390 | }; 391 | 392 | 393 | /* Monkey Patches */ 394 | var monkeyPatches = { 395 | focusOptions:1, 396 | elContainsText:1, 397 | forceToggle:1, 398 | addEventListenerSignal:1, 399 | }; 400 | var dummyEl = document.createElement('i'); 401 | // focus options 402 | dummyEl.focus({ 403 | get preventScroll() { 404 | delete monkeyPatches.focusOptions; 405 | }, 406 | }); 407 | // IE11 contains-bug, textNodes are not containing 408 | dummyEl.innerHTML = ' '; 409 | if (dummyEl.contains(dummyEl.firstChild)) delete monkeyPatches.elContainsText; 410 | 411 | // classList.toggle force options 412 | var cl = dummyEl.classList; 413 | cl.toggle('test',false); 414 | if (!cl.contains('test')) delete monkeyPatches.forceToggle 415 | 416 | // addEventListener signal option 417 | dummyEl.addEventListener('click',()=>{}, { 418 | get signal() { 419 | delete monkeyPatches.addEventListenerSignal; 420 | }, 421 | }); 422 | 423 | // load patches 424 | for (let patch in monkeyPatches) { 425 | console.log(patch) 426 | loadScriptAsync('https://'+root + 'monkeyPatches/' + patch + ending, true); 427 | } 428 | 429 | 430 | 431 | /* helpers */ 432 | function loadScriptSync(path) { 433 | var xhr = new XMLHttpRequest(); 434 | xhr.open('GET', path, false); 435 | xhr.send(null); 436 | if (xhr.status === 200) { 437 | var elem = document.createElement('script'); 438 | elem.text = xhr.responseText; 439 | document.documentElement.firstChild.appendChild(elem); 440 | elem.setAttribute('data-src',path); 441 | } else { 442 | console.warn('💊 lazyfill: load failed '+path) 443 | } 444 | } 445 | function loadScriptAsync(path) { 446 | var elem = document.createElement('script'); 447 | elem.async = false; 448 | elem.src = path; 449 | //elem.setAttribute('src',path); 450 | document.documentElement.firstChild.appendChild(elem); 451 | } 452 | 453 | 454 | /* more * 455 | // iterators, available on ch/ff, not useable for ie11 456 | if (window.Symbol && Symbol.iterator) { 457 | [HTMLCollection,NodeList,StyleSheetList,window.CSSRuleList].forEach(function(Interface){ 458 | if (!Interface) return; 459 | var proto = Interface.prototype; 460 | if (proto[Symbol.iterator]) return; 461 | proto[Symbol.iterator] = Array.prototype[Symbol.iterator]; 462 | }); 463 | } 464 | /* */ 465 | 466 | 467 | }(window, document); 468 | -------------------------------------------------------------------------------- /monkeyPatches/addEventListenerSignal.js: -------------------------------------------------------------------------------- 1 | // idea from https://gist.github.com/samthor/2e11de5976fe673557b0ee14a3cb621a#file-eventlistener-signal-support-js 2 | 3 | !function(){ 4 | 5 | let supported = false; 6 | document.createElement('i').addEventListener('click',()=>{}, { 7 | get signal() { supported = true; }, 8 | }); 9 | if (supported) return; 10 | if (!window.AbortController) throw new Error(`AbortController not supported`); 11 | 12 | const orig = EventTarget.prototype.addEventListener; 13 | 14 | EventTarget.prototype.addEventListener = function (eventName, fn, options) { 15 | if (options && options.signal) { 16 | if (options.signal.aborted) return; // do nothing, already aborted 17 | options.signal.addEventListener('abort', () => this.removeEventListener(eventName, fn, { ...options }) ); 18 | } 19 | return orig.call(this, eventName, fn, options); 20 | }; 21 | 22 | }(); 23 | -------------------------------------------------------------------------------- /monkeyPatches/addEventListenerSignal.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 19 | 20 | -------------------------------------------------------------------------------- /monkeyPatches/elContainsText.js: -------------------------------------------------------------------------------- 1 | /* IE11 contains-bug, textNodes are not containing */ 2 | !function(d){ 3 | var t = d.createTextNode(''), el = d.createElement('span'); 4 | el.appendChild(t); 5 | if (!el.contains(t)) { 6 | HTMLElement.prototype.contains = function(contains) { 7 | return function(el) { 8 | return contains.call(this, !el || el.nodeType === 1 ? el : el.parentNode); 9 | }; 10 | }(HTMLElement.prototype.contains); 11 | } 12 | }(document); 13 | -------------------------------------------------------------------------------- /monkeyPatches/focusOptions.js: -------------------------------------------------------------------------------- 1 | 2 | !function(){ 3 | 4 | let supported = false; 5 | document.createElement('i').focus({ 6 | get preventScroll() { 7 | supported = true; 8 | }, 9 | }); 10 | 11 | if (!supported) { 12 | let original = HTMLElement.prototype.focus; 13 | Element.prototype.focus = HTMLElement.prototype.focus = function(options){ 14 | if (options && options.preventScroll) { 15 | const map = new Map(); 16 | let p = this; 17 | while (p = p.parentNode) map.set(p, [p.scrollLeft, p.scrollTop]); 18 | original.apply(this, arguments); 19 | map.forEach(function(pos, el){ 20 | // todo: test: only if changed? does it trigger scroll? 21 | // IE flickers 22 | el.scrollLeft = pos[0] 23 | el.scrollTop = pos[1] 24 | }); 25 | } else { 26 | original.apply(this, arguments); 27 | } 28 | } 29 | } 30 | 31 | 32 | }(); 33 | -------------------------------------------------------------------------------- /monkeyPatches/forceToggle.js: -------------------------------------------------------------------------------- 1 | // classList.toggle(x, force!) ie11 2 | !function(){ 3 | var cl = document.createElement('div').classList; 4 | cl.toggle('test',false); 5 | if (!cl.contains('test')) return; 6 | var original = DOMTokenList.prototype.toggle; 7 | DOMTokenList.prototype.toggle = function(name, force){ 8 | if (force!==undefined) { 9 | this[force?'add':'remove'](name); 10 | return force; 11 | } 12 | return original.call(this, name); 13 | } 14 | }(); 15 | -------------------------------------------------------------------------------- /monkeyPatches/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Level.css TEST 6 | 7 | 8 | 9 | 10 | 11 |

Element contains text-nodes

12 | 22 | 23 | 24 |

ClassList force toggle

25 | 36 | 37 | 38 |

focus options preventScroll

39 |

IE 11 and Safari 14+?

40 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | 165 |
166 | scrollable div 167 |
168 |
169 |
170 |
171 |
172 |
173 | scrollable div 174 | 175 |
176 | -------------------------------------------------------------------------------- /polyfills/Array/from.js: -------------------------------------------------------------------------------- 1 | if (!Array.from) { 2 | Array.from = (function () { 3 | var toStr = Object.prototype.toString; 4 | var isCallable = function (fn) { 5 | return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; 6 | }; 7 | var toInteger = function (value) { 8 | var number = Number(value); 9 | if (isNaN(number)) { 10 | return 0; 11 | } 12 | if (number === 0 || !isFinite(number)) { 13 | return number; 14 | } 15 | return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); 16 | }; 17 | var maxSafeInteger = Math.pow(2, 53) - 1; 18 | var toLength = function (value) { 19 | var len = toInteger(value); 20 | return Math.min(Math.max(len, 0), maxSafeInteger); 21 | }; 22 | 23 | // The length property of the from method is 1. 24 | return function from(arrayLike /*, mapFn, thisArg */) { 25 | // 1. Let C be the this value. 26 | var C = this; 27 | 28 | // 2. Let items be ToObject(arrayLike). 29 | var items = Object(arrayLike); 30 | 31 | // 3. ReturnIfAbrupt(items). 32 | if (arrayLike == null) { 33 | throw new TypeError( 34 | 'Array.from requires an array-like object - not null or undefined' 35 | ); 36 | } 37 | 38 | // 4. If mapfn is undefined, then let mapping be false. 39 | var mapFn = arguments.length > 1 ? arguments[1] : void undefined; 40 | var T; 41 | if (typeof mapFn !== 'undefined') { 42 | // 5. else 43 | // 5. a If IsCallable(mapfn) is false, throw a TypeError exception. 44 | if (!isCallable(mapFn)) { 45 | throw new TypeError( 46 | 'Array.from: when provided, the second argument must be a function' 47 | ); 48 | } 49 | 50 | // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined. 51 | if (arguments.length > 2) { 52 | T = arguments[2]; 53 | } 54 | } 55 | 56 | // 10. Let lenValue be Get(items, "length"). 57 | // 11. Let len be ToLength(lenValue). 58 | var len = toLength(items.length); 59 | 60 | // 13. If IsConstructor(C) is true, then 61 | // 13. a. Let A be the result of calling the [[Construct]] internal method 62 | // of C with an argument list containing the single item len. 63 | // 14. a. Else, Let A be ArrayCreate(len). 64 | var A = isCallable(C) ? Object(new C(len)) : new Array(len); 65 | 66 | // 16. Let k be 0. 67 | var k = 0; 68 | // 17. Repeat, while k < len… (also steps a - h) 69 | var kValue; 70 | while (k < len) { 71 | kValue = items[k]; 72 | if (mapFn) { 73 | A[k] = 74 | typeof T === 'undefined' 75 | ? mapFn(kValue, k) 76 | : mapFn.call(T, kValue, k); 77 | } else { 78 | A[k] = kValue; 79 | } 80 | k += 1; 81 | } 82 | // 18. Let putStatus be Put(A, "length", len, true). 83 | A.length = len; 84 | // 20. Return A. 85 | return A; 86 | }; 87 | })(); 88 | } 89 | -------------------------------------------------------------------------------- /polyfills/Array/of.js: -------------------------------------------------------------------------------- 1 | if (!Array.of) { 2 | Array.of = function () { 3 | return Array.prototype.slice.call(arguments); 4 | }; 5 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/at.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.at) { 2 | Array.prototype.at = function(n){ 3 | //n = Math.trunc(n) || 0; not in ie11 4 | n = n < 0 ? Math.ceil(n) : Math.floor(n); 5 | if (n < 0) n += this.length; 6 | if (n < 0 || n >= this.length) return undefined; 7 | return this[n]; 8 | } 9 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/copyWithin.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.copyWithin) { 2 | Object.defineProperty(Array.prototype, 'copyWithin', { 3 | configurable: true, 4 | writable: true, 5 | value: function (target, start /*, end*/) { 6 | // Steps 1-2. 7 | if (this == null) { 8 | throw new TypeError('this is null or not defined'); 9 | } 10 | 11 | var O = Object(this); 12 | 13 | // Steps 3-5. 14 | var len = O.length >>> 0; 15 | 16 | // Steps 6-8. 17 | var relativeTarget = target >> 0; 18 | 19 | var to = 20 | relativeTarget < 0 21 | ? Math.max(len + relativeTarget, 0) 22 | : Math.min(relativeTarget, len); 23 | 24 | // Steps 9-11. 25 | var relativeStart = start >> 0; 26 | 27 | var from = 28 | relativeStart < 0 29 | ? Math.max(len + relativeStart, 0) 30 | : Math.min(relativeStart, len); 31 | 32 | // Steps 12-14. 33 | var end = arguments[2]; 34 | var relativeEnd = end === undefined ? len : end >> 0; 35 | 36 | var final = 37 | relativeEnd < 0 38 | ? Math.max(len + relativeEnd, 0) 39 | : Math.min(relativeEnd, len); 40 | 41 | // Step 15. 42 | var count = Math.min(final - from, len - to); 43 | 44 | // Steps 16-17. 45 | var direction = 1; 46 | 47 | if (from < to && to < from + count) { 48 | direction = -1; 49 | from += count - 1; 50 | to += count - 1; 51 | } 52 | 53 | // Step 18. 54 | while (count > 0) { 55 | if (from in O) { 56 | O[to] = O[from]; 57 | } else { 58 | delete O[to]; 59 | } 60 | 61 | from += direction; 62 | to += direction; 63 | count--; 64 | } 65 | 66 | // Step 19. 67 | return O; 68 | }, 69 | }); 70 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/entries.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.entries) { 2 | Array.prototype.entries = function () { 3 | function Iterator() { } 4 | 5 | Iterator.prototype.next = function () { 6 | if (index > selfThis.length - 1) { 7 | done = true; 8 | } 9 | if (done) { 10 | return { value: undefined, done: true }; 11 | } 12 | return { value: [index, selfThis[index++]], done: false }; 13 | }; 14 | 15 | var selfThis = this; 16 | var index = 0; 17 | var done; 18 | 19 | return new Iterator(); 20 | }; 21 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/fill.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.fill) { 2 | Object.defineProperty(Array.prototype, 'fill', { 3 | configurable: true, 4 | writable: true, 5 | value: function (value) { 6 | // Steps 1-2. 7 | if (this == null) { 8 | throw new TypeError('this is null or not defined'); 9 | } 10 | 11 | var O = Object(this); 12 | 13 | // Steps 3-5. 14 | var len = O.length >>> 0; 15 | 16 | // Steps 6-7. 17 | var start = arguments[1]; 18 | var relativeStart = start >> 0; 19 | 20 | // Step 8. 21 | var k = 22 | relativeStart < 0 23 | ? Math.max(len + relativeStart, 0) 24 | : Math.min(relativeStart, len); 25 | 26 | // Steps 9-10. 27 | var end = arguments[2]; 28 | var relativeEnd = end === undefined ? len : end >> 0; 29 | 30 | // Step 11. 31 | var final = 32 | relativeEnd < 0 33 | ? Math.max(len + relativeEnd, 0) 34 | : Math.min(relativeEnd, len); 35 | 36 | // Step 12. 37 | while (k < final) { 38 | O[k] = value; 39 | k++; 40 | } 41 | 42 | // Step 13. 43 | return O; 44 | }, 45 | }); 46 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/find.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.find) { 2 | Object.defineProperty(Array.prototype, 'find', { 3 | configurable: true, 4 | writable: true, 5 | value: function (predicate) { 6 | // 1. Let O be ? ToObject(this value). 7 | if (this == null) { 8 | throw new TypeError('"this" is null or not defined'); 9 | } 10 | 11 | var o = Object(this); 12 | 13 | // 2. Let len be ? ToLength(? Get(O, "length")). 14 | var len = o.length >>> 0; 15 | 16 | // 3. If IsCallable(predicate) is false, throw a TypeError exception. 17 | if (typeof predicate !== 'function') { 18 | throw new TypeError('predicate must be a function'); 19 | } 20 | 21 | // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. 22 | var thisArg = arguments[1]; 23 | 24 | // 5. Let k be 0. 25 | var k = 0; 26 | 27 | // 6. Repeat, while k < len 28 | while (k < len) { 29 | // a. Let Pk be ! ToString(k). 30 | // b. Let kValue be ? Get(O, Pk). 31 | // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). 32 | // d. If testResult is true, return kValue. 33 | var kValue = o[k]; 34 | if (predicate.call(thisArg, kValue, k, o)) { 35 | return kValue; 36 | } 37 | // e. Increase k by 1. 38 | k++; 39 | } 40 | 41 | // 7. Return undefined. 42 | return undefined; 43 | }, 44 | }); 45 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/findIndex.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.findIndex) { 2 | Object.defineProperty(Array.prototype, 'findIndex', { 3 | configurable: true, 4 | writable: true, 5 | value: function (predicate) { 6 | // 1. Let O be ? ToObject(this value). 7 | if (this == null) { 8 | throw new TypeError('"this" is null or not defined'); 9 | } 10 | 11 | var o = Object(this); 12 | 13 | // 2. Let len be ? ToLength(? Get(O, "length")). 14 | var len = o.length >>> 0; 15 | 16 | // 3. If IsCallable(predicate) is false, throw a TypeError exception. 17 | if (typeof predicate !== 'function') { 18 | throw new TypeError('predicate must be a function'); 19 | } 20 | 21 | // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. 22 | var thisArg = arguments[1]; 23 | 24 | // 5. Let k be 0. 25 | var k = 0; 26 | 27 | // 6. Repeat, while k < len 28 | while (k < len) { 29 | // a. Let Pk be ! ToString(k). 30 | // b. Let kValue be ? Get(O, Pk). 31 | // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). 32 | // d. If testResult is true, return k. 33 | var kValue = o[k]; 34 | if (predicate.call(thisArg, kValue, k, o)) { 35 | return k; 36 | } 37 | // e. Increase k by 1. 38 | k++; 39 | } 40 | 41 | // 7. Return -1. 42 | return -1; 43 | }, 44 | }); 45 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/findLast.js: -------------------------------------------------------------------------------- 1 | // https://raw.githubusercontent.com/behnammodi/polyfill/master/array.polyfill.js 2 | 3 | if (!Array.prototype.findLast) { 4 | Object.defineProperty(Array.prototype, "findLast", { 5 | value: function (predicate, thisArg) { 6 | let idx = this.length - 1; 7 | while (idx >= 0) { 8 | const value = this[idx]; 9 | if (predicate.call(thisArg, value, idx, this)) { 10 | return value; 11 | } 12 | idx--; 13 | } 14 | return undefined; 15 | } 16 | , 17 | writable: true, 18 | enumerable: false, 19 | configurable: true 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /polyfills/Array/prototype/findLastIndex.js: -------------------------------------------------------------------------------- 1 | // https://raw.githubusercontent.com/behnammodi/polyfill/master/array.polyfill.js 2 | 3 | if (!Array.prototype.findLastIndex) { 4 | Object.defineProperty(Array.prototype, 'findLastIndex', { 5 | value: function (predicate, thisArg) { 6 | let idx = this.length - 1; 7 | while (idx >= 0) { 8 | const value = this[idx]; 9 | if (predicate.call(thisArg, value, idx, this)) { 10 | return idx; 11 | } 12 | idx--; 13 | } 14 | return -1; 15 | } 16 | , 17 | writable: true, 18 | enumerable: false, 19 | configurable: true 20 | }); 21 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/flat.js: -------------------------------------------------------------------------------- 1 | // from https://github.com/behnammodi/polyfill/blob/master/array.polyfill.js 2 | if (!Array.prototype.flat) { 3 | Object.defineProperty(Array.prototype, 'flat', { 4 | configurable: true, 5 | writable: true, 6 | value: function () { 7 | var depth = 8 | typeof arguments[0] === 'undefined' ? 1 : Number(arguments[0]) || 0; 9 | var result = []; 10 | var forEach = result.forEach; 11 | 12 | var flatDeep = function (arr, depth) { 13 | forEach.call(arr, function (val) { 14 | if (depth > 0 && Array.isArray(val)) { 15 | flatDeep(val, depth - 1); 16 | } else { 17 | result.push(val); 18 | } 19 | }); 20 | }; 21 | 22 | flatDeep(this, depth); 23 | return result; 24 | }, 25 | }); 26 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/flatMap.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.flatMap) { 2 | Object.defineProperty(Array.prototype, 'flatMap', { 3 | configurable: true, 4 | writable: true, 5 | value: function () { 6 | return Array.prototype.map.apply(this, arguments).flat(1); 7 | }, 8 | }); 9 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/includes.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.includes) { 2 | Object.defineProperty(Array.prototype, 'includes', { 3 | configurable: true, 4 | writable: true, 5 | value: function (searchElement, fromIndex) { 6 | // 1. Let O be ? ToObject(this value). 7 | if (this == null) { 8 | throw new TypeError('"this" is null or not defined'); 9 | } 10 | 11 | var o = Object(this); 12 | 13 | // 2. Let len be ? ToLength(? Get(O, "length")). 14 | var len = o.length >>> 0; 15 | 16 | // 3. If len is 0, return false. 17 | if (len === 0) { 18 | return false; 19 | } 20 | 21 | // 4. Let n be ? ToInteger(fromIndex). 22 | // (If fromIndex is undefined, this step produces the value 0.) 23 | var n = fromIndex | 0; 24 | 25 | // 5. If n ≥ 0, then 26 | // a. Let k be n. 27 | // 6. Else n < 0, 28 | // a. Let k be len + n. 29 | // b. If k < 0, let k be 0. 30 | var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); 31 | 32 | function sameValueZero(x, y) { 33 | return ( 34 | x === y || 35 | (typeof x === 'number' && 36 | typeof y === 'number' && 37 | isNaN(x) && 38 | isNaN(y)) 39 | ); 40 | } 41 | 42 | // 7. Repeat, while k < len 43 | while (k < len) { 44 | // a. Let elementK be the result of ? Get(O, ! ToString(k)). 45 | // b. If SameValueZero(searchElement, elementK) is true, return true. 46 | // c. Increase k by 1. 47 | if (sameValueZero(o[k], searchElement)) { 48 | return true; 49 | } 50 | k++; 51 | } 52 | 53 | // 8. Return false 54 | return false; 55 | }, 56 | }); 57 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/item.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxodin/lazyfill/c53e43fe2d88269cf84b924461218c23422cc49a/polyfills/Array/prototype/item.js -------------------------------------------------------------------------------- /polyfills/Array/prototype/keys.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.keys) { 2 | Array.prototype.keys = function () { 3 | function Iterator() { } 4 | 5 | Iterator.prototype.next = function () { 6 | if (index > selfThis.length - 1) { 7 | done = true; 8 | } 9 | if (done) { 10 | return { value: undefined, done: true }; 11 | } 12 | return { value: index++, done: false }; 13 | }; 14 | 15 | var selfThis = this; 16 | var index = 0; 17 | var done; 18 | 19 | return new Iterator(); 20 | }; 21 | } -------------------------------------------------------------------------------- /polyfills/Array/prototype/values.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.values) { 2 | Array.prototype.values = function () { 3 | function Iterator() { } 4 | 5 | Iterator.prototype.next = function () { 6 | if (index > selfThis.length - 1) { 7 | done = true; 8 | } 9 | if (done) { 10 | return { value: undefined, done: true }; 11 | } 12 | return { value: selfThis[index++], done: false }; 13 | }; 14 | 15 | var selfThis = this; 16 | var index = 0; 17 | var done; 18 | 19 | return new Iterator(); 20 | }; 21 | } -------------------------------------------------------------------------------- /polyfills/CSS/escape.js: -------------------------------------------------------------------------------- 1 | /*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */ 2 | ;(function(root, factory) { 3 | // https://github.com/umdjs/umd/blob/master/returnExports.js 4 | if (typeof exports == 'object') { 5 | // For Node.js. 6 | module.exports = factory(root); 7 | } else if (typeof define == 'function' && define.amd) { 8 | // For AMD. Register as an anonymous module. 9 | define([], factory.bind(root, root)); 10 | } else { 11 | // For browser globals (not exposing the function separately). 12 | factory(root); 13 | } 14 | }(typeof global != 'undefined' ? global : this, function(root) { 15 | 16 | if (root.CSS && root.CSS.escape) { 17 | return root.CSS.escape; 18 | } 19 | 20 | // https://drafts.csswg.org/cssom/#serialize-an-identifier 21 | var cssEscape = function(value) { 22 | if (arguments.length == 0) throw new TypeError('`CSS.escape` requires an argument.'); 23 | var string = String(value); 24 | var length = string.length; 25 | var index = -1; 26 | var codeUnit; 27 | var result = ''; 28 | var firstCodeUnit = string.charCodeAt(0); 29 | while (++index < length) { 30 | codeUnit = string.charCodeAt(index); 31 | // Note: there’s no need to special-case astral symbols, surrogate 32 | // pairs, or lone surrogates. 33 | 34 | // If the character is NULL (U+0000), then the REPLACEMENT CHARACTER 35 | // (U+FFFD). 36 | if (codeUnit == 0x0000) { 37 | result += '\uFFFD'; 38 | continue; 39 | } 40 | 41 | if ( 42 | // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is 43 | // U+007F, […] 44 | (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F || 45 | // If the character is the first character and is in the range [0-9] 46 | // (U+0030 to U+0039), […] 47 | (index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || 48 | // If the character is the second character and is in the range [0-9] 49 | // (U+0030 to U+0039) and the first character is a `-` (U+002D), […] 50 | ( 51 | index == 1 && 52 | codeUnit >= 0x0030 && codeUnit <= 0x0039 && 53 | firstCodeUnit == 0x002D 54 | ) 55 | ) { 56 | // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point 57 | result += '\\' + codeUnit.toString(16) + ' '; 58 | continue; 59 | } 60 | 61 | if ( 62 | // If the character is the first character and is a `-` (U+002D), and 63 | // there is no second character, […] 64 | index == 0 && 65 | length == 1 && 66 | codeUnit == 0x002D 67 | ) { 68 | result += '\\' + string.charAt(index); 69 | continue; 70 | } 71 | 72 | // If the character is not handled by one of the above rules and is 73 | // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or 74 | // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to 75 | // U+005A), or [a-z] (U+0061 to U+007A), […] 76 | if ( 77 | codeUnit >= 0x0080 || 78 | codeUnit == 0x002D || 79 | codeUnit == 0x005F || 80 | codeUnit >= 0x0030 && codeUnit <= 0x0039 || 81 | codeUnit >= 0x0041 && codeUnit <= 0x005A || 82 | codeUnit >= 0x0061 && codeUnit <= 0x007A 83 | ) { 84 | // the character itself 85 | result += string.charAt(index); 86 | continue; 87 | } 88 | 89 | // Otherwise, the escaped character. 90 | // https://drafts.csswg.org/cssom/#escape-a-character 91 | result += '\\' + string.charAt(index); 92 | 93 | } 94 | return result; 95 | }; 96 | 97 | if (!root.CSS) root.CSS = {}; 98 | 99 | root.CSS.escape = cssEscape; 100 | return cssEscape; 101 | 102 | })); -------------------------------------------------------------------------------- /polyfills/CSS/registerProperty.js: -------------------------------------------------------------------------------- 1 | 2 | if (!CSS.registerProperty) { 3 | const pool = new Set(); 4 | CSS.registerProperty = function(def){ 5 | if (pool.has(def.name)) throw new Error(`property ${def.name} already registered`); 6 | pool.add(def.name); 7 | 8 | if (def.syntax!=null && def.syntax !== '*') console.log('CSS.registerProperty: syntax not supported in your browser'); 9 | 10 | let hasWhere = CSS.supports('selector(:where(x))'); 11 | let where = selector => hasWhere?`:where(${selector})`:selector; 12 | 13 | let style = ''; 14 | if (def.initialValue != null) { 15 | style += where('html')+` { ${def.name}:${def.initialValue}; }`; 16 | } 17 | if (!def.inherits) { // if not inherited and no initial value, it inherits anyway, but the native chrome behavoir is the same! 18 | style += where('*,::before,::after') + ` { ${def.name}:${def.initialValue??''}; }`; 19 | } 20 | document.head.insertAdjacentHTML('afterbegin', ``); 21 | } 22 | } 23 | 24 | /* 25 | note: 26 | definition.syntax is not supported 27 | */ 28 | 29 | /* test: 30 | 38 | 39 | 47 | 48 |
49 | This article has the style color:var(--my-color) and --my-color is defined as red. 50 |

For H2, the style color:var(--my-color) is applyed, but as --my-color does not inherit, it gets the initialValue (blue)

51 |
52 | */ 53 | -------------------------------------------------------------------------------- /polyfills/CSS/supports.js: -------------------------------------------------------------------------------- 1 | /*! CSS.supports() Polyfill 2 | * https://gist.github.com/codler/03a0995195aa2859465f 3 | * Copyright (c) 2014 Han Lin Yap http://yap.nu; MIT license */ 4 | 5 | /* 6 | * This polyfill has 2 issues: 7 | * On presto-based opera browsers (12.1, op_mini) it just uses window.supportsCSS with whatever limitations this has (i couldnt find out). 8 | * when there is an earlier version of window.CSS.supports present, it will get used and the parentheses-less one-argument version will not work. 9 | * It maybe not be performant when used excessively, once requested values will get cached though (will increase memory usage if used excessively). 10 | */ 11 | (function () { 12 | //reassignment for presto-based opera-browsers 13 | if ("supportsCSS" in window) { 14 | window.CSS = {}; 15 | window.CSS.supports = window.supportsCSS; 16 | return; 17 | } 18 | // if window.CSS doesnt exist, add it 19 | if (!("CSS" in window)) window.CSS = {}; 20 | // if window.CSS.supports doesnt exist, use polyfill 21 | if (!("supports" in window.CSS)) { 22 | var _cache = {}; 23 | window.CSS.supports = function (propertyName, value) { 24 | var key = [propertyName, value].toString(); 25 | if (key in _cache) return _cache[key]; 26 | 27 | //recursive calls if there are multiple CSS Property Values 28 | function cssSupports(propertyName, value) { 29 | var style = document.createElement("div").style; 30 | //case 1: boolean supports(CSSOMString conditionText); 31 | if (typeof propertyName === "string" && !value) { 32 | var arrOr = mergeOdd(propertyName, /([)])\s*or\s*([(])/gi); 33 | if (arrOr) 34 | return arrOr.some(function (supportsCondition) { 35 | return window.CSS.supports(supportsCondition); 36 | }); 37 | var arrAnd = mergeOdd(propertyName, /([)])\s*and\s*([(])/gi); 38 | if (arrAnd) 39 | return arrAnd.every(function (supportsCondition) { 40 | return window.CSS.supports(supportsCondition); 41 | }); 42 | //remove the first and last parentheses 43 | style.cssText = propertyName.replace("(", "").replace(/[)]$/, ""); 44 | //is invalid when it doesnt get parsed 45 | return !!style.length; 46 | } 47 | //case 2: boolean supports(CSSOMString property, CSSOMString value); 48 | else if ( 49 | typeof propertyName === "string" && 50 | typeof value === "string" 51 | ) { 52 | style.cssText = propertyName + ":" + value; 53 | return !!style.length; 54 | } 55 | //doesnt match either function signature 56 | else return false; 57 | } 58 | 59 | return (_cache[key] = cssSupports(propertyName, value)); 60 | }; 61 | } 62 | 63 | //split string with regex -> pair strings -> filter out falsy values 64 | function mergeOdd(propertyName, reg) { 65 | var arr = propertyName.split(reg); 66 | if (arr.length > 1) 67 | return arr 68 | .map(function (value, index, arr) { 69 | return index % 2 == 0 ? value + arr[index + 1] : ""; 70 | }) 71 | .filter(Boolean); 72 | } 73 | })(); -------------------------------------------------------------------------------- /polyfills/Element/aom.combo.js: -------------------------------------------------------------------------------- 1 | // aom (beta) 2 | 3 | // https://www.digitala11y.com/wai-aria-1-1-cheat-sheet/ 4 | // https://github.com/A11yance/aria-query 5 | // https://github.com/xi/aria-api 6 | 7 | 8 | // role reflection 9 | // https://wicg.github.io/aom/spec/aria-reflection.html#role-reflection 10 | if (!('role' in Element.prototype)) { 11 | Object.defineProperty(Element.prototype, 'role', { 12 | get: function() { 13 | return this.getAttribute('role'); 14 | }, 15 | set: function(value) { 16 | this.setAttribute('role', value); 17 | } 18 | }); 19 | } 20 | 21 | // reflected attributes 22 | // https://wicg.github.io/aom/spec/aria-reflection.html#attribute-reflection 23 | const props = ['ActiveDescendant','Atomic','AutoComplete','Busy','Checked','ColCount','ColIndex','ColSpan','Controls','Current','DescribedBy','Details','Disabled','ErrorMessage','Expanded','FlowTo','HasPopup','Hidden','Invalid','KeyShortcuts','Label','LabelledBy','Level','Live','Modal','MultiLine','MultiSelectable','Orientation','Owns','Placeholder','PosInSet','Pressed','ReadOnly','Relevant','Required','RoleDescription','RowCount','RowIndex','RowSpan','Selected','SetSize','Sort','ValueMax','ValueMin','ValueNow','ValueText']; 24 | for (const prop of props) { 25 | const realProp = 'aria'+prop; 26 | const attr = 'aria-'+prop.toLowerCase(); 27 | if (!(realProp in Element.prototype)) { 28 | Object.defineProperty(Element.prototype, realProp, { 29 | get: function() { 30 | return this.getAttribute(attr); 31 | }, 32 | set: function(value) { 33 | this.setAttribute(attr, value); 34 | } 35 | }); 36 | } 37 | } 38 | 39 | // computedRole 40 | if (!('computedRole' in Element.prototype)) { 41 | Object.defineProperty(Element.prototype, 'computedRole', { 42 | get: function() { 43 | let role = this.getAttribute('role'); 44 | if (roles[role]) return role; 45 | const tag = this.tagName.toLowerCase(); 46 | if (elementToRoles[tag]) { 47 | return elementToRoles[tag][0]; 48 | } else { 49 | for (selector in elementToRoles) { 50 | if (this.matches(selector)) { 51 | return elementToRoles[selector][0]; 52 | } 53 | } 54 | return null; 55 | } 56 | }, 57 | set: function() {} 58 | }); 59 | 60 | const roles = {alert:1,alertdialog:1,application:1,article:1,banner:1,button:1,cell:1,checkbox:1,columnheader:1,combobox:1,command:1,complementary:1,composite:1,contentinfo:1,definition:1,dialog:1,directory:1,document:1,feed:1,figure:1,form:1,grid:1,gridcell:1,group:1,heading:1,img:1,input:1,landmark:1,link:1,list:1,listbox:1,listitem:1,log:1,main:1,marquee:1,math:1,menu:1,menubar:1,menuitem:1,menuitemcheckbox:1,menuitemradio:1,navigation:1,note:1,option:1,presentation:1,progressbar:1,radio:1,radiogroup:1,range:1,region:1,roletype:1,row:1,rowgroup:1,rowheader:1,scrollbar:1,search:1,searchbox:1,section:1,sectionhead:1,select:1,separator:1,slider:1,spinbutton:1,status:1,structure:1,tab:1,Table:1,tablist:1,tabpanel:1,Term:1,textbox:1,timer:1,toolbar:1,tooltip:1,tree:1,treegrid:1,treeitem:1,widget:1,window:1,none:1}; 61 | 62 | const elementToRoles = { 63 | 'article': [ 'article' ] , 64 | 'button': [ 'button' ] , 65 | 'td': ['cell', 'gridcell' ] , 66 | 'input[type=checkbox]': [ 'checkbox' ] , 67 | 'th': [ 'columnheader' ] , 68 | 'select': [ 'combobox', 'listbox' ] , 69 | 'menuitem': [ 'command', 'menuitem' ] , 70 | 'dd': [ 'definition' ] , 71 | 'figure': [ 'figure' ] , 72 | 'form': [ 'form' ] , 73 | 'table': [ 'table', 'grid' ] , 74 | 'fieldset': [ 'group' ] , 75 | 'h1': [ 'heading' ] , 76 | 'h2': [ 'heading' ] , 77 | 'h3': [ 'heading' ] , 78 | 'h4': [ 'heading' ] , 79 | 'h5': [ 'heading' ] , 80 | 'h6': [ 'heading' ] , 81 | 'img': [ 'img' ] , 82 | 'a': [ 'link' ] , 83 | 'link': [ 'link' ] , 84 | 'ol': [ 'list' ] , 85 | 'ul': [ 'list' ] , 86 | 'li': [ 'listitem' ] , 87 | 'nav': [ 'navigation' ] , 88 | 'option': [ 'option' ] , 89 | 'input[type=radio]' : [ 'radio' ] , 90 | 'frame': [ 'region' ] , 91 | 'rel': [ 'roletype' ] , 92 | 'tr': [ 'row' ] , 93 | 'tbody': [ 'rowgroup' ] , 94 | 'tfoot': [ 'rowgroup' ] , 95 | 'thead': [ 'rowgroup' ] , 96 | 'th[scrope=row]': [ 'rowheader' ] , 97 | 'input[type=search]': [ 'searchbox' ] , 98 | 'hr': [ 'separator' ] , 99 | 'dt': [ 'term' ] , 100 | 'dfn': [ 'term' ] , 101 | 'textarea': [ 'textbox' ] , 102 | 'input[type=text]': [ 'textbox' ] , 103 | 'input:not([type])': [ 'textbox' ] , 104 | 'input[type=submit]': [ 'pushbutton' ] , 105 | }; 106 | } 107 | 108 | 109 | 110 | 111 | 112 | 113 | /* 114 | todo: 115 | 116 | ariaActiveDescendantElement 117 | ariaAtomic 118 | ariaAutoComplete 119 | ariaBusy 120 | ariaChecked 121 | ariaColCount 122 | ariaColIndex 123 | ariaColSpan 124 | ariaControlsElements 125 | ariaCurrent 126 | ariaDescribedByElements 127 | ariaDescription 128 | ariaDetailsElements 129 | ariaDisabled 130 | ariaErrorMessageElement 131 | ariaExpanded 132 | ariaFlowToElements 133 | ariaHasPopup 134 | ariaHidden 135 | ariaInvalid 136 | ariaKeyShortcuts 137 | ariaLabel 138 | ariaLabelledByElements 139 | ariaLevel 140 | ariaLive 141 | ariaModal 142 | ariaMultiLine 143 | ariaMultiSelectable 144 | ariaOrientation 145 | ariaOwnsElements 146 | ariaPlaceholder 147 | ariaPosInSet 148 | ariaPressed 149 | ariaReadOnly 150 | ariaRelevant 151 | ariaRequired 152 | ariaRoleDescription 153 | ariaRowCount 154 | ariaRowIndex 155 | ariaRowSpan 156 | ariaSelected 157 | ariaSetSize 158 | ariaSort 159 | ariaValueMax 160 | ariaValueMin 161 | ariaValueNow 162 | ariaValueText 163 | ariaVirtualContent 164 | */ -------------------------------------------------------------------------------- /polyfills/Element/aom.combo.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Element.computedRole polyfill test 6 | 7 | 8 | 9 |
10 |

Here the header

11 |
12 |
Main
13 |
14 |

h1 inside article

15 |
16 |
div
17 |
18 | 19 | 20 | 21 | 24 | 25 | 26 | 27 | 30 | 31 | 34 |
cell 22 | cell 23 |
cell 28 | cell 29 |
cell 32 | cell 33 |
35 | 36 |
37 | 38 | 39 | 40 | 41 |
42 |
section
43 | 44 | 45 | 46 | 47 | 87 | -------------------------------------------------------------------------------- /polyfills/Element/combo.js: -------------------------------------------------------------------------------- 1 | !function(){ 'use strict'; 2 | 3 | var ElProto = Element.prototype; 4 | 5 | var poly = { 6 | matches: ElProto.msMatchesSelector || ElProto.webkitMatchesSelector, 7 | closest: function(sel) { 8 | return this.matches(sel) ? this : (this.parentNode && this.parentNode.closest ? this.parentNode.closest(sel) : null); 9 | }, 10 | prepend: function prepend() { 11 | this.insertBefore(mutationMacro(arguments) , this.firstChild); 12 | }, 13 | append: function append() { 14 | this.appendChild(mutationMacro(arguments)); 15 | }, 16 | before: function before() { 17 | var parentNode = this.parentNode; 18 | parentNode && parentNode.insertBefore(mutationMacro(arguments), this); 19 | }, 20 | after: function after() { 21 | var parentNode = this.parentNode; 22 | parentNode && parentNode.insertBefore(mutationMacro(arguments) , this.nextSibling); 23 | }, 24 | replaceWidth: function replace() { 25 | var parentNode = this.parentNode; 26 | parentNode && parentNode.replaceChild(mutationMacro(arguments), this); 27 | }, 28 | remove: function remove() { 29 | var parentNode = this.parentNode; 30 | parentNode && parentNode.removeChild(this); 31 | } 32 | }; 33 | for (var prop in poly) { 34 | if (!(prop in ElProto)) ElProto[prop] = poly[prop]; 35 | } 36 | function textNodeIfString(node) { 37 | return typeof node === 'string' ? d.createTextNode(node) : node; 38 | } 39 | function mutationMacro(nodes) { 40 | if (nodes.length === 1) return textNodeIfString(nodes[0]); 41 | for (var 42 | fragment = d.createDocumentFragment(), 43 | list = slice.call(nodes), 44 | i = 0; 45 | i < nodes.length; 46 | i++ 47 | ) { 48 | fragment.appendChild(textNodeIfString(list[i])); 49 | } 50 | return fragment; 51 | } 52 | 53 | 54 | // copy from HTMLElement.proto to Element.proto (mainly for SVGElements ie11) 55 | var props = [ 56 | 'blur', // ie11 57 | 'focus', 58 | 'classList', 59 | 'getElementsByClassName', 60 | // 'className', 61 | // 'insertAdjacentElement', 62 | // 'insertAdjacentHTML', 63 | // 'insertAdjacentText', 64 | 'children' // bug, webkit, chrome, ie has not children on the prototype 65 | ]; 66 | function copyProperty(prop, from, to){ 67 | var desc = Object.getOwnPropertyDescriptor(from, prop); 68 | Object.defineProperty(to, prop, desc); 69 | } 70 | for (var i=0, prop; prop = props[i++];) { 71 | !(prop in ElProto) && copyProperty(prop, HTMLElement.prototype, ElProto); 72 | } 73 | 74 | 75 | 76 | }(); 77 | -------------------------------------------------------------------------------- /polyfills/Element/prototype/isVisible.js: -------------------------------------------------------------------------------- 1 | // todo 2 | // wpt: https://github.com/web-platform-tests/wpt/blob/ff7c98f8fa23c8c36099d267ac258c0005f81180/css/cssom-view/isVisible.html 3 | 4 | if (!Element.prototype.isVisible) { 5 | Element.prototype.isVisible = function(options){ 6 | 7 | // If this does not have an associated layout box, return false. 8 | if (!this.offsetParent) return false; 9 | //if (this.offsetWidth === 0 || this.offsetHeight === 0) return false; 10 | 11 | const style = getComputedStyle(this); 12 | 13 | // If a shadow-inclusive ancestor of this has content-visibility: hidden, return false. 14 | // can we skip "this"? It probably won't make offsetHeight. 15 | let oParent = this; 16 | while (oParent) { 17 | const style = getComputedStyle(oParent); 18 | if (style.getPropertyValue('content-visibility') === 'hidden') return false; 19 | oParent = oParent.offsetParent; 20 | } 21 | 22 | // If the checkAriaHidden dictionary member of options is true, and this is hidden (in the ARIA sense), return false. (removed from spec?) 23 | 24 | // If the checkInert dictionary member of options is true, and this is inert, return false. 25 | if (options && options.checkInert && this.closest('[inert]')) return false; 26 | 27 | // If the checkOpacity dictionary member of options is true, and this, or a shadow-inclusive ancestor of this, has a computed opacity value of 0, return false. 28 | if (options && options.checkOpacity && (style.getPropertyValue('opacity') === '0' || style.getPropertyValue('opacity') === '0.0')) return false; 29 | 30 | // If the checkVisibilityCSS dictionary member of options is true, and this is invisible, return false. 31 | if (options && options.checkVisibilityCSS && style.getPropertyValue('visibility') === 'hidden') return false; 32 | 33 | return true; 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /polyfills/Element/prototype/replaceChildren.js: -------------------------------------------------------------------------------- 1 | if (!('replaceChildren' in Element.prototype)) { 2 | Document.prototype.replaceChildren = Element.prototype.replaceChildren = function replaceChildren() { 3 | while (this.firstChild) this.removeChild(this.firstChild); 4 | this.append.apply(this, arguments); 5 | }; 6 | } -------------------------------------------------------------------------------- /polyfills/Element/prototype/scrollIntoViewIfNeeded.js: -------------------------------------------------------------------------------- 1 | // firefox 2 | if ( !Element.prototype.scrollIntoViewIfNeeded ) { 3 | Element.prototype.scrollIntoViewIfNeeded = function ( centerIfNeeded = true ) { 4 | const el = this; 5 | new IntersectionObserver( function( [entry] ) { 6 | const ratio = entry.intersectionRatio; 7 | if (ratio < 1) { 8 | let place = ratio <= 0 && centerIfNeeded ? 'center' : 'nearest'; 9 | el.scrollIntoView( { 10 | block: place, 11 | inline: place, 12 | } ); 13 | } 14 | this.disconnect(); 15 | } ).observe(this); 16 | }; 17 | } -------------------------------------------------------------------------------- /polyfills/Element/prototype/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Element prototype tests 6 | 7 | 8 | 9 | 16 | 17 |
18 | 19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 |
27 | There is more 🔽 28 |
29 | 30 |
31 |
32 | bottom 33 |
34 |
35 | -------------------------------------------------------------------------------- /polyfills/Element/prototype/toggleAttribute.js: -------------------------------------------------------------------------------- 1 | if (!Element.prototype.toggleAttribute) { 2 | Element.prototype.toggleAttribute = function (name, force) { 3 | if (force !== void 0) force = !!force 4 | if (this.hasAttribute(name)) { 5 | if (force) return true; 6 | this.removeAttribute(name); 7 | return false; 8 | } 9 | if (force === false) return false; 10 | this.setAttribute(name, ""); 11 | return true; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /polyfills/HTMLElement/prototype/inert.js: -------------------------------------------------------------------------------- 1 | 2 | if (!('inert' in HTMLElement.prototype)) { 3 | 4 | Object.defineProperty(HTMLElement.prototype, 'inert', { 5 | enumerable: true, 6 | get: function() { 7 | return this.hasAttribute('inert'); 8 | }, 9 | set: function(inert) { 10 | inert ? this.setAttribute('inert','') : this.removeAttribute('inert'); 11 | }, 12 | }); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /polyfills/HTMLFormElement/prototype/reportValidity.js: -------------------------------------------------------------------------------- 1 | if (!HTMLFormElement.prototype.reportValidity) { 2 | HTMLFormElement.prototype.reportValidity = function() { 3 | if (this.checkValidity()) return true; 4 | if (this.noValidate) { 5 | this.noValidate = false; 6 | this.requestSubmit(); 7 | this.noValidate = true; 8 | } else { 9 | this.requestSubmit(); 10 | } 11 | return false; 12 | }; 13 | } 14 | 15 | /* old 16 | if (!HTMLFormElement.prototype.reportValidity) { 17 | HTMLFormElement.prototype.reportValidity = function() { 18 | if (this.checkValidity()) return true; 19 | var btn = d.createElement('button'); 20 | this.appendChild(btn); 21 | btn.click(); 22 | this.removeChild(btn); 23 | return false; 24 | }; 25 | } 26 | */ -------------------------------------------------------------------------------- /polyfills/HTMLFormElement/prototype/requestSubmit.js: -------------------------------------------------------------------------------- 1 | if (!HTMLFormElement.prototype.requestSubmit) { 2 | HTMLFormElement.prototype.requestSubmit = function(submitter) { 3 | let submitBtn = submitter; 4 | if (!submitBtn) { 5 | submitBtn = document.createElement('input'); 6 | submitBtn.type = 'submit'; 7 | submitBtn.hidden = true; 8 | this.appendChild(submitBtn); 9 | } 10 | submitBtn.click(); 11 | !submitter && this.removeChild(submitBtn); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /polyfills/HTMLInputElement/prototype/reportValidity.js: -------------------------------------------------------------------------------- 1 | if (!HTMLInputElement.prototype.reportValidity) { 2 | HTMLInputElement.prototype.reportValidity = function(){ 3 | if (this.checkValidity()) return true 4 | var tmpForm; 5 | if (!this.form) { 6 | var tmpForm = d.createElement('form'); 7 | tmpForm.style.display = 'inline'; 8 | this.before(tmpForm); 9 | tmpForm.append(this); 10 | } 11 | var siblings = Array.from(this.form.elements).filter(function(input){ 12 | return input !== this && !!input.checkValidity && !input.disabled; 13 | },this); 14 | siblings.forEach(function(input){ 15 | input.disabled = true; 16 | }); 17 | this.form.reportValidity(); 18 | siblings.forEach(function(input){ 19 | input.disabled = false; 20 | }); 21 | if (tmpForm) { 22 | tmpForm.before(this); 23 | tmpForm.remove(); 24 | } 25 | this.focus(); 26 | this.selectionStart = 0; 27 | return false; 28 | }; 29 | } -------------------------------------------------------------------------------- /polyfills/HTMLInputElement/prototype/showPicker.js: -------------------------------------------------------------------------------- 1 | 2 | if (!HTMLInputElement.prototype.showPicker) { 3 | let types = {'date':1, 'month':1, 'week':1, 'time':1, 'datetime-local':1, 'color':1, 'file':1}; 4 | HTMLInputElement.prototype.showPicker = function() { 5 | if (this.type in types) { 6 | this.click(); 7 | } 8 | }; 9 | } -------------------------------------------------------------------------------- /polyfills/HTMLSlotElement/prototype/assignedElements.js: -------------------------------------------------------------------------------- 1 | if (!HTMLSlotElement.prototype.assignedElements) { 2 | HTMLSlotElement.prototype.assignedElements = function () { 3 | return this.assignedNodes().filter(n => n instanceof Element) 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /polyfills/Math/sign.js: -------------------------------------------------------------------------------- 1 | if (!Math.sign) { 2 | Math.sign = function (x) { 3 | // If x is NaN, the result is NaN. 4 | // If x is -0, the result is -0. 5 | // If x is +0, the result is +0. 6 | // If x is negative and not -0, the result is -1. 7 | // If x is positive and not +0, the result is +1. 8 | return ((x > 0) - (x < 0)) || +x; 9 | // A more aesthetic pseudo-representation: 10 | // 11 | // ( (x > 0) ? 1 : 0 ) // if x is positive, then positive one 12 | // + // else (because you can't be both - and +) 13 | // ( (x < 0) ? -1 : 0 ) // if x is negative, then negative one 14 | // || // if x is 0, -0, or NaN, or not a number, 15 | // +x // then the result will be x, (or) if x is 16 | // // not a number, then x converts to number 17 | }; 18 | } -------------------------------------------------------------------------------- /polyfills/Math/trunc.js: -------------------------------------------------------------------------------- 1 | if (!Math.trunc) { 2 | Math.trunc = function (n) { 3 | return n < 0 ? Math.ceil(n) : Math.floor(n); 4 | }; 5 | } -------------------------------------------------------------------------------- /polyfills/Node/prototype/contains.js: -------------------------------------------------------------------------------- 1 | if (!('contains' in Node.prototype)) { 2 | Node.prototype.contains = function(el){ 3 | if (el instanceof CharacterData) { 4 | if (!el.parentNode) return false; 5 | el = el.parentNode; 6 | } 7 | if (this === el) return true; 8 | if (this instanceof Document) { 9 | return this.documentElement.contains(el) 10 | } 11 | return HTMLElement.prototype.contains.call(this, el); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /polyfills/Node/prototype/insertAfter.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi - ISC */ 2 | /* 3 | https://github.com/ungap/insert-after/blob/main/index.js 4 | */ 5 | if (!('insertAfter' in Node.prototype)) 6 | Node.prototype.insertAfter = function insertAfter(node, ref) { 7 | return this.insertBefore(node, ref ? ref.nextSibling : this.firstChild); 8 | }; -------------------------------------------------------------------------------- /polyfills/Node/prototype/isConnected.js: -------------------------------------------------------------------------------- 1 | if (!('isConnected' in Node.prototype)) { 2 | Object.defineProperty(Node.prototype, 'isConnected',{ 3 | get:function(){ 4 | return this.ownerDocument.contains(this); 5 | } 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /polyfills/Node/prototype/tests/contains.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Level.css TEST 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 33 | -------------------------------------------------------------------------------- /polyfills/Number/isNumber.js: -------------------------------------------------------------------------------- 1 | if (!Number.isInteger) { 2 | Number.isInteger = function (value) { 3 | return ( 4 | typeof value === 'number' && 5 | isFinite(value) && 6 | Math.floor(value) === value 7 | ); 8 | }; 9 | } -------------------------------------------------------------------------------- /polyfills/Object/assign.js: -------------------------------------------------------------------------------- 1 | if (typeof Object.assign != 'function') { 2 | Object.defineProperty(Object, "assign", { 3 | value: function assign(target, varArgs) { 4 | if (target == null) { 5 | throw new TypeError('Cannot convert undefined or null to object'); 6 | } 7 | var to = Object(target); 8 | for (var index = 1; index < arguments.length; index++) { 9 | var nextSource = arguments[index]; 10 | if (nextSource != null) { 11 | for (var nextKey in nextSource) { 12 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 13 | to[nextKey] = nextSource[nextKey]; 14 | } 15 | } 16 | } 17 | } 18 | return to; 19 | }, 20 | writable: true, 21 | configurable: true 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /polyfills/Object/entries.js: -------------------------------------------------------------------------------- 1 | if (!Object.entries) { 2 | Object.entries = function (obj) { 3 | var ownProps = Object.keys(obj), 4 | i = ownProps.length, 5 | resArray = new Array(i); // preallocate the Array 6 | while (i--) resArray[i] = [ownProps[i], obj[ownProps[i]]]; 7 | return resArray; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /polyfills/Object/fromEntries.js: -------------------------------------------------------------------------------- 1 | if (!Object.fromEntries) { 2 | Object.fromEntries = function (arr) { 3 | var obj = {}, item, i; 4 | for (i=0; item=arr[i++];) { 5 | obj[item[0]] = item[1]; 6 | } 7 | return obj; 8 | }; 9 | } -------------------------------------------------------------------------------- /polyfills/Object/hasOwn.js: -------------------------------------------------------------------------------- 1 | !Object.hasOwn && (Object.hasOwn = Object.call.bind(Object.hasOwnProperty)); -------------------------------------------------------------------------------- /polyfills/Object/is.js: -------------------------------------------------------------------------------- 1 | if (!Object.is) { 2 | Object.defineProperty(Object, "is", { 3 | value: function (x, y) { 4 | // SameValue algorithm 5 | if (x === y) { 6 | // return true if x and y are not 0, OR 7 | // if x and y are both 0 of the same sign. 8 | // This checks for cases 1 and 2 above. 9 | return x !== 0 || 1 / x === 1 / y; 10 | } else { 11 | // return true if both x AND y evaluate to NaN. 12 | // The only possibility for a variable to not be strictly equal to itself 13 | // is when that variable evaluates to NaN (example: Number.NaN, 0/0, NaN). 14 | // This checks for case 3. 15 | return x !== x && y !== y; 16 | } 17 | } 18 | }); 19 | } -------------------------------------------------------------------------------- /polyfills/Object/values.js: -------------------------------------------------------------------------------- 1 | if (!Object.values) { 2 | Object.values = function values(O) { 3 | return Object.keys(O).map(function(key) { 4 | return O[key]; 5 | }); 6 | }; 7 | } 8 | /* 9 | Object.key available in ie11! 10 | if (!Object.values) Object.values = function (o) { 11 | if (o !== Object(o)) throw new TypeError('Object.values called on a non-object'); 12 | var values = [], key; 13 | for (key in o) if (Object.prototype.hasOwnProperty.call(o, key)) values.push(o[key]); 14 | return values; 15 | } 16 | */ -------------------------------------------------------------------------------- /polyfills/Promise/allSettled.js: -------------------------------------------------------------------------------- 1 | if (Promise && !Promise.allSettled) { 2 | Promise.allSettled = function (promises) { 3 | return Promise.all(promises.map(function (promise) { 4 | return promise.then(function (value) { 5 | return { state: 'fulfilled', value: value }; 6 | }).catch(function (reason) { 7 | return { state: 'rejected', reason: reason }; 8 | }); 9 | })); 10 | }; 11 | } -------------------------------------------------------------------------------- /polyfills/Promise/any.js: -------------------------------------------------------------------------------- 1 | https://github.com/ungap/promise-any/blob/master/index.js 2 | var any = (Promise.any || function ($) { 3 | return new Promise(function (D, E, A, L) { 4 | A = []; 5 | L = $.map(function ($, i) { 6 | return Promise.resolve($).then(D, function (O) { 7 | return ((A[i] = O), --L) || E({ errors: A }); 8 | }); 9 | }).length; 10 | }); 11 | }).bind(Promise); -------------------------------------------------------------------------------- /polyfills/Promise/withResolvers.js: -------------------------------------------------------------------------------- 1 | Promise.withResolvers || (Promise.withResolvers = function withResolvers() { 2 | var a, b, c = new this(function (resolve, reject) { 3 | a = resolve; 4 | b = reject; 5 | }); 6 | return {resolve: a, reject: b, promise: c}; 7 | }); -------------------------------------------------------------------------------- /polyfills/RegExp/prototype/flags.js: -------------------------------------------------------------------------------- 1 | if (RegExp.prototype.flags === undefined) { 2 | Object.defineProperty(RegExp.prototype, 'flags', { 3 | configurable: true, 4 | get: function () { 5 | return this.toString().match(/[gimuy]*$/)[0]; 6 | } 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /polyfills/SVGStyleElement/combo.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxodin/lazyfill/c53e43fe2d88269cf84b924461218c23422cc49a/polyfills/SVGStyleElement/combo.js -------------------------------------------------------------------------------- /polyfills/SVGStyleElement/prototype/sheet.js: -------------------------------------------------------------------------------- 1 | // ie11 2 | if (!('sheet' in SVGStyleElement.prototype)) { 3 | Object.defineProperty(SVGStyleElement.prototype, 'sheet', { 4 | get:function(){ 5 | var all = d.styleSheets; 6 | for (var i=0, sheet; sheet=all[i++];) { 7 | if (sheet.ownerNode === this) return sheet; 8 | } 9 | } 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /polyfills/String/fromCodePoint.js: -------------------------------------------------------------------------------- 1 | if (!String.fromCodePoint) { 2 | (function () { 3 | var defineProperty = (function () { 4 | try { 5 | var object = {}; 6 | var $defineProperty = Object.defineProperty; 7 | var result = $defineProperty(object, object, object) && $defineProperty; 8 | } catch (error) { } 9 | return result; 10 | })(); 11 | var stringFromCharCode = String.fromCharCode; 12 | var floor = Math.floor; 13 | var fromCodePoint = function () { 14 | var MAX_SIZE = 0x4000; 15 | var codeUnits = []; 16 | var highSurrogate; 17 | var lowSurrogate; 18 | var index = -1; 19 | var length = arguments.length; 20 | if (!length) { 21 | return ''; 22 | } 23 | var result = ''; 24 | while (++index < length) { 25 | var codePoint = Number(arguments[index]); 26 | if ( 27 | !isFinite(codePoint) || 28 | codePoint < 0 || 29 | codePoint > 0x10ffff || 30 | floor(codePoint) != codePoint 31 | ) { 32 | throw RangeError('Invalid code point: ' + codePoint); 33 | } 34 | if (codePoint <= 0xffff) { 35 | // BMP code point 36 | codeUnits.push(codePoint); 37 | } else { 38 | codePoint -= 0x10000; 39 | highSurrogate = (codePoint >> 10) + 0xd800; 40 | lowSurrogate = (codePoint % 0x400) + 0xdc00; 41 | codeUnits.push(highSurrogate, lowSurrogate); 42 | } 43 | if (index + 1 == length || codeUnits.length > MAX_SIZE) { 44 | result += stringFromCharCode.apply(null, codeUnits); 45 | codeUnits.length = 0; 46 | } 47 | } 48 | return result; 49 | }; 50 | if (defineProperty) { 51 | defineProperty(String, 'fromCodePoint', { 52 | value: fromCodePoint, 53 | configurable: true, 54 | writable: true, 55 | }); 56 | } else { 57 | String.fromCodePoint = fromCodePoint; 58 | } 59 | })(); 60 | } -------------------------------------------------------------------------------- /polyfills/String/prototype/at.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.at) { 2 | Object.defineProperty(String.prototype, "at", 3 | { 4 | value: function (n) { 5 | // ToInteger() abstract op 6 | n = Math.trunc(n) || 0; 7 | // Allow negative indexing from the end 8 | if (n < 0) n += this.length; 9 | // OOB access is guaranteed to return undefined 10 | if (n < 0 || n >= this.length) return undefined; 11 | // Otherwise, this is just normal property access 12 | return this[n]; 13 | }, 14 | writable: true, 15 | enumerable: false, 16 | configurable: true 17 | }); 18 | } -------------------------------------------------------------------------------- /polyfills/String/prototype/codePointAt.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.codePointAt) { 2 | Object.defineProperty(String.prototype, 'codePointAt', { 3 | configurable: true, 4 | writable: true, 5 | value: function codePointAt (position) { 6 | if (this == null) { 7 | throw TypeError(); 8 | } 9 | var string = String(this); 10 | var size = string.length; 11 | var index = position ? Number(position) : 0; 12 | if (index != index) { 13 | index = 0; 14 | } 15 | if (index < 0 || index >= size) { 16 | return undefined; 17 | } 18 | var first = string.charCodeAt(index); 19 | var second; 20 | if (first >= 0xd800 && first <= 0xdbff && size > index + 1) { 21 | second = string.charCodeAt(index + 1); 22 | if (second >= 0xdc00 && second <= 0xdfff) { 23 | return (first - 0xd800) * 0x400 + second - 0xdc00 + 0x10000; 24 | } 25 | } 26 | return first; 27 | }, 28 | }); 29 | } -------------------------------------------------------------------------------- /polyfills/String/prototype/endsWith.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.endsWith) { 2 | Object.defineProperty(String.prototype, 'endsWith', { 3 | configurable: true, 4 | writable: true, 5 | value: function (searchString, position) { 6 | var subjectString = this.toString(); 7 | if ( 8 | typeof position !== 'number' || 9 | !isFinite(position) || 10 | Math.floor(position) !== position || 11 | position > subjectString.length 12 | ) { 13 | position = subjectString.length; 14 | } 15 | position -= searchString.length; 16 | var lastIndex = subjectString.lastIndexOf(searchString, position); 17 | return lastIndex !== -1 && lastIndex === position; 18 | }, 19 | }); 20 | } -------------------------------------------------------------------------------- /polyfills/String/prototype/includes.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.includes) { 2 | String.prototype.includes = function(search, start){ 3 | if (typeof start !== 'number') start = 0; 4 | if (start + search.length > this.length) return false; 5 | return this.indexOf(search, start) !== -1; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /polyfills/String/prototype/padEnd.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.padEnd) { 2 | Object.defineProperty(String.prototype, 'padEnd', { 3 | configurable: true, 4 | writable: true, 5 | value: function (targetLength, padString) { 6 | targetLength = targetLength >> 0; //floor if number or convert non-number to 0; 7 | padString = String(typeof padString !== 'undefined' ? padString : ' '); 8 | if (this.length > targetLength) { 9 | return String(this); 10 | } else { 11 | targetLength = targetLength - this.length; 12 | if (targetLength > padString.length) { 13 | padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed 14 | } 15 | return String(this) + padString.slice(0, targetLength); 16 | } 17 | }, 18 | }); 19 | } -------------------------------------------------------------------------------- /polyfills/String/prototype/padStart.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.padStart) { 2 | Object.defineProperty(String.prototype, 'padStart', { 3 | configurable: true, 4 | writable: true, 5 | value: function (targetLength, padString) { 6 | targetLength = targetLength >> 0; //floor if number or convert non-number to 0; 7 | padString = String(typeof padString !== 'undefined' ? padString : ' '); 8 | if (this.length > targetLength) { 9 | return String(this); 10 | } else { 11 | targetLength = targetLength - this.length; 12 | if (targetLength > padString.length) { 13 | padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed 14 | } 15 | return padString.slice(0, targetLength) + String(this); 16 | } 17 | }, 18 | }); 19 | } -------------------------------------------------------------------------------- /polyfills/String/prototype/repeat.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.repeat) { 2 | Object.defineProperty(String.prototype, 'repeat', { 3 | configurable: true, 4 | writable: true, 5 | value: function (count) { 6 | if (this == null) throw new TypeError("can't convert " + this + ' to object'); 7 | var str = '' + this; 8 | count = +count; 9 | if (count != count) count = 0; 10 | if (count < 0) throw new RangeError('repeat count must be non-negative'); 11 | if (count == Infinity) throw new RangeError('repeat count must be less than infinity'); 12 | count = Math.floor(count); 13 | if (str.length == 0 || count == 0) return ''; 14 | if (str.length * count >= 1 << 28) { 15 | throw new RangeError('repeat count must not overflow maximum string size'); 16 | } 17 | var rpt = ''; 18 | for (; ;) { 19 | if ((count & 1) == 1) rpt += str; 20 | count >>>= 1; 21 | if (count == 0) break; 22 | str += str; 23 | } 24 | return rpt; 25 | }, 26 | }); 27 | } -------------------------------------------------------------------------------- /polyfills/String/prototype/replaceAll.js: -------------------------------------------------------------------------------- 1 | // https://github.com/zloirock/core-js/blob/d7409d106383f252ab25215a287d9b8160785918/packages/core-js/modules/es.string.replace-all.js#L23 2 | if (!''.replaceAll) { 3 | !function(){ 4 | 5 | var stringIndexOf = function (string, searchValue, fromIndex) { 6 | if (fromIndex > string.length) return -1; 7 | if (searchValue === '') return fromIndex; 8 | return string.indexOf(searchValue, fromIndex); 9 | }; 10 | 11 | var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d{1,2}|<[^>]*>)/g; 12 | var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d{1,2})/g; 13 | function GetSubstitution(matched, str, position, captures, namedCaptures, replacement) { 14 | var tailPos = position + matched.length; 15 | var m = captures.length; 16 | var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED; 17 | if (namedCaptures !== undefined) { 18 | namedCaptures = toObject(namedCaptures); 19 | symbols = SUBSTITUTION_SYMBOLS; 20 | } 21 | return ''.replace.call(replacement, symbols, function (match, ch) { 22 | var capture; 23 | switch (ch.charAt(0)) { 24 | case '$': return '$'; 25 | case '&': return matched; 26 | case '`': return str.slice(0, position); 27 | case "'": return str.slice(tailPos); 28 | case '<': 29 | capture = namedCaptures[ch.slice(1, -1)]; 30 | break; 31 | default: // \d\d? 32 | var n = +ch; 33 | if (n === 0) return match; 34 | if (n > m) { 35 | var f = Math.floor(n / 10); 36 | if (f === 0) return match; 37 | if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1); 38 | return match; 39 | } 40 | capture = captures[n - 1]; 41 | } 42 | return capture === undefined ? '' : capture; 43 | }); 44 | }; 45 | 46 | Object.defineProperty(String.prototype, 'replaceAll', { 47 | configurable: true, 48 | writable: true, 49 | value: function replaceAll(searchValue, replaceValue) { 50 | if (this == null) throw TypeError("Can't call method on " + this); 51 | var O = this; 52 | var IS_REG_EXP, flags, replacer, string, searchString, functionalReplace, searchLength, advanceBy, replacement; 53 | var position = 0; 54 | var endOfLastMatch = 0; 55 | var result = ''; 56 | if (searchValue != null) { 57 | IS_REG_EXP = searchValue instanceof RegExp; 58 | if (IS_REG_EXP) { 59 | flags = String(searchValue.flags); 60 | if (!~flags.indexOf('g')) throw TypeError('`.replaceAll` does not allow non-global regexes'); 61 | } 62 | replacer = window.Symbol && searchValue[Symbol.replace]; 63 | var IS_PURE = true; // ?? 64 | if (replacer !== undefined) { 65 | return replacer.call(searchValue, O, replaceValue); 66 | } else if (IS_PURE && IS_REG_EXP) { 67 | return String(O).replace(searchValue, replaceValue); 68 | } 69 | } 70 | string = String(O); 71 | searchString = String(searchValue); 72 | functionalReplace = typeof replaceValue === 'function'; 73 | if (!functionalReplace) replaceValue = String(replaceValue); 74 | searchLength = searchString.length; 75 | advanceBy = Math.max(1, searchLength); 76 | position = stringIndexOf(string, searchString, 0); 77 | while (position !== -1) { 78 | if (functionalReplace) { 79 | replacement = String(replaceValue(searchString, position, string)); 80 | } else { 81 | replacement = GetSubstitution(searchString, string, position, [], undefined, replaceValue); 82 | } 83 | result += string.slice(endOfLastMatch, position) + replacement; 84 | endOfLastMatch = position + searchLength; 85 | position = stringIndexOf(string, searchString, position + advanceBy); 86 | } 87 | if (endOfLastMatch < string.length) { 88 | result += string.slice(endOfLastMatch); 89 | } 90 | return result; 91 | } 92 | }); 93 | 94 | 95 | 96 | }(); 97 | 98 | } 99 | -------------------------------------------------------------------------------- /polyfills/String/prototype/startsWith.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.startsWith) { 2 | Object.defineProperty(String.prototype, 'startsWith', { 3 | configurable: true, 4 | writable: true, 5 | value: function (searchString, position) { 6 | position = position || 0; 7 | return this.substr(position, searchString.length) === searchString; 8 | }, 9 | }); 10 | } -------------------------------------------------------------------------------- /polyfills/SubmitEvent/prototype/submitter.js: -------------------------------------------------------------------------------- 1 | !function(){ 'use strict'; 2 | let lastBtn = null; 3 | 4 | addEventListener('click',function(e){ 5 | if (!e.target.closest) return; 6 | lastBtn = e.target.closest('button, input[type=submit]'); 7 | }, true); 8 | 9 | addEventListener('submit',function(e){ 10 | if ('submitter' in e) return; 11 | var canditates = [document.activeElement, lastBtn]; 12 | lastBtn = null; 13 | for (var i=0; i < canditates.length; i++) { 14 | var candidate = canditates[i]; 15 | if (!candidate) continue; 16 | if (!candidate.form) continue; 17 | if (!candidate.matches('button, input[type=button], input[type=image]')) continue; 18 | e.submitter = candidate; 19 | return; 20 | } 21 | e.submitter = e.target.querySelector('button, input[type=button], input[type=image]') 22 | }, true); 23 | }(); 24 | -------------------------------------------------------------------------------- /polyfills/SubmitEvent/prototype/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SubmitEvent prototype test 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /polyfills/WeakRef.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | 4 | 5 | Works in IE and Firefox 6 | not in Chrome and Safari :( 7 | 8 | Not very efficient, as it creates a HTMLCollection in the constructor and for deref() 9 | AND as it dont work for safari and chrome, it looses even more memory as the HTMLCollections are not garbage collected 10 | 11 | inspiration: https://github.com/whatwg/dom/issues/706 12 | "Creating new HTMLCollection instances everytime will increase management cost." 13 | 14 | 15 | Todo: any other solutions / hacks? 16 | 17 | */ 18 | 19 | console.log('dont use this!'); 20 | 21 | if (!window.WeakRef) { 22 | let el = document.createElement('div'); 23 | window.WeakRef = function(value) { 24 | this.id = Math.random(); 25 | let collection = el.getElementsByTagName("x"+this.id); 26 | collection.expando = value; 27 | collection = null; 28 | } 29 | WeakRef.prototype = { 30 | deref: function() { 31 | return el.getElementsByTagName("x"+this.id).expando; 32 | } 33 | } 34 | } 35 | 36 | /* todo: how to? 37 | function FinalizationGroup(fn) { 38 | 39 | } 40 | FinalizationGroup.prototype = { 41 | register(value, name) { 42 | }, 43 | unregister(value, name) { 44 | }, 45 | cleanupSome(fn) { 46 | } 47 | } 48 | */ -------------------------------------------------------------------------------- /polyfills/WeakSet.js: -------------------------------------------------------------------------------- 1 | if (!window.WeakSet) { 'use strict' 2 | WeakSet = function(iterable){ 3 | this.Map = new WeakMap(); 4 | iterable && iterable.forEach(this.add, this); 5 | } 6 | WeakSet.prototype = { 7 | add:function(value){ 8 | this.Map.set(value, 1); 9 | return this; 10 | }, 11 | delete:function(value){ return this.Map.delete(value); }, 12 | has:function(value){ return this.Map.has(value); } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /polyfills/cancelIdleCallback.js: -------------------------------------------------------------------------------- 1 | if (!window.cancelIdleCallback) { 2 | window.cancelIdleCallback = function (id) { 3 | clearTimeout(id); 4 | }; 5 | } -------------------------------------------------------------------------------- /polyfills/crypto/randomUUID.js: -------------------------------------------------------------------------------- 1 | // Code based on Node.js' `lib/internal/crypto/random.js`, subject 2 | // to Node.js license found at: 3 | // https://raw.githubusercontent.com/nodejs/node/master/LICENSE 4 | 5 | !function () { 6 | 7 | const randomFillSync = window.crypto.getRandomValues.bind(window.crypto); 8 | 9 | // Implements an RFC 4122 version 4 random UUID. 10 | // To improve performance, random data is generated in batches 11 | // large enough to cover kBatchSize UUID's at a time. The uuidData 12 | // and uuid buffers are reused. Each call to randomUUID() consumes 13 | // 16 bytes from the buffer. 14 | 15 | const kHexDigits = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102]; 16 | const kBatchSize = 128; 17 | let uuidData; 18 | let uuidNotBuffered; 19 | let uuid; 20 | let uuidBatch = 0; 21 | let slice = Uint8Array.prototype.slice || Array.prototype.slice; 22 | 23 | function getBufferedUUID() { 24 | if (uuidData === undefined) uuidData = new Uint8Array(16 * kBatchSize); 25 | if (uuidBatch === 0) randomFillSync(uuidData); 26 | uuidBatch = (uuidBatch + 1) % kBatchSize; 27 | return slice.call(uuidData, uuidBatch * 16, uuidBatch * 16 + 16); 28 | } 29 | 30 | function randomUUID(options) { 31 | const disableEntropyCache = options ? options.disableEntropyCache : false; 32 | 33 | if (uuid === undefined) { 34 | uuid = new Uint8Array(36); 35 | uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'.charCodeAt(0); 36 | uuid[14] = 52; // '4', identifies the UUID version 37 | } 38 | 39 | let uuidBuf; 40 | if (!disableEntropyCache) { 41 | uuidBuf = getBufferedUUID(); 42 | } else { 43 | uuidBuf = uuidNotBuffered; 44 | if (uuidBuf === undefined) uuidBuf = uuidNotBuffered = new Uint8Array(16); 45 | randomFillSync(uuidBuf); 46 | } 47 | 48 | // Variant byte: 10xxxxxx (variant 1) 49 | uuidBuf[8] = (uuidBuf[8] & 0x3f) | 0x80; 50 | 51 | // This function is structured the way it is for performance. 52 | // The uuid buffer stores the serialization of the random 53 | // bytes from uuidData. 54 | // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 55 | let n = 0; 56 | uuid[0] = kHexDigits[uuidBuf[n] >> 4]; 57 | uuid[1] = kHexDigits[uuidBuf[n++] & 0xf]; 58 | uuid[2] = kHexDigits[uuidBuf[n] >> 4]; 59 | uuid[3] = kHexDigits[uuidBuf[n++] & 0xf]; 60 | uuid[4] = kHexDigits[uuidBuf[n] >> 4]; 61 | uuid[5] = kHexDigits[uuidBuf[n++] & 0xf]; 62 | uuid[6] = kHexDigits[uuidBuf[n] >> 4]; 63 | uuid[7] = kHexDigits[uuidBuf[n++] & 0xf]; 64 | // - 65 | uuid[9] = kHexDigits[uuidBuf[n] >> 4]; 66 | uuid[10] = kHexDigits[uuidBuf[n++] & 0xf]; 67 | uuid[11] = kHexDigits[uuidBuf[n] >> 4]; 68 | uuid[12] = kHexDigits[uuidBuf[n++] & 0xf]; 69 | // - 70 | // 4, uuid[14] is set already... 71 | uuid[15] = kHexDigits[uuidBuf[n++] & 0xf]; 72 | uuid[16] = kHexDigits[uuidBuf[n] >> 4]; 73 | uuid[17] = kHexDigits[uuidBuf[n++] & 0xf]; 74 | // - 75 | uuid[19] = kHexDigits[uuidBuf[n] >> 4]; 76 | uuid[20] = kHexDigits[uuidBuf[n++] & 0xf]; 77 | uuid[21] = kHexDigits[uuidBuf[n] >> 4]; 78 | uuid[22] = kHexDigits[uuidBuf[n++] & 0xf]; 79 | // - 80 | uuid[24] = kHexDigits[uuidBuf[n] >> 4]; 81 | uuid[25] = kHexDigits[uuidBuf[n++] & 0xf]; 82 | uuid[26] = kHexDigits[uuidBuf[n] >> 4]; 83 | uuid[27] = kHexDigits[uuidBuf[n++] & 0xf]; 84 | uuid[28] = kHexDigits[uuidBuf[n] >> 4]; 85 | uuid[29] = kHexDigits[uuidBuf[n++] & 0xf]; 86 | uuid[30] = kHexDigits[uuidBuf[n] >> 4]; 87 | uuid[31] = kHexDigits[uuidBuf[n++] & 0xf]; 88 | uuid[32] = kHexDigits[uuidBuf[n] >> 4]; 89 | uuid[33] = kHexDigits[uuidBuf[n++] & 0xf]; 90 | uuid[34] = kHexDigits[uuidBuf[n] >> 4]; 91 | uuid[35] = kHexDigits[uuidBuf[n] & 0xf]; 92 | 93 | return String.fromCharCode.apply(null, uuid); 94 | } 95 | 96 | window.crypto.randomUUID = randomUUID; 97 | 98 | 99 | }(); 100 | -------------------------------------------------------------------------------- /polyfills/crypto/randomUUID.original.js: -------------------------------------------------------------------------------- 1 | // Code based on Node.js' `lib/internal/crypto/random.js`, subject 2 | // to Node.js license found at: 3 | // https://raw.githubusercontent.com/nodejs/node/master/LICENSE 4 | 5 | !function () { 6 | 7 | // 8 | // internal/errors 9 | // 10 | class ERR_INVALID_ARG_TYPE extends TypeError { 11 | constructor(name, type, value) { 12 | super(`${name} variable is not of type ${type} (value: '${value}')`); 13 | } 14 | code = 'ERR_INVALID_ARG_TYPE'; 15 | } 16 | 17 | // 18 | // internal/validators 19 | // 20 | function validateBoolean(value, name) { 21 | if (typeof value !== 'boolean') throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value); 22 | } 23 | 24 | function validateObject(value, name) { 25 | if (value === null || Array.isArray(value) || typeof value !== 'object') { 26 | throw new ERR_INVALID_ARG_TYPE(name, 'Object', value); 27 | } 28 | } 29 | 30 | // 31 | // crypto 32 | // 33 | const randomFillSync = 34 | typeof window === 'undefined' 35 | ? require('crypto').randomFillSync 36 | : window.crypto.getRandomValues.bind(window.crypto); 37 | 38 | // Implements an RFC 4122 version 4 random UUID. 39 | // To improve performance, random data is generated in batches 40 | // large enough to cover kBatchSize UUID's at a time. The uuidData 41 | // and uuid buffers are reused. Each call to randomUUID() consumes 42 | // 16 bytes from the buffer. 43 | 44 | const kHexDigits = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102]; 45 | const kBatchSize = 128; 46 | let uuidData; 47 | let uuidNotBuffered; 48 | let uuid; 49 | let uuidBatch = 0; 50 | 51 | function getBufferedUUID() { 52 | if (uuidData === undefined) { 53 | uuidData = new Uint8Array(16 * kBatchSize); 54 | } 55 | if (uuidBatch === 0) randomFillSync(uuidData); 56 | uuidBatch = (uuidBatch + 1) % kBatchSize; 57 | return uuidData.slice(uuidBatch * 16, uuidBatch * 16 + 16); 58 | } 59 | 60 | function randomUUID(options) { 61 | if (options !== undefined) validateObject(options, 'options'); 62 | const { disableEntropyCache = false } = { ...options }; 63 | 64 | validateBoolean(disableEntropyCache, 'options.disableEntropyCache'); 65 | 66 | if (uuid === undefined) { 67 | uuid = new Uint8Array(36); 68 | uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'.charCodeAt(0); 69 | uuid[14] = 52; // '4', identifies the UUID version 70 | } 71 | 72 | let uuidBuf; 73 | if (!disableEntropyCache) { 74 | uuidBuf = getBufferedUUID(); 75 | } else { 76 | uuidBuf = uuidNotBuffered; 77 | if (uuidBuf === undefined) uuidBuf = uuidNotBuffered = new Uint8Array(16); 78 | randomFillSync(uuidBuf); 79 | } 80 | 81 | // Variant byte: 10xxxxxx (variant 1) 82 | uuidBuf[8] = (uuidBuf[8] & 0x3f) | 0x80; 83 | 84 | // This function is structured the way it is for performance. 85 | // The uuid buffer stores the serialization of the random 86 | // bytes from uuidData. 87 | // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 88 | let n = 0; 89 | uuid[0] = kHexDigits[uuidBuf[n] >> 4]; 90 | uuid[1] = kHexDigits[uuidBuf[n++] & 0xf]; 91 | uuid[2] = kHexDigits[uuidBuf[n] >> 4]; 92 | uuid[3] = kHexDigits[uuidBuf[n++] & 0xf]; 93 | uuid[4] = kHexDigits[uuidBuf[n] >> 4]; 94 | uuid[5] = kHexDigits[uuidBuf[n++] & 0xf]; 95 | uuid[6] = kHexDigits[uuidBuf[n] >> 4]; 96 | uuid[7] = kHexDigits[uuidBuf[n++] & 0xf]; 97 | // - 98 | uuid[9] = kHexDigits[uuidBuf[n] >> 4]; 99 | uuid[10] = kHexDigits[uuidBuf[n++] & 0xf]; 100 | uuid[11] = kHexDigits[uuidBuf[n] >> 4]; 101 | uuid[12] = kHexDigits[uuidBuf[n++] & 0xf]; 102 | // - 103 | // 4, uuid[14] is set already... 104 | uuid[15] = kHexDigits[uuidBuf[n++] & 0xf]; 105 | uuid[16] = kHexDigits[uuidBuf[n] >> 4]; 106 | uuid[17] = kHexDigits[uuidBuf[n++] & 0xf]; 107 | // - 108 | uuid[19] = kHexDigits[uuidBuf[n] >> 4]; 109 | uuid[20] = kHexDigits[uuidBuf[n++] & 0xf]; 110 | uuid[21] = kHexDigits[uuidBuf[n] >> 4]; 111 | uuid[22] = kHexDigits[uuidBuf[n++] & 0xf]; 112 | // - 113 | uuid[24] = kHexDigits[uuidBuf[n] >> 4]; 114 | uuid[25] = kHexDigits[uuidBuf[n++] & 0xf]; 115 | uuid[26] = kHexDigits[uuidBuf[n] >> 4]; 116 | uuid[27] = kHexDigits[uuidBuf[n++] & 0xf]; 117 | uuid[28] = kHexDigits[uuidBuf[n] >> 4]; 118 | uuid[29] = kHexDigits[uuidBuf[n++] & 0xf]; 119 | uuid[30] = kHexDigits[uuidBuf[n] >> 4]; 120 | uuid[31] = kHexDigits[uuidBuf[n++] & 0xf]; 121 | uuid[32] = kHexDigits[uuidBuf[n] >> 4]; 122 | uuid[33] = kHexDigits[uuidBuf[n++] & 0xf]; 123 | uuid[34] = kHexDigits[uuidBuf[n] >> 4]; 124 | uuid[35] = kHexDigits[uuidBuf[n] & 0xf]; 125 | 126 | return String.fromCharCode.apply(null, uuid); 127 | } 128 | 129 | window.crypto.randomUUID = randomUUID; 130 | 131 | 132 | }(); 133 | -------------------------------------------------------------------------------- /polyfills/document/caretRangeFromPoint.js: -------------------------------------------------------------------------------- 1 | if (!document.caretRangeFromPoint) { // polyfill for ff 2 | document.caretRangeFromPoint = function(x,y){ 3 | let caretP = document.caretPositionFromPoint(x,y); 4 | let range = document.createRange(); 5 | range.setStart(caretP.offsetNode, caretP.offset); 6 | return range; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /polyfills/document/currentScript.js: -------------------------------------------------------------------------------- 1 | if (!('currentScript' in document)) { 2 | 3 | Object.defineProperty(document, 'currentScript', { 4 | get: function () { 5 | // todo: find script without src 6 | try { throw new Error(); } 7 | catch (e) { 8 | if (!e.stack) throw new Error('error.stack not available'); 9 | var i = 0; 10 | var res = ((/.*at [^(]*\((.*):.+:.+\)$/ig).exec(e.stack) || [false])[1]; 11 | var scripts = document.scripts; 12 | for (i = 0; i < scripts.length; i++) { 13 | if (scripts[i].src == res || scripts[i].readyState == "interactive") { 14 | return scripts[i]; 15 | } 16 | } 17 | } 18 | console.warn('currentScript not found') 19 | } 20 | }); 21 | 22 | } -------------------------------------------------------------------------------- /polyfills/navigator/share.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2016 Tobias Buschor https://goo.gl/gl0mbf | MIT License https://goo.gl/HgajeK */ 2 | !function(){ 'use strict'; 3 | 4 | const share = async function(data){ 5 | 6 | if (!window.HTMLDialogElement) { 7 | await import('https://cdn.jsdelivr.net/gh/nuxodin/dialog-polyfill@1.4.1/dialog.min.js'); 8 | } 9 | 10 | const dialog = document.createElement('dialog'); 11 | dialog.className = 'c1Share'; 12 | dialog.innerHTML = '

'+txt.shareTitle+'

'+style; 13 | const body = dialog.querySelector('.-body'); 14 | 15 | //let shared = false; 16 | function close(){ // to be animated 17 | dialog.classList.remove('-Open'); 18 | setTimeout(()=>{ 19 | dialog.close(); 20 | },200); 21 | } 22 | 23 | const buildText = (...parts) => parts.filter(Boolean).join('\n\n'); 24 | const payload = { 25 | title: enc(data.title), 26 | text: enc(data.text), 27 | url: enc(data.url), 28 | titleText: enc(buildText(data.title, data.text)+'\n'), 29 | titleTextUrl: enc(buildText(data.title, data.text, data.url)+'\n'), 30 | textUrl: enc(buildText(data.text, data.url)+'\n'), 31 | } 32 | 33 | document.body.append(dialog); 34 | dialog.showModal(); 35 | dialog.classList.add('-Open'); 36 | dialog.addEventListener('close', () => { 37 | //shared ? resolve() : reject(); // safaris implementation of the promise 38 | dialog.remove(); 39 | }); 40 | 41 | share.items.forEach((item,name)=>{ 42 | name = txt[name] || name; 43 | const a = document.createElement('a'); 44 | a.innerHTML = item.svg+name; 45 | // not mentoned in screenreader 46 | a.firstElementChild.setAttribute('aria-hidden',true); 47 | a.href = item.url ? item.url(payload) : ''; 48 | a.target = 'share_poly'; 49 | a.tabindex = 0; 50 | a.addEventListener('click',e=>{ 51 | if (item.click) item.click(data); 52 | else window.open(a.href, 'share_poly', 'width=700,height=500'); 53 | close(); 54 | //shared = true; 55 | e.preventDefault(); 56 | }); 57 | body.append(a); 58 | }); 59 | dialog.addEventListener('click', e => e.target === dialog && close() ); 60 | 61 | // like the Chrome implementation, it resolves when the dialogue is opened. (not like safari) 62 | // now that we made the share function async, we dont need the promse anymore. 63 | // return new Promise((resolve)=>resolve()); 64 | }; 65 | share.items = new Map(); 66 | 67 | share.items.set('E-Mail',{ 68 | url: ({title, textUrl}) => 'mailto:?subject='+title+'&body='+textUrl, 69 | svg:'', 70 | }); 71 | share.items.set('SMS',{ 72 | url: ({titleTextUrl}) => 'sms:?body='+titleTextUrl, 73 | svg:'', 74 | }); 75 | share.items.set('Copy',{ 76 | click: data => navigator.clipboard.writeText(`${data.title}\n${data.text || ''}\n${data.url}`), 77 | svg:'', 78 | }); 79 | share.items.set('Twitter',{ 80 | url: ({titleText, url}) => 'https://twitter.com/intent/tweet?original_referer='+enc(location.href)+'&ref_src=twsrc%5Etfw&text='+titleText+'&tw_p=tweetbutton&url='+url, 81 | svg:'', 82 | }); 83 | share.items.set('Facebook',{ 84 | url: ({url, title}) => 'https://www.facebook.com/sharer/sharer.php?u='+url+'&t='+title, 85 | svg:'', 86 | }); 87 | share.items.set('Telegram',{ 88 | url: ({titleTextUrl}) => 'https://telegram.me/share/msg?url='+enc(location.host)+'&text=' + titleTextUrl, 89 | svg: '' 90 | }); 91 | share.items.set('Pinterest',{ 92 | url: ({url,titleText}) => 'https://pinterest.com/pin/create/button/?url='+url+'&xmedia='+'&description='+titleText, 93 | svg:'', 94 | }); 95 | share.items.set('WhatsApp',{ 96 | url: ({titleTextUrl}) => 'https://api.whatsapp.com/send?text='+titleTextUrl, //nativ: url: ({titleTextUrl}) => 'whatsapp://send?text='+titleTextUrl, 97 | svg:'', 98 | }); 99 | share.items.set('LinkedIn',{ 100 | url: ({title,text,url}) => 'https://www.linkedin.com/shareArticle?mini=true&url='+url+'&title='+title+'&summary='+text, 101 | svg:'', 102 | }); 103 | 104 | if (!navigator.share) navigator.share = share; 105 | window.u1Share = share; 106 | 107 | 108 | const enc = encodeURIComponent; 109 | 110 | const style = 111 | ''; 161 | 162 | 163 | 164 | // thanks: https://github.com/on2-dev/share-api-polyfill/blob/main/src/share.js 165 | const languages = { 166 | cs: { 167 | shareTitle: 'Sdílet', 168 | //cancel: 'Zrušit', 169 | Copy: 'Kopírovat', 170 | //print: 'Tisk', 171 | //selectSms: 'Vyberte kontakt' 172 | }, 173 | sk: { 174 | shareTitle: 'Zdieľať', 175 | //cancel: 'Zrušiť', 176 | Copy: 'Kopírovat', 177 | //print: 'Tlač', 178 | //selectSms: 'Vyberte kontakt' 179 | }, 180 | ja: { 181 | shareTitle: '共有する', 182 | //cancel: 'キャンセル', 183 | Copy: 'コピーする', 184 | //print: '印刷する', 185 | //selectSms: '連絡先を選択してください' 186 | }, 187 | zh: { 188 | shareTitle: '分享', 189 | //cancel: '取消', 190 | Copy: '複製連結', 191 | //print: '列印', 192 | //selectSms: '選擇聯絡人' 193 | }, 194 | pt: { 195 | shareTitle: 'Compartilhar', 196 | //cancel: 'Cancelar', 197 | Copy: 'Copiar', 198 | //print: 'Imprimir', 199 | //selectSms: 'Selecione um contato' 200 | }, 201 | en: { 202 | shareTitle: 'Share', 203 | //cancel: 'Cancel', 204 | Copy: 'Copy', 205 | //print: 'Print', 206 | //selectSms: 'Pick a contact' 207 | }, 208 | es: { 209 | shareTitle: 'Compartir', 210 | //cancel: 'Cancelar', 211 | Copy: 'Copiar', 212 | //print: 'Imprimir', 213 | 'E-Mail': 'Correo', 214 | //selectSms: 'Seleccionar un contacto' 215 | }, 216 | fr: { 217 | shareTitle: 'Partager', 218 | //cancel: 'Annuler', 219 | Copy: 'Copier', 220 | //print: 'Imprimer', 221 | //selectSms: 'Veuillez choisir un contact' 222 | }, 223 | de: { 224 | shareTitle: 'Teilen', 225 | //cancel: 'Abbrechen', 226 | Copy: 'Kopieren', 227 | //print: 'Drucken', 228 | //selectSms: 'Wählen Sie einen Kontakt aus' 229 | }, 230 | it: { 231 | shareTitle: 'Condividi', 232 | //cancel: 'Annulla', 233 | Copy: 'Copia', 234 | //print: 'Stampa', 235 | 'E-Mail': 'Email', 236 | //selectSms: 'Seleziona un contatto' 237 | }, 238 | nl: { 239 | shareTitle: 'Delen', 240 | //cancel: 'Annuleren', 241 | Copy: 'Kopiëren', 242 | //print: 'Printen', 243 | //selectSms: 'Selecteer een contact' 244 | }, 245 | sv: { 246 | shareTitle: 'Dela', 247 | //cancel: 'Avbryt', 248 | Copy: 'Kopiera', 249 | //print: 'Skriv ut', 250 | //selectSms: 'Välj en kontakt' 251 | }, 252 | da: { 253 | shareTitle: 'Del', 254 | //cancel: 'Luk', 255 | Copy: 'Kopiér', 256 | //print: 'Udskriv', 257 | //selectSms: 'Vælg en kontaktperson' 258 | }, 259 | ru: { 260 | shareTitle: 'Поделиться', 261 | //cancel: 'Отмена', 262 | Copy: 'Скопировать', 263 | //print: 'Печать', 264 | 'E-Mail': 'Э-майл', 265 | //selectSms: 'Выбери контакт' 266 | }, 267 | tr: { 268 | shareTitle: 'Paylaş', 269 | //cancel: 'Vazgeç', 270 | Copy: 'Kopyala', 271 | //print: 'Yazdır', 272 | 'E-Mail': 'E-posta', 273 | //selectSms: 'Bir kişi seç' 274 | }, 275 | ko: { 276 | shareTitle: '공유', 277 | //cancel: '취소', 278 | Copy: '링크 복사', 279 | //print: '인쇄', 280 | //selectSms: '연락처를 선택하세요' 281 | }, 282 | ta: { 283 | shareTitle: 'பகிர்', 284 | //cancel: 'இரத்து', 285 | Copy: 'நகலெடு', 286 | //print: 'அச்சிடு', 287 | 'E-Mail': 'மின்னஞ்சல்', 288 | //selectSms: 'ஒரு தொடர்பைத் தேர்வுசெய்க' 289 | }, 290 | pl: { 291 | shareTitle: 'Dzielić', 292 | //cancel: 'Anuluj', 293 | Copy: 'Kopiuj', 294 | //print: 'Wydrukować', 295 | //selectSms: 'Wybierz kontakt' 296 | }, 297 | is: { 298 | shareTitle: 'Deila', 299 | //cancel: 'Hætta við', 300 | Copy: 'Afrita', 301 | //print: 'Prenta', 302 | 'E-Mail': 'Póstur', 303 | //selectSms: 'Veldu tengilið' 304 | }, 305 | hu: { 306 | shareTitle: 'Megosztás', 307 | //cancel: 'Bezárás', 308 | Copy: 'Másolás', 309 | //print: 'Nyomtatás', 310 | //selectSms: 'Válasszon egy kontaktot' 311 | }, 312 | }; 313 | 314 | const lang = navigator.language.substr(0, 2).toLowerCase(); 315 | const txt = languages[lang] || languages['en']; 316 | 317 | }(); 318 | -------------------------------------------------------------------------------- /polyfills/navigator/share.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | navigator.share 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 | 28 | 38 | -------------------------------------------------------------------------------- /polyfills/requestIdleCallback.js: -------------------------------------------------------------------------------- 1 | if (!window.requestIdleCallback) { 2 | window.requestIdleCallback = function (callback, options) { 3 | var options = options || {}; 4 | var relaxation = 1; 5 | var timeout = options.timeout || relaxation; 6 | var start = performance.now(); 7 | return setTimeout(function () { 8 | callback({ 9 | get didTimeout() { 10 | return options.timeout ? false : (performance.now() - start) - relaxation > timeout; 11 | }, 12 | timeRemaining: function () { 13 | return Math.max(0, relaxation + (performance.now() - start)); 14 | }, 15 | }); 16 | }, relaxation); 17 | }; 18 | } -------------------------------------------------------------------------------- /polyfills/tests/WeakRef.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WeakRef test 7 | 8 | 9 | 14 | 15 | 16 |
17 | 18 | -------------------------------------------------------------------------------- /polyfills/tests/structuredClone.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WeakRef test 7 | 8 | 9 | 10 | 11 | 12 | 27 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lazyfill TEST 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 79 | 80 | 81 |
82 | 83 | 84 | Hello World 85 | 86 | 87 |
88 | 89 | 90 | Hello demo 91 | 92 | 93 | 94 |
95 |

inert

96 | 100 |
101 | 102 |
103 |

focusgroup

104 | 109 |
110 | 111 | 112 | inside search element. 113 | It sould be block and have a role=search 114 | 118 | 119 | 120 | 121 | --------------------------------------------------------------------------------