dom-mutator
Advanced tools
Comparing version 0.3.2 to 0.4.0
@@ -13,12 +13,8 @@ 'use strict'; | ||
function getObserverInit(attr) { | ||
if (attr === 'html') { | ||
return { | ||
childList: true, | ||
subtree: true, | ||
attributes: true, | ||
characterData: true | ||
}; | ||
} | ||
return { | ||
return attr === 'html' ? { | ||
childList: true, | ||
subtree: true, | ||
attributes: true, | ||
characterData: true | ||
} : { | ||
childList: false, | ||
@@ -31,19 +27,19 @@ subtree: false, | ||
function getElementRecord(el) { | ||
var ret = elements.get(el); | ||
function getElementRecord(element) { | ||
var record = elements.get(element); | ||
if (!ret) { | ||
ret = { | ||
el: el, | ||
if (!record) { | ||
record = { | ||
element: element, | ||
attributes: {} | ||
}; | ||
elements.set(el, ret); | ||
elements.set(element, record); | ||
} | ||
return ret; | ||
return record; | ||
} | ||
function newMutatedElementAttribute(el, attr, getCurrentValue, setValue, runMutations) { | ||
function createElementPropertyRecord(el, attr, getCurrentValue, setValue, mutationRunner) { | ||
var currentValue = getCurrentValue(el); | ||
var ret = { | ||
var record = { | ||
isDirty: false, | ||
@@ -56,29 +52,14 @@ originalValue: currentValue, | ||
var currentValue = getCurrentValue(el); | ||
if (currentValue === ret.virtualValue) return; | ||
ret.originalValue = currentValue; | ||
runMutations(ret); | ||
if (currentValue === record.virtualValue) return; | ||
record.originalValue = currentValue; | ||
mutationRunner(record); | ||
}), | ||
runMutations: runMutations, | ||
mutationRunner: mutationRunner, | ||
setValue: setValue, | ||
getCurrentValue: getCurrentValue | ||
}; | ||
ret.observer.observe(el, getObserverInit(attr)); | ||
return ret; | ||
record.observer.observe(el, getObserverInit(attr)); | ||
return record; | ||
} | ||
function stringRunner(record) { | ||
var val = record.originalValue; | ||
record.mutations.forEach(function (m) { | ||
return val = m.mutate(val); | ||
}); | ||
return val; | ||
} | ||
function setRunner(val, record) { | ||
record.mutations.forEach(function (m) { | ||
return m.mutate(val); | ||
}); | ||
return val; | ||
} | ||
function queueIfNeeded(val, record) { | ||
@@ -94,13 +75,24 @@ var currentVal = record.getCurrentValue(record.el); | ||
function HTMLMutationRunner(record) { | ||
queueIfNeeded(getTransformedHTML(stringRunner(record)), record); | ||
function htmlMutationRunner(record) { | ||
var val = record.originalValue; | ||
record.mutations.forEach(function (m) { | ||
return val = m.mutate(val); | ||
}); | ||
queueIfNeeded(getTransformedHTML(val), record); | ||
} | ||
function ClassMutationRunner(record) { | ||
var val = setRunner(new Set(record.originalValue.split(/\s+/).filter(Boolean)), record); | ||
function classMutationRunner(record) { | ||
var val = new Set(record.originalValue.split(/\s+/).filter(Boolean)); | ||
record.mutations.forEach(function (m) { | ||
return m.mutate(val); | ||
}); | ||
queueIfNeeded(Array.from(val).filter(Boolean).join(' '), record); | ||
} | ||
function AttributeMutationRunner(record) { | ||
queueIfNeeded(stringRunner(record), record); | ||
function attrMutationRunner(record) { | ||
var val = record.originalValue; | ||
record.mutations.forEach(function (m) { | ||
return val = m.mutate(val); | ||
}); | ||
queueIfNeeded(val, record); | ||
} | ||
@@ -116,7 +108,7 @@ | ||
function getElementHTMLRecord(el) { | ||
var elementRecord = getElementRecord(el); | ||
function getElementHTMLRecord(element) { | ||
var elementRecord = getElementRecord(element); | ||
if (!elementRecord.html) { | ||
elementRecord.html = newMutatedElementAttribute(el, 'html', getHTMLValue, setHTMLValue, HTMLMutationRunner); | ||
elementRecord.html = createElementPropertyRecord(element, 'html', getHTMLValue, setHTMLValue, htmlMutationRunner); | ||
} | ||
@@ -139,3 +131,3 @@ | ||
if (!elementRecord.classes) { | ||
elementRecord.classes = newMutatedElementAttribute(el, 'class', getClassValue, setClassValue, ClassMutationRunner); | ||
elementRecord.classes = createElementPropertyRecord(el, 'class', getClassValue, setClassValue, classMutationRunner); | ||
} | ||
@@ -146,2 +138,16 @@ | ||
var getAttrValue = function getAttrValue(attrName) { | ||
return function (el) { | ||
var _el$getAttribute; | ||
return (_el$getAttribute = el.getAttribute(attrName)) != null ? _el$getAttribute : null; | ||
}; | ||
}; | ||
var setAttrValue = function setAttrValue(attrName) { | ||
return function (el, val) { | ||
return val !== null ? el.setAttribute(attrName, val) : el.removeAttribute(attrName); | ||
}; | ||
}; | ||
function getElementAttributeRecord(el, attr) { | ||
@@ -151,7 +157,3 @@ var elementRecord = getElementRecord(el); | ||
if (!elementRecord.attributes[attr]) { | ||
elementRecord.attributes[attr] = newMutatedElementAttribute(el, attr, function (el) { | ||
return el.getAttribute(attr) || ''; | ||
}, function (el, val) { | ||
return val ? el.setAttribute(attr, val) : el.removeAttribute(attr); | ||
}, AttributeMutationRunner); | ||
elementRecord.attributes[attr] = createElementPropertyRecord(el, attr, getAttrValue(attr), setAttrValue(attr), attrMutationRunner); | ||
} | ||
@@ -162,6 +164,4 @@ | ||
function deleteElementAttributeRecord(el, attr) { | ||
function deleteElementPropertyRecord(el, attr) { | ||
var element = elements.get(el); | ||
/* istanbul ignore next */ | ||
if (!element) return; | ||
@@ -198,3 +198,3 @@ | ||
function setAttributeValue(el, attr, m) { | ||
function setPropertyValue(el, attr, m) { | ||
if (!m.isDirty) return; | ||
@@ -205,3 +205,3 @@ m.isDirty = false; | ||
if (!m.mutations.length) { | ||
deleteElementAttributeRecord(el, attr); | ||
deleteElementPropertyRecord(el, attr); | ||
} | ||
@@ -215,6 +215,6 @@ | ||
function setValue(m, el) { | ||
m.html && setAttributeValue(el, 'html', m.html); | ||
m.classes && setAttributeValue(el, 'class', m.classes); | ||
m.html && setPropertyValue(el, 'html', m.html); | ||
m.classes && setPropertyValue(el, 'class', m.classes); | ||
Object.keys(m.attributes).forEach(function (attr) { | ||
setAttributeValue(el, attr, m.attributes[attr]); | ||
setPropertyValue(el, attr, m.attributes[attr]); | ||
}); | ||
@@ -233,74 +233,55 @@ } | ||
} | ||
} | ||
} // find or create ElementPropertyRecord, add mutation to it, then run | ||
function startMutating(mutation, el) { | ||
mutation.elements.add(el); | ||
function startMutating(mutation, element) { | ||
var record = null; | ||
if (mutation.kind === 'html') { | ||
var record = getElementHTMLRecord(el); | ||
record.mutations.push(mutation); | ||
record.runMutations(record); | ||
record = getElementHTMLRecord(element); | ||
} else if (mutation.kind === 'class') { | ||
var _record = getElementClassRecord(el); | ||
_record.mutations.push(mutation); | ||
_record.runMutations(_record); | ||
record = getElementClassRecord(element); | ||
} else if (mutation.kind === 'attribute') { | ||
var _record2 = getElementAttributeRecord(el, mutation.attribute); | ||
record = getElementAttributeRecord(element, mutation.attribute); | ||
} | ||
_record2.mutations.push(mutation); | ||
if (!record) return; | ||
record.mutations.push(mutation); | ||
record.mutationRunner(record); | ||
} // get (existing) ElementPropertyRecord, remove mutation from it, then run | ||
_record2.runMutations(_record2); | ||
} | ||
} | ||
function stopMutating(mutation, el) { | ||
mutation.elements["delete"](el); | ||
var record = null; | ||
if (mutation.kind === 'html') { | ||
var record = getElementHTMLRecord(el); | ||
var index = record.mutations.indexOf(mutation); | ||
if (index !== -1) { | ||
record.mutations.splice(index, 1); | ||
} | ||
record.runMutations(record); | ||
record = getElementHTMLRecord(el); | ||
} else if (mutation.kind === 'class') { | ||
var _record3 = getElementClassRecord(el); | ||
var _index = _record3.mutations.indexOf(mutation); | ||
if (_index !== -1) { | ||
_record3.mutations.splice(_index, 1); | ||
} | ||
_record3.runMutations(_record3); | ||
record = getElementClassRecord(el); | ||
} else if (mutation.kind === 'attribute') { | ||
var _record4 = getElementAttributeRecord(el, mutation.attribute); | ||
record = getElementAttributeRecord(el, mutation.attribute); | ||
} | ||
var _index2 = _record4.mutations.indexOf(mutation); | ||
if (!record) return; | ||
var index = record.mutations.indexOf(mutation); | ||
if (index !== -1) record.mutations.splice(index, 1); | ||
record.mutationRunner(record); | ||
} // maintain list of elements associated with mutation | ||
if (_index2 !== -1) { | ||
_record4.mutations.splice(_index2, 1); | ||
} | ||
_record4.runMutations(_record4); | ||
} | ||
} | ||
function refreshElementsSet(mutation) { | ||
var existingEls = new Set(mutation.elements); | ||
var existingElements = new Set(mutation.elements); | ||
var newElements = new Set(); | ||
var nodes = document.querySelectorAll(mutation.selector); | ||
nodes.forEach(function (el) { | ||
var matchingElements = document.querySelectorAll(mutation.selector); | ||
matchingElements.forEach(function (el) { | ||
newElements.add(el); | ||
if (!existingEls.has(el)) { | ||
if (!existingElements.has(el)) { | ||
mutation.elements.add(el); | ||
startMutating(mutation, el); | ||
} | ||
}); | ||
existingEls.forEach(function (el) { | ||
existingElements.forEach(function (el) { | ||
if (!newElements.has(el)) { | ||
mutation.elements["delete"](el); | ||
stopMutating(mutation, el); | ||
@@ -312,5 +293,4 @@ } | ||
function revertMutation(mutation) { | ||
var els = new Set(mutation.elements); | ||
els.forEach(function (el) { | ||
stopMutating(mutation, el); | ||
mutation.elements.forEach(function (el) { | ||
return stopMutating(mutation, el); | ||
}); | ||
@@ -331,3 +311,2 @@ mutation.elements.clear(); | ||
function connectGlobalObserver() { | ||
/* istanbul ignore next */ | ||
if (typeof document === 'undefined') return; | ||
@@ -348,13 +327,12 @@ | ||
}); | ||
} | ||
} // run on init | ||
connectGlobalObserver(); | ||
function newMutationRecord(m) { | ||
/* istanbul ignore next */ | ||
if (typeof document === 'undefined') { | ||
// Not in a browser | ||
return nullController; | ||
} | ||
function newMutation(m) { | ||
// Not in a browser | ||
if (typeof document === 'undefined') return nullController; // add to global index of mutations | ||
mutations.add(m); | ||
mutations.add(m); // run refresh on init to establish list of elements associated w/ mutation | ||
refreshElementsSet(m); | ||
@@ -369,3 +347,3 @@ return { | ||
function html(selector, mutate) { | ||
return newMutationRecord({ | ||
return newMutation({ | ||
kind: 'html', | ||
@@ -379,3 +357,3 @@ elements: new Set(), | ||
function classes(selector, mutate) { | ||
return newMutationRecord({ | ||
return newMutation({ | ||
kind: 'class', | ||
@@ -388,28 +366,21 @@ elements: new Set(), | ||
function attribute(selector, attribute, _mutate) { | ||
if (!validAttributeName.test(attribute)) { | ||
return nullController; | ||
} | ||
function attribute(selector, attribute, mutate) { | ||
if (!validAttributeName.test(attribute)) return nullController; | ||
if (attribute === 'class' || attribute === 'className') { | ||
return newMutationRecord({ | ||
kind: 'class', | ||
elements: new Set(), | ||
mutate: function mutate(classes) { | ||
var val = _mutate(Array.from(classes).join(' ')); | ||
classes.clear(); | ||
val.split(/\s+/g).filter(Boolean).forEach(function (c) { | ||
classes.add(c); | ||
}); | ||
}, | ||
selector: selector | ||
return classes(selector, function (classnames) { | ||
var mutatedClassnames = mutate(Array.from(classnames).join(' ')); | ||
classnames.clear(); | ||
if (!mutatedClassnames) return; | ||
mutatedClassnames.split(/\s+/g).filter(Boolean).forEach(function (c) { | ||
return classnames.add(c); | ||
}); | ||
}); | ||
} | ||
return newMutationRecord({ | ||
return newMutation({ | ||
kind: 'attribute', | ||
attribute: attribute, | ||
elements: new Set(), | ||
mutate: _mutate, | ||
mutate: mutate, | ||
selector: selector | ||
@@ -428,7 +399,7 @@ }); | ||
return html(selector, function (val) { | ||
return val + value; | ||
return val + (value != null ? value : ''); | ||
}); | ||
} else if (action === 'set') { | ||
return html(selector, function () { | ||
return value; | ||
return value != null ? value : ''; | ||
}); | ||
@@ -439,7 +410,7 @@ } | ||
return classes(selector, function (val) { | ||
return val.add(value); | ||
if (value) val.add(value); | ||
}); | ||
} else if (action === 'remove') { | ||
return classes(selector, function (val) { | ||
return val["delete"](value); | ||
if (value) val["delete"](value); | ||
}); | ||
@@ -449,3 +420,3 @@ } else if (action === 'set') { | ||
val.clear(); | ||
val.add(value); | ||
if (value) val.add(value); | ||
}); | ||
@@ -456,8 +427,12 @@ } | ||
return attribute(selector, attr, function (val) { | ||
return val + value; | ||
return val !== null ? val + (value != null ? value : '') : value != null ? value : ''; | ||
}); | ||
} else if (action === 'set') { | ||
return attribute(selector, attr, function () { | ||
return value; | ||
return value != null ? value : ''; | ||
}); | ||
} else if (action === 'remove') { | ||
return attribute(selector, attr, function () { | ||
return null; | ||
}); | ||
} | ||
@@ -479,2 +454,3 @@ } | ||
exports.disconnectGlobalObserver = disconnectGlobalObserver; | ||
exports.validAttributeName = validAttributeName; | ||
//# sourceMappingURL=dom-mutator.cjs.development.js.map |
@@ -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={el: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))})),runMutations: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){var e=t.originalValue;return t.mutations.forEach((function(t){return e=t.mutate(e)})),e}function s(t,e){var n=e.getCurrentValue(e.el);e.virtualValue=t,t!==n&&(e.isDirty=!0,g||(g=!0,requestAnimationFrame(y)))}function o(t){s(function(t){return v||(v=document.createElement("div")),v.innerHTML=t,v.innerHTML}(a(t)),t)}function l(t){var e=function(t,e){return e.mutations.forEach((function(e){return e.mutate(t)})),t}(new Set(t.originalValue.split(/\s+/).filter(Boolean)),t);s(Array.from(e).filter(Boolean).join(" "),t)}function c(t){s(a(t),t)}var f=function(t){return t.innerHTML},m=function(t,e){return t.innerHTML=e};function d(t){var e=u(t);return e.html||(e.html=i(t,"html",f,m,o)),e.html}var v,b=function(t,e){return e?t.className=e:t.removeAttribute("class")},h=function(t){return t.className};function p(t){var e=u(t);return e.classes||(e.classes=i(t,"class",h,b,l)),e.classes}function M(t,e){var n=u(t);return n.attributes[e]||(n.attributes[e]=i(t,e,(function(t){return t.getAttribute(e)||""}),(function(t,n){return n?t.setAttribute(e,n):t.removeAttribute(e)}),c)),n.attributes[e]}function w(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,s;null==(a=i.classes)||null==(s=a.observer)||s.disconnect(),delete i.classes}else{var o,l,c;null==(o=i.attributes)||null==(l=o[e])||null==(c=l.observer)||c.disconnect(),delete i.attributes[e]}}(t,e),r.setValue(t,u)}}var V,g=!1;function k(t,e){t.html&&w(e,"html",t.html),t.classes&&w(e,"class",t.classes),Object.keys(t.attributes).forEach((function(n){w(e,n,t.attributes[n])}))}function y(){g=!1,n.forEach(k)}function E(t,e){if(t.elements.delete(e),"html"===t.kind){var n=d(e),r=n.mutations.indexOf(t);-1!==r&&n.mutations.splice(r,1),n.runMutations(n)}else if("class"===t.kind){var u=p(e),i=u.mutations.indexOf(t);-1!==i&&u.mutations.splice(i,1),u.runMutations(u)}else if("attribute"===t.kind){var a=M(e,t.attribute),s=a.mutations.indexOf(t);-1!==s&&a.mutations.splice(s,1),a.runMutations(a)}}function A(t){var e=new Set(t.elements),n=new Set;document.querySelectorAll(t.selector).forEach((function(r){n.add(r),e.has(r)||function(t,e){if(t.elements.add(e),"html"===t.kind){var n=d(e);n.mutations.push(t),n.runMutations(n)}else if("class"===t.kind){var r=p(e);r.mutations.push(t),r.runMutations(r)}else if("attribute"===t.kind){var u=M(e,t.attribute);u.mutations.push(t),u.runMutations(u)}}(t,r)})),e.forEach((function(e){n.has(e)||E(t,e)}))}function S(){r.forEach(A)}function O(){"undefined"!=typeof document&&(V||(V=new MutationObserver((function(){S()}))),S(),V.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!1,characterData:!1}))}function x(t){return"undefined"==typeof document?e:(r.add(t),A(t),{revert:function(){var e;e=t,new Set(e.elements).forEach((function(t){E(e,t)})),e.elements.clear(),r.delete(e)}})}function L(t,e){return x({kind:"html",elements:new Set,mutate:e,selector:t})}function D(t,e){return x({kind:"class",elements:new Set,mutate:e,selector:t})}function j(n,r,u){return t.test(r)?x("class"===r||"className"===r?{kind:"class",elements:new Set,mutate:function(t){var e=u(Array.from(t).join(" "));t.clear(),e.split(/\s+/g).filter(Boolean).forEach((function(e){t.add(e)}))},selector:n}:{kind:"attribute",attribute:r,elements:new Set,mutate:u,selector:n}):e}O();var H={html:L,classes:D,attribute:j,declarative:function(t){var n=t.selector,r=t.action,u=t.value,i=t.attribute;if("html"===i){if("append"===r)return L(n,(function(t){return t+u}));if("set"===r)return L(n,(function(){return u}))}else if("class"===i){if("append"===r)return D(n,(function(t){return t.add(u)}));if("remove"===r)return D(n,(function(t){return t.delete(u)}));if("set"===r)return D(n,(function(t){t.clear(),t.add(u)}))}else{if("append"===r)return j(n,i,(function(t){return t+u}));if("set"===r)return j(n,i,(function(){return u}))}return e}};exports.connectGlobalObserver=O,exports.default=H,exports.disconnectGlobalObserver=function(){V&&V.disconnect()}; | ||
"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; | ||
//# sourceMappingURL=dom-mutator.cjs.production.min.js.map |
@@ -9,12 +9,8 @@ var validAttributeName = /^[a-zA-Z:_][a-zA-Z0-9:_.-]*$/; | ||
function getObserverInit(attr) { | ||
if (attr === 'html') { | ||
return { | ||
childList: true, | ||
subtree: true, | ||
attributes: true, | ||
characterData: true | ||
}; | ||
} | ||
return { | ||
return attr === 'html' ? { | ||
childList: true, | ||
subtree: true, | ||
attributes: true, | ||
characterData: true | ||
} : { | ||
childList: false, | ||
@@ -27,19 +23,19 @@ subtree: false, | ||
function getElementRecord(el) { | ||
var ret = elements.get(el); | ||
function getElementRecord(element) { | ||
var record = elements.get(element); | ||
if (!ret) { | ||
ret = { | ||
el: el, | ||
if (!record) { | ||
record = { | ||
element: element, | ||
attributes: {} | ||
}; | ||
elements.set(el, ret); | ||
elements.set(element, record); | ||
} | ||
return ret; | ||
return record; | ||
} | ||
function newMutatedElementAttribute(el, attr, getCurrentValue, setValue, runMutations) { | ||
function createElementPropertyRecord(el, attr, getCurrentValue, setValue, mutationRunner) { | ||
var currentValue = getCurrentValue(el); | ||
var ret = { | ||
var record = { | ||
isDirty: false, | ||
@@ -52,29 +48,14 @@ originalValue: currentValue, | ||
var currentValue = getCurrentValue(el); | ||
if (currentValue === ret.virtualValue) return; | ||
ret.originalValue = currentValue; | ||
runMutations(ret); | ||
if (currentValue === record.virtualValue) return; | ||
record.originalValue = currentValue; | ||
mutationRunner(record); | ||
}), | ||
runMutations: runMutations, | ||
mutationRunner: mutationRunner, | ||
setValue: setValue, | ||
getCurrentValue: getCurrentValue | ||
}; | ||
ret.observer.observe(el, getObserverInit(attr)); | ||
return ret; | ||
record.observer.observe(el, getObserverInit(attr)); | ||
return record; | ||
} | ||
function stringRunner(record) { | ||
var val = record.originalValue; | ||
record.mutations.forEach(function (m) { | ||
return val = m.mutate(val); | ||
}); | ||
return val; | ||
} | ||
function setRunner(val, record) { | ||
record.mutations.forEach(function (m) { | ||
return m.mutate(val); | ||
}); | ||
return val; | ||
} | ||
function queueIfNeeded(val, record) { | ||
@@ -90,13 +71,24 @@ var currentVal = record.getCurrentValue(record.el); | ||
function HTMLMutationRunner(record) { | ||
queueIfNeeded(getTransformedHTML(stringRunner(record)), record); | ||
function htmlMutationRunner(record) { | ||
var val = record.originalValue; | ||
record.mutations.forEach(function (m) { | ||
return val = m.mutate(val); | ||
}); | ||
queueIfNeeded(getTransformedHTML(val), record); | ||
} | ||
function ClassMutationRunner(record) { | ||
var val = setRunner(new Set(record.originalValue.split(/\s+/).filter(Boolean)), record); | ||
function classMutationRunner(record) { | ||
var val = new Set(record.originalValue.split(/\s+/).filter(Boolean)); | ||
record.mutations.forEach(function (m) { | ||
return m.mutate(val); | ||
}); | ||
queueIfNeeded(Array.from(val).filter(Boolean).join(' '), record); | ||
} | ||
function AttributeMutationRunner(record) { | ||
queueIfNeeded(stringRunner(record), record); | ||
function attrMutationRunner(record) { | ||
var val = record.originalValue; | ||
record.mutations.forEach(function (m) { | ||
return val = m.mutate(val); | ||
}); | ||
queueIfNeeded(val, record); | ||
} | ||
@@ -112,7 +104,7 @@ | ||
function getElementHTMLRecord(el) { | ||
var elementRecord = getElementRecord(el); | ||
function getElementHTMLRecord(element) { | ||
var elementRecord = getElementRecord(element); | ||
if (!elementRecord.html) { | ||
elementRecord.html = newMutatedElementAttribute(el, 'html', getHTMLValue, setHTMLValue, HTMLMutationRunner); | ||
elementRecord.html = createElementPropertyRecord(element, 'html', getHTMLValue, setHTMLValue, htmlMutationRunner); | ||
} | ||
@@ -135,3 +127,3 @@ | ||
if (!elementRecord.classes) { | ||
elementRecord.classes = newMutatedElementAttribute(el, 'class', getClassValue, setClassValue, ClassMutationRunner); | ||
elementRecord.classes = createElementPropertyRecord(el, 'class', getClassValue, setClassValue, classMutationRunner); | ||
} | ||
@@ -142,2 +134,16 @@ | ||
var getAttrValue = function getAttrValue(attrName) { | ||
return function (el) { | ||
var _el$getAttribute; | ||
return (_el$getAttribute = el.getAttribute(attrName)) != null ? _el$getAttribute : null; | ||
}; | ||
}; | ||
var setAttrValue = function setAttrValue(attrName) { | ||
return function (el, val) { | ||
return val !== null ? el.setAttribute(attrName, val) : el.removeAttribute(attrName); | ||
}; | ||
}; | ||
function getElementAttributeRecord(el, attr) { | ||
@@ -147,7 +153,3 @@ var elementRecord = getElementRecord(el); | ||
if (!elementRecord.attributes[attr]) { | ||
elementRecord.attributes[attr] = newMutatedElementAttribute(el, attr, function (el) { | ||
return el.getAttribute(attr) || ''; | ||
}, function (el, val) { | ||
return val ? el.setAttribute(attr, val) : el.removeAttribute(attr); | ||
}, AttributeMutationRunner); | ||
elementRecord.attributes[attr] = createElementPropertyRecord(el, attr, getAttrValue(attr), setAttrValue(attr), attrMutationRunner); | ||
} | ||
@@ -158,6 +160,4 @@ | ||
function deleteElementAttributeRecord(el, attr) { | ||
function deleteElementPropertyRecord(el, attr) { | ||
var element = elements.get(el); | ||
/* istanbul ignore next */ | ||
if (!element) return; | ||
@@ -194,3 +194,3 @@ | ||
function setAttributeValue(el, attr, m) { | ||
function setPropertyValue(el, attr, m) { | ||
if (!m.isDirty) return; | ||
@@ -201,3 +201,3 @@ m.isDirty = false; | ||
if (!m.mutations.length) { | ||
deleteElementAttributeRecord(el, attr); | ||
deleteElementPropertyRecord(el, attr); | ||
} | ||
@@ -211,6 +211,6 @@ | ||
function setValue(m, el) { | ||
m.html && setAttributeValue(el, 'html', m.html); | ||
m.classes && setAttributeValue(el, 'class', m.classes); | ||
m.html && setPropertyValue(el, 'html', m.html); | ||
m.classes && setPropertyValue(el, 'class', m.classes); | ||
Object.keys(m.attributes).forEach(function (attr) { | ||
setAttributeValue(el, attr, m.attributes[attr]); | ||
setPropertyValue(el, attr, m.attributes[attr]); | ||
}); | ||
@@ -229,74 +229,55 @@ } | ||
} | ||
} | ||
} // find or create ElementPropertyRecord, add mutation to it, then run | ||
function startMutating(mutation, el) { | ||
mutation.elements.add(el); | ||
function startMutating(mutation, element) { | ||
var record = null; | ||
if (mutation.kind === 'html') { | ||
var record = getElementHTMLRecord(el); | ||
record.mutations.push(mutation); | ||
record.runMutations(record); | ||
record = getElementHTMLRecord(element); | ||
} else if (mutation.kind === 'class') { | ||
var _record = getElementClassRecord(el); | ||
_record.mutations.push(mutation); | ||
_record.runMutations(_record); | ||
record = getElementClassRecord(element); | ||
} else if (mutation.kind === 'attribute') { | ||
var _record2 = getElementAttributeRecord(el, mutation.attribute); | ||
record = getElementAttributeRecord(element, mutation.attribute); | ||
} | ||
_record2.mutations.push(mutation); | ||
if (!record) return; | ||
record.mutations.push(mutation); | ||
record.mutationRunner(record); | ||
} // get (existing) ElementPropertyRecord, remove mutation from it, then run | ||
_record2.runMutations(_record2); | ||
} | ||
} | ||
function stopMutating(mutation, el) { | ||
mutation.elements["delete"](el); | ||
var record = null; | ||
if (mutation.kind === 'html') { | ||
var record = getElementHTMLRecord(el); | ||
var index = record.mutations.indexOf(mutation); | ||
if (index !== -1) { | ||
record.mutations.splice(index, 1); | ||
} | ||
record.runMutations(record); | ||
record = getElementHTMLRecord(el); | ||
} else if (mutation.kind === 'class') { | ||
var _record3 = getElementClassRecord(el); | ||
var _index = _record3.mutations.indexOf(mutation); | ||
if (_index !== -1) { | ||
_record3.mutations.splice(_index, 1); | ||
} | ||
_record3.runMutations(_record3); | ||
record = getElementClassRecord(el); | ||
} else if (mutation.kind === 'attribute') { | ||
var _record4 = getElementAttributeRecord(el, mutation.attribute); | ||
record = getElementAttributeRecord(el, mutation.attribute); | ||
} | ||
var _index2 = _record4.mutations.indexOf(mutation); | ||
if (!record) return; | ||
var index = record.mutations.indexOf(mutation); | ||
if (index !== -1) record.mutations.splice(index, 1); | ||
record.mutationRunner(record); | ||
} // maintain list of elements associated with mutation | ||
if (_index2 !== -1) { | ||
_record4.mutations.splice(_index2, 1); | ||
} | ||
_record4.runMutations(_record4); | ||
} | ||
} | ||
function refreshElementsSet(mutation) { | ||
var existingEls = new Set(mutation.elements); | ||
var existingElements = new Set(mutation.elements); | ||
var newElements = new Set(); | ||
var nodes = document.querySelectorAll(mutation.selector); | ||
nodes.forEach(function (el) { | ||
var matchingElements = document.querySelectorAll(mutation.selector); | ||
matchingElements.forEach(function (el) { | ||
newElements.add(el); | ||
if (!existingEls.has(el)) { | ||
if (!existingElements.has(el)) { | ||
mutation.elements.add(el); | ||
startMutating(mutation, el); | ||
} | ||
}); | ||
existingEls.forEach(function (el) { | ||
existingElements.forEach(function (el) { | ||
if (!newElements.has(el)) { | ||
mutation.elements["delete"](el); | ||
stopMutating(mutation, el); | ||
@@ -308,5 +289,4 @@ } | ||
function revertMutation(mutation) { | ||
var els = new Set(mutation.elements); | ||
els.forEach(function (el) { | ||
stopMutating(mutation, el); | ||
mutation.elements.forEach(function (el) { | ||
return stopMutating(mutation, el); | ||
}); | ||
@@ -327,3 +307,2 @@ mutation.elements.clear(); | ||
function connectGlobalObserver() { | ||
/* istanbul ignore next */ | ||
if (typeof document === 'undefined') return; | ||
@@ -344,13 +323,12 @@ | ||
}); | ||
} | ||
} // run on init | ||
connectGlobalObserver(); | ||
function newMutationRecord(m) { | ||
/* istanbul ignore next */ | ||
if (typeof document === 'undefined') { | ||
// Not in a browser | ||
return nullController; | ||
} | ||
function newMutation(m) { | ||
// Not in a browser | ||
if (typeof document === 'undefined') return nullController; // add to global index of mutations | ||
mutations.add(m); | ||
mutations.add(m); // run refresh on init to establish list of elements associated w/ mutation | ||
refreshElementsSet(m); | ||
@@ -365,3 +343,3 @@ return { | ||
function html(selector, mutate) { | ||
return newMutationRecord({ | ||
return newMutation({ | ||
kind: 'html', | ||
@@ -375,3 +353,3 @@ elements: new Set(), | ||
function classes(selector, mutate) { | ||
return newMutationRecord({ | ||
return newMutation({ | ||
kind: 'class', | ||
@@ -384,28 +362,21 @@ elements: new Set(), | ||
function attribute(selector, attribute, _mutate) { | ||
if (!validAttributeName.test(attribute)) { | ||
return nullController; | ||
} | ||
function attribute(selector, attribute, mutate) { | ||
if (!validAttributeName.test(attribute)) return nullController; | ||
if (attribute === 'class' || attribute === 'className') { | ||
return newMutationRecord({ | ||
kind: 'class', | ||
elements: new Set(), | ||
mutate: function mutate(classes) { | ||
var val = _mutate(Array.from(classes).join(' ')); | ||
classes.clear(); | ||
val.split(/\s+/g).filter(Boolean).forEach(function (c) { | ||
classes.add(c); | ||
}); | ||
}, | ||
selector: selector | ||
return classes(selector, function (classnames) { | ||
var mutatedClassnames = mutate(Array.from(classnames).join(' ')); | ||
classnames.clear(); | ||
if (!mutatedClassnames) return; | ||
mutatedClassnames.split(/\s+/g).filter(Boolean).forEach(function (c) { | ||
return classnames.add(c); | ||
}); | ||
}); | ||
} | ||
return newMutationRecord({ | ||
return newMutation({ | ||
kind: 'attribute', | ||
attribute: attribute, | ||
elements: new Set(), | ||
mutate: _mutate, | ||
mutate: mutate, | ||
selector: selector | ||
@@ -424,7 +395,7 @@ }); | ||
return html(selector, function (val) { | ||
return val + value; | ||
return val + (value != null ? value : ''); | ||
}); | ||
} else if (action === 'set') { | ||
return html(selector, function () { | ||
return value; | ||
return value != null ? value : ''; | ||
}); | ||
@@ -435,7 +406,7 @@ } | ||
return classes(selector, function (val) { | ||
return val.add(value); | ||
if (value) val.add(value); | ||
}); | ||
} else if (action === 'remove') { | ||
return classes(selector, function (val) { | ||
return val["delete"](value); | ||
if (value) val["delete"](value); | ||
}); | ||
@@ -445,3 +416,3 @@ } else if (action === 'set') { | ||
val.clear(); | ||
val.add(value); | ||
if (value) val.add(value); | ||
}); | ||
@@ -452,8 +423,12 @@ } | ||
return attribute(selector, attr, function (val) { | ||
return val + value; | ||
return val !== null ? val + (value != null ? value : '') : value != null ? value : ''; | ||
}); | ||
} else if (action === 'set') { | ||
return attribute(selector, attr, function () { | ||
return value; | ||
return value != null ? value : ''; | ||
}); | ||
} else if (action === 'remove') { | ||
return attribute(selector, attr, function () { | ||
return null; | ||
}); | ||
} | ||
@@ -473,3 +448,3 @@ } | ||
export default index; | ||
export { connectGlobalObserver, disconnectGlobalObserver }; | ||
export { connectGlobalObserver, disconnectGlobalObserver, validAttributeName }; | ||
//# sourceMappingURL=dom-mutator.esm.js.map |
@@ -0,6 +1,7 @@ | ||
export declare const validAttributeName: RegExp; | ||
export declare function disconnectGlobalObserver(): void; | ||
export declare function connectGlobalObserver(): void; | ||
declare function html(selector: string, mutate: (value: string) => string): MutationController; | ||
declare function classes(selector: string, mutate: (classes: Set<string>) => void): MutationController; | ||
declare function attribute(selector: string, attribute: string, mutate: (value: string) => string): MutationController; | ||
declare function html(selector: HTMLMutation['selector'], mutate: HTMLMutation['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; | ||
@@ -14,3 +15,3 @@ export declare type MutationController = { | ||
action: 'append' | 'set' | 'remove'; | ||
value: string; | ||
value?: string; | ||
}; | ||
@@ -17,0 +18,0 @@ declare const _default: { |
@@ -1,41 +0,40 @@ | ||
interface HTMLMutationRecord { | ||
kind: 'html'; | ||
interface BaseMutation { | ||
selector: string; | ||
mutate: (val: string) => string; | ||
elements: Set<Element>; | ||
} | ||
interface ClassMutationRecord { | ||
interface HTMLMutation extends BaseMutation { | ||
kind: 'html'; | ||
mutate: (innerHtml: string) => string; | ||
} | ||
interface ClassnameMutation extends BaseMutation { | ||
kind: 'class'; | ||
selector: string; | ||
mutate: (val: Set<string>) => void; | ||
elements: Set<Element>; | ||
mutate: (classNames: Set<string>) => void; | ||
} | ||
interface AttributeMutationRecord { | ||
interface AttrMutation extends BaseMutation { | ||
kind: 'attribute'; | ||
attribute: string; | ||
selector: string; | ||
mutate: (val: string) => string; | ||
elements: Set<Element>; | ||
mutate: (value: string | null) => string | null; | ||
} | ||
declare type AnyMutationRecord = StringMutationRecord | SetMutationRecord; | ||
declare type StringMutationRecord = HTMLMutationRecord | AttributeMutationRecord; | ||
declare type SetMutationRecord = ClassMutationRecord; | ||
interface ElementAttributeRecord<T> { | ||
declare type Mutation = HTMLMutation | ClassnameMutation | AttrMutation; | ||
interface ElementPropertyRecord<T, V> { | ||
observer: MutationObserver; | ||
originalValue: string; | ||
virtualValue: string; | ||
originalValue: V; | ||
virtualValue: V; | ||
isDirty: boolean; | ||
mutations: T[]; | ||
el: Element; | ||
getCurrentValue: (el: Element) => string; | ||
setValue: (el: Element, value: string) => void; | ||
runMutations: (record: ElementAttributeRecord<T>) => void; | ||
getCurrentValue: (el: Element) => V; | ||
setValue: (el: Element, value: V) => void; | ||
mutationRunner: (record: ElementPropertyRecord<T, V>) => void; | ||
} | ||
declare type HTMLRecord = ElementPropertyRecord<HTMLMutation, string>; | ||
declare type ClassnameRecord = ElementPropertyRecord<ClassnameMutation, string>; | ||
declare type AttributeRecord = ElementPropertyRecord<AttrMutation, string | null>; | ||
interface ElementRecord { | ||
el: Element; | ||
html?: ElementAttributeRecord<HTMLMutationRecord>; | ||
classes?: ElementAttributeRecord<ClassMutationRecord>; | ||
element: Element; | ||
html?: HTMLRecord; | ||
classes?: ClassnameRecord; | ||
attributes: { | ||
[key: string]: ElementAttributeRecord<AttributeMutationRecord>; | ||
[key: string]: AttributeRecord; | ||
}; | ||
} |
{ | ||
"version": "0.3.2", | ||
"version": "0.4.0", | ||
"license": "MIT", | ||
@@ -4,0 +4,0 @@ "main": "dist/index.js", |
340
src/index.ts
@@ -1,2 +0,2 @@ | ||
const validAttributeName = /^[a-zA-Z:_][a-zA-Z0-9:_.-]*$/; | ||
export const validAttributeName = /^[a-zA-Z:_][a-zA-Z0-9:_.-]*$/; | ||
const nullController: MutationController = { | ||
@@ -7,39 +7,40 @@ revert: () => {}, | ||
const elements: Map<Element, ElementRecord> = new Map(); | ||
const mutations: Set<AnyMutationRecord> = new Set(); | ||
const mutations: Set<Mutation> = new Set(); | ||
function getObserverInit(attr: string): MutationObserverInit { | ||
if (attr === 'html') { | ||
return { | ||
childList: true, | ||
subtree: true, | ||
attributes: true, | ||
characterData: true, | ||
}; | ||
} | ||
return { | ||
childList: false, | ||
subtree: false, | ||
attributes: true, | ||
attributeFilter: [attr], | ||
}; | ||
return attr === 'html' | ||
? { | ||
childList: true, | ||
subtree: true, | ||
attributes: true, | ||
characterData: true, | ||
} | ||
: { | ||
childList: false, | ||
subtree: false, | ||
attributes: true, | ||
attributeFilter: [attr], | ||
}; | ||
} | ||
function getElementRecord(el: Element): ElementRecord { | ||
let ret = elements.get(el); | ||
if (!ret) { | ||
ret = { el, attributes: {} }; | ||
elements.set(el, ret); | ||
function getElementRecord(element: Element): ElementRecord { | ||
let record = elements.get(element); | ||
if (!record) { | ||
record = { element, attributes: {} }; | ||
elements.set(element, record); | ||
} | ||
return ret; | ||
return record; | ||
} | ||
function newMutatedElementAttribute<T>( | ||
function createElementPropertyRecord( | ||
el: Element, | ||
attr: string, | ||
getCurrentValue: (el: Element) => string, | ||
setValue: (el: Element, val: string) => void, | ||
runMutations: (record: ElementAttributeRecord<T>) => void | ||
): ElementAttributeRecord<T> { | ||
getCurrentValue: (el: Element) => any, | ||
setValue: (el: Element, val: any) => void, | ||
mutationRunner: (record: ElementPropertyRecord<any, any>) => void | ||
) { | ||
const currentValue = getCurrentValue(el); | ||
const ret: ElementAttributeRecord<T> = { | ||
const record: ElementPropertyRecord<any, any> = { | ||
isDirty: false, | ||
@@ -52,39 +53,17 @@ originalValue: currentValue, | ||
const currentValue = getCurrentValue(el); | ||
if (currentValue === ret.virtualValue) return; | ||
ret.originalValue = currentValue; | ||
runMutations(ret); | ||
if (currentValue === record.virtualValue) return; | ||
record.originalValue = currentValue; | ||
mutationRunner(record); | ||
}), | ||
runMutations, | ||
mutationRunner, | ||
setValue, | ||
getCurrentValue, | ||
}; | ||
ret.observer.observe(el, getObserverInit(attr)); | ||
return ret; | ||
record.observer.observe(el, getObserverInit(attr)); | ||
return record; | ||
} | ||
function stringRunner(record: { | ||
originalValue: string; | ||
mutations: { mutate: (v: string) => string }[]; | ||
}) { | ||
let val = record.originalValue; | ||
record.mutations.forEach(m => (val = m.mutate(val))); | ||
return val; | ||
} | ||
function setRunner( | ||
val: Set<string>, | ||
record: { | ||
mutations: { mutate: (v: Set<string>) => void }[]; | ||
} | ||
) { | ||
record.mutations.forEach(m => m.mutate(val)); | ||
return val; | ||
} | ||
function queueIfNeeded( | ||
val: string, | ||
record: { | ||
el: Element; | ||
getCurrentValue: (el: Element) => string; | ||
virtualValue: string; | ||
isDirty: boolean; | ||
} | ||
val: string | null, | ||
record: ElementPropertyRecord<any, any> | ||
) { | ||
@@ -99,14 +78,10 @@ const currentVal = record.getCurrentValue(record.el); | ||
function HTMLMutationRunner( | ||
record: ElementAttributeRecord<HTMLMutationRecord> | ||
) { | ||
queueIfNeeded(getTransformedHTML(stringRunner(record)), record); | ||
function htmlMutationRunner(record: HTMLRecord) { | ||
let val = record.originalValue; | ||
record.mutations.forEach(m => (val = m.mutate(val))); | ||
queueIfNeeded(getTransformedHTML(val), record); | ||
} | ||
function ClassMutationRunner( | ||
record: ElementAttributeRecord<ClassMutationRecord> | ||
) { | ||
const val = setRunner( | ||
new Set(record.originalValue.split(/\s+/).filter(Boolean)), | ||
record | ||
); | ||
function classMutationRunner(record: ClassnameRecord) { | ||
const val = new Set(record.originalValue.split(/\s+/).filter(Boolean)); | ||
record.mutations.forEach(m => m.mutate(val)); | ||
queueIfNeeded( | ||
@@ -119,6 +94,6 @@ Array.from(val) | ||
} | ||
function AttributeMutationRunner( | ||
record: ElementAttributeRecord<AttributeMutationRecord> | ||
) { | ||
queueIfNeeded(stringRunner(record), record); | ||
function attrMutationRunner(record: AttributeRecord) { | ||
let val: string | null = record.originalValue; | ||
record.mutations.forEach(m => (val = m.mutate(val))); | ||
queueIfNeeded(val, record); | ||
} | ||
@@ -128,13 +103,11 @@ | ||
const setHTMLValue = (el: Element, value: string) => (el.innerHTML = value); | ||
function getElementHTMLRecord( | ||
el: Element | ||
): ElementAttributeRecord<HTMLMutationRecord> { | ||
const elementRecord = getElementRecord(el); | ||
function getElementHTMLRecord(element: Element): HTMLRecord { | ||
const elementRecord = getElementRecord(element); | ||
if (!elementRecord.html) { | ||
elementRecord.html = newMutatedElementAttribute( | ||
el, | ||
elementRecord.html = createElementPropertyRecord( | ||
element, | ||
'html', | ||
getHTMLValue, | ||
setHTMLValue, | ||
HTMLMutationRunner | ||
htmlMutationRunner | ||
); | ||
@@ -148,8 +121,6 @@ } | ||
const getClassValue = (el: Element) => el.className; | ||
function getElementClassRecord( | ||
el: Element | ||
): ElementAttributeRecord<ClassMutationRecord> { | ||
function getElementClassRecord(el: Element): ClassnameRecord { | ||
const elementRecord = getElementRecord(el); | ||
if (!elementRecord.classes) { | ||
elementRecord.classes = newMutatedElementAttribute( | ||
elementRecord.classes = createElementPropertyRecord( | ||
el, | ||
@@ -159,3 +130,3 @@ 'class', | ||
setClassValue, | ||
ClassMutationRunner | ||
classMutationRunner | ||
); | ||
@@ -166,15 +137,15 @@ } | ||
function getElementAttributeRecord( | ||
el: Element, | ||
attr: string | ||
): ElementAttributeRecord<AttributeMutationRecord> { | ||
const getAttrValue = (attrName: string) => (el: Element) => | ||
el.getAttribute(attrName) ?? null; | ||
const setAttrValue = (attrName: string) => (el: Element, val: string | null) => | ||
val !== null ? el.setAttribute(attrName, val) : el.removeAttribute(attrName); | ||
function getElementAttributeRecord(el: Element, attr: string): AttributeRecord { | ||
const elementRecord = getElementRecord(el); | ||
if (!elementRecord.attributes[attr]) { | ||
elementRecord.attributes[attr] = newMutatedElementAttribute( | ||
elementRecord.attributes[attr] = createElementPropertyRecord( | ||
el, | ||
attr, | ||
el => el.getAttribute(attr) || '', | ||
(el, val) => | ||
val ? el.setAttribute(attr, val) : el.removeAttribute(attr), | ||
AttributeMutationRunner | ||
getAttrValue(attr), | ||
setAttrValue(attr), | ||
attrMutationRunner | ||
); | ||
@@ -185,5 +156,4 @@ } | ||
function deleteElementAttributeRecord(el: Element, attr: string) { | ||
function deleteElementPropertyRecord(el: Element, attr: string) { | ||
const element = elements.get(el); | ||
/* istanbul ignore next */ | ||
if (!element) return; | ||
@@ -211,6 +181,6 @@ if (attr === 'html') { | ||
function setAttributeValue<T>( | ||
function setPropertyValue<T extends ElementPropertyRecord<any, any>>( | ||
el: Element, | ||
attr: string, | ||
m: ElementAttributeRecord<T> | ||
m: T | ||
) { | ||
@@ -221,3 +191,3 @@ if (!m.isDirty) return; | ||
if (!m.mutations.length) { | ||
deleteElementAttributeRecord(el, attr); | ||
deleteElementPropertyRecord(el, attr); | ||
} | ||
@@ -228,7 +198,8 @@ m.setValue(el, val); | ||
let raf = false; | ||
function setValue(m: ElementRecord, el: Element) { | ||
m.html && setAttributeValue(el, 'html', m.html); | ||
m.classes && setAttributeValue(el, 'class', m.classes); | ||
m.html && setPropertyValue<HTMLRecord>(el, 'html', m.html); | ||
m.classes && setPropertyValue<ClassnameRecord>(el, 'class', m.classes); | ||
Object.keys(m.attributes).forEach(attr => { | ||
setAttributeValue(el, attr, m.attributes[attr]); | ||
setPropertyValue<AttributeRecord>(el, attr, m.attributes[attr]); | ||
}); | ||
@@ -247,54 +218,43 @@ } | ||
function startMutating(mutation: AnyMutationRecord, el: Element) { | ||
mutation.elements.add(el); | ||
// find or create ElementPropertyRecord, add mutation to it, then run | ||
function startMutating(mutation: Mutation, element: Element) { | ||
let record: ElementPropertyRecord<any, any> | null = null; | ||
if (mutation.kind === 'html') { | ||
const record = getElementHTMLRecord(el); | ||
record.mutations.push(mutation); | ||
record.runMutations(record); | ||
record = getElementHTMLRecord(element); | ||
} else if (mutation.kind === 'class') { | ||
const record = getElementClassRecord(el); | ||
record.mutations.push(mutation); | ||
record.runMutations(record); | ||
record = getElementClassRecord(element); | ||
} else if (mutation.kind === 'attribute') { | ||
const record = getElementAttributeRecord(el, mutation.attribute); | ||
record.mutations.push(mutation); | ||
record.runMutations(record); | ||
record = getElementAttributeRecord(element, mutation.attribute); | ||
} | ||
if (!record) return; | ||
record.mutations.push(mutation); | ||
record.mutationRunner(record); | ||
} | ||
function stopMutating(mutation: AnyMutationRecord, el: Element) { | ||
mutation.elements.delete(el); | ||
// get (existing) ElementPropertyRecord, remove mutation from it, then run | ||
function stopMutating(mutation: Mutation, el: Element) { | ||
let record: ElementPropertyRecord<any, any> | null = null; | ||
if (mutation.kind === 'html') { | ||
const record = getElementHTMLRecord(el); | ||
const index = record.mutations.indexOf(mutation); | ||
if (index !== -1) { | ||
record.mutations.splice(index, 1); | ||
} | ||
record.runMutations(record); | ||
record = getElementHTMLRecord(el); | ||
} else if (mutation.kind === 'class') { | ||
const record = getElementClassRecord(el); | ||
const index = record.mutations.indexOf(mutation); | ||
if (index !== -1) { | ||
record.mutations.splice(index, 1); | ||
} | ||
record.runMutations(record); | ||
record = getElementClassRecord(el); | ||
} else if (mutation.kind === 'attribute') { | ||
const record = getElementAttributeRecord(el, mutation.attribute); | ||
const index = record.mutations.indexOf(mutation); | ||
if (index !== -1) { | ||
record.mutations.splice(index, 1); | ||
} | ||
record.runMutations(record); | ||
record = getElementAttributeRecord(el, mutation.attribute); | ||
} | ||
if (!record) return; | ||
const index = record.mutations.indexOf(mutation); | ||
if (index !== -1) record.mutations.splice(index, 1); | ||
record.mutationRunner(record); | ||
} | ||
function refreshElementsSet(mutation: AnyMutationRecord) { | ||
const existingEls = new Set(mutation.elements); | ||
// maintain list of elements associated with mutation | ||
function refreshElementsSet(mutation: Mutation) { | ||
const existingElements = new Set(mutation.elements); | ||
const newElements: Set<Element> = new Set(); | ||
const nodes = document.querySelectorAll(mutation.selector); | ||
nodes.forEach(el => { | ||
const matchingElements = document.querySelectorAll(mutation.selector); | ||
matchingElements.forEach(el => { | ||
newElements.add(el); | ||
if (!existingEls.has(el)) { | ||
if (!existingElements.has(el)) { | ||
mutation.elements.add(el); | ||
startMutating(mutation, el); | ||
@@ -304,4 +264,5 @@ } | ||
existingEls.forEach(el => { | ||
existingElements.forEach(el => { | ||
if (!newElements.has(el)) { | ||
mutation.elements.delete(el); | ||
stopMutating(mutation, el); | ||
@@ -312,7 +273,4 @@ } | ||
function revertMutation(mutation: AnyMutationRecord) { | ||
const els = new Set(mutation.elements); | ||
els.forEach(el => { | ||
stopMutating(mutation, el); | ||
}); | ||
function revertMutation(mutation: Mutation) { | ||
mutation.elements.forEach(el => stopMutating(mutation, el)); | ||
mutation.elements.clear(); | ||
@@ -332,3 +290,2 @@ mutations.delete(mutation); | ||
export function connectGlobalObserver() { | ||
/* istanbul ignore next */ | ||
if (typeof document === 'undefined') return; | ||
@@ -350,14 +307,13 @@ | ||
} | ||
// run on init | ||
connectGlobalObserver(); | ||
function newMutationRecord(m: AnyMutationRecord): MutationController { | ||
/* istanbul ignore next */ | ||
if (typeof document === 'undefined') { | ||
// Not in a browser | ||
return nullController; | ||
} | ||
function newMutation(m: Mutation): MutationController { | ||
// Not in a browser | ||
if (typeof document === 'undefined') return nullController; | ||
// add to global index of mutations | ||
mutations.add(m); | ||
// run refresh on init to establish list of elements associated w/ mutation | ||
refreshElementsSet(m); | ||
return { | ||
@@ -370,4 +326,7 @@ revert: () => { | ||
function html(selector: string, mutate: (value: string) => string) { | ||
return newMutationRecord({ | ||
function html( | ||
selector: HTMLMutation['selector'], | ||
mutate: HTMLMutation['mutate'] | ||
) { | ||
return newMutation({ | ||
kind: 'html', | ||
@@ -380,4 +339,7 @@ elements: new Set(), | ||
function classes(selector: string, mutate: (classes: Set<string>) => void) { | ||
return newMutationRecord({ | ||
function classes( | ||
selector: ClassnameMutation['selector'], | ||
mutate: ClassnameMutation['mutate'] | ||
) { | ||
return newMutation({ | ||
kind: 'class', | ||
@@ -389,29 +351,23 @@ elements: new Set(), | ||
} | ||
function attribute( | ||
selector: string, | ||
attribute: string, | ||
mutate: (value: string) => string | ||
selector: AttrMutation['selector'], | ||
attribute: AttrMutation['attribute'], | ||
mutate: AttrMutation['mutate'] | ||
) { | ||
if (!validAttributeName.test(attribute)) { | ||
return nullController; | ||
} | ||
if (!validAttributeName.test(attribute)) return nullController; | ||
if (attribute === 'class' || attribute === 'className') { | ||
return newMutationRecord({ | ||
kind: 'class', | ||
elements: new Set(), | ||
mutate: classes => { | ||
const val = mutate(Array.from(classes).join(' ')); | ||
classes.clear(); | ||
val | ||
.split(/\s+/g) | ||
.filter(Boolean) | ||
.forEach(c => { | ||
classes.add(c); | ||
}); | ||
}, | ||
selector, | ||
return classes(selector, classnames => { | ||
const mutatedClassnames = mutate(Array.from(classnames).join(' ')); | ||
classnames.clear(); | ||
if (!mutatedClassnames) return; | ||
mutatedClassnames | ||
.split(/\s+/g) | ||
.filter(Boolean) | ||
.forEach(c => classnames.add(c)); | ||
}); | ||
} | ||
return newMutationRecord({ | ||
return newMutation({ | ||
kind: 'attribute', | ||
@@ -433,15 +389,19 @@ attribute, | ||
if (action === 'append') { | ||
return html(selector, val => val + value); | ||
return html(selector, val => val + (value ?? '')); | ||
} else if (action === 'set') { | ||
return html(selector, () => value); | ||
return html(selector, () => value ?? ''); | ||
} | ||
} else if (attr === 'class') { | ||
if (action === 'append') { | ||
return classes(selector, val => val.add(value)); | ||
return classes(selector, val => { | ||
if (value) val.add(value); | ||
}); | ||
} else if (action === 'remove') { | ||
return classes(selector, val => val.delete(value)); | ||
return classes(selector, val => { | ||
if (value) val.delete(value); | ||
}); | ||
} else if (action === 'set') { | ||
return classes(selector, val => { | ||
val.clear(); | ||
val.add(value); | ||
if (value) val.add(value); | ||
}); | ||
@@ -451,5 +411,9 @@ } | ||
if (action === 'append') { | ||
return attribute(selector, attr, val => val + value); | ||
return attribute(selector, attr, val => | ||
val !== null ? val + (value ?? '') : value ?? '' | ||
); | ||
} else if (action === 'set') { | ||
return attribute(selector, attr, () => value); | ||
return attribute(selector, attr, () => value ?? ''); | ||
} else if (action === 'remove') { | ||
return attribute(selector, attr, () => null); | ||
} | ||
@@ -468,3 +432,3 @@ } | ||
action: 'append' | 'set' | 'remove'; | ||
value: string; | ||
value?: string; | ||
}; | ||
@@ -471,0 +435,0 @@ |
@@ -1,44 +0,47 @@ | ||
interface HTMLMutationRecord { | ||
kind: 'html'; | ||
interface BaseMutation { | ||
selector: string; | ||
mutate: (val: string) => string; | ||
elements: Set<Element>; | ||
} | ||
interface ClassMutationRecord { | ||
interface HTMLMutation extends BaseMutation { | ||
kind: 'html'; | ||
mutate: (innerHtml: string) => string; | ||
} | ||
interface ClassnameMutation extends BaseMutation { | ||
kind: 'class'; | ||
selector: string; | ||
mutate: (val: Set<string>) => void; | ||
elements: Set<Element>; | ||
mutate: (classNames: Set<string>) => void; | ||
} | ||
interface AttributeMutationRecord { | ||
interface AttrMutation extends BaseMutation { | ||
kind: 'attribute'; | ||
attribute: string; | ||
selector: string; | ||
mutate: (val: string) => string; | ||
elements: Set<Element>; | ||
mutate: (value: string | null) => string | null; | ||
} | ||
type AnyMutationRecord = StringMutationRecord | SetMutationRecord; | ||
type StringMutationRecord = HTMLMutationRecord | AttributeMutationRecord; | ||
type Mutation = HTMLMutation | ClassnameMutation | AttrMutation; | ||
type SetMutationRecord = ClassMutationRecord; | ||
interface ElementAttributeRecord<T> { | ||
interface ElementPropertyRecord<T, V> { | ||
observer: MutationObserver; | ||
originalValue: string; | ||
virtualValue: string; | ||
originalValue: V; | ||
virtualValue: V; | ||
isDirty: boolean; | ||
mutations: T[]; | ||
el: Element; | ||
getCurrentValue: (el: Element) => string; | ||
setValue: (el: Element, value: string) => void; | ||
runMutations: (record: ElementAttributeRecord<T>) => void; | ||
getCurrentValue: (el: Element) => V; | ||
setValue: (el: Element, value: V) => void; | ||
mutationRunner: (record: ElementPropertyRecord<T, V>) => void; | ||
} | ||
type HTMLRecord = ElementPropertyRecord<HTMLMutation, string>; | ||
type ClassnameRecord = ElementPropertyRecord<ClassnameMutation, string>; | ||
type AttributeRecord = ElementPropertyRecord<AttrMutation, string | null>; | ||
interface ElementRecord { | ||
el: Element; | ||
html?: ElementAttributeRecord<HTMLMutationRecord>; | ||
classes?: ElementAttributeRecord<ClassMutationRecord>; | ||
element: Element; | ||
html?: HTMLRecord; | ||
classes?: ClassnameRecord; | ||
attributes: { | ||
[key: string]: ElementAttributeRecord<AttributeMutationRecord>; | ||
[key: string]: AttributeRecord; | ||
}; | ||
} |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
117220
1221