Socket
Socket
Sign inDemoInstall

dom-mutator

Package Overview
Dependencies
0
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.4.0 to 0.5.0

94

dist/dom-mutator.cjs.development.js

@@ -66,3 +66,8 @@ 'use strict';

if (val !== currentVal) {
if (val && typeof val !== 'string') {
if (!currentVal || val.parentNode !== currentVal.parentNode || val.insertBeforeNode !== currentVal.insertBeforeNode) {
record.isDirty = true;
queueDOMUpdates();
}
} else if (val !== currentVal) {
record.isDirty = true;

@@ -97,2 +102,27 @@ queueDOMUpdates();

function _loadDOMNodes(_ref) {
var parentSelector = _ref.parentSelector,
insertBeforeSelector = _ref.insertBeforeSelector;
var parentNode = document.querySelector(parentSelector);
if (!parentNode) return null;
var insertBeforeNode = insertBeforeSelector ? document.querySelector(insertBeforeSelector) : null;
if (insertBeforeSelector && !insertBeforeNode) return null;
return {
parentNode: parentNode,
insertBeforeNode: insertBeforeNode
};
}
function positionMutationRunner(record) {
var val = record.originalValue;
record.mutations.forEach(function (m) {
var selectors = m.mutate();
var newNodes = _loadDOMNodes(selectors);
val = newNodes || val;
});
queueIfNeeded(val, record);
}
var getHTMLValue = function getHTMLValue(el) {

@@ -116,2 +146,23 @@ return el.innerHTML;

var getElementPosition = function getElementPosition(el) {
return {
parentNode: el.parentElement,
insertBeforeNode: el.nextElementSibling
};
};
var setElementPosition = function setElementPosition(el, value) {
value.parentNode.insertBefore(el, value.insertBeforeNode);
};
function getElementPositionRecord(element) {
var elementRecord = getElementRecord(element);
if (!elementRecord.position) {
elementRecord.position = createElementPropertyRecord(element, 'position', getElementPosition, setElementPosition, positionMutationRunner);
}
return elementRecord.position;
}
var setClassValue = function setClassValue(el, val) {

@@ -173,2 +224,7 @@ return val ? el.className = val : el.removeAttribute('class');

delete element.classes;
} else if (attr === 'position') {
var _element$position, _element$position$obs;
(_element$position = element.position) == null ? void 0 : (_element$position$obs = _element$position.observer) == null ? void 0 : _element$position$obs.disconnect();
delete element.position;
} else {

@@ -210,2 +266,3 @@ var _element$attributes, _element$attributes$a, _element$attributes$a2;

m.classes && setPropertyValue(el, 'class', m.classes);
m.position && setPropertyValue(el, 'position', m.position);
Object.keys(m.attributes).forEach(function (attr) {

@@ -238,2 +295,4 @@ setPropertyValue(el, attr, m.attributes[attr]);

record = getElementAttributeRecord(element, mutation.attribute);
} else if (mutation.kind === 'position') {
record = getElementPositionRecord(element);
}

@@ -256,2 +315,4 @@

record = getElementAttributeRecord(el, mutation.attribute);
} else if (mutation.kind === 'position') {
record = getElementPositionRecord(el);
}

@@ -346,2 +407,11 @@

function position(selector, mutate) {
return newMutation({
kind: 'position',
elements: new Set(),
mutate: mutate,
selector: selector
});
}
function classes(selector, mutate) {

@@ -379,7 +449,9 @@ return newMutation({

function declarative(_ref) {
var selector = _ref.selector,
action = _ref.action,
value = _ref.value,
attr = _ref.attribute;
function declarative(_ref2) {
var selector = _ref2.selector,
action = _ref2.action,
value = _ref2.value,
attr = _ref2.attribute,
parentSelector = _ref2.parentSelector,
insertBeforeSelector = _ref2.insertBeforeSelector;

@@ -411,2 +483,11 @@ if (attr === 'html') {

}
} else if (attr === 'position') {
if (action === 'set' && parentSelector) {
return position(selector, function () {
return {
insertBeforeSelector: insertBeforeSelector,
parentSelector: parentSelector
};
});
}
} else {

@@ -435,2 +516,3 @@ if (action === 'append') {

attribute: attribute,
position: position,
declarative: declarative

@@ -437,0 +519,0 @@ };

2

dist/dom-mutator.cjs.production.min.js

@@ -1,2 +0,2 @@

"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=/^[a-zA-Z:_][a-zA-Z0-9:_.-]*$/,e={revert:function(){}},n=new Map,r=new Set;function u(t){var e=n.get(t);return e||n.set(t,e={element:t,attributes:{}}),e}function i(t,e,n,r,u){var i=n(t),a={isDirty:!1,originalValue:i,virtualValue:i,mutations:[],el:t,observer:new MutationObserver((function(){var e=n(t);e!==a.virtualValue&&(a.originalValue=e,u(a))})),mutationRunner:u,setValue:r,getCurrentValue:n};return a.observer.observe(t,function(t){return"html"===t?{childList:!0,subtree:!0,attributes:!0,characterData:!0}:{childList:!1,subtree:!1,attributes:!0,attributeFilter:[t]}}(e)),a}function a(t,e){var n=e.getCurrentValue(e.el);e.virtualValue=t,t!==n&&(e.isDirty=!0,E||(E=!0,requestAnimationFrame(A)))}function l(t){var e=t.originalValue;t.mutations.forEach((function(t){return e=t.mutate(e)})),a(function(t){return d||(d=document.createElement("div")),d.innerHTML=t,d.innerHTML}(e),t)}function s(t){var e=new Set(t.originalValue.split(/\s+/).filter(Boolean));t.mutations.forEach((function(t){return t.mutate(e)})),a(Array.from(e).filter(Boolean).join(" "),t)}function o(t){var e=t.originalValue;t.mutations.forEach((function(t){return e=t.mutate(e)})),a(e,t)}var c=function(t){return t.innerHTML},f=function(t,e){return t.innerHTML=e};function m(t){var e=u(t);return e.html||(e.html=i(t,"html",c,f,l)),e.html}var d,v=function(t,e){return e?t.className=e:t.removeAttribute("class")},b=function(t){return t.className};function h(t){var e=u(t);return e.classes||(e.classes=i(t,"class",b,v,s)),e.classes}function p(t,e){var n,r=u(t);return r.attributes[e]||(r.attributes[e]=i(t,e,(n=e,function(t){var e;return null!=(e=t.getAttribute(n))?e:null}),function(t){return function(e,n){return null!==n?e.setAttribute(t,n):e.removeAttribute(t)}}(e),o)),r.attributes[e]}function V(t,e,r){if(r.isDirty){r.isDirty=!1;var u=r.virtualValue;r.mutations.length||function(t,e){var r,u,i=n.get(t);if(i)if("html"===e)null==(r=i.html)||null==(u=r.observer)||u.disconnect(),delete i.html;else if("class"===e){var a,l;null==(a=i.classes)||null==(l=a.observer)||l.disconnect(),delete i.classes}else{var s,o,c;null==(s=i.attributes)||null==(o=s[e])||null==(c=o.observer)||c.disconnect(),delete i.attributes[e]}}(t,e),r.setValue(t,u)}}var g,E=!1;function y(t,e){t.html&&V(e,"html",t.html),t.classes&&V(e,"class",t.classes),Object.keys(t.attributes).forEach((function(n){V(e,n,t.attributes[n])}))}function A(){E=!1,n.forEach(y)}function k(t,e){var n=null;if("html"===t.kind?n=m(e):"class"===t.kind?n=h(e):"attribute"===t.kind&&(n=p(e,t.attribute)),n){var r=n.mutations.indexOf(t);-1!==r&&n.mutations.splice(r,1),n.mutationRunner(n)}}function w(t){var e=new Set(t.elements),n=new Set;document.querySelectorAll(t.selector).forEach((function(r){n.add(r),e.has(r)||(t.elements.add(r),function(t,e){var n=null;"html"===t.kind?n=m(e):"class"===t.kind?n=h(e):"attribute"===t.kind&&(n=p(e,t.attribute)),n&&(n.mutations.push(t),n.mutationRunner(n))}(t,r))})),e.forEach((function(e){n.has(e)||(t.elements.delete(e),k(t,e))}))}function M(){r.forEach(w)}function S(){"undefined"!=typeof document&&(g||(g=new MutationObserver((function(){M()}))),M(),g.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!1,characterData:!1}))}function L(t){return"undefined"==typeof document?e:(r.add(t),w(t),{revert:function(){var e;(e=t).elements.forEach((function(t){return k(e,t)})),e.elements.clear(),r.delete(e)}})}function O(t,e){return L({kind:"html",elements:new Set,mutate:e,selector:t})}function x(t,e){return L({kind:"class",elements:new Set,mutate:e,selector:t})}function D(n,r,u){return t.test(r)?"class"===r||"className"===r?x(n,(function(t){var e=u(Array.from(t).join(" "));t.clear(),e&&e.split(/\s+/g).filter(Boolean).forEach((function(e){return t.add(e)}))})):L({kind:"attribute",attribute:r,elements:new Set,mutate:u,selector:n}):e}S();var j={html:O,classes:x,attribute:D,declarative:function(t){var n=t.selector,r=t.action,u=t.value,i=t.attribute;if("html"===i){if("append"===r)return O(n,(function(t){return t+(null!=u?u:"")}));if("set"===r)return O(n,(function(){return null!=u?u:""}))}else if("class"===i){if("append"===r)return x(n,(function(t){u&&t.add(u)}));if("remove"===r)return x(n,(function(t){u&&t.delete(u)}));if("set"===r)return x(n,(function(t){t.clear(),u&&t.add(u)}))}else{if("append"===r)return D(n,i,(function(t){return null!==t?t+(null!=u?u:""):null!=u?u:""}));if("set"===r)return D(n,i,(function(){return null!=u?u:""}));if("remove"===r)return D(n,i,(function(){return null}))}return e}};exports.connectGlobalObserver=S,exports.default=j,exports.disconnectGlobalObserver=function(){g&&g.disconnect()},exports.validAttributeName=t;
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=/^[a-zA-Z:_][a-zA-Z0-9:_.-]*$/,t={revert:function(){}},n=new Map,r=new Set;function i(e){var t=n.get(e);return t||n.set(e,t={element:e,attributes:{}}),t}function u(e,t,n,r,i){var u=n(e),o={isDirty:!1,originalValue:u,virtualValue:u,mutations:[],el:e,observer:new MutationObserver((function(){var t=n(e);t!==o.virtualValue&&(o.originalValue=t,i(o))})),mutationRunner:i,setValue:r,getCurrentValue:n};return o.observer.observe(e,function(e){return"html"===e?{childList:!0,subtree:!0,attributes:!0,characterData:!0}:{childList:!1,subtree:!1,attributes:!0,attributeFilter:[e]}}(t)),o}function o(e,t){var n=t.getCurrentValue(t.el);t.virtualValue=e,e&&"string"!=typeof e?n&&e.parentNode===n.parentNode&&e.insertBeforeNode===n.insertBeforeNode||(t.isDirty=!0,A()):e!==n&&(t.isDirty=!0,A())}function a(e){var t=e.originalValue;e.mutations.forEach((function(e){return t=e.mutate(t)})),o(function(e){return h||(h=document.createElement("div")),h.innerHTML=e,h.innerHTML}(t),e)}function l(e){var t=new Set(e.originalValue.split(/\s+/).filter(Boolean));e.mutations.forEach((function(e){return e.mutate(t)})),o(Array.from(t).filter(Boolean).join(" "),e)}function s(e){var t=e.originalValue;e.mutations.forEach((function(e){return t=e.mutate(t)})),o(t,e)}function c(e){var t=e.originalValue;e.mutations.forEach((function(e){var n=function(e){var t=e.insertBeforeSelector,n=document.querySelector(e.parentSelector);if(!n)return null;var r=t?document.querySelector(t):null;return t&&!r?null:{parentNode:n,insertBeforeNode:r}}(e.mutate());t=n||t})),o(t,e)}var f=function(e){return e.innerHTML},d=function(e,t){return e.innerHTML=t};function m(e){var t=i(e);return t.html||(t.html=u(e,"html",f,d,a)),t.html}var v=function(e){return{parentNode:e.parentElement,insertBeforeNode:e.nextElementSibling}},b=function(e,t){t.parentNode.insertBefore(e,t.insertBeforeNode)};function p(e){var t=i(e);return t.position||(t.position=u(e,"position",v,b,c)),t.position}var h,S=function(e,t){return t?e.className=t:e.removeAttribute("class")},g=function(e){return e.className};function y(e){var t=i(e);return t.classes||(t.classes=u(e,"class",g,S,l)),t.classes}function E(e,t){var n,r=i(e);return r.attributes[t]||(r.attributes[t]=u(e,t,(n=t,function(e){var t;return null!=(t=e.getAttribute(n))?t:null}),function(e){return function(t,n){return null!==n?t.setAttribute(e,n):t.removeAttribute(e)}}(t),s)),r.attributes[t]}function N(e,t,r){if(r.isDirty){r.isDirty=!1;var i=r.virtualValue;r.mutations.length||function(e,t){var r,i,u=n.get(e);if(u)if("html"===t)null==(r=u.html)||null==(i=r.observer)||i.disconnect(),delete u.html;else if("class"===t){var o,a;null==(o=u.classes)||null==(a=o.observer)||a.disconnect(),delete u.classes}else if("position"===t){var l,s;null==(l=u.position)||null==(s=l.observer)||s.disconnect(),delete u.position}else{var c,f,d;null==(c=u.attributes)||null==(f=c[t])||null==(d=f.observer)||d.disconnect(),delete u.attributes[t]}}(e,t),r.setValue(e,i)}}var V,k=!1;function B(e,t){e.html&&N(t,"html",e.html),e.classes&&N(t,"class",e.classes),e.position&&N(t,"position",e.position),Object.keys(e.attributes).forEach((function(n){N(t,n,e.attributes[n])}))}function w(){k=!1,n.forEach(B)}function A(){k||(k=!0,requestAnimationFrame(w))}function M(e,t){var n=null;if("html"===e.kind?n=m(t):"class"===e.kind?n=y(t):"attribute"===e.kind?n=E(t,e.attribute):"position"===e.kind&&(n=p(t)),n){var r=n.mutations.indexOf(e);-1!==r&&n.mutations.splice(r,1),n.mutationRunner(n)}}function x(e){var t=new Set(e.elements),n=new Set;document.querySelectorAll(e.selector).forEach((function(r){n.add(r),t.has(r)||(e.elements.add(r),function(e,t){var n=null;"html"===e.kind?n=m(t):"class"===e.kind?n=y(t):"attribute"===e.kind?n=E(t,e.attribute):"position"===e.kind&&(n=p(t)),n&&(n.mutations.push(e),n.mutationRunner(n))}(e,r))})),t.forEach((function(t){n.has(t)||(e.elements.delete(t),M(e,t))}))}function D(){r.forEach(x)}function L(){"undefined"!=typeof document&&(V||(V=new MutationObserver((function(){D()}))),D(),V.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!1,characterData:!1}))}function O(e){return"undefined"==typeof document?t:(r.add(e),x(e),{revert:function(){var t;(t=e).elements.forEach((function(e){return M(t,e)})),t.elements.clear(),r.delete(t)}})}function j(e,t){return O({kind:"html",elements:new Set,mutate:t,selector:e})}function q(e,t){return O({kind:"position",elements:new Set,mutate:t,selector:e})}function H(e,t){return O({kind:"class",elements:new Set,mutate:t,selector:e})}function T(n,r,i){return e.test(r)?"class"===r||"className"===r?H(n,(function(e){var t=i(Array.from(e).join(" "));e.clear(),t&&t.split(/\s+/g).filter(Boolean).forEach((function(t){return e.add(t)}))})):O({kind:"attribute",attribute:r,elements:new Set,mutate:i,selector:n}):t}L();var _={html:j,classes:H,attribute:T,position:q,declarative:function(e){var n=e.selector,r=e.action,i=e.value,u=e.attribute,o=e.parentSelector,a=e.insertBeforeSelector;if("html"===u){if("append"===r)return j(n,(function(e){return e+(null!=i?i:"")}));if("set"===r)return j(n,(function(){return null!=i?i:""}))}else if("class"===u){if("append"===r)return H(n,(function(e){i&&e.add(i)}));if("remove"===r)return H(n,(function(e){i&&e.delete(i)}));if("set"===r)return H(n,(function(e){e.clear(),i&&e.add(i)}))}else if("position"===u){if("set"===r&&o)return q(n,(function(){return{insertBeforeSelector:a,parentSelector:o}}))}else{if("append"===r)return T(n,u,(function(e){return null!==e?e+(null!=i?i:""):null!=i?i:""}));if("set"===r)return T(n,u,(function(){return null!=i?i:""}));if("remove"===r)return T(n,u,(function(){return null}))}return t}};exports.connectGlobalObserver=L,exports.default=_,exports.disconnectGlobalObserver=function(){V&&V.disconnect()},exports.validAttributeName=e;
//# sourceMappingURL=dom-mutator.cjs.production.min.js.map

@@ -62,3 +62,8 @@ var validAttributeName = /^[a-zA-Z:_][a-zA-Z0-9:_.-]*$/;

if (val !== currentVal) {
if (val && typeof val !== 'string') {
if (!currentVal || val.parentNode !== currentVal.parentNode || val.insertBeforeNode !== currentVal.insertBeforeNode) {
record.isDirty = true;
queueDOMUpdates();
}
} else if (val !== currentVal) {
record.isDirty = true;

@@ -93,2 +98,27 @@ queueDOMUpdates();

function _loadDOMNodes(_ref) {
var parentSelector = _ref.parentSelector,
insertBeforeSelector = _ref.insertBeforeSelector;
var parentNode = document.querySelector(parentSelector);
if (!parentNode) return null;
var insertBeforeNode = insertBeforeSelector ? document.querySelector(insertBeforeSelector) : null;
if (insertBeforeSelector && !insertBeforeNode) return null;
return {
parentNode: parentNode,
insertBeforeNode: insertBeforeNode
};
}
function positionMutationRunner(record) {
var val = record.originalValue;
record.mutations.forEach(function (m) {
var selectors = m.mutate();
var newNodes = _loadDOMNodes(selectors);
val = newNodes || val;
});
queueIfNeeded(val, record);
}
var getHTMLValue = function getHTMLValue(el) {

@@ -112,2 +142,23 @@ return el.innerHTML;

var getElementPosition = function getElementPosition(el) {
return {
parentNode: el.parentElement,
insertBeforeNode: el.nextElementSibling
};
};
var setElementPosition = function setElementPosition(el, value) {
value.parentNode.insertBefore(el, value.insertBeforeNode);
};
function getElementPositionRecord(element) {
var elementRecord = getElementRecord(element);
if (!elementRecord.position) {
elementRecord.position = createElementPropertyRecord(element, 'position', getElementPosition, setElementPosition, positionMutationRunner);
}
return elementRecord.position;
}
var setClassValue = function setClassValue(el, val) {

@@ -169,2 +220,7 @@ return val ? el.className = val : el.removeAttribute('class');

delete element.classes;
} else if (attr === 'position') {
var _element$position, _element$position$obs;
(_element$position = element.position) == null ? void 0 : (_element$position$obs = _element$position.observer) == null ? void 0 : _element$position$obs.disconnect();
delete element.position;
} else {

@@ -206,2 +262,3 @@ var _element$attributes, _element$attributes$a, _element$attributes$a2;

m.classes && setPropertyValue(el, 'class', m.classes);
m.position && setPropertyValue(el, 'position', m.position);
Object.keys(m.attributes).forEach(function (attr) {

@@ -234,2 +291,4 @@ setPropertyValue(el, attr, m.attributes[attr]);

record = getElementAttributeRecord(element, mutation.attribute);
} else if (mutation.kind === 'position') {
record = getElementPositionRecord(element);
}

@@ -252,2 +311,4 @@

record = getElementAttributeRecord(el, mutation.attribute);
} else if (mutation.kind === 'position') {
record = getElementPositionRecord(el);
}

@@ -342,2 +403,11 @@

function position(selector, mutate) {
return newMutation({
kind: 'position',
elements: new Set(),
mutate: mutate,
selector: selector
});
}
function classes(selector, mutate) {

@@ -375,7 +445,9 @@ return newMutation({

function declarative(_ref) {
var selector = _ref.selector,
action = _ref.action,
value = _ref.value,
attr = _ref.attribute;
function declarative(_ref2) {
var selector = _ref2.selector,
action = _ref2.action,
value = _ref2.value,
attr = _ref2.attribute,
parentSelector = _ref2.parentSelector,
insertBeforeSelector = _ref2.insertBeforeSelector;

@@ -407,2 +479,11 @@ if (attr === 'html') {

}
} else if (attr === 'position') {
if (action === 'set' && parentSelector) {
return position(selector, function () {
return {
insertBeforeSelector: insertBeforeSelector,
parentSelector: parentSelector
};
});
}
} else {

@@ -431,2 +512,3 @@ if (action === 'append') {

attribute: attribute,
position: position,
declarative: declarative

@@ -433,0 +515,0 @@ };

@@ -5,5 +5,6 @@ export declare const validAttributeName: RegExp;

declare function html(selector: HTMLMutation['selector'], mutate: HTMLMutation['mutate']): MutationController;
declare function position(selector: PositionMutation['selector'], mutate: PositionMutation['mutate']): MutationController;
declare function classes(selector: ClassnameMutation['selector'], mutate: ClassnameMutation['mutate']): MutationController;
declare function attribute(selector: AttrMutation['selector'], attribute: AttrMutation['attribute'], mutate: AttrMutation['mutate']): MutationController;
declare function declarative({ selector, action, value, attribute: attr, }: DeclarativeMutation): MutationController;
declare function declarative({ selector, action, value, attribute: attr, parentSelector, insertBeforeSelector, }: DeclarativeMutation): MutationController;
export declare type MutationController = {

@@ -17,2 +18,4 @@ revert: () => void;

value?: string;
parentSelector?: string;
insertBeforeSelector?: string;
};

@@ -23,4 +26,5 @@ declare const _default: {

attribute: typeof attribute;
position: typeof position;
declarative: typeof declarative;
};
export default _default;

@@ -18,3 +18,16 @@ interface BaseMutation {

}
declare type Mutation = HTMLMutation | ClassnameMutation | AttrMutation;
interface PositionMutation extends BaseMutation {
kind: 'position';
mutate: () => ElementPosition;
}
interface ElementPosition {
parentSelector: string;
insertBeforeSelector?: null | string;
}
interface ElementPositionWithDomNode {
parentNode: HTMLElement;
insertBeforeNode: HTMLElement | null;
}
declare type Mutation = HTMLMutation | ClassnameMutation | AttrMutation | PositionMutation;
declare type MutationKind = Mutation['kind'];
interface ElementPropertyRecord<T, V> {

@@ -34,2 +47,3 @@ observer: MutationObserver;

declare type AttributeRecord = ElementPropertyRecord<AttrMutation, string | null>;
declare type PositionRecord = ElementPropertyRecord<PositionMutation, ElementPositionWithDomNode>;
interface ElementRecord {

@@ -42,2 +56,3 @@ element: Element;

};
position?: PositionRecord;
}
{
"version": "0.4.0",
"version": "0.5.0",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
"dist",
"src"
],
"files": ["dist", "src"],
"engines": {

@@ -11,0 +8,0 @@ "node": ">=10"

@@ -8,3 +8,3 @@ # DOM Mutator

```ts
const mutation = mutate.html("#greeting", html => html + ' world');
const mutation = mutate.html('#greeting', (html) => html + ' world');

@@ -28,9 +28,13 @@ // works even if the selector doesn't exist yet

```ts
import mutate from "dom-mutator";
import mutate from 'dom-mutator';
mutate.html("h1", html => html.toUpperCase());
mutate.html('h1', (html) => html.toUpperCase());
mutate.classes("div.greeting", classes => classes.add("new-class"));
mutate.classes('div.greeting', (classes) => classes.add('new-class'));
mutate.attribute(".get-started", "title", (oldVal) => "This is my new title attribute");
mutate.attribute(
'.get-started',
'title',
(oldVal) => 'This is my new title attribute'
);
```

@@ -40,7 +44,7 @@

* No dependencies, written in Typescript, 100% test coverage
* Super fast and light-weight (1Kb gzipped)
* Persists mutations even if the underlying element is updated externally (e.g. by a React render)
* Picks up new matching elements that are added to the DOM
* Easily remove a mutation at any time
- No dependencies, written in Typescript, 100% test coverage
- Super fast and light-weight (1Kb gzipped)
- Persists mutations even if the underlying element is updated externally (e.g. by a React render)
- Picks up new matching elements that are added to the DOM
- Easily remove a mutation at any time

@@ -64,4 +68,4 @@ ![Build Status](https://github.com/growthbook/dom-mutator/workflows/CI/badge.svg)

<script type="module">
import mutate from "https://unpkg.com/dom-mutator/dist/dom-mutator.esm.js";
...
import mutate from "https://unpkg.com/dom-mutator/dist/dom-mutator.esm.js";
...
</script>

@@ -113,2 +117,14 @@ ```

### position
Mutate the position of an HTML element by supplying a target parent element to append it to (and optional sibling element to place it next to).
```ts
// Signature
mutate.position(selector: string, () => ({ parentSelector: string; insertBeforeSelector?: string; }));
// Example
mutate.attribute(".link", () => ({ parentSelector: '.parent', insertBeforeSelector: 'p.body' }));
```
### declarative

@@ -122,6 +138,6 @@

mutate.declarative({
selector: string,
action: "set" | "append" | "remove",
attribute: "html" | "class" | string,
value: string
selector: string,
action: 'set' | 'append' | 'remove',
attribute: 'html' | 'class' | string,
value: string,
});

@@ -131,22 +147,29 @@

const mutations = [
{
selector: "h1",
action: "set",
attribute: "html",
value: "new text"
},
{
selector: ".get-started",
action: "remove",
attribute: "class",
value: "green"
},
{
selector: "a",
action: "append",
attribute: "href",
value: "?foo"
}
{
selector: 'h1',
action: 'set',
attribute: 'html',
value: 'new text',
},
{
selector: '.get-started',
action: 'remove',
attribute: 'class',
value: 'green',
},
{
selector: 'a',
action: 'append',
attribute: 'href',
value: '?foo',
},
{
selector: 'a',
action: 'set',
attribute: 'position',
parentSelector: '.header',
insertBeforeSelector: '.menu-button',
},
];
mutations.forEach(m=>mutate.declarative(m));
mutations.forEach((m) => mutate.declarative(m));
```

@@ -158,3 +181,3 @@

When a matching element is found, we attach a separate MutationObserver filtered to the exact attribute being mutated. If an external change happens (e.g. from a React render), we re-apply your mutation on top of the new baseline value.
When a matching element is found, we attach a separate MutationObserver filtered to the exact attribute being mutated. If an external change happens (e.g. from a React render), we re-apply your mutation on top of the new baseline value.

@@ -172,3 +195,3 @@ When `revert` is called, we undo the change and go back to the last externally set value. We also disconnect the element's MutationObserver to save resources.

```ts
import {disconnectGlobalObserver, connectGlobalObserver} from "dom-mutator";
import { disconnectGlobalObserver, connectGlobalObserver } from 'dom-mutator';

@@ -175,0 +198,0 @@ // Pause

@@ -65,3 +65,3 @@ export const validAttributeName = /^[a-zA-Z:_][a-zA-Z0-9:_.-]*$/;

function queueIfNeeded(
val: string | null,
val: string | null | ElementPositionWithDomNode,
record: ElementPropertyRecord<any, any>

@@ -71,3 +71,12 @@ ) {

record.virtualValue = val;
if (val !== currentVal) {
if (val && typeof val !== 'string') {
if (
!currentVal ||
val.parentNode !== currentVal.parentNode ||
val.insertBeforeNode !== currentVal.insertBeforeNode
) {
record.isDirty = true;
queueDOMUpdates();
}
} else if (val !== currentVal) {
record.isDirty = true;

@@ -93,2 +102,3 @@ queueDOMUpdates();

}
function attrMutationRunner(record: AttributeRecord) {

@@ -100,2 +110,28 @@ let val: string | null = record.originalValue;

function _loadDOMNodes({
parentSelector,
insertBeforeSelector,
}: ElementPosition): ElementPositionWithDomNode | null {
const parentNode = document.querySelector<HTMLElement>(parentSelector);
if (!parentNode) return null;
const insertBeforeNode = insertBeforeSelector
? document.querySelector<HTMLElement>(insertBeforeSelector)
: null;
if (insertBeforeSelector && !insertBeforeNode) return null;
return {
parentNode,
insertBeforeNode,
};
}
function positionMutationRunner(record: PositionRecord) {
let val = record.originalValue;
record.mutations.forEach(m => {
const selectors = m.mutate();
const newNodes = _loadDOMNodes(selectors);
val = newNodes || val;
});
queueIfNeeded(val, record);
}
const getHTMLValue = (el: Element) => el.innerHTML;

@@ -117,2 +153,25 @@ const setHTMLValue = (el: Element, value: string) => (el.innerHTML = value);

const getElementPosition = (el: Element): ElementPositionWithDomNode => {
return {
parentNode: el.parentElement as HTMLElement,
insertBeforeNode: el.nextElementSibling as HTMLElement | null,
};
};
const setElementPosition = (el: Element, value: ElementPositionWithDomNode) => {
value.parentNode.insertBefore(el, value.insertBeforeNode);
};
function getElementPositionRecord(element: Element): PositionRecord {
const elementRecord = getElementRecord(element);
if (!elementRecord.position) {
elementRecord.position = createElementPropertyRecord(
element,
'position',
getElementPosition,
setElementPosition,
positionMutationRunner
);
}
return elementRecord.position;
}
const setClassValue = (el: Element, val: string) =>

@@ -162,2 +221,5 @@ val ? (el.className = val) : el.removeAttribute('class');

delete element.classes;
} else if (attr === 'position') {
element.position?.observer?.disconnect();
delete element.position;
} else {

@@ -197,2 +259,3 @@ element.attributes?.[attr]?.observer?.disconnect();

m.classes && setPropertyValue<ClassnameRecord>(el, 'class', m.classes);
m.position && setPropertyValue<PositionRecord>(el, 'position', m.position);
Object.keys(m.attributes).forEach(attr => {

@@ -222,2 +285,4 @@ setPropertyValue<AttributeRecord>(el, attr, m.attributes[attr]);

record = getElementAttributeRecord(element, mutation.attribute);
} else if (mutation.kind === 'position') {
record = getElementPositionRecord(element);
}

@@ -238,2 +303,4 @@ if (!record) return;

record = getElementAttributeRecord(el, mutation.attribute);
} else if (mutation.kind === 'position') {
record = getElementPositionRecord(el);
}

@@ -330,2 +397,14 @@ if (!record) return;

function position(
selector: PositionMutation['selector'],
mutate: PositionMutation['mutate']
) {
return newMutation({
kind: 'position',
elements: new Set(),
mutate,
selector,
});
}
function classes(

@@ -376,2 +455,4 @@ selector: ClassnameMutation['selector'],

attribute: attr,
parentSelector,
insertBeforeSelector,
}: DeclarativeMutation): MutationController {

@@ -399,2 +480,9 @@ if (attr === 'html') {

}
} else if (attr === 'position') {
if (action === 'set' && parentSelector) {
return position(selector, () => ({
insertBeforeSelector,
parentSelector,
}));
}
} else {

@@ -423,2 +511,4 @@ if (action === 'append') {

value?: string;
parentSelector?: string;
insertBeforeSelector?: string;
};

@@ -430,3 +520,4 @@

attribute,
position,
declarative,
};

@@ -22,4 +22,24 @@ interface BaseMutation {

type Mutation = HTMLMutation | ClassnameMutation | AttrMutation;
interface PositionMutation extends BaseMutation {
kind: 'position';
mutate: () => ElementPosition;
}
interface ElementPosition {
parentSelector: string;
insertBeforeSelector?: null | string;
}
interface ElementPositionWithDomNode {
parentNode: HTMLElement;
insertBeforeNode: HTMLElement | null;
}
type Mutation =
| HTMLMutation
| ClassnameMutation
| AttrMutation
| PositionMutation;
type MutationKind = Mutation['kind'];
interface ElementPropertyRecord<T, V> {

@@ -40,2 +60,6 @@ observer: MutationObserver;

type AttributeRecord = ElementPropertyRecord<AttrMutation, string | null>;
type PositionRecord = ElementPropertyRecord<
PositionMutation,
ElementPositionWithDomNode
>;

@@ -49,2 +73,3 @@ interface ElementRecord {

};
position?: PositionRecord;
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc