Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

can-dom-mutate

Package Overview
Dependencies
Maintainers
2
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

can-dom-mutate - npm Package Compare versions

Comparing version 0.1.0 to 0.2.1

-util.js

301

can-dom-mutate.js
'use strict';
var each = require('can-util/js/each/each');
var domData = require('can-util/dom/data/data');
var CIDMap = require('can-util/js/cid-map/cid-map');
var setImmediate = require('can-util/js/set-immediate/set-immediate');
var observer = require('./-observer');
var globals = require('can-globals');
var getRoot = require('can-globals/global/global');
var getMutationObserver = require('can-globals/mutation-observer/mutation-observer');
var setImmediate = getRoot().setImmediate || function (cb) {
return setTimeout(cb, 0);
};
var util = require('./-util');
var getDocument = util.getDocument;
var eliminate = util.eliminate;
var subscription = util.subscription;
var isDocumentElement = util.isDocumentElement;
var getAllNodes = util.getAllNodes;
var push = Array.prototype.push;
var slice = Array.prototype.slice;
var domMutate;
var dataStore = new WeakMap();
function eliminate(array, item) {
var index = array.indexOf(item);
if (index >= 0) {
array.splice(index, 1);
function getRelatedData(node, key) {
var data = dataStore.get(node);
if (data) {
return data[key];
}
}
function batch(processBatchItems) {
function setRelatedData(node, key, targetListenersMap) {
var data = dataStore.get(node) || dataStore.set(node, {}).get(node);
data[key] = targetListenersMap;
}
function deleteRelatedData(node, key) {
var data = dataStore.get(node);
return delete data[key];
}
function batch(processBatchItems, shouldDeduplicate) {
var waitingBatch = [];
var waitingCalls = [];
var dispatchSet = new Set();
var isPrimed = false;
return function batchAdd(items, callback) {
waitingBatch = waitingBatch.concat(items);
if (shouldDeduplicate) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
var target = item.target;
if (!dispatchSet.has(target)) {
waitingBatch.push(item);
dispatchSet.add(target);
}
}
} else {
push.apply(waitingBatch, items);
}
if (callback) {

@@ -36,7 +70,11 @@ waitingCalls.push(callback);

waitingCalls = [];
if (shouldDeduplicate) {
dispatchSet = new Set();
}
isPrimed = false;
processBatchItems(currentBatch);
currentCalls.forEach(function (callback) {
callback();
});
var callCount = currentCalls.length;
for (var c = 0; c < callCount; c++) {
currentCalls[c]();
}
});

@@ -47,13 +85,5 @@ }

function getDocument(target) {
return target.ownerDocument || target.document || target;
}
function isDocumentElement (node) {
return getDocument(node).documentElement === node;
}
function getDocumentListeners (target, key) {
var doc = getDocument(target);
var data = domData.get.call(doc, key);
var data = getRelatedData(doc, key);
if (data) {

@@ -66,3 +96,3 @@ return data.listeners;

var doc = getDocument(target);
var targetListenersMap = domData.get.call(doc, key);
var targetListenersMap = getRelatedData(doc, key);
if (!targetListenersMap) {

@@ -77,6 +107,6 @@ return;

var doc = getDocument(target);
var targetListenersMap = domData.get.call(doc, key);
var targetListenersMap = getRelatedData(doc, key);
if (!targetListenersMap) {
targetListenersMap = new CIDMap();
domData.set.call(doc, key, targetListenersMap);
targetListenersMap = new Map();
setRelatedData(doc, key, targetListenersMap);
}

@@ -93,3 +123,3 @@ var targetListeners = targetListenersMap.get(target);

var doc = getDocument(target);
var targetListenersMap = domData.get.call(doc, key);
var targetListenersMap = getRelatedData(doc, key);
if (!targetListenersMap) {

@@ -103,6 +133,6 @@ return;

eliminate(targetListeners, listener);
if (targetListeners.size === 0) {
if (targetListeners.length === 0) {
targetListenersMap['delete'](target);
if (targetListenersMap.size === 0) {
domData.clean.call(doc, key);
deleteRelatedData(doc, key);
}

@@ -112,18 +142,23 @@ }

function dispatch(listenerKey, documentDataKey, isAttributes) {
function fire (callbacks, arg) {
var safeCallbacks = slice.call(callbacks, 0);
var safeCallbackCount = safeCallbacks.length;
for (var i = 0; i < safeCallbackCount; i++) {
safeCallbacks[i](arg);
}
}
function dispatch(listenerKey, documentDataKey) {
return function dispatchEvents(events) {
for (var e = 0; e < events.length; e++) {
var event = events[e];
var target = isAttributes ? event.node : event;
var target = event.target;
var targetListeners = getTargetListeners(target, listenerKey);
if (targetListeners) {
for (var t = 0; t < targetListeners.length; t++) {
targetListeners[t](event);
}
fire(targetListeners, event);
}
if (!documentDataKey) {
return;
continue;
}

@@ -133,5 +168,3 @@

if (documentListeners) {
for (var l = 0; l < documentListeners.length; l++) {
documentListeners[l](event);
}
fire(documentListeners, event);
}

@@ -143,27 +176,44 @@ }

function observeMutations(target, observerKey, config, handler) {
var MutationObserver = observer.getValue();
if (!MutationObserver) {
return function () {
};
}
var observerData = domData.get.call(target, observerKey);
var observerData = getRelatedData(target, observerKey);
if (!observerData) {
var targetObserver = new MutationObserver(handler);
targetObserver.observe(target, config);
observerData = {
observer: targetObserver,
observingCount: 0
};
domData.set.call(target, observerKey, observerData);
setRelatedData(target, observerKey, observerData);
}
var setupObserver = function () {
var MutationObserver = getMutationObserver();
if (MutationObserver) {
var Node = getRoot().Node;
var isRealNode = !!(Node && target instanceof Node);
if (isRealNode) {
var targetObserver = new MutationObserver(handler);
targetObserver.observe(target, config);
observerData.observer = targetObserver;
}
} else {
if (observerData.observer) {
observerData.observer.disconnect();
observerData.observer = null;
}
}
};
if (observerData.observingCount === 0) {
globals.onKeyValue('MutationObserver', setupObserver);
setupObserver();
}
observerData.observingCount++;
return function stopObservingMutations() {
var observerData = domData.get.call(target, observerKey);
var observerData = getRelatedData(target, observerKey);
if (observerData) {
observerData.observingCount--;
if (observerData.observingCount <= 0) {
observerData.observer.disconnect();
domData.clean.call(target, observerKey);
if (observerData.observer) {
observerData.observer.disconnect();
}
deleteRelatedData(target, observerKey);
globals.offKeyValue('MutationObserver', setupObserver);
}

@@ -175,14 +225,24 @@ }

function handleTreeMutations(mutations) {
mutations.forEach(function (mutation) {
each(mutation.addedNodes, function (node) {
domMutate.dispatchNodeInsertion(node);
});
each(mutation.removedNodes, function (node) {
domMutate.dispatchNodeRemoval(node);
});
});
var mutationCount = mutations.length;
for (var m = 0; m < mutationCount; m++) {
var mutation = mutations[m];
var addedNodes = mutation.addedNodes;
var addedCount = addedNodes.length;
for (var a = 0; a < addedCount; a++) {
domMutate.dispatchNodeInsertion(addedNodes[a]);
}
var removedNodes = mutation.removedNodes;
var removedCount = removedNodes.length;
for (var r = 0; r < removedCount; r++) {
domMutate.dispatchNodeRemoval(removedNodes[r]);
}
}
}
function handleAttributeMutations(mutations) {
mutations.forEach(function (mutation) {
var mutationCount = mutations.length;
for (var m = 0; m < mutationCount; m++) {
var mutation = mutations[m];
if (mutation.type === 'attributes') {

@@ -194,3 +254,3 @@ var node = mutation.target;

}
});
}
}

@@ -208,18 +268,2 @@

function subscription (fn) {
return function _subscription () {
var disposal = fn.apply(this, arguments);
var isDisposed = false;
return function _disposal () {
if (isDisposed) {
var fnName = fn.name || fn.displayName || 'an anonymous function';
var message = 'Disposal function returned by ' + fnName + ' called more than once.';
throw new Error(message);
}
disposal.apply(this, arguments);
isDisposed = true;
};
};
}
function addNodeListener(listenerKey, observerKey, isAttributes) {

@@ -231,3 +275,3 @@ return subscription(function _addNodeListener(target, listener) {

} else {
stopObserving = observeMutations(getDocument(target).documentElement, observerKey, treeMutationConfig, handleTreeMutations);
stopObserving = observeMutations(getDocument(target), observerKey, treeMutationConfig, handleTreeMutations);
}

@@ -238,3 +282,3 @@

stopObserving();
removeTargetListener(target, listenerKey, listenerKey);
removeTargetListener(target, listenerKey, listener);
};

@@ -251,6 +295,6 @@ });

var doc = getDocument(documentElement);
var documentData = domData.get.call(doc, globalDataKey);
var documentData = getRelatedData(doc, globalDataKey);
if (!documentData) {
documentData = {listeners: []};
domData.set.call(doc, globalDataKey, documentData);
setRelatedData(doc, globalDataKey, documentData);
}

@@ -267,3 +311,3 @@

return function removeGlobalGroupListener() {
var documentData = domData.get.call(doc, globalDataKey);
var documentData = getRelatedData(doc, globalDataKey);
if (!documentData) {

@@ -277,3 +321,3 @@ return;

documentData.removeListener();
domData.clean.call(doc, globalDataKey);
deleteRelatedData(doc, globalDataKey);
}

@@ -284,19 +328,8 @@ };

function toNodes(child) {
var isFragment = child.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
if (!isFragment) {
return [child];
function toMutationEvents (nodes) {
var events = [];
for (var i = 0; i < nodes.length; i++) {
events.push({target: nodes[i]});
}
var children = [];
var node = child.firstChild;
while (node) {
var nodes = toNodes(child);
for (var i = 0; i < nodes.length; i++) {
children.push(nodes[i]);
}
node = node.nextSibling;
}
return children;
return events;
}

@@ -312,3 +345,5 @@

// document listener keys
var documentInsertionDataKey = domMutationPrefix + 'DocumentInsertionData';
var documentRemovalDataKey = domMutationPrefix + 'DocumentRemovalData';
var documentAttributeChangeDataKey = domMutationPrefix + 'DocumentAttributeChangeData';

@@ -319,5 +354,5 @@ // observer keys

var dispatchInsertion = batch(dispatch(insertionDataKey));
var dispatchRemoval = batch(dispatch(removalDataKey, documentRemovalDataKey));
var dispatchAttributeChange = batch(dispatch(attributeChangeDataKey, null, true));
var dispatchInsertion = batch(dispatch(insertionDataKey, documentInsertionDataKey), true);
var dispatchRemoval = batch(dispatch(removalDataKey, documentRemovalDataKey), true);
var dispatchAttributeChange = batch(dispatch(attributeChangeDataKey, documentAttributeChangeDataKey));

@@ -330,2 +365,6 @@ // node listeners

// global listeners
var addInsertionListener = addGlobalListener(
documentInsertionDataKey,
addNodeInsertionListener
);
var addRemovalListener = addGlobalListener(

@@ -335,2 +374,6 @@ documentRemovalDataKey,

);
var addAttributeChangeListener = addGlobalListener(
documentAttributeChangeDataKey,
addNodeAttributeChangeListener
);

@@ -357,3 +400,4 @@ /**

dispatchNodeInsertion: function (node, callback) {
dispatchInsertion(toNodes(node), callback);
var events = toMutationEvents(getAllNodes(node));
dispatchInsertion(events, callback);
},

@@ -372,3 +416,4 @@

dispatchNodeRemoval: function (node, callback) {
dispatchRemoval(toNodes(node), callback);
var events = toMutationEvents(getAllNodes(node));
dispatchRemoval(events, callback);
},

@@ -383,3 +428,3 @@

* @parent can-dom-mutate.static
* @param {Node} node The node on which to dispatch an attribute change mutation.
* @param {Node} target The node on which to dispatch an attribute change mutation.
* @param {String} attributeName The attribute name whose value has changed.

@@ -389,8 +434,8 @@ * @param {String} oldValue The attribute value before the change.

*/
dispatchNodeAttributeChange: function (node, attributeName, oldValue, callback) {
dispatchAttributeChange({
node: node,
dispatchNodeAttributeChange: function (target, attributeName, oldValue, callback) {
dispatchAttributeChange([{
target: target,
attributeName: attributeName,
oldValue: oldValue
}, callback);
}], callback);
},

@@ -442,11 +487,37 @@

*
* @signature `onRemoval( node, callback )`
* @signature `onRemoval( documentElement, callback )`
* @parent can-dom-mutate.static
* @param {Node} documentElement The doucmentElement on which to listen for removal mutations.
* @param {Node} documentElement The documentElement on which to listen for removal mutations.
* @param {function} callback The callback called when a removal mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onRemoval: addRemovalListener
onRemoval: addRemovalListener,
/**
* @function can-dom-mutate.onInsertion onInsertion
*
* Listen for insertion mutations on any node within the documentElement.
*
* @signature `onInsertion( documentElement, callback )`
* @parent can-dom-mutate.static
* @param {Node} documentElement The documentElement on which to listen for removal mutations.
* @param {function} callback The callback called when a insertion mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onInsertion: addInsertionListener,
/**
* @function can-dom-mutate.onAttributeChange onAttributeChange
*
* Listen for attribute change mutations on any node within the documentElement.
*
* @signature `onAttributeChange( documentElement, callback )`
* @parent can-dom-mutate.static
* @param {Node} documentElement The documentElement on which to listen for removal mutations.
* @param {function} callback The callback called when an attribute change mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onAttributeChange: addAttributeChangeListener
};
module.exports = domMutate;
'use strict';
var assign = require('can-util/js/assign/assign');
var observer = require('./-observer');
var globals = require('can-globals');
var domMutate = require('./can-dom-mutate');
var util = require('./-util');
function isInDocument (node) {
var root = node.ownerDocument.documentElement;
if (root === node) {
return true;
}
return root.contains(node);
}
var isInDocument = util.isInDocument;
var getParents = util.getParents;

@@ -30,5 +25,8 @@ var synthetic = {

replaceChild: function (newChild, oldChild) {
var newChildren = getParents(newChild);
var result = this.replaceChild(newChild, oldChild);
synthetic.dispatchNodeRemoval(this, oldChild);
synthetic.dispatchNodeInsertion(this, newChild);
for (var i = 0; i < newChildren.length; i++) {
synthetic.dispatchNodeInsertion(this, newChildren[i]);
}
return result;

@@ -39,4 +37,15 @@ },

var result = this.setAttribute(name, value);
domMutate.dispatchNodeAttributeChange(this, name, oldAttributeValue);
var newAttributeValue = this.getAttribute(name);
if (oldAttributeValue !== newAttributeValue) {
domMutate.dispatchNodeAttributeChange(this, name, oldAttributeValue);
}
return result;
},
removeAttribute: function (name) {
var oldAttributeValue = this.getAttribute(name);
var result = this.removeAttribute(name);
if (oldAttributeValue) {
domMutate.dispatchNodeAttributeChange(this, name, oldAttributeValue);
}
return result;
}

@@ -54,4 +63,7 @@ };

compat[nodeMethod] = function (node) {
var nodes = getParents(node);
var result = this[nodeMethod].apply(this, arguments);
synthetic[dispatchMethod](this, node);
for (var i = 0; i < nodes.length; i++) {
synthetic[dispatchMethod](this, nodes[i]);
}
return result;

@@ -62,3 +74,3 @@ };

var normal = {};
var nodeMethods = ['appendChild', 'insertBefore', 'removeChild', 'replaceChild', 'setAttribute'];
var nodeMethods = ['appendChild', 'insertBefore', 'removeChild', 'replaceChild', 'setAttribute', 'removeAttribute'];
nodeMethods.forEach(function (methodName) {

@@ -148,10 +160,24 @@ normal[methodName] = function () {

/**
* @function can-dom-mutate/node.removeAttribute removeAttribute
*
* Removes an attribute from an element, effectively `Element.prototype.removeAttribute`.
*
* @signature `mutate.removeAttribute.call(element, name, value)`
* @parent can-dom-mutate.node
* @param {Element} element The element from which to remove the attribute.
* @param {String} name The name of the attribute to remove.
*/
function setMutateStrategy(observer) {
var strategy = observer ? normal : compat;
assign(mutate, strategy);
for (var key in strategy) {
mutate[key] = strategy[key];
}
}
setMutateStrategy(observer.getValue());
observer.onValue(setMutateStrategy);
var mutationObserverKey = 'MutationObserver';
setMutateStrategy(globals.getKeyValue(mutationObserverKey));
globals.onKeyValue(mutationObserverKey, setMutateStrategy);
module.exports = mutate;
{
"name": "can-dom-mutate",
"description": "Dispatch and listen for DOM mutations",
"version": "0.1.0",
"version": "0.2.1",
"author": {

@@ -14,5 +14,3 @@ "name": "DoneJS Team",

"dependencies": {
"can-dom-events": "^1.0.2",
"can-symbol": "^1.0.0",
"can-util": "^3.8.4"
"can-globals": "<2.0.0"
},

@@ -41,7 +39,9 @@ "devDependencies": {

"scripts": {
"install-canary": "npm install --no-shrinkwrap",
"install-locked": "npm install",
"jshint": "jshint ./*.js ./events/*.js ./test/**/*.js --config",
"jshint": "jshint ./*.js ./test/*.js --config",
"lint": "fixpack && npm run jshint",
"preversion": "npm test",
"release:major": "npm version major && npm publish",
"release:minor": "npm version minor && npm publish",
"release:patch": "npm version patch && npm publish",
"release:pre": "npm version prerelease && npm publish --tag pre",
"test": "npm run lint && npm run testee",

@@ -48,0 +48,0 @@ "testee": "testee test.html --browsers firefox"

import './test/can-dom-mutate-test';
import './test/events/attributes-test';
import './test/events/inserted-test';
import './test/events/removed-test';
import './test/node-test';

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc