PageSourceSearch

https://rondocoach.com/wp-content/plugins/formationTool/assets/js1/dom-to-image-more.js?ver=12:29:12

js rondocoach.com collected 2026-10-06 12:29:48 UTC 53,171 bytes, 1,403 lines download raw bytes

1
2    'use strict';
3
4    const util = newUtil();
5    const inliner = newInliner();
6    const fontFaces = newFontFaces();
7    const images = newImages();
8
9    // Default impl options
10    const defaultOptions = {
11        // Default is to copy default styles of elements
12        copyDefaultStyles: true,
13        // Default is to fail on error, no placeholder
14        imagePlaceholder: undefined,
15        // Default cache bust is false, it will use the cache
16        cacheBust: false,
17        // Use (existing) authentication credentials for external URIs (CORS requests)
18        useCredentials: false,
19        // Default resolve timeout
20        httpTimeout: 30000,
21        // Style computation cache tag rules (options are strict, relaxed)
22        styleCaching: 'strict',
23    };
24
25    const domtoimage = {
26        toSvg: toSvg,
27        toPng: toPng,
28        toJpeg: toJpeg,
29        toBlob: toBlob,
30        toPixelData: toPixelData,
31        toCanvas: toCanvas,
32        impl: {
33            fontFaces: fontFaces,
34            images: images,
35            util: util,
36            inliner: inliner,
37            urlCache: [],
38            options: {},
39        },
40    };
41
42    //if (typeof exports === 'object' && typeof module === 'object') {
43    //    module.exports = domtoimage; // eslint-disable-line no-undef
44    //} else {
45    //    global.domtoimage = domtoimage;
46    //}
47
48    // support node and browsers
49    const ELEMENT_NODE =
50        (typeof Node !== 'undefined' ? Node.ELEMENT_NODE : undefined) || 1;
51    const getComputedStyle =
52        (typeof global !== 'undefined' ? global.getComputedStyle : undefined) ||
53        (typeof window !== 'undefined' ? window.getComputedStyle : undefined) ||
54        globalThis.getComputedStyle;
55    const atob =
56        (typeof global !== 'undefined' ? global.atob : undefined) ||
57        (typeof window !== 'undefined' ? window.atob : undefined) ||
58        globalThis.atob;
59
60    /**
61     * @param {Node} node - The DOM Node object to render
62     * @param {Object} options - Rendering options
63     * @param {Function} options.filter - Should return true if passed node should be included in the output
64     *          (excluding node means excluding it's children as well). Not called on the root node.
65     * @param {Function} options.onclone - Callback function which is called when the Document has been cloned for
66     *         rendering, can be used to modify the contents that will be rendered without affecting the original
67     *         source document.
68     * @param {String} options.bgcolor - color for the background, any valid CSS color value.
69     * @param {Number} options.width - width to be applied to node before rendering.
70     * @param {Number} options.height - height to be applied to node before rendering.
71     * @param {Object} options.style - an object whose properties to be copied to node's style before rendering.
72     * @param {Number} options.quality - a Number between 0 and 1 indicating image quality (applicable to JPEG only),
73                defaults to 1.0.
74     * @param {Number} options.scale - a Number multiplier to scale up the canvas before rendering to reduce fuzzy images, defaults to 1.0.
75     * @param {String} options.imagePlaceholder - dataURL to use as a placeholder for failed images, default behaviour is to fail fast on images we can't fetch
76     * @param {Boolean} options.cacheBust - set to true to cache bust by appending the time to the request url
77     * @param {String} options.styleCaching - set to 'strict', 'relaxed' to select style caching rules
78     * @param {Boolean} options.copyDefaultStyles - set to false to disable use of default styles of elements
79     * @return {Promise} - A promise that is fulfilled with a SVG image data URL
80     * */
81    function toSvg(node, options) {
82        const ownerWindow = domtoimage.impl.util.getWindow(node);
83        options = options || {};
84        copyOptions(options);
85        let restorations = [];
86        return Promise.resolve(node)
87            .then(ensureElement)
88            .then(function (clonee) {
89                return cloneNode(clonee, options, null, ownerWindow);
90            })
91            .then(embedFonts)
92            .then(inlineImages)
93            .then(applyOptions)
94            .then(makeSvgDataUri)
95            .then(restoreWrappers)
96            .then(clearCache);
97
98        function ensureElement(node) {
99            if (node.nodeType === ELEMENT_NODE) return node;
100
101            const originalChild = node;
102            const originalParent = node.parentNode;
103            const wrappingSpan = document.createElement('span');
104            originalParent.replaceChild(wrappingSpan, originalChild);
105            wrappingSpan.append(node);
106            restorations.push({
107                parent: originalParent,
108                child: originalChild,
109                wrapper: wrappingSpan,
110            });
111            return wrappingSpan;
112        }
113
114        function restoreWrappers(result) {
115            // put the original children back where the wrappers were inserted
116            while (restorations.length > 0) {
117                const restoration = restorations.pop();
118                restoration.parent.replaceChild(restoration.child, restoration.wrapper);
119            }
120
121            return result;
122        }
123
124        function clearCache(result) {
125            domtoimage.impl.urlCache = [];
126            removeSandbox();
127            return result;
128        }
129
130        function applyOptions(clone) {
131            if (options.bgcolor) {
132                clone.style.backgroundColor = options.bgcolor;
133            }
134            if (options.width) {
135                clone.style.width = `${options.width}px`;
136            }
137            if (options.height) {
138                clone.style.height = `${options.height}px`;
139            }
140            if (options.style) {
141                Object.keys(options.style).forEach(function (property) {
142                    clone.style[property] = options.style[property];
143                });
144            }
145
146            let onCloneResult = null;
147
148            if (typeof options.onclone === 'function') {
149                onCloneResult = options.onclone(clone);
150            }
151
152            return Promise.resolve(onCloneResult).then(function () {
153                return clone;
154            });
155        }
156
157        function makeSvgDataUri(node) {
158            let width = options.width || util.width(node);
159            let height = options.height || util.height(node);
160
161            return Promise.resolve(node)
162                .then(function (svg) {
163                    svg.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
164                    return new XMLSerializer().serializeToString(svg);
165                })
166                .then(function (xhtml) {
167                    const foreignObjectSizing =
168                        (util.isDimensionMissing(width)
169                            ? ' width="100%"'
170                            : ` width="${width}"`) +
171                        (util.isDimensionMissing(height)
172                            ? ' height="100%"'
173                            : ` height="${height}"`);
174                    const svgSizing =
175                        (util.isDimensionMissing(width) ? '' : ` width="${width}"`) +
176                        (util.isDimensionMissing(height) ? '' : ` height="${height}"`);
177                    return `<svg xmlns="http://www.w3.org/2000/svg"${svgSizing}><foreignObject${foreignObjectSizing}>${xhtml}</foreignObject></svg>`;
178                })
179                .then(function (svg) {
180                    return `data:image/svg+xml;charset=utf-8,${svg}`;
181                });
182        }
183    }
184
185    /**
186     * @param {Node} node - The DOM Node object to render
187     * @param {Object} options - Rendering options, @see {@link toSvg}
188     * @return {Promise} - A promise that is fulfilled with a Uint8Array containing RGBA pixel data.
189     * */
190    function toPixelData(node, options) {
191        return draw(node, options).then(function (canvas) {
192            return canvas
193                .getContext('2d')
194                .getImageData(0, 0, util.width(node), util.height(node)).data;
195        });
196    }
197
198    /**
199     * @param {Node} node - The DOM Node object to render
200     * @param {Object} options - Rendering options, @see {@link toSvg}
201     * @return {Promise} - A promise that is fulfilled with a PNG image data URL
202     * */
203    function toPng(node, options) {
204        return draw(node, options).then(function (canvas) {
205            return canvas.toDataURL();
206        });
207    }
208
209    /**
210     * @param {Node} node - The DOM Node object to render
211     * @param {Object} options - Rendering options, @see {@link toSvg}
212     * @return {Promise} - A promise that is fulfilled with a JPEG image data URL
213     * */
214    function toJpeg(node, options) {
215        return draw(node, options).then(function (canvas) {
216            return canvas.toDataURL(
217                'image/jpeg',
218                (options ? options.quality : undefined) || 1.0
219            );
220        });
221    }
222
223    /**
224     * @param {Node} node - The DOM Node object to render
225     * @param {Object} options - Rendering options, @see {@link toSvg}
226     * @return {Promise} - A promise that is fulfilled with a PNG image blob
227     * */
228    function toBlob(node, options) {
229        return draw(node, options).then(util.canvasToBlob);
230    }
231
232    /**
233     * @param {Node} node - The DOM Node object to render
234     * @param {Object} options - Rendering options, @see {@link toSvg}
235     * @return {Promise} - A promise that is fulfilled with a canvas object
236     * */
237    function toCanvas(node, options) {
238        return draw(node, options);
239    }
240
241    function copyOptions(options) {
242        // Copy options to impl options for use in impl
243        if (typeof options.copyDefaultStyles === 'undefined') {
244            domtoimage.impl.options.copyDefaultStyles = defaultOptions.copyDefaultStyles;
245        } else {
246            domtoimage.impl.options.copyDefaultStyles = options.copyDefaultStyles;
247        }
248
249        if (typeof options.imagePlaceholder === 'undefined') {
250            domtoimage.impl.options.imagePlaceholder = defaultOptions.imagePlaceholder;
251        } else {
252            domtoimage.impl.options.imagePlaceholder = options.imagePlaceholder;
253        }
254
255        if (typeof options.cacheBust === 'undefined') {
256            domtoimage.impl.options.cacheBust = defaultOptions.cacheBust;
257        } else {
258            domtoimage.impl.options.cacheBust = options.cacheBust;
259        }
260
261        if (typeof options.useCredentials === 'undefined') {
262            domtoimage.impl.options.useCredentials = defaultOptions.useCredentials;
263        } else {
264            domtoimage.impl.options.useCredentials = options.useCredentials;
265        }
266
267        if (typeof options.httpTimeout === 'undefined') {
268            domtoimage.impl.options.httpTimeout = defaultOptions.httpTimeout;
269        } else {
270            domtoimage.impl.options.httpTimeout = options.httpTimeout;
271        }
272
273        if (typeof options.styleCaching === 'undefined') {
274            domtoimage.impl.options.styleCaching = defaultOptions.styleCaching;
275        } else {
276            domtoimage.impl.options.styleCaching = options.styleCaching;
277        }
278    }
279
280    function draw(domNode, options) {
281        options = options || {};
282        return toSvg(domNode, options)
283            .then(util.makeImage)
284            .then(function (image) {
285                const scale = typeof options.scale !== 'number' ? 1 : options.scale;
286                const canvas = newCanvas(domNode, scale);
287                const ctx = canvas.getContext('2d');
288                ctx.msImageSmoothingEnabled = false;
289                ctx.imageSmoothingEnabled = false;
290                if (image) {
291                    ctx.scale(scale, scale);
292                    ctx.drawImage(image, 0, 0);
293                }
294                return canvas;
295            });
296
297        function newCanvas(node, scale) {
298            let width = options.width || util.width(node);
299            let height = options.height || util.height(node);
300
301            // per https://www.w3.org/TR/CSS2/visudet.html#inline-replaced-width the default width should be 300px if height
302            // not set, otherwise should be 2:1 aspect ratio for whatever height is specified
303            if (util.isDimensionMissing(width)) {
304                width = util.isDimensionMissing(height) ? 300 : height * 2.0;
305            }
306
307            if (util.isDimensionMissing(height)) {
308                height = width / 2.0;
309            }
310
311            const canvas = document.createElement('canvas');
312            canvas.width = width * scale;
313            canvas.height = height * scale;
314
315            if (options.bgcolor) {
316                const ctx = canvas.getContext('2d');
317                ctx.fillStyle = options.bgcolor;
318                ctx.fillRect(0, 0, canvas.width, canvas.height);
319            }
320
321            return canvas;
322        }
323    }
324
325    let sandbox = null;
326
327    function cloneNode(node, options, parentComputedStyles, ownerWindow) {
328        const filter = options.filter;
329        if (
330            node === sandbox ||
331            util.isHTMLScriptElement(node) ||
332            util.isHTMLStyleElement(node) ||
333            util.isHTMLLinkElement(node) ||
334            (parentComputedStyles !== null && filter && !filter(node))
335        ) {
336            return Promise.resolve();
337        }
338
339        return Promise.resolve(node)
340            .then(makeNodeCopy)
341            .then(function (clone) {
342                return cloneChildren(clone, getParentOfChildren(node));
343            })
344            .then(function (clone) {
345                return processClone(clone, node);
346            });
347
348        function makeNodeCopy(original) {
349            if (util.isHTMLCanvasElement(original)) {
350                return util.makeImage(original.toDataURL());
351            }
352            return original.cloneNode(false);
353        }
354
355        function getParentOfChildren(original) {
356            if (util.isElementHostForOpenShadowRoot(original)) {
357                return original.shadowRoot; // jump "down" to #shadow-root
358            }
359            return original;
360        }
361
362        function cloneChildren(clone, original) {
363            const originalChildren = getRenderedChildren(original);
364            let done = Promise.resolve();
365
366            if (originalChildren.length !== 0) {
367                const originalComputedStyles = getComputedStyle(
368                    getRenderedParent(original)
369                );
370
371                util.asArray(originalChildren).forEach(function (originalChild) {
372                    done = done.then(function () {
373                        return cloneNode(
374                            originalChild,
375                            options,
376                            originalComputedStyles,
377                            ownerWindow
378                        ).then(function (clonedChild) {
379                            if (clonedChild) {
380                                clone.appendChild(clonedChild);
381                            }
382                        });
383                    });
384                });
385            }
386
387            return done.then(function () {
388                return clone;
389            });
390
391            function getRenderedParent(original) {
392                if (util.isShadowRoot(original)) {
393                    return original.host; // jump up from #shadow-root to its parent <element>
394                }
395                return original;
396            }
397
398            function getRenderedChildren(original) {
399                if (util.isShadowSlotElement(original)) {
400                    return original.assignedNodes(); // shadow DOM <slot> has "assigned nodes" as rendered children
401                }
402                return original.childNodes;
403            }
404        }
405
406        function processClone(clone, original) {
407            if (!util.isElement(clone) || util.isShadowSlotElement(original)) {
408                return Promise.resolve(clone);
409            }
410
411            return Promise.resolve()
412                .then(cloneStyle)
413                .then(clonePseudoElements)
414                .then(copyUserInput)
415                .then(fixSvg)
416                .then(function () {
417                    return clone;
418                });
419
420            function cloneStyle() {
421                copyStyle(original, clone);
422
423                function copyFont(source, target) {
424                    target.font = source.font;
425                    target.fontFamily = source.fontFamily;
426                    target.fontFeatureSettings = source.fontFeatureSettings;
427                    target.fontKerning = source.fontKerning;
428                    target.fontSize = source.fontSize;
429                    target.fontStretch = source.fontStretch;
430                    target.fontStyle = source.fontStyle;
431                    target.fontVariant = source.fontVariant;
432                    target.fontVariantCaps = source.fontVariantCaps;
433                    target.fontVariantEastAsian = source.fontVariantEastAsian;
434                    target.fontVariantLigatures = source.fontVariantLigatures;
435                    target.fontVariantNumeric = source.fontVariantNumeric;
436                    target.fontVariationSettings = source.fontVariationSettings;
437                    target.fontWeight = source.fontWeight;
438                }
439
440                function copyStyle(sourceElement, targetElement) {
441                    const sourceComputedStyles = getComputedStyle(sourceElement);
442                    if (sourceComputedStyles.cssText) {
443                        targetElement.style.cssText = sourceComputedStyles.cssText;
444                        copyFont(sourceComputedStyles, targetElement.style); // here we re-assign the font props.
445                    } else {
446                        copyUserComputedStyleFast(
447                            options,
448                            sourceElement,
449                            sourceComputedStyles,
450                            parentComputedStyles,
451                            targetElement
452                        );
453
454                        // Remove positioning of initial element, which stops them from being captured correctly
455                        if (parentComputedStyles === null) {
456                            [
457                                'inset-block',
458                                'inset-block-start',
459                                'inset-block-end',
460                            ].forEach((prop) => targetElement.style.removeProperty(prop));
461                            ['left', 'right', 'top', 'bottom'].forEach((prop) => {
462                                if (targetElement.style.getPropertyValue(prop)) {
463                                    targetElement.style.setProperty(prop, '0px');
464                                }
465                            });
466                        }
467                    }
468                }
469            }
470
471            function clonePseudoElements() {
472                const cloneClassName = util.uid();
473
474                [':before', ':after'].forEach(function (element) {
475                    clonePseudoElement(element);
476                });
477
478                function clonePseudoElement(element) {
479                    const style = getComputedStyle(original, element);
480                    const content = style.getPropertyValue('content');
481
482                    if (content === '' || content === 'none') {
483                        return;
484                    }
485
486                    const currentClass = clone.getAttribute('class') || '';
487                    clone.setAttribute('class', `${currentClass} ${cloneClassName}`);
488
489                    const styleElement = document.createElement('style');
490                    styleElement.appendChild(formatPseudoElementStyle());
491                    clone.appendChild(styleElement);
492
493                    function formatPseudoElementStyle() {
494                        const selector = `.${cloneClassName}:${element}`;
495                        const cssText = style.cssText
496                            ? formatCssText()
497                            : formatCssProperties();
498
499                        return document.createTextNode(`${selector}{${cssText}}`);
500
501                        function formatCssText() {
502                            return `${style.cssText} content: ${content};`;
503                        }
504
505                        function formatCssProperties() {
506                            const styleText = util
507                                .asArray(style)
508                                .map(formatProperty)
509                                .join('; ');
510                            return `${styleText};`;
511
512                            function formatProperty(name) {
513                                const propertyValue = style.getPropertyValue(name);
514                                const propertyPriority = style.getPropertyPriority(name)
515                                    ? ' !important'
516                                    : '';
517                                return `${name}: ${propertyValue}${propertyPriority}`;
518                            }
519                        }
520                    }
521                }
522            }
523
524            function copyUserInput() {
525                if (util.isHTMLTextAreaElement(original)) {
526                    clone.innerHTML = original.value;
527                }
528                if (util.isHTMLInputElement(original)) {
529                    clone.setAttribute('value', original.value);
530                }
531            }
532
533            function fixSvg() {
534                if (util.isSVGElement(clone)) {
535                    clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
536
537                    if (util.isSVGRectElement(clone)) {
538                        ['width', 'height'].forEach(function (attribute) {
539                            const value = clone.getAttribute(attribute);
540                            if (value) {
541                                clone.style.setProperty(attribute, value);
542                            }
543                        });
544                    }
545                }
546            }
547        }
548    }
549
550    function embedFonts(node) {
551        return fontFaces.resolveAll().then(function (cssText) {
552            if (cssText !== '') {
553                const styleNode = document.createElement('style');
554                node.appendChild(styleNode);
555                styleNode.appendChild(document.createTextNode(cssText));
556            }
557            return node;
558        });
559    }
560
561    function inlineImages(node) {
562        return images.inlineAll(node).then(function () {
563            return node;
564        });
565    }
566    function newUtil() {
567        let uid_index = 0;
568
569        return {
570            escape: escapeRegEx,
571            isDataUrl: isDataUrl,
572            canvasToBlob: canvasToBlob,
573            resolveUrl: resolveUrl,
574            getAndEncode: getAndEncode,
575            uid: uid,
576            delay: delay,
577            asArray: asArray,
578            escapeXhtml: escapeXhtml,
579            makeImage: makeImage,
580            width: width,
581            height: height,
582            getWindow: getWindow,
583            isElement: isElement,
584            isElementHostForOpenShadowRoot: isElementHostForOpenShadowRoot,
585            isShadowRoot: isShadowRoot,
586            isInShadowRoot: isInShadowRoot,
587            isHTMLElement: isHTMLElement,
588            isHTMLCanvasElement: isHTMLCanvasElement,
589            isHTMLInputElement: isHTMLInputElement,
590            isHTMLImageElement: isHTMLImageElement,
591            isHTMLLinkElement: isHTMLLinkElement,
592            isHTMLScriptElement: isHTMLScriptElement,
593            isHTMLStyleElement: isHTMLStyleElement,
594            isHTMLTextAreaElement: isHTMLTextAreaElement,
595            isShadowSlotElement: isShadowSlotElement,
596            isSVGElement: isSVGElement,
597            isSVGRectElement: isSVGRectElement,
598            isDimensionMissing: isDimensionMissing,
599        };
600
601        function getWindow(node) {
602            const ownerDocument = node ? node.ownerDocument : undefined;
603            return (
604                (ownerDocument ? ownerDocument.defaultView : undefined) ||
605                global ||
606                window
607            );
608        }
609
610        function isElementHostForOpenShadowRoot(value) {
611            return isElement(value) && value.shadowRoot !== null;
612        }
613
614        function isShadowRoot(value) {
615            return value instanceof getWindow(value).ShadowRoot;
616        }
617
618        function isInShadowRoot(value) {
619            return (
620                value !== null &&
621                Object.prototype.hasOwnProperty.call(value, 'getRootNode') &&
622                isShadowRoot(value.getRootNode())
623            );
624        }
625
626        function isElement(value) {
627            return value instanceof getWindow(value).Element;
628        }
629
630        function isHTMLCanvasElement(value) {
631            return value instanceof getWindow(value).HTMLCanvasElement;
632        }
633
634        function isHTMLElement(value) {
635            return value instanceof getWindow(value).HTMLElement;
636        }
637
638        function isHTMLImageElement(value) {
639            return value instanceof getWindow(value).HTMLImageElement;
640        }
641
642        function isHTMLInputElement(value) {
643            return value instanceof getWindow(value).HTMLInputElement;
644        }
645
646        function isHTMLLinkElement(value) {
647            return value instanceof getWindow(value).HTMLLinkElement;
648        }
649
650        function isHTMLScriptElement(value) {
651            return value instanceof getWindow(value).HTMLScriptElement;
652        }
653
654        function isHTMLStyleElement(value) {
655            return value instanceof getWindow(value).HTMLStyleElement;
656        }
657
658        function isHTMLTextAreaElement(value) {
659            return value instanceof getWindow(value).HTMLTextAreaElement;
660        }
661
662        function isShadowSlotElement(value) {
663            return (
664                isInShadowRoot(value) && value instanceof getWindow(value).HTMLSlotElement
665            );
666        }
667
668        function isSVGElement(value) {
669            return value instanceof getWindow(value).SVGElement;
670        }
671
672        function isSVGRectElement(value) {
673            return value instanceof getWindow(value).SVGRectElement;
674        }
675
676        function isDataUrl(url) {
677            return url.search(/^(data:)/) !== -1;
678        }
679
680        function isDimensionMissing(value) {
681            return isNaN(value) || value <= 0;
682        }
683
684        function asBlob(canvas) {
685            return new Promise(function (resolve) {
686                const binaryString = atob(canvas.toDataURL().split(',')[1]);
687                const length = binaryString.length;
688                const binaryArray = new Uint8Array(length);
689
690                for (let i = 0; i < length; i++) {
691                    binaryArray[i] = binaryString.charCodeAt(i);
692                }
693
694                resolve(
695                    new Blob([binaryArray], {
696                        type: 'image/png',
697                    })
698                );
699            });
700        }
701
702        function canvasToBlob(canvas) {
703            if (canvas.toBlob) {
704                return new Promise(function (resolve) {
705                    canvas.toBlob(resolve);
706                });
707            }
708
709            return asBlob(canvas);
710        }
711
712        function resolveUrl(url, baseUrl) {
713            const doc = document.implementation.createHTMLDocument();
714            const base = doc.createElement('base');
715            doc.head.appendChild(base);
716            const a = doc.createElement('a');
717            doc.body.appendChild(a);
718            base.href = baseUrl;
719            a.href = url;
720            return a.href;
721        }
722
723        function uid() {
724            return `u${fourRandomChars()}${uid_index++}`;
725
726            function fourRandomChars() {
727                /* see https://stackoverflow.com/a/6248722/2519373 */
728                return `0000${((Math.random() * Math.pow(36, 4)) << 0).toString(
729                    36
730                )}`.slice(-4);
731            }
732        }
733
734        function makeImage(uri) {
735            if (uri === 'data:,') {
736                return Promise.resolve();
737            }
738            
739            return new Promise(function (resolve, reject) {
740                const image = new Image();
741                if (domtoimage.impl.options.useCredentials) {
742                    image.crossOrigin = 'use-credentials';
743                }
744                image.onload = function () {
745                    
746                    if (window && window.requestAnimationFrame) {
747                        // In order to work around a Firefox bug (webcompat/web-bugs#119834) we
748                        // need to wait one extra frame before it's s
748afe to read the image data.
749                        window.requestAnimationFrame(function () {
750                            resolve(image);
751                        });
752                    } else {
753                        // If we don't have a window or requestAnimationFrame function proceed immediately.
754                        resolve(image);
755                    }
756                };
757                
758                image.onerror = reject;
759                image.src = uri;
760            });
761        }
762
763        function getAndEncode(url) {
764            let cacheEntry = domtoimage.impl.urlCache.find(function (el) {
765                return el.url === url;
766            });
767
768            if (!cacheEntry) {
769                cacheEntry = {
770                    url: url,
771                    promise: null,
772                };
773                domtoimage.impl.urlCache.push(cacheEntry);
774            }
775
776            if (cacheEntry.promise === null) {
777                if (domtoimage.impl.options.cacheBust) {
778                    // Cache bypass so we dont have CORS issues with cached images
779                    // Source: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache
780                    url += (/\?/.test(url) ? '&' : '?') + new Date().getTime();
781                }
782
783                cacheEntry.promise = new Promise(function (resolve) {
784                    const httpTimeout = domtoimage.impl.options.httpTimeout;
785                    const request = new XMLHttpRequest();
786
787                    request.onreadystatechange = done;
788                    request.ontimeout = timeout;
789                    request.responseType = 'blob';
790                    request.timeout = httpTimeout;
791                    if (domtoimage.impl.options.useCredentials) {
792                        request.withCredentials = true;
793                    }
794                    request.open('GET', url, true);
795                    request.send();
796
797                    let placeholder;
798                    if (domtoimage.impl.options.imagePlaceholder) {
799                        const split = domtoimage.impl.options.imagePlaceholder.split(/,/);
800                        if (split && split[1]) {
801                            placeholder = split[1];
802                        }
803                    }
804
805                    function done() {
806                        if (request.readyState !== 4) {
807                            return;
808                        }
809
810                        if (request.status !== 200) {
811                            if (placeholder) {
812                                resolve(placeholder);
813                            } else {
814                                fail(
815                                    `cannot fetch resource: ${url}, status: ${request.status}`
816                                );
817                            }
818
819                            return;
820                        }
821
822                        const encoder = new FileReader();
823                        encoder.onloadend = function () {
824                            resolve(encoder.result);
825                        };
826                        encoder.readAsDataURL(request.response);
827                    }
828
829                    function timeout() {
830                        if (placeholder) {
831                            resolve(placeholder);
832                        } else {
833                            fail(
834                                `timeout of ${httpTimeout}ms occured while fetching resource: ${url}`
835                            );
836                        }
837                    }
838
839                    function fail(message) {
840                        console.error(message);
841                        resolve('');
842                    }
843                });
844            }
845            return cacheEntry.promise;
846        }
847
848        function escapeRegEx(string) {
849            return string.replace(/([.*+?^${}()|[]\/\\])/g, '\\$1');
850        }
851
852        function delay(ms) {
853            return function (arg) {
854                return new Promise(function (resolve) {
855                    setTimeout(function () {
856                        resolve(arg);
857                    }, ms);
858                });
859            };
860        }
861
862        function asArray(arrayLike) {
863            const array = [];
864            const length = arrayLike.length;
865            for (let i = 0; i < length; i++) {
866                array.push(arrayLike[i]);
867            }
868
869            return array;
870        }
871
872        function escapeXhtml(string) {
873            return string.replace(/%/g, '%25').replace(/#/g, '%23').replace(/\n/g, '%0A');
874        }
875
876        function width(node) {
877            const width = px(node, 'width');
878
879            if (!isNaN(width)) return width;
880
881            const leftBorder = px(node, 'border-left-width');
882            const rightBorder = px(node, 'border-right-width');
883            return node.scrollWidth + leftBorder + rightBorder;
884        }
885
886        function height(node) {
887            const height = px(node, 'height');
888
889            if (!isNaN(height)) return height;
890
891            const topBorder = px(node, 'border-top-width');
892            const bottomBorder = px(node, 'border-bottom-width');
893            return node.scrollHeight + topBorder + bottomBorder;
894        }
895
896        function px(node, styleProperty) {
897            if (node.nodeType === ELEMENT_NODE) {
898                let value = getComputedStyle(node).getPropertyValue(styleProperty);
899                if (value.slice(-2) === 'px') {
900                    value = value.slice(0, -2);
901                    return parseFloat(value);
902                }
903            }
904
905            return NaN;
906        }
907    }
908
909    function newInliner() {
910        const URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/g;
911
912        return {
913            inlineAll: inlineAll,
914            shouldProcess: shouldProcess,
915            impl: {
916                readUrls: readUrls,
917                inline: inline,
918            },
919        };
920
921        function shouldProcess(string) {
922            return string.search(URL_REGEX) !== -1;
923        }
924
925        function readUrls(string) {
926            const result = [];
927            let match;
928            while ((match = URL_REGEX.exec(string)) !== null) {
929                result.push(match[1]);
930            }
931            return result.filter(function (url) {
932                return !util.isDataUrl(url);
933            });
934        }
935
936        function inline(string, url, baseUrl, get) {
937            return Promise.resolve(url)
938                .then(function (urlValue) {
939                    return baseUrl ? util.resolveUrl(urlValue, baseUrl) : urlValue;
940                })
941                .then(get || util.getAndEncode)
942                .then(function (dataUrl) {
943                    return string.replace(urlAsRegex(url), `$1${dataUrl}$3`);
944                });
945
946            function urlAsRegex(urlValue) {
947                return new RegExp(
948                    `(url\\(['"]?)(${util.escape(urlValue)})(['"]?\\))`,
949                    'g'
950                );
951            }
952        }
953
954        function inlineAll(string, baseUrl, get) {
955            if (nothingToInline()) {
956                return Promise.resolve(string);
957            }
958
959            return Promise.resolve(string)
960                .then(readUrls)
961                .then(function (urls) {
962                    let done = Promise.resolve(string);
963                    urls.forEach(function (url) {
964                        done = done.then(function (prefix) {
965                            return inline(prefix, url, baseUrl, get);
966                        });
967                    });
968                    return done;
969                });
970
971            function nothingToInline() {
972                return !shouldProcess(string);
973            }
974        }
975    }
976
977    function newFontFaces() {
978        return {
979            resolveAll: resolveAll,
980            impl: {
981                readAll: readAll,
982            },
983        };
984
985        function resolveAll() {
986            return readAll()
987                .then(function (webFonts) {
988                    return Promise.all(
989                        webFonts.map(function (webFont) {
990                            return webFont.resolve();
991                        })
992                    );
993                })
994                .then(function (cssStrings) {
995                    return cssStrings.join('\n');
996                });
997        }
998
999        function readAll() {
1000            return Promise.resolve(util.asArray(document.styleSheets))
1001                .then(getCssRules)
1002                .then(selectWebFontRules)
1003                .then(function (rules) {
1004                    return rules.map(newWebFont);
1005                });
1006
1007            function selectWebFontRules(cssRules) {
1008                return cssRules
1009                    .filter(function (rule) {
1010                        return rule.type === CSSRule.FONT_FACE_RULE;
1011                    })
1012                    .filter(function (rule) {
1013                        return inliner.shouldProcess(rule.style.getPropertyValue('src'));
1014                    });
1015            }
1016
1017            function getCssRules(styleSheets) {
1018                const cssRules = [];
1019                styleSheets.forEach(function (sheet) {
1020                    if (
1021                        Object.prototype.hasOwnProperty.call(
1022                            Object.getPrototypeOf(sheet),
1023                            'cssRules'
1024                        )
1025                    ) {
1026                        try {
1027                            util.asArray(sheet.cssRules || []).forEach(
1028                                cssRules.push.bind(cssRules)
1029                            );
1030                        } catch (e) {
1031                            console.error(
1032                                `domtoimage: Error while reading CSS rules from ${sheet.href}`,
1033                                e.toString()
1034                            );
1035                        }
1036                    }
1037                });
1038                return cssRules;
1039            }
1040
1041            function newWebFont(webFontRule) {
1042                return {
1043                    resolve: function resolve() {
1044                        const baseUrl = (webFontRule.parentStyleSheet || {}).href;
1045                        return inliner.inlineAll(webFontRule.cssText, baseUrl);
1046                    },
1047                    src: function () {
1048                        return webFontRule.style.getPropertyValue('src');
1049                    },
1050                };
1051            }
1052        }
1053    }
1054
1055    function newImages() {
1056        return {
1057            inlineAll: inlineAll,
1058            impl: {
1059                newImage: newImage,
1060            },
1061        };
1062
1063        function newImage(element) {
1064            return {
1065                inline: inline,
1066            };
1067
1068            function inline(get) {
1069                if (util.isDataUrl(element.src)) {
1070                    return Promise.resolve();
1071                }
1072
1073                return Promise.resolve(element.src)
1074                    .then(get || util.getAndEncode)
1075                    .then(function (dataUrl) {
1076                        return new Promise(function (resolve) {
1077                            element.onload = resolve;
1078                            // for any image with invalid src(such as <img src />), just ignore it
1079                            element.onerror = resolve;
1080                            element.src = dataUrl;
1081                        });
1082                    });
1083            }
1084        }
1085
1086        function inlineAll(node) {
1087            if (!util.isElement(node)) {
1088                return Promise.resolve(node);
1089            }
1090
1091            return inlineCSSProperty(node).then(function () {
1092                if (util.isHTMLImageElement(node)) {
1093                    return newImage(node).inline();
1094                } else {
1095                    return Promise.all(
1096                        util.asArray(node.childNodes).map(function (child) {
1097                            return inlineAll(child);
1098                        })
1099                    );
1100                }
1101            });
1102
1103            function inlineCSSProperty(node) {
1104                const properties = ['background', 'background-image'];
1105
1106                const inliningTasks = properties.map(function (propertyName) {
1107                    const value = node.style.getPropertyValue(propertyName);
1108                    const priority = node.style.getPropertyPriority(propertyName);
1109
1110                    if (!value) {
1111                        return Promise.resolve();
1112                    }
1113
1114                    return inliner.inlineAll(value).then(function (inlinedValue) {
1115                        node.style.setProperty(propertyName, inlinedValue, priority);
1116                    });
1117                });
1118
1119                return Promise.all(inliningTasks).then(function () {
1120                    return node;
1121                });
1122            }
1123        }
1124    }
1125
1126    function setStyleProperty(targetStyle, name, value, priority) {
1127        const needs_prefixing = ['background-clip'].indexOf(name) >= 0;
1128        if (priority) {
1129            targetStyle.setProperty(name, value, priority);
1130            if (needs_prefixing) {
1131                targetStyle.setProperty(`-webkit-${name}`, value, priority);
1132            }
1133        } else {
1134            targetStyle.setProperty(name, value);
1135            if (needs_prefixing) {
1136                targetStyle.setProperty(`-webkit-${name}`, value);
1137            }
1138        }
1139    }
1140
1141    function copyUserComputedStyleFast(
1142        options,
1143        sourceElement,
1144        sourceComputedStyles,
1145        parentComputedStyles,
1146        targetElement
1147    ) {
1148        const defaultStyle = domtoimage.impl.options.copyDefaultStyles
1149            ? getDefaultStyle(options, sourceElement)
1150            : {};
1151        const targetStyle = targetElement.style;
1152
1153        util.asArray(sourceComputedStyles).forEach(function (name) {
1154            const sourceValue = sourceComputedStyles.getPropertyValue(name);
1155            const defaultValue = defaultStyle[name];
1156            const parentValue = parentComputedStyles
1157                ? parentComputedStyles.getPropertyValue(name)
1158                : undefined;
1159
1160            // If the style does not match the default, or it does not match the parent's, set it. We don't know which
1161            // styles are inherited from the parent and which aren't, so we have to always check both.
1162            if (
1163                sourceValue !== defaultValue ||
1164                (parentComputedStyles && sourceValue !== parentValue)
1165            ) {
1166                const priority = sourceComputedStyles.getPropertyPriority(name);
1167                setStyleProperty(targetStyle, name, sourceValue, priority);
1168            }
1169        });
1170    }
1171
1172    let removeDefaultStylesTimeoutId = null;
1173    let tagNameDefaultStyles = {};
1174
1175    const ascentStoppers = [
1176        // these come from https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements
1177        'ADDRESS',
1178        'ARTICLE',
1179        'ASIDE',
1180        'BLOCKQUOTE',
1181        'DETAILS',
1182        'DIALOG',
1183        'DD',
1184        'DIV',
1185        'DL',
1186        'DT',
1187        'FIELDSET',
1188        'FIGCAPTION',
1189        'FIGURE',
1190        'FOOTER',
1191        'FORM',
1192        'H1',
1193        'H2',
1194        'H3',
1195        'H4',
1196        'H5',
1197        'H6',
1198        'HEADER',
1199        'HGROUP',
1200        'HR',
1201        'LI',
1202        'MAIN',
1203        'NAV',
1204        'OL',
1205        'P',
1206        'PRE',
1207        'SECTION',
1208        'SVG',
1209        'TABLE',
1210        'UL',
1211        // this is some non-standard ones
1212        'math', // intentionally lowercase, thanks Safari
1213        'svg', // in case we have an svg embedded element
1214        // these are ultimate stoppers in case something drastic changes in how the DOM works
1215        'BODY',
1216        'HEAD',
1217        'HTML',
1218    ];
1219
1220    function getDefaultStyle(options, sourceElement) {
1221        const tagHierarchy = computeTagHierarchy(sourceElement);
1222        const tagKey = computeTagKey(tagHierarchy);
1223        if (tagNameDefaultStyles[tagKey]) {
1224            return tagNameDefaultStyles[tagKey];
1225        }
1226
1227        // We haven't cached the answer for that hierachy yet, build a
1228        // sandbox (if not yet created), fill it with the hierarchy that
1229        // matters, and grab the default styles associated
1230        const sandboxWindow = ensureSandboxWindow();
1231        const defaultElement = constructElementHierachy(
1232            sandboxWindow.document,
1233            tagHierarchy
1234        );
1235        const defaultStyle = computeStyleForDefaults(sandboxWindow, defaultElement);
1236        destroyElementHierarchy(defaultElement);
1237
1238        tagNameDefaultStyles[tagKey] = defaultStyle;
1239        return defaultStyle;
1240
1241        function computeTagHierarchy(sourceNode) {
1242            const tagNames = [];
1243
1244            do {
1245                if (sourceNode.nodeType === ELEMENT_NODE) {
1246                    const tagName = sourceNode.tagName;
1247                    tagNames.push(tagName);
1248
1249                    if (ascentStoppers.includes(tagName)) {
1250                        break;
1251                    }
1252                }
1253
1254                sourceNode = sourceNode.parentNode;
1255            } while (sourceNode);
1256
1257            return tagNames;
1258        }
1259
1260        function computeTagKey(tagHierarchy) {
1261            if (options.styleCaching === 'relaxed') {
1262                // pick up only the ascent-stopping element tag and the element tag itself
1263                /* jshint unused:true */
1264                return tagHierarchy
1265                    .filter((_, i, a) => i === 0 || i === a.length - 1)
1266                    .join('>');
1267            }
1268            // for all other cases, fall back the the entire path
1269            return tagHierarchy.join('>'); // it's like CSS
1270        }
1271
1272        function constructElementHierachy(sandboxDocument, tagHierarchy) {
1273            let element = sandboxDocument.body;
1274            do {
1275                const childTagName = tagHierarchy.pop();
1276                const childElement = sandboxDocument.createElement(childTagName);
1277                element.appendChild(childElement);
1278                element = childElement;
1279            } while (tagHierarchy.length > 0);
1280
1281            // Ensure that there is some content, so that properties like margin are applied.
1282            // we use zero-width space to handle FireFox adding a pixel
1283            element.textContent = '\u200b';
1284            return element;
1285        }
1286
1287        function computeStyleForDefaults(sandboxWindow, defaultElement) {
1288            const defaultStyle = {};
1289            const defaultComputedStyle = sandboxWindow.getComputedStyle(defaultElement);
1290
1291            // Copy styles to an object, making sure that 'width' and 'height' are given the default value of 'auto', since
1292            // their initial value is always 'auto' despite that the default computed value is sometimes an absolute length.
1293            util.asArray(defaultComputedStyle).forEach(function (name) {
1294                defaultStyle[name] =
1295                    name === 'width' || name === 'height'
1296                        ? 'auto'
1297                        : defaultComputedStyle.getPropertyValue(name);
1298            });
1299            return defaultStyle;
1300        }
1301
1302        function destroyElementHierarchy(element) {
1303            do {
1304                const parentElement = element.parentElement;
1305                if (parentElement !== null) {
1306                    parentElement.removeChild(element);
1307                }
1308                element = parentElement;
1309            } while (element && element.tagName !== 'BODY');
1310        }
1311    }
1312
1313    function ensureSandboxWindow() {
1314        if (sandbox) {
1315            return sandbox.contentWindow;
1316        }
1317
1318        // figure out how this document is defined (doctype and charset)
1319        const charsetToUse = document.characterSet || 'UTF-8';
1320        const docType = document.doctype;
1321        const docTypeDeclaration = docType
1322            ? `<!DOCTYPE ${escapeHTML(docType.name)}
1322 ${escapeHTML(
1323                  docType.publicId
1324              )} ${escapeHTML(docType.systemId)}`.trim() + '>'
1325            : '';
1326
1327        // Create a hidden sandbox <iframe> element within we can create default HTML elements and query their
1328        // computed styles. Elements must be rendered in order to query their computed styles. The <iframe> won't
1329        // render at all with `display: none`, so we have to use `visibility: hidden` with `position: fixed`.
1330        sandbox = document.createElement('iframe');
1331        sandbox.id = 'domtoimage-sandbox-' + util.uid();
1332        sandbox.style.visibility = 'hidden';
1333        sandbox.style.position = 'fixed';
1334        document.body.appendChild(sandbox);
1335
1336        return tryTechniques(
1337            sandbox,
1338            docTypeDeclaration,
1339            charsetToUse,
1340            'domtoimage-sandbox'
1341        );
1342
1343        function escapeHTML(unsafeText) {
1344            if (unsafeText) {
1345                const div = document.createElement('div');
1346                div.innerText = unsafeText;
1347                return div.innerHTML;
1348            } else {
1349                return '';
1350            }
1351        }
1352
1353        function tryTechniques(sandbox, doctype, charset, title) {
1354            // try the good old-fashioned document write with all the correct attributes set
1355            try {
1356                sandbox.contentWindow.document.write(
1357                    `${doctype}<html><head><meta charset='${charset}'><title>${title}</title></head><body></body></html>`
1358                );
1359                return sandbox.contentWindow;
1360            } catch (_) {
1361                // swallow exception and fall through to next technique
1362            }
1363
1364            const metaCharset = document.createElement('meta');
1365            metaCharset.setAttribute('charset', charset);
1366
1367            // let's attempt it using srcdoc, so we can still set the doctype and charset
1368            try {
1369                const sandboxDocument = document.implementation.createHTMLDocument(title);
1370                sandboxDocument.head.appendChild(metaCharset);
1371                const sandboxHTML = doctype + sandboxDocument.documentElement.outerHTML;
1372                sandbox.setAttribute('srcdoc', sandboxHTML);
1373                return sandbox.contentWindow;
1374            } catch (_) {
1375                // swallow exception and fall through to the simplest path
1376            }
1377
1378            // let's attempt it using contentDocument... here we're not able to set the doctype
1379            sandbox.contentDocument.head.appendChild(metaCharset);
1380            sandbox.contentDocument.title = title;
1381            return sandbox.contentWindow;
1382        }
1383    }
1384
1385    function removeSandbox() {
1386        if (sandbox) {
1387            document.body.removeChild(sandbox);
1388            sandbox = null;
1389        }
1390
1391        if (removeDefaultStylesTimeoutId) {
1392            clearTimeout(removeDefaultStylesTimeoutId);
1393        }
1394
1395        removeDefaultStylesTimeoutId = setTimeout(() => {
1396            removeDefaultStylesTimeoutId = null;
1397            tagNameDefaultStyles = {};
1398        }, 20 * 1000);
1399    }
1400
1401    
1402    //    module.exports = domtoimage; // eslint-disable-line no-undef
1403    export default domtoimage;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.