fix(js): add insertAdjacentText/insertAdjacentElement polyfills (#285) (#286)

DDoS-Guard's view.js challenge calls Element.prototype.insertAdjacentText
and dies with 'TypeError: t.insertAdjacentText is not a function', blocking
any DDoS-Guard-protected site (e.g. pikabu.ru). insertAdjacentElement was
missing too. insertAdjacentHTML was already implemented, so this just lifts
the same insertion pattern for Text-node and Element insertion semantics.

Both methods mirror the spec: case-insensitive position keywords, four
insertion points (beforebegin/afterbegin/beforeend/afterend), and
insertAdjacentElement returns the inserted element (or null when
beforebegin/afterend has no parent). Registered with _markNative so
Function.prototype.toString keeps reporting [native code] — consistent
with the existing Element.prototype.insertAdjacentHTML stealth registration.
This commit is contained in:
Ben Younes authored and GitHub committed 2026-06-10 19:08:46 +00:00
1 parent 4a00a6ac2c
commit 38fa85946c
2 files changed
+121 -1

No files matched your search

+47 -1
View File
@@ -1111,6 +1111,51 @@ class Element extends Node {
break;
}
}
// Same insertion semantics as insertAdjacentHTML but inserts a Text node
// instead of parsing markup — that distinction is the whole point of the API
// (DDoS-Guard, reCAPTCHA, and others use it precisely because it does NOT
// parse HTML). Position string is case-insensitive per spec. See issue #285.
insertAdjacentText(position, text) {
const parent = this.parentNode;
const node = document.createTextNode(String(text));
switch (String(position).toLowerCase()) {
case 'beforebegin':
if (parent) parent.insertBefore(node, this);
break;
case 'afterbegin':
this.insertBefore(node, this.firstChild);
break;
case 'beforeend':
this.appendChild(node);
break;
case 'afterend':
if (parent) parent.insertBefore(node, this.nextSibling);
break;
}
}
// Per spec, returns the inserted element, or null when position is
// beforebegin/afterend and this element has no parent (so the node could
// not be placed). See issue #285.
insertAdjacentElement(position, element) {
const parent = this.parentNode;
switch (String(position).toLowerCase()) {
case 'beforebegin':
if (!parent) return null;
parent.insertBefore(element, this);
return element;
case 'afterbegin':
this.insertBefore(element, this.firstChild);
return element;
case 'beforeend':
this.appendChild(element);
return element;
case 'afterend':
if (!parent) return null;
parent.insertBefore(element, this.nextSibling);
return element;
}
return null;
}
addEventListener(type, handler, opts) {
const key = this._nid;
if (!_eventRegistry[key]) _eventRegistry[key] = {};
@@ -4823,7 +4868,8 @@ _markNative(globalThis.Selection);
Element.prototype.focus, Element.prototype.blur,
Element.prototype.showPopover, Element.prototype.hidePopover, Element.prototype.togglePopover,
Element.prototype.cloneNode, Element.prototype.attachShadow,
Element.prototype.insertAdjacentHTML, Element.prototype.scrollIntoView,
Element.prototype.insertAdjacentHTML, Element.prototype.insertAdjacentText,
Element.prototype.insertAdjacentElement, Element.prototype.scrollIntoView,
Element.prototype.append, Element.prototype.prepend, Element.prototype.remove,
Element.prototype.before, Element.prototype.after, Element.prototype.replaceWith,
HTMLFormElement.prototype.reset,