diff --git a/.eslintrc b/.eslintrc index ac3506b6d..5570f8073 100644 --- a/.eslintrc +++ b/.eslintrc @@ -51,6 +51,7 @@ "unicorn/no-useless-spread": "error", "unicorn/prefer-at": "error", "unicorn/prefer-date-now": "error", + "unicorn/prefer-dom-node-append": "error", "unicorn/prefer-dom-node-remove": "error", "unicorn/prefer-string-starts-ends-with": "error", diff --git a/examples/node/domstubs.js b/examples/node/domstubs.js index 19c541209..373fd1c26 100644 --- a/examples/node/domstubs.js +++ b/examples/node/domstubs.js @@ -100,6 +100,15 @@ DOMElement.prototype = { this.setAttribute(name, value); }, + append: function DOMElement_append(...elements) { + const childNodes = this.childNodes; + for (const element of elements) { + if (!childNodes.includes(element)) { + childNodes.push(element); + } + } + }, + appendChild: function DOMElement_appendChild(element) { const childNodes = this.childNodes; if (!childNodes.includes(element)) { diff --git a/examples/text-only/pdf2svg.js b/examples/text-only/pdf2svg.js index df9652ede..e7242f4af 100644 --- a/examples/text-only/pdf2svg.js +++ b/examples/text-only/pdf2svg.js @@ -43,7 +43,7 @@ function buildSVG(viewport, textContent) { text.setAttribute("transform", "matrix(" + tx.join(" ") + ")"); text.setAttribute("font-family", style.fontFamily); text.textContent = textItem.str; - svg.appendChild(text); + svg.append(text); }); return svg; } @@ -57,7 +57,7 @@ async function pageLoaded() { const textContent = await page.getTextContent(); // building SVG and adding that to the DOM const svg = buildSVG(viewport, textContent); - document.getElementById("pageContainer").appendChild(svg); + document.getElementById("pageContainer").append(svg); // Release page resources. page.cleanup(); } diff --git a/extensions/chromium/contentscript.js b/extensions/chromium/contentscript.js index 674c274ab..749e1ae03 100644 --- a/extensions/chromium/contentscript.js +++ b/extensions/chromium/contentscript.js @@ -160,7 +160,7 @@ function updateObjectElement(elem) { if (!iframe || !iframe.__inserted_by_pdfjs) { iframe = createFullSizeIframe(); elem.textContent = ""; - elem.appendChild(iframe); + elem.append(iframe); iframe.__inserted_by_pdfjs = true; } iframe.src = getEmbeddedViewerURL(elem.data); diff --git a/extensions/chromium/options/options.js b/extensions/chromium/options/options.js index 27df162d5..3867a11b9 100644 --- a/extensions/chromium/options/options.js +++ b/extensions/chromium/options/options.js @@ -155,7 +155,7 @@ function renderBooleanPref(shortDescription, description, prefName) { storageArea.set(pref); }; wrapper.querySelector("span").textContent = shortDescription; - document.getElementById("settings-boxes").appendChild(wrapper); + document.getElementById("settings-boxes").append(wrapper); function renderPreference(value) { checkbox.checked = value; @@ -172,7 +172,7 @@ function renderEnumPref(shortDescription, prefName) { storageArea.set(pref); }; wrapper.querySelector("span").textContent = shortDescription; - document.getElementById("settings-boxes").appendChild(wrapper); + document.getElementById("settings-boxes").append(wrapper); function renderPreference(value) { select.value = value; @@ -189,7 +189,7 @@ function renderDefaultZoomValue(shortDescription) { }); }; wrapper.querySelector("span").textContent = shortDescription; - document.getElementById("settings-boxes").appendChild(wrapper); + document.getElementById("settings-boxes").append(wrapper); function renderPreference(value) { value = value || "auto"; diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index b74a15dbb..cd1bdb69a 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -448,7 +448,7 @@ class AnnotationElement { trigger = document.createElement("div"); trigger.style.height = container.style.height; trigger.style.width = container.style.width; - container.appendChild(trigger); + container.append(trigger); } const popupElement = new PopupElement({ @@ -466,7 +466,7 @@ class AnnotationElement { // Position the popup next to the annotation's container. popup.style.left = container.style.width; - container.appendChild(popup); + container.append(popup); } /** @@ -607,7 +607,7 @@ class LinkAnnotationElement extends AnnotationElement { return this._renderQuadrilaterals("linkAnnotation").map( (quadrilateral, index) => { const linkElement = index === 0 ? link : link.cloneNode(); - quadrilateral.appendChild(linkElement); + quadrilateral.append(linkElement); return quadrilateral; } ); @@ -615,7 +615,7 @@ class LinkAnnotationElement extends AnnotationElement { this.container.className = "linkAnnotation"; if (isBound) { - this.container.appendChild(link); + this.container.append(link); } return this.container; @@ -828,7 +828,7 @@ class TextAnnotationElement extends AnnotationElement { this._createPopup(image, this.data); } - this.container.appendChild(image); + this.container.append(image); return this.container; } } @@ -1234,7 +1234,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement { this._setBackgroundColor(element); this._setDefaultPropertiesFromJS(element); - this.container.appendChild(element); + this.container.append(element); return this.container; } } @@ -1319,7 +1319,7 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement { this._setBackgroundColor(element); this._setDefaultPropertiesFromJS(element); - this.container.appendChild(element); + this.container.append(element); return this.container; } } @@ -1408,7 +1408,7 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement { this._setBackgroundColor(element); this._setDefaultPropertiesFromJS(element); - this.container.appendChild(element); + this.container.append(element); return this.container; } } @@ -1490,7 +1490,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { optionElement.setAttribute("selected", true); addAnEmptyEntry = false; } - selectElement.appendChild(optionElement); + selectElement.append(optionElement); } let removeEmptyEntry = null; @@ -1595,7 +1595,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { const optionElement = document.createElement("option"); optionElement.textContent = displayValue; optionElement.value = exportValue; - selectElement.appendChild(optionElement); + selectElement.append(optionElement); } if (selectElement.options.length > 0) { selectElement.options[0].selected = true; @@ -1668,7 +1668,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { this._setBackgroundColor(selectElement); this._setDefaultPropertiesFromJS(selectElement); - this.container.appendChild(selectElement); + this.container.append(selectElement); return this.container; } } @@ -1734,7 +1734,7 @@ class PopupAnnotationElement extends AnnotationElement { this.container.style.left = `${popupLeft}px`; this.container.style.top = `${popupTop}px`; - this.container.appendChild(popup.render()); + this.container.append(popup.render()); return this.container; } } @@ -1781,7 +1781,7 @@ class PopupElement { const title = document.createElement("h1"); title.dir = this.titleObj.dir; title.textContent = this.titleObj.str; - popup.appendChild(title); + popup.append(title); // The modification date is shown in the popup instead of the creation // date if it is available and can be parsed correctly, which is @@ -1796,7 +1796,7 @@ class PopupElement { date: dateObject.toLocaleDateString(), time: dateObject.toLocaleTimeString(), }); - popup.appendChild(modificationDate); + popup.append(modificationDate); } if ( @@ -1811,7 +1811,7 @@ class PopupElement { popup.lastChild.className = "richText popupContent"; } else { const contents = this._formatContents(this.contentsObj); - popup.appendChild(contents); + popup.append(contents); } if (!Array.isArray(this.trigger)) { @@ -1826,7 +1826,7 @@ class PopupElement { } popup.addEventListener("click", this._hide.bind(this, true)); - wrapper.appendChild(popup); + wrapper.append(popup); return wrapper; } @@ -1845,9 +1845,9 @@ class PopupElement { const lines = str.split(/(?:\r\n?|\n)/); for (let i = 0, ii = lines.length; i < ii; ++i) { const line = lines[i]; - p.appendChild(document.createTextNode(line)); + p.append(document.createTextNode(line)); if (i < ii - 1) { - p.appendChild(document.createElement("br")); + p.append(document.createElement("br")); } } return p; @@ -1957,7 +1957,7 @@ class LineAnnotationElement extends AnnotationElement { line.setAttribute("stroke", "transparent"); line.setAttribute("fill", "transparent"); - svg.appendChild(line); + svg.append(line); this.container.append(svg); // Create the popup ourselves so that we can bind it to the line instead @@ -2004,7 +2004,7 @@ class SquareAnnotationElement extends AnnotationElement { square.setAttribute("stroke", "transparent"); square.setAttribute("fill", "transparent"); - svg.appendChild(square); + svg.append(square); this.container.append(svg); // Create the popup ourselves so that we can bind it to the square instead @@ -2051,7 +2051,7 @@ class CircleAnnotationElement extends AnnotationElement { circle.setAttribute("stroke", "transparent"); circle.setAttribute("fill", "transparent"); - svg.appendChild(circle); + svg.append(circle); this.container.append(svg); // Create the popup ourselves so that we can bind it to the circle instead @@ -2106,7 +2106,7 @@ class PolylineAnnotationElement extends AnnotationElement { polyline.setAttribute("stroke", "transparent"); polyline.setAttribute("fill", "transparent"); - svg.appendChild(polyline); + svg.append(polyline); this.container.append(svg); // Create the popup ourselves so that we can bind it to the polyline @@ -2199,7 +2199,7 @@ class InkAnnotationElement extends AnnotationElement { // instead of to the entire container (which is the default). this._createPopup(polyline, data); - svg.appendChild(polyline); + svg.append(polyline); } this.container.append(svg); @@ -2376,7 +2376,7 @@ class FileAttachmentAnnotationElement extends AnnotationElement { this._createPopup(trigger, this.data); } - this.container.appendChild(trigger); + this.container.append(trigger); return this.container; } @@ -2471,7 +2471,7 @@ class AnnotationLayer { } if (Array.isArray(rendered)) { for (const renderedElement of rendered) { - div.appendChild(renderedElement); + div.append(renderedElement); } } else { if (element instanceof PopupAnnotationElement) { @@ -2479,7 +2479,7 @@ class AnnotationLayer { // annotation elements to prevent interfering with mouse events. div.prepend(rendered); } else { - div.appendChild(rendered); + div.append(rendered); } } } @@ -2557,7 +2557,7 @@ class AnnotationLayer { const { firstChild } = element; if (!firstChild) { - element.appendChild(canvas); + element.append(canvas); } else if (firstChild.nodeName === "CANVAS") { element.replaceChild(canvas, firstChild); } else { diff --git a/src/display/display_utils.js b/src/display/display_utils.js index cdfaa1c91..60162f696 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -459,7 +459,7 @@ function loadScript(src, removeScriptElement = false) { script.onerror = function () { reject(new Error(`Cannot load script at: ${script.src}`)); }; - (document.head || document.documentElement).appendChild(script); + (document.head || document.documentElement).append(script); }); } diff --git a/src/display/editor/annotation_editor_layer.js b/src/display/editor/annotation_editor_layer.js index da5931676..d9cef7dec 100644 --- a/src/display/editor/annotation_editor_layer.js +++ b/src/display/editor/annotation_editor_layer.js @@ -232,7 +232,7 @@ class AnnotationEditorLayer { editor.parent = this; if (editor.div && editor.isAttachedToDOM) { editor.div.remove(); - this.div.appendChild(editor.div); + this.div.append(editor.div); } } @@ -248,7 +248,7 @@ class AnnotationEditorLayer { if (!editor.isAttachedToDOM) { const div = editor.render(); - this.div.appendChild(div); + this.div.append(div); editor.isAttachedToDOM = true; } diff --git a/src/display/editor/freetext.js b/src/display/editor/freetext.js index efaa41885..14cb17390 100644 --- a/src/display/editor/freetext.js +++ b/src/display/editor/freetext.js @@ -211,11 +211,11 @@ class FreeTextEditor extends AnnotationEditor { style.fontSize = `calc(${this.#fontSize}px * var(--zoom-factor))`; style.color = this.#color; - this.div.appendChild(this.editorDiv); + this.div.append(this.editorDiv); this.overlayDiv = document.createElement("div"); this.overlayDiv.classList.add("overlay", "enabled"); - this.div.appendChild(this.overlayDiv); + this.div.append(this.overlayDiv); // TODO: implement paste callback. // The goal is to sanitize and have something suitable for this diff --git a/src/display/editor/ink.js b/src/display/editor/ink.js index 431ead2c6..cb8c4ea4d 100644 --- a/src/display/editor/ink.js +++ b/src/display/editor/ink.js @@ -353,7 +353,7 @@ class InkEditor extends AnnotationEditor { #createCanvas() { this.canvas = document.createElement("canvas"); this.canvas.className = "inkEditorCanvas"; - this.div.appendChild(this.canvas); + this.div.append(this.canvas); this.ctx = this.canvas.getContext("2d"); } diff --git a/src/display/font_loader.js b/src/display/font_loader.js index a80a7de6e..b6212d4eb 100644 --- a/src/display/font_loader.js +++ b/src/display/font_loader.js @@ -58,7 +58,7 @@ class BaseFontLoader { styleElement.id = `PDFJS_FONT_STYLE_TAG_${this.docId}`; this._document.documentElement .getElementsByTagName("head")[0] - .appendChild(styleElement); + .append(styleElement); } const styleSheet = styleElement.sheet; styleSheet.insertRule(rule, styleSheet.cssRules.length); @@ -345,9 +345,9 @@ if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) { const span = this._document.createElement("span"); span.textContent = "Hi"; span.style.fontFamily = name; - div.appendChild(span); + div.append(span); } - this._document.body.appendChild(div); + this._document.body.append(div); isFontReady(loadTestFontId, () => { div.remove(); diff --git a/src/display/svg.js b/src/display/svg.js index 5e542953c..a0e9813e9 100644 --- a/src/display/svg.js +++ b/src/display/svg.js @@ -778,7 +778,7 @@ if ( current.tspan.setAttributeNS(null, "y", pf(-current.y)); current.txtElement = this.svgFactory.createElement("svg:text"); - current.txtElement.appendChild(current.tspan); + current.txtElement.append(current.tspan); } beginText() { @@ -959,10 +959,10 @@ if ( `${pm(textMatrix)} scale(${pf(textHScale)}, -1)` ); current.txtElement.setAttributeNS(XML_NS, "xml:space", "preserve"); - current.txtElement.appendChild(current.tspan); - current.txtgrp.appendChild(current.txtElement); + current.txtElement.append(current.tspan); + current.txtgrp.append(current.txtElement); - this._ensureTransformGroup().appendChild(current.txtElement); + this._ensureTransformGroup().append(current.txtElement); } setLeadingMoveText(x, y) { @@ -980,7 +980,7 @@ if ( if (!this.cssStyle) { this.cssStyle = this.svgFactory.createElement("svg:style"); this.cssStyle.setAttributeNS(null, "type", "text/css"); - this.defs.appendChild(this.cssStyle); + this.defs.append(this.cssStyle); } const url = createObjectURL( @@ -1115,7 +1115,7 @@ if ( if (this.current.fillAlpha < 1) { rect.setAttributeNS(null, "fill-opacity", this.current.fillAlpha); } - this._ensureTransformGroup().appendChild(rect); + this._ensureTransformGroup().append(rect); } /** @@ -1179,8 +1179,8 @@ if ( this.current.fillColor = fillColor; this.current.strokeColor = strokeColor; - tiling.appendChild(bbox.childNodes[0]); - this.defs.appendChild(tiling); + tiling.append(bbox.childNodes[0]); + this.defs.append(tiling); return `url(#${tilingId})`; } @@ -1231,9 +1231,9 @@ if ( const stop = this.svgFactory.createElement("svg:stop"); stop.setAttributeNS(null, "offset", colorStop[0]); stop.setAttributeNS(null, "stop-color", colorStop[1]); - gradient.appendChild(stop); + gradient.append(stop); } - this.defs.appendChild(gradient); + this.defs.append(gradient); return `url(#${shadingId})`; case "Mesh": warn("Unimplemented pattern Mesh"); @@ -1354,7 +1354,7 @@ if ( d = current.path.getAttributeNS(null, "d") + d; } else { current.path = this.svgFactory.createElement("svg:path"); - this._ensureTransformGroup().appendChild(current.path); + this._ensureTransformGroup().append(current.path); } current.path.setAttributeNS(null, "d", d); @@ -1394,8 +1394,8 @@ if ( clipElement.setAttributeNS(null, "clip-rule", "nonzero"); } this.pendingClip = null; - clipPath.appendChild(clipElement); - this.defs.appendChild(clipPath); + clipPath.append(clipElement); + this.defs.append(clipPath); if (current.activeClipUrl) { // The previous clipping group content can go out of order -- resetting @@ -1583,7 +1583,7 @@ if ( rect.setAttributeNS(null, "height", "1px"); rect.setAttributeNS(null, "fill", this.current.fillColor); - this._ensureTransformGroup().appendChild(rect); + this._ensureTransformGroup().append(rect); } paintImageXObject(objId) { @@ -1622,9 +1622,9 @@ if ( `scale(${pf(1 / width)} ${pf(-1 / height)})` ); if (mask) { - mask.appendChild(imgEl); + mask.append(imgEl); } else { - this._ensureTransformGroup().appendChild(imgEl); + this._ensureTransformGroup().append(imgEl); } } @@ -1646,8 +1646,8 @@ if ( rect.setAttributeNS(null, "fill", fillColor); rect.setAttributeNS(null, "mask", `url(#${current.maskId})`); - this.defs.appendChild(mask); - this._ensureTransformGroup().appendChild(rect); + this.defs.append(mask); + this._ensureTransformGroup().append(rect); this.paintInlineImageXObject(imgData, mask); } @@ -1689,14 +1689,14 @@ if ( // Create the definitions element. const definitions = this.svgFactory.createElement("svg:defs"); - svg.appendChild(definitions); + svg.append(definitions); this.defs = definitions; // Create the root group element, which acts a container for all other // groups and applies the viewport transform. const rootGroup = this.svgFactory.createElement("svg:g"); rootGroup.setAttributeNS(null, "transform", pm(viewport.transform)); - svg.appendChild(rootGroup); + svg.append(rootGroup); // For the construction of the SVG image we are only interested in the // root group, so we expose it as the entry point of the SVG image for @@ -1713,7 +1713,7 @@ if ( if (!this.current.clipGroup) { const clipGroup = this.svgFactory.createElement("svg:g"); clipGroup.setAttributeNS(null, "clip-path", this.current.activeClipUrl); - this.svg.appendChild(clipGroup); + this.svg.append(clipGroup); this.current.clipGroup = clipGroup; } return this.current.clipGroup; @@ -1727,9 +1727,9 @@ if ( this.tgrp = this.svgFactory.createElement("svg:g"); this.tgrp.setAttributeNS(null, "transform", pm(this.transformMatrix)); if (this.current.activeClipUrl) { - this._ensureClipGroup().appendChild(this.tgrp); + this._ensureClipGroup().append(this.tgrp); } else { - this.svg.appendChild(this.tgrp); + this.svg.append(this.tgrp); } } return this.tgrp; diff --git a/src/display/text_layer.js b/src/display/text_layer.js index b0d33e77a..5a27f1723 100644 --- a/src/display/text_layer.js +++ b/src/display/text_layer.js @@ -658,7 +658,7 @@ class TextLayerRenderTask { if (items[i].id !== null) { this._container.setAttribute("id", `${items[i].id}`); } - parent.appendChild(this._container); + parent.append(this._container); } else if (items[i].type === "endMarkedContent") { this._container = this._container.parentNode; } @@ -710,12 +710,12 @@ class TextLayerRenderTask { } if (textDivProperties.hasText) { - this._container.appendChild(textDiv); + this._container.append(textDiv); } if (textDivProperties.hasEOL) { const br = document.createElement("br"); br.setAttribute("role", "presentation"); - this._container.appendChild(br); + this._container.append(br); } } diff --git a/src/display/xfa_layer.js b/src/display/xfa_layer.js index 6f8933e1b..ed3dd7a51 100644 --- a/src/display/xfa_layer.js +++ b/src/display/xfa_layer.js @@ -169,7 +169,7 @@ class XfaLayer { const stack = [[root, -1, rootHtml]]; const rootDiv = parameters.div; - rootDiv.appendChild(rootHtml); + rootDiv.append(rootHtml); if (parameters.viewport) { const transform = `matrix(${parameters.viewport.transform.join(",")})`; @@ -200,7 +200,7 @@ class XfaLayer { if (name === "#text") { const node = document.createTextNode(child.value); textDivs.push(node); - html.appendChild(node); + html.append(node); continue; } @@ -211,7 +211,7 @@ class XfaLayer { childHtml = document.createElement(name); } - html.appendChild(childHtml); + html.append(childHtml); if (child.attributes) { this.setAttributes({ html: childHtml, @@ -229,7 +229,7 @@ class XfaLayer { if (XfaText.shouldBuildText(name)) { textDivs.push(node); } - childHtml.appendChild(node); + childHtml.append(node); } } diff --git a/test/driver.js b/test/driver.js index bd943b0cb..bba4a0906 100644 --- a/test/driver.js +++ b/test/driver.js @@ -192,10 +192,10 @@ class Rasterize { foreignObject.setAttribute("height", `${viewport.height}px`); const style = document.createElement("style"); - foreignObject.appendChild(style); + foreignObject.append(style); const div = document.createElement("div"); - foreignObject.appendChild(div); + foreignObject.append(div); return { svg, foreignObject, style, div }; } @@ -238,8 +238,8 @@ class Rasterize { // Inline SVG images from text annotations. await inlineImages(div); - foreignObject.appendChild(div); - svg.appendChild(foreignObject); + foreignObject.append(div); + svg.append(foreignObject); await writeSVG(svg, ctx); } catch (reason) { @@ -268,7 +268,7 @@ class Rasterize { await task.promise; task.expandTextDivs(true); - svg.appendChild(foreignObject); + svg.append(foreignObject); await writeSVG(svg, ctx); } catch (reason) { @@ -302,7 +302,7 @@ class Rasterize { // Some unsupported type of images (e.g. tiff) lead to errors. await inlineImages(div, /* silentErrors = */ true); - svg.appendChild(foreignObject); + svg.append(foreignObject); await writeSVG(svg, ctx); } catch (reason) { @@ -468,7 +468,7 @@ class Driver { xfaStyleElement = document.createElement("style"); document.documentElement .getElementsByTagName("head")[0] - .appendChild(xfaStyleElement); + .append(xfaStyleElement); } const loadingTask = getDocument({ diff --git a/test/resources/reftest-analyzer.js b/test/resources/reftest-analyzer.js index 1c4312d39..6a6ed2488 100644 --- a/test/resources/reftest-analyzer.js +++ b/test/resources/reftest-analyzer.js @@ -79,7 +79,7 @@ window.onload = function () { r.setAttribute("y", (gMagZoom * -gMagHeight) / 2); r.setAttribute("width", gMagZoom * gMagWidth); r.setAttribute("height", gMagZoom * gMagHeight); - mag.appendChild(r); + mag.append(r); mag.setAttribute( "transform", "translate(" + @@ -124,8 +124,7 @@ window.onload = function () { p2.setAttribute("stroke-width", "1px"); p2.setAttribute("fill", "#888"); - mag.appendChild(p1); - mag.appendChild(p2); + mag.append(p1, p2); gMagPixPaths[x][y] = [p1, p2]; } } @@ -251,7 +250,7 @@ window.onload = function () { const table = document.getElementById("itemtable"); table.textContent = ""; // Remove any table contents from the DOM. const tbody = document.createElement("tbody"); - table.appendChild(tbody); + table.append(tbody); for (const i in gTestItems) { const item = gTestItems[i]; @@ -276,8 +275,8 @@ window.onload = function () { text += "S"; rowclass += " skip"; } - td.appendChild(document.createTextNode(text)); - tr.appendChild(td); + td.append(document.createTextNode(text)); + tr.append(td); td = document.createElement("td"); td.id = "url" + i; @@ -290,14 +289,14 @@ window.onload = function () { a.id = i; a.className = "image"; a.href = "#"; - a.appendChild(text); - td.appendChild(a); + a.append(text); + td.append(a); } else { - td.appendChild(text); + td.append(text); } - tr.appendChild(td); + tr.append(td); tr.className = rowclass; - tbody.appendChild(tr); + tbody.append(tr); } // Bind an event handler to each image link @@ -481,8 +480,8 @@ window.onload = function () { p2.setAttribute("fill", color2); if (color1 !== color2) { gFlashingPixels.push(p1, p2); - p1.parentNode.appendChild(p1); - p2.parentNode.appendChild(p2); + p1.parentNode.append(p1); + p2.parentNode.append(p2); } if (i === 0 && j === 0) { centerPixelColor1 = color1; diff --git a/test/unit/custom_spec.js b/test/unit/custom_spec.js index 0c562cda2..a0773c369 100644 --- a/test/unit/custom_spec.js +++ b/test/unit/custom_spec.js @@ -134,7 +134,7 @@ describe("custom ownerDocument", function () { fonts: new Set(), createElement, documentElement: { - getElementsByTagName: () => [{ appendChild: () => {} }], + getElementsByTagName: () => [{ append: () => {} }], }, }; const CanvasFactory = new DefaultCanvasFactory({ ownerDocument }); diff --git a/test/unit/display_svg_spec.js b/test/unit/display_svg_spec.js index 1a63ef86b..305b03a30 100644 --- a/test/unit/display_svg_spec.js +++ b/test/unit/display_svg_spec.js @@ -84,8 +84,8 @@ describe("SVGGraphics", function () { let svgImg; // A mock to steal the svg:image element from paintInlineImageXObject. const elementContainer = { - appendChild(element) { - svgImg = element; + append(...elements) { + svgImg = elements.at(-1); }, }; diff --git a/web/annotation_editor_layer_builder.js b/web/annotation_editor_layer_builder.js index 158fe9516..7c785dd0e 100644 --- a/web/annotation_editor_layer_builder.js +++ b/web/annotation_editor_layer_builder.js @@ -94,7 +94,7 @@ class AnnotationEditorLayerBuilder { this.annotationEditorLayer.render(parameters); - this.pageDiv.appendChild(this.div); + this.pageDiv.append(this.div); } cancel() { diff --git a/web/annotation_layer_builder.js b/web/annotation_layer_builder.js index 6c6fea2a1..aa1d9ac4b 100644 --- a/web/annotation_layer_builder.js +++ b/web/annotation_layer_builder.js @@ -123,7 +123,7 @@ class AnnotationLayerBuilder { // if there is at least one annotation. this.div = document.createElement("div"); this.div.className = "annotationLayer"; - this.pageDiv.appendChild(this.div); + this.pageDiv.append(this.div); parameters.div = this.div; AnnotationLayer.render(parameters); diff --git a/web/base_tree_viewer.js b/web/base_tree_viewer.js index 7a3168128..4fc37a5fd 100644 --- a/web/base_tree_viewer.js +++ b/web/base_tree_viewer.js @@ -122,7 +122,7 @@ class BaseTreeViewer { this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden"); } - this.container.appendChild(fragment); + this.container.append(fragment); this._dispatchEvent(count); } diff --git a/web/base_viewer.js b/web/base_viewer.js index f5241bcc8..d4a34ce1d 100644 --- a/web/base_viewer.js +++ b/web/base_viewer.js @@ -941,7 +941,7 @@ class BaseViewer { if (this._spreadMode === SpreadMode.NONE && !this.isInPresentationMode) { // Finally, append the new page to the viewer. const pageView = this._pages[pageNumber - 1]; - viewer.appendChild(pageView.div); + viewer.append(pageView.div); state.pages.push(pageView); } else { @@ -969,7 +969,7 @@ class BaseViewer { if (this.isInPresentationMode) { const dummyPage = document.createElement("div"); dummyPage.className = "dummyPage"; - spread.appendChild(dummyPage); + spread.append(dummyPage); } for (const i of pageIndexSet) { @@ -977,11 +977,11 @@ class BaseViewer { if (!pageView) { continue; } - spread.appendChild(pageView.div); + spread.append(pageView.div); state.pages.push(pageView); } - viewer.appendChild(spread); + viewer.append(spread); } state.scrollDown = pageNumber >= state.previousPageNumber; @@ -1925,7 +1925,7 @@ class BaseViewer { if (this._spreadMode === SpreadMode.NONE) { for (const pageView of this._pages) { - viewer.appendChild(pageView.div); + viewer.append(pageView.div); } } else { const parity = this._spreadMode - 1; @@ -1934,12 +1934,12 @@ class BaseViewer { if (spread === null) { spread = document.createElement("div"); spread.className = "spread"; - viewer.appendChild(spread); + viewer.append(spread); } else if (i % 2 === parity) { spread = spread.cloneNode(false); - viewer.appendChild(spread); + viewer.append(spread); } - spread.appendChild(pages[i].div); + spread.append(pages[i].div); } } } diff --git a/web/debugger.js b/web/debugger.js index 5bc6bdf95..210e388ad 100644 --- a/web/debugger.js +++ b/web/debugger.js @@ -68,10 +68,10 @@ const FontInspector = (function FontInspectorClosure() { const tmp = document.createElement("button"); tmp.addEventListener("click", resetSelection); tmp.textContent = "Refresh"; - panel.appendChild(tmp); + panel.append(tmp); fonts = document.createElement("div"); - panel.appendChild(fonts); + panel.append(fonts); }, cleanup() { fonts.textContent = ""; @@ -98,11 +98,11 @@ const FontInspector = (function FontInspectorClosure() { const tr = document.createElement("tr"); const td1 = document.createElement("td"); td1.textContent = entry; - tr.appendChild(td1); + tr.append(td1); const td2 = document.createElement("td"); td2.textContent = obj[entry].toString(); - tr.appendChild(td2); - moreInfo.appendChild(tr); + tr.append(td2); + moreInfo.append(tr); } return moreInfo; } @@ -134,14 +134,8 @@ const FontInspector = (function FontInspectorClosure() { select.addEventListener("click", function () { selectFont(fontName, select.checked); }); - font.appendChild(select); - font.appendChild(name); - font.appendChild(document.createTextNode(" ")); - font.appendChild(download); - font.appendChild(document.createTextNode(" ")); - font.appendChild(logIt); - font.appendChild(moreInfo); - fonts.appendChild(font); + font.append(select, name, " ", download, " ", logIt, moreInfo); + fonts.append(font); // Somewhat of a hack, should probably add a hook for when the text layer // is done rendering. setTimeout(() => { @@ -173,10 +167,9 @@ const StepperManager = (function StepperManagerClosure() { stepperChooser.addEventListener("change", function (event) { self.selectStepper(this.value); }); - stepperControls.appendChild(stepperChooser); + stepperControls.append(stepperChooser); stepperDiv = document.createElement("div"); - this.panel.appendChild(stepperControls); - this.panel.appendChild(stepperDiv); + this.panel.append(stepperControls, stepperDiv); if (sessionStorage.getItem("pdfjsBreakPoints")) { breakPoints = JSON.parse(sessionStorage.getItem("pdfjsBreakPoints")); } @@ -199,11 +192,11 @@ const StepperManager = (function StepperManagerClosure() { debug.id = "stepper" + pageIndex; debug.hidden = true; debug.className = "stepper"; - stepperDiv.appendChild(debug); + stepperDiv.append(debug); const b = document.createElement("option"); b.textContent = "Page " + (pageIndex + 1); b.value = pageIndex; - stepperChooser.appendChild(b); + stepperChooser.append(b); const initBreakPoints = breakPoints[pageIndex] || []; const stepper = new Stepper(debug, pageIndex, initBreakPoints); steppers.push(stepper); @@ -289,15 +282,17 @@ const Stepper = (function StepperClosure() { const panel = this.panel; const content = c("div", "c=continue, s=step"); const table = c("table"); - content.appendChild(table); + content.append(table); table.cellSpacing = 0; const headerRow = c("tr"); - table.appendChild(headerRow); - headerRow.appendChild(c("th", "Break")); - headerRow.appendChild(c("th", "Idx")); - headerRow.appendChild(c("th", "fn")); - headerRow.appendChild(c("th", "args")); - panel.appendChild(content); + table.append(headerRow); + headerRow.append( + c("th", "Break"), + c("th", "Idx"), + c("th", "fn"), + c("th", "args") + ); + panel.append(content); this.table = table; this.updateOperatorList(operatorList); } @@ -329,7 +324,7 @@ const Stepper = (function StepperClosure() { const line = c("tr"); line.className = "line"; line.dataset.idx = i; - chunk.appendChild(line); + chunk.append(line); const checked = this.breakPoints.includes(i); const args = operatorList.argsArray[i] || []; @@ -341,9 +336,8 @@ const Stepper = (function StepperClosure() { cbox.dataset.idx = i; cbox.onclick = cboxOnClick; - breakCell.appendChild(cbox); - line.appendChild(breakCell); - line.appendChild(c("td", i.toString())); + breakCell.append(cbox); + line.append(breakCell, c("td", i.toString())); const fn = opMap[operatorList.fnArray[i]]; let decArgs = args; if (fn === "showText") { @@ -353,46 +347,44 @@ const Stepper = (function StepperClosure() { const unicodeRow = c("tr"); for (const glyph of glyphs) { if (typeof glyph === "object" && glyph !== null) { - charCodeRow.appendChild(c("td", glyph.originalCharCode)); - fontCharRow.appendChild(c("td", glyph.fontChar)); - unicodeRow.appendChild(c("td", glyph.unicode)); + charCodeRow.append(c("td", glyph.originalCharCode)); + fontCharRow.append(c("td", glyph.fontChar)); + unicodeRow.append(c("td", glyph.unicode)); } else { // null or number const advanceEl = c("td", glyph); advanceEl.classList.add("advance"); - charCodeRow.appendChild(advanceEl); - fontCharRow.appendChild(c("td")); - unicodeRow.appendChild(c("td")); + charCodeRow.append(advanceEl); + fontCharRow.append(c("td")); + unicodeRow.append(c("td")); } } decArgs = c("td"); const table = c("table"); table.classList.add("showText"); - decArgs.appendChild(table); - table.appendChild(charCodeRow); - table.appendChild(fontCharRow); - table.appendChild(unicodeRow); + decArgs.append(table); + table.append(charCodeRow, fontCharRow, unicodeRow); } else if (fn === "restore") { this.indentLevel--; } - line.appendChild(c("td", " ".repeat(this.indentLevel * 2) + fn)); + line.append(c("td", " ".repeat(this.indentLevel * 2) + fn)); if (fn === "save") { this.indentLevel++; } if (decArgs instanceof HTMLElement) { - line.appendChild(decArgs); + line.append(decArgs); } else { - line.appendChild(c("td", JSON.stringify(simplifyArgs(decArgs)))); + line.append(c("td", JSON.stringify(simplifyArgs(decArgs)))); } } if (operatorsToDisplay < operatorList.fnArray.length) { const lastCell = c("td", "..."); lastCell.colspan = 4; - chunk.appendChild(lastCell); + chunk.append(lastCell); } this.operatorListIdx = operatorList.fnArray.length; - this.table.appendChild(chunk); + this.table.append(chunk); } getNextBreakPoint() { @@ -485,15 +477,14 @@ const Stats = (function Stats() { title.textContent = "Page: " + pageNumber; const statsDiv = document.createElement("div"); statsDiv.textContent = stat.toString(); - wrapper.appendChild(title); - wrapper.appendChild(statsDiv); + wrapper.append(title, statsDiv); stats.push({ pageNumber, div: wrapper }); stats.sort(function (a, b) { return a.pageNumber - b.pageNumber; }); clear(this.panel); for (const entry of stats) { - this.panel.appendChild(entry.div); + this.panel.append(entry.div); } }, cleanup() { @@ -547,13 +538,13 @@ const PDFBug = (function PDFBugClosure() { const controls = document.createElement("div"); controls.setAttribute("class", "controls"); - ui.appendChild(controls); + ui.append(controls); const panels = document.createElement("div"); panels.setAttribute("class", "panels"); - ui.appendChild(panels); + ui.append(panels); - container.appendChild(ui); + container.append(ui); container.style.right = panelWidth + "px"; // Initialize all the debugging tools. @@ -565,8 +556,8 @@ const PDFBug = (function PDFBugClosure() { event.preventDefault(); this.selectPanel(tool); }); - controls.appendChild(panelButton); - panels.appendChild(panel); + controls.append(panelButton); + panels.append(panel); tool.panel = panel; tool.manager = this; if (tool.enabled) { @@ -587,7 +578,7 @@ const PDFBug = (function PDFBugClosure() { link.rel = "stylesheet"; link.href = url.replace(/.js$/, ".css"); - document.head.appendChild(link); + document.head.append(link); }, cleanup() { for (const tool of this.tools) { diff --git a/web/download_manager.js b/web/download_manager.js index 91b24ee61..3ac266d66 100644 --- a/web/download_manager.js +++ b/web/download_manager.js @@ -38,7 +38,7 @@ function download(blobUrl, filename) { } // must be in the document for recent Firefox versions, // otherwise .click() is ignored. - (document.body || document.documentElement).appendChild(a); + (document.body || document.documentElement).append(a); a.click(); a.remove(); } diff --git a/web/firefox_print_service.js b/web/firefox_print_service.js index 1bde7c4ed..772e5b34f 100644 --- a/web/firefox_print_service.js +++ b/web/firefox_print_service.js @@ -40,8 +40,8 @@ function composePage( const canvasWrapper = document.createElement("div"); canvasWrapper.className = "printedPage"; - canvasWrapper.appendChild(canvas); - printContainer.appendChild(canvasWrapper); + canvasWrapper.append(canvas); + printContainer.append(canvasWrapper); // A callback for a given page may be executed multiple times for different // print operations (think of changing the print settings in the browser). diff --git a/web/firefoxcom.js b/web/firefoxcom.js index ecbb10eeb..5819efcb8 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -38,7 +38,7 @@ class FirefoxCom { */ static requestSync(action, data) { const request = document.createTextNode(""); - document.documentElement.appendChild(request); + document.documentElement.append(request); const sender = document.createEvent("CustomEvent"); sender.initCustomEvent("pdf.js.message", true, false, { @@ -86,7 +86,7 @@ class FirefoxCom { { once: true } ); } - document.documentElement.appendChild(request); + document.documentElement.append(request); const sender = document.createEvent("CustomEvent"); sender.initCustomEvent("pdf.js.message", true, false, { diff --git a/web/grab_to_pan.js b/web/grab_to_pan.js index c4b509487..760e75e7c 100644 --- a/web/grab_to_pan.js +++ b/web/grab_to_pan.js @@ -153,7 +153,7 @@ class GrabToPan { this.element.scrollLeft = scrollLeft; } if (!this.overlay.parentNode) { - document.body.appendChild(this.overlay); + document.body.append(this.overlay); } } diff --git a/web/pdf_attachment_viewer.js b/web/pdf_attachment_viewer.js index bc5ecacb5..2bf4bb88a 100644 --- a/web/pdf_attachment_viewer.js +++ b/web/pdf_attachment_viewer.js @@ -127,9 +127,9 @@ class PDFAttachmentViewer extends BaseTreeViewer { this._bindLink(element, { content, filename }); element.textContent = this._normalizeTextContent(filename); - div.appendChild(element); + div.append(element); - fragment.appendChild(div); + fragment.append(div); attachmentsCount++; } diff --git a/web/pdf_layer_viewer.js b/web/pdf_layer_viewer.js index 2c90988bc..3851008b5 100644 --- a/web/pdf_layer_viewer.js +++ b/web/pdf_layer_viewer.js @@ -135,7 +135,7 @@ class PDFLayerViewer extends BaseTreeViewer { div.className = "treeItem"; const element = document.createElement("a"); - div.appendChild(element); + div.append(element); if (typeof groupId === "object") { hasAnyNesting = true; @@ -144,7 +144,7 @@ class PDFLayerViewer extends BaseTreeViewer { const itemsDiv = document.createElement("div"); itemsDiv.className = "treeItems"; - div.appendChild(itemsDiv); + div.append(itemsDiv); queue.push({ parent: itemsDiv, groups: groupId.order }); } else { @@ -160,13 +160,11 @@ class PDFLayerViewer extends BaseTreeViewer { label.setAttribute("for", groupId); label.textContent = this._normalizeTextContent(group.name); - element.appendChild(input); - element.appendChild(label); - + element.append(input, label); layersCount++; } - levelData.parent.appendChild(div); + levelData.parent.append(div); } } diff --git a/web/pdf_outline_viewer.js b/web/pdf_outline_viewer.js index fd03829f7..de02e3a97 100644 --- a/web/pdf_outline_viewer.js +++ b/web/pdf_outline_viewer.js @@ -204,7 +204,7 @@ class PDFOutlineViewer extends BaseTreeViewer { this._setStyles(element, item); element.textContent = this._normalizeTextContent(item.title); - div.appendChild(element); + div.append(element); if (item.items.length > 0) { hasAnyNesting = true; @@ -212,12 +212,12 @@ class PDFOutlineViewer extends BaseTreeViewer { const itemsDiv = document.createElement("div"); itemsDiv.className = "treeItems"; - div.appendChild(itemsDiv); + div.append(itemsDiv); queue.push({ parent: itemsDiv, items: item.items }); } - levelData.parent.appendChild(div); + levelData.parent.append(div); outlineCount++; } } diff --git a/web/pdf_page_view.js b/web/pdf_page_view.js index d40779f5a..acfdcf557 100644 --- a/web/pdf_page_view.js +++ b/web/pdf_page_view.js @@ -169,7 +169,7 @@ class PDFPageView { }); this.div = div; - container?.appendChild(div); + container?.append(div); } setPdfPage(pdfPage) { @@ -358,7 +358,7 @@ class PDFPageView { this.l10n.get("loading").then(msg => { this.loadingIconDiv?.setAttribute("aria-label", msg); }); - div.appendChild(this.loadingIconDiv); + div.append(this.loadingIconDiv); } update({ scale = 0, rotation = null, optionalContentConfigPromise = null }) { @@ -629,7 +629,7 @@ class PDFPageView { // The annotation layer needs to stay on top. div.insertBefore(canvasWrapper, lastDivBeforeTextDiv); } else { - div.appendChild(canvasWrapper); + div.append(canvasWrapper); } let textLayer = null; @@ -642,7 +642,7 @@ class PDFPageView { // The annotation layer needs to stay on top. div.insertBefore(textLayerDiv, lastDivBeforeTextDiv); } else { - div.appendChild(textLayerDiv); + div.append(textLayerDiv); } textLayer = this.textLayerFactory.createTextLayerBuilder( @@ -679,7 +679,7 @@ class PDFPageView { if (this.xfaLayer?.div) { // The xfa layer needs to stay on top. - div.appendChild(this.xfaLayer.div); + div.append(this.xfaLayer.div); } let renderContinueCallback = null; @@ -806,7 +806,7 @@ class PDFPageView { } const treeDom = this.structTreeLayer.render(tree); treeDom.classList.add("structTree"); - this.canvas.appendChild(treeDom); + this.canvas.append(treeDom); }); }; this.eventBus._on("textlayerrendered", this._onTextLayerRendered); @@ -850,7 +850,7 @@ class PDFPageView { } }; - canvasWrapper.appendChild(canvas); + canvasWrapper.append(canvas); this.canvas = canvas; const ctx = canvas.getContext("2d", { alpha: false }); @@ -967,7 +967,7 @@ class PDFPageView { svg.style.width = wrapper.style.width; svg.style.height = wrapper.style.height; this.renderingState = RenderingStates.FINISHED; - wrapper.appendChild(svg); + wrapper.append(svg); }); }); diff --git a/web/pdf_print_service.js b/web/pdf_print_service.js index f58cabd38..b5730d78d 100644 --- a/web/pdf_print_service.js +++ b/web/pdf_print_service.js @@ -110,7 +110,7 @@ PDFPrintService.prototype = { const pageSize = this.pagesOverview[0]; this.pageStyleSheet.textContent = "@page { size: " + pageSize.width + "pt " + pageSize.height + "pt;}"; - body.appendChild(this.pageStyleSheet); + body.append(this.pageStyleSheet); }, destroy() { @@ -184,8 +184,8 @@ PDFPrintService.prototype = { const wrapper = document.createElement("div"); wrapper.className = "printedPage"; - wrapper.appendChild(img); - this.printContainer.appendChild(wrapper); + wrapper.append(img); + this.printContainer.append(wrapper); return new Promise(function (resolve, reject) { img.onload = resolve; diff --git a/web/pdf_thumbnail_view.js b/web/pdf_thumbnail_view.js index fcd7889f1..e45c61f7d 100644 --- a/web/pdf_thumbnail_view.js +++ b/web/pdf_thumbnail_view.js @@ -148,9 +148,9 @@ class PDFThumbnailView { ring.style.height = this.canvasHeight + borderAdjustment + "px"; this.ring = ring; - div.appendChild(ring); - anchor.appendChild(div); - container.appendChild(anchor); + div.append(ring); + anchor.append(div); + container.append(anchor); } setPdfPage(pdfPage) { @@ -257,7 +257,7 @@ class PDFThumbnailView { this.image = image; this.div.setAttribute("data-loaded", true); - this.ring.appendChild(image); + this.ring.append(image); // Zeroing the width and height causes Firefox to release graphics // resources immediately, which can greatly reduce memory consumption. diff --git a/web/print_utils.js b/web/print_utils.js index 19488aa28..349ee1370 100644 --- a/web/print_utils.js +++ b/web/print_utils.js @@ -25,7 +25,7 @@ function getXfaHtmlForPrinting(printContainer, pdfDocument) { for (const xfaPage of xfaHtml.children) { const page = document.createElement("div"); page.className = "xfaPrintedPage"; - printContainer.appendChild(page); + printContainer.append(page); const builder = new XfaLayerBuilder({ pageDiv: page, diff --git a/web/struct_tree_layer_builder.js b/web/struct_tree_layer_builder.js index a0b276417..41306d1c7 100644 --- a/web/struct_tree_layer_builder.js +++ b/web/struct_tree_layer_builder.js @@ -128,7 +128,7 @@ class StructTreeLayerBuilder { this._setAttributes(node.children[0], element); } else { for (const kid of node.children) { - element.appendChild(this._walk(kid)); + element.append(this._walk(kid)); } } } diff --git a/web/text_highlighter.js b/web/text_highlighter.js index 27e84f01b..fbd238b3d 100644 --- a/web/text_highlighter.js +++ b/web/text_highlighter.js @@ -177,7 +177,7 @@ class TextHighlighter { if (div.nodeType === Node.TEXT_NODE) { const span = document.createElement("span"); div.parentNode.insertBefore(span, div); - span.appendChild(div); + span.append(div); textDivs[divIdx] = span; div = span; } @@ -189,11 +189,11 @@ class TextHighlighter { if (className) { const span = document.createElement("span"); span.className = `${className} appended`; - span.appendChild(node); - div.appendChild(span); + span.append(node); + div.append(span); return className.includes("selected") ? span.offsetLeft : 0; } - div.appendChild(node); + div.append(node); return 0; } diff --git a/web/text_layer_builder.js b/web/text_layer_builder.js index 8767ba360..69982b7a9 100644 --- a/web/text_layer_builder.js +++ b/web/text_layer_builder.js @@ -73,7 +73,7 @@ class TextLayerBuilder { if (!this.enhanceTextSelection) { const endOfContent = document.createElement("div"); endOfContent.className = "endOfContent"; - this.textLayerDiv.appendChild(endOfContent); + this.textLayerDiv.append(endOfContent); } this.eventBus.dispatch("textlayerrendered", { @@ -111,7 +111,7 @@ class TextLayerBuilder { }); this.textLayerRenderTask.promise.then( () => { - this.textLayerDiv.appendChild(textLayerFrag); + this.textLayerDiv.append(textLayerFrag); this._finishRendering(); this.highlighter?.enable(); }, diff --git a/web/viewer.js b/web/viewer.js index 0d33dd160..8acc7c8d4 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -212,7 +212,7 @@ function webViewerLoad() { link.rel = "stylesheet"; link.href = "../build/dev-css/viewer.css"; - document.head.appendChild(link); + document.head.append(link); } Promise.all([ diff --git a/web/xfa_layer_builder.js b/web/xfa_layer_builder.js index b4e933b35..9358417e1 100644 --- a/web/xfa_layer_builder.js +++ b/web/xfa_layer_builder.js @@ -70,7 +70,7 @@ class XfaLayerBuilder { // Create an xfa layer div and render the form const div = document.createElement("div"); - this.pageDiv.appendChild(div); + this.pageDiv.append(div); parameters.div = div; const result = XfaLayer.render(parameters); @@ -99,7 +99,7 @@ class XfaLayerBuilder { } // Create an xfa layer div and render the form this.div = document.createElement("div"); - this.pageDiv.appendChild(this.div); + this.pageDiv.append(this.div); parameters.div = this.div; return XfaLayer.render(parameters); })