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

can-dom-mutate

Package Overview
Dependencies
Maintainers
8
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 2.0.2 to 2.0.3

-is-connected.js

12

-util.js

@@ -10,9 +10,11 @@ "use strict";

}
function addToSet(items, set) {
for(var i =0, length = items.length; i < length; i++) {
set.add(items[i]);
function wasNotInSet(item, set) {
var inSet = set.has(item);
if(inSet === false) {
set.add(item);
}
return !inSet;
}
function contains(parent, child){

@@ -164,4 +166,4 @@ if(parent.contains) {

subscription: subscription,
addToSet: addToSet,
wasNotInSet: wasNotInSet,
contains: contains
};

@@ -7,3 +7,2 @@ 'use strict';

var DOCUMENT = require("can-globals/document/document");
var canReflect = require("can-reflect");

@@ -16,5 +15,17 @@ var util = require('./-util');

var domMutate, dispatchInsertion, dispatchRemoval, dispatchAttributeChange;
var domMutate,
dispatchNodeInserted,
dispatchNodeConnected,
dispatchGlobalConnected,
dispatchNodeRemoved,
dispatchNodeDisconnected,
dispatchGlobalDisconnected,
dispatchAttributeChange,
dispatchGlobalAttributeChange;
var dataStore = new WeakMap();
var isConnected = require("./-is-connected");
var queue;
function getRelatedData(node, key) {

@@ -41,5 +52,9 @@ var data = dataStore.get(node);

function toMutationEvent(node, mutation) {
return {target: node, sourceMutation: mutation};
}
/*
function toMutationEvents (nodes) {
var events = [];
for (var i = 0; i < nodes.length; i++) {
for (var i = 0, length = nodes.length; i < length; i++) {
events.push({target: nodes[i]});

@@ -49,14 +64,8 @@ }

}
*/
function batch(processBatchItems) {
return function batchAdd(items, callback, dispatchConnected, flush) {
processBatchItems(items, dispatchConnected, flush);
if(callback){
callback();
}
};
}
function getDocumentListeners (target, key) {
// TODO: it's odd these functions read DOCUMENT() instead of
// target.ownerDocument. To change to ownerDocument, we might need a "is document"
// check.
var doc = DOCUMENT();

@@ -118,3 +127,3 @@ var data = getRelatedData(doc, key);

var recordsAndCallbacks = null;
//var recordsAndCallbacks = null;

@@ -128,3 +137,3 @@ function flushCallbacks(callbacks, arg){

}
/*
function flushRecords(){

@@ -153,42 +162,16 @@ if(recordsAndCallbacks === null) {

}
*/
function dispatch(getListeners, targetKey) {
function dispatch(targetKey, connectedKey, documentDataKey) {
return function dispatchEvents(events, dispatchConnected, flush) {
// we could check the first element and see if it's in the document
// if it is conditionally fire "connected" events
for (var e = 0; e < events.length; e++) {
var event = events[e];
var target = event.target;
// we need to check
//
var targetListeners = getTargetListeners(target, targetKey);
return function dispatchEvents(event) {
if (targetListeners) {
flush(targetListeners, event);
}
var targetListeners = getListeners(event.target, targetKey);
if(!dispatchConnected) {
continue;
}
if (targetListeners) {
flushCallbacks(targetListeners, event);
}
var connectedListeners;
if(connectedKey){
connectedListeners = getTargetListeners(target, connectedKey);
}
if (connectedListeners) {
flush(connectedListeners, event);
}
if (!documentDataKey) {
continue;
}
var documentListeners = getDocumentListeners(target, documentDataKey);
if (documentListeners) {
flush(documentListeners, event);
}
}
};
}
var count = 0;

@@ -244,3 +227,3 @@

}
/*
function handleTreeMutations(mutations) {

@@ -254,21 +237,33 @@ // in IE11, if the document is being removed

if(this.flushing === true) {
this.mutations.push.apply(this.mutations, mutations);
return;
}
this.flushing = true;
this.mutations = [].slice.call(mutations);
var mutation;
var mutationCount = mutations.length;
var added = new Set(), removed = new Set();
for (var m = 0; m < mutationCount; m++) {
var mutation = mutations[m];
while(mutation = this.mutations.shift()) {
var removedCount = mutation.removedNodes.length;
for (var r = 0; r < removedCount; r++) {
// get what already isn't in `removed`
var newRemoved = util.addToSet( getAllNodes(mutation.removedNodes[r]), removed);
dispatchRemoval( newRemoved.map(toMutationEvent), null, true, flushCallbacks );
}
var addedCount = mutation.addedNodes.length;
for (var a = 0; a < addedCount; a++) {
util.addToSet( getAllNodes(mutation.addedNodes[a]), added);
var newAdded = util.addToSet( getAllNodes(mutation.addedNodes[a]), added);
dispatchInsertion( newAdded.map(toMutationEvent), null, true, flushCallbacks );
}
var removedCount = mutation.removedNodes.length;
for (var r = 0; r < removedCount; r++) {
util.addToSet( getAllNodes(mutation.removedNodes[r]), removed);
}
}
dispatchRemoval( toMutationEvents( canReflect.toArray(removed) ), null, true, flushCallbacks );
dispatchInsertion( toMutationEvents( canReflect.toArray(added) ), null, true, flushCallbacks );
this.flushing = false;
//dispatchRemoval( toMutationEvents( canReflect.toArray(removed) ), null, true, flushCallbacks );
//dispatchInsertion( toMutationEvents( canReflect.toArray(added) ), null, true, flushCallbacks );
}

@@ -292,3 +287,7 @@

}
*/
var treeMutationConfig = {

@@ -317,5 +316,5 @@ subtree: true,

if (isAttributes) {
stopObserving = observeMutations(target, observerKey, attributeMutationConfig, handleAttributeMutations);
stopObserving = observeMutations(target, observerKey, attributeMutationConfig, queue.enqueueAndFlushMutations);
} else {
stopObserving = observeMutations(DOCUMENT(), observerKey, treeMutationConfig, handleTreeMutations);
stopObserving = observeMutations(DOCUMENT(), observerKey, treeMutationConfig, queue.enqueueAndFlushMutations);
}

@@ -391,6 +390,13 @@

dispatchInsertion = batch(dispatch(insertedDataKey, connectedDataKey, documentConnectedDataKey));
dispatchRemoval = batch(dispatch(removedDataKey, disconnectedDataKey, documentDisconnectedDataKey));
dispatchAttributeChange = batch(dispatch(attributeChangeDataKey, null , documentAttributeChangeDataKey));
dispatchNodeInserted = dispatch(getTargetListeners, insertedDataKey);
dispatchNodeConnected = dispatch(getTargetListeners, connectedDataKey);
dispatchGlobalConnected = dispatch(getDocumentListeners, documentConnectedDataKey);
dispatchNodeRemoved = dispatch(getTargetListeners, removedDataKey);
dispatchNodeDisconnected = dispatch(getTargetListeners, disconnectedDataKey);
dispatchGlobalDisconnected = dispatch(getDocumentListeners, documentDisconnectedDataKey);
dispatchAttributeChange = dispatch(getTargetListeners, attributeChangeDataKey);
dispatchGlobalAttributeChange = dispatch(getDocumentListeners, documentAttributeChangeDataKey);
// node listeners

@@ -417,3 +423,125 @@ var addNodeConnectedListener = addNodeListener(connectedDataKey, treeDataKey);

// ==========================================
function dispatchTreeMutation(mutation, processedState) {
// was the mutation connected
var wasConnected = mutation.isConnected === true || mutation.isConnected === undefined;
// there are
// - the global connected
// - individual connected
// - individual inserted
var removedCount = mutation.removedNodes.length;
for (var r = 0; r < removedCount; r++) {
// get what already isn't in `removed`
// see if "removed"
// if wasConnected .. dispatch disconnected
var removedNodes = getAllNodes(mutation.removedNodes[r]);
removedNodes.forEach(function(node){
var event = toMutationEvent(node, mutation);
if( util.wasNotInSet(node, processedState.removed) ) {
dispatchNodeRemoved( event );
}
if(wasConnected && util.wasNotInSet(node, processedState.disconnected) ) {
dispatchNodeDisconnected( event );
dispatchGlobalDisconnected( event );
}
});
}
var addedCount = mutation.addedNodes.length;
for (var a = 0; a < addedCount; a++) {
var insertedNodes = getAllNodes(mutation.addedNodes[a]);
insertedNodes.forEach(function(node){
var event = toMutationEvent(node, mutation);
if(util.wasNotInSet(node, processedState.inserted)) {
dispatchNodeInserted( event );
}
if(wasConnected && util.wasNotInSet(node, processedState.connected) ) {
dispatchNodeConnected( event );
dispatchGlobalConnected( event );
}
});
}
// run mutation
}
var FLUSHING_MUTATIONS = [];
var IS_FLUSHING = false;
var IS_FLUSH_PENDING = false;
var ENQUEUED_MUTATIONS = [];
queue = {
// This is used to dispatch mutations immediately.
// This is usually called by the result of a mutation observer.
enqueueAndFlushMutations: function(mutations) {
if(IS_FLUSH_PENDING) {
FLUSHING_MUTATIONS.push.apply(FLUSHING_MUTATIONS, ENQUEUED_MUTATIONS);
IS_FLUSH_PENDING = false;
ENQUEUED_MUTATIONS = [];
}
FLUSHING_MUTATIONS.push.apply(FLUSHING_MUTATIONS, mutations);
if(IS_FLUSHING) {
return;
}
IS_FLUSHING = true;
var index = 0;
var processedState = {
connected: new Set(),
disconnected: new Set(),
inserted: new Set(),
removed: new Set()
};
while(index < FLUSHING_MUTATIONS.length) {
var mutation = FLUSHING_MUTATIONS[index];
// process mutation
if(mutation.type === "childList") {
dispatchTreeMutation(mutation, processedState);
} else if(mutation.type === "attributes") {
dispatchAttributeChange(mutation);
}
index++;
}
FLUSHING_MUTATIONS = [];
IS_FLUSHING = false;
},
// called to dipatch later unless we are already dispatching.
enqueueMutationsAndFlushAsync: function(mutations){
ENQUEUED_MUTATIONS.push.apply(ENQUEUED_MUTATIONS, mutations);
// if there are currently dispatching mutations, this should happen sometime after
if(!IS_FLUSH_PENDING) {
IS_FLUSH_PENDING = true;
nextTick(function(){
if(IS_FLUSH_PENDING) {
IS_FLUSH_PENDING = false;
var pending = ENQUEUED_MUTATIONS;
ENQUEUED_MUTATIONS = [];
queue.enqueueAndFlushMutations(pending);
} else {
// Someone called enqueueAndFlushMutations before this finished.
}
});
}
}
};
// ==========================================
domMutate = {

@@ -429,5 +557,14 @@ /**

* @param {Node} node The node on which to dispatch an insertion mutation.
* @param {function} callback The optional callback called after the mutation is dispatched.
*/
dispatchNodeInsertion: function (node, callback, dispatchConnected) {
dispatchNodeInsertion: function (node, target) {
queue.enqueueMutationsAndFlushAsync(
[{
type: "childList",
target: target,
addedNodes: [node],
isConnected: isConnected.isConnected(target),
removedNodes: []
}]
);
/*
var nodes = new Set();

@@ -437,3 +574,3 @@ util.addToSet( getAllNodes(node), nodes);

// this is basically an array of every single child of node including node
dispatchInsertion(events, callback, dispatchConnected, flushAsync);
dispatchInsertion(events, callback, dispatchConnected, flushAsync);*/
},

@@ -452,7 +589,17 @@

*/
dispatchNodeRemoval: function (node, callback, dispatchConnected) {
dispatchNodeRemoval: function (node, target) {
queue.enqueueMutationsAndFlushAsync(
[{
type: "childList",
target: target,
addedNodes: [],
removedNodes: [node],
isConnected: isConnected.isConnected(target)
}]
);
/*
var nodes = new Set();
util.addToSet( getAllNodes(node), nodes);
var events = toMutationEvents( canReflect.toArray(nodes) );
dispatchRemoval(events, callback, dispatchConnected, flushAsync);
dispatchRemoval(events, callback, dispatchConnected, flushAsync);*/
},

@@ -478,10 +625,12 @@

* @param {String} oldValue The attribute value before the change.
* @param {function} callback The optional callback called after the mutation is dispatched.
*/
dispatchNodeAttributeChange: function (target, attributeName, oldValue, callback) {
dispatchAttributeChange([{
target: target,
attributeName: attributeName,
oldValue: oldValue
}], callback, true, flushAsync);
dispatchNodeAttributeChange: function (target, attributeName, oldValue) {
queue.enqueueMutationsAndFlushAsync(
[{
type: "attributes",
target: target,
attributeName: attributeName,
oldValue: oldValue
}]
);
},

@@ -585,13 +734,10 @@

doc = doc || DOCUMENT();
var data = dataStore.get(doc);
var data = dataStore.get(doc),
records = [];
if(data) {
if(data.domMutationTreeData && data.domMutationTreeData.observer) {
var records = data.domMutationTreeData.observer.takeRecords();
handleTreeMutations(records);
records = data.domMutationTreeData.observer.takeRecords();
}
// flush any synthetic records
flushRecords();
}
queue.enqueueAndFlushMutations(records);
},

@@ -598,0 +744,0 @@ onNodeInserted: addNodeInsertedListener,

@@ -7,2 +7,3 @@ var unit = require('steal-qunit');

var makeSimpleDocument = require("can-vdom/make-document/make-document");
var isConnected = require("../-is-connected");

@@ -35,3 +36,3 @@ var test = unit.test;

// IE 11 doesn't support isConnected, so both isConnected() calls will go through here
assert.ok(true, "Native Node.prototype does not support isConnected");
assert.ok(true, "Native Node.prototype does not support isConnected");
}

@@ -42,5 +43,5 @@ return null;

assert.ok(node.isConnected(fakenode), "Real document connected");
assert.ok(isConnected.isConnected(fakenode), "Real document connected");
getDocument(makeSimpleDocument());
assert.ok(node.isConnected(fakenode), "SimpleDocument connected");
assert.ok(isConnected.isConnected(fakenode), "SimpleDocument connected");
getDocument(doc);

@@ -156,5 +157,5 @@ });

var undo = mock(domMutate, 'dispatchNodeInsertion', function (node, callback) {
var undo = mock(domMutate, 'dispatchNodeInsertion', function (node, parentNode) {
assert.equal(node, child, 'Should pass the child being appended');
assert.equal(callback, undefined, 'Should not pass a callback');
assert.equal(parentNode , parent, 'Should pass the parent');
assert.ok(parent.contains(node), 'Node should be in parent before dispatch is called');

@@ -209,5 +210,5 @@ undo();

var undo = mock(domMutate, 'dispatchNodeInsertion', function (node, callback) {
var undo = mock(domMutate, 'dispatchNodeInsertion', function (node, parentNode) {
assert.equal(node, child, 'Should pass the child being appended');
assert.equal(callback, undefined, 'Should not pass a callback');
assert.equal(parentNode, parent, 'Should pass the parent node');
assert.ok(parent.contains(node), 'Node should be in parent before dispatch is called');

@@ -240,5 +241,5 @@ undo();

var undo = mock(domMutate, 'dispatchNodeRemoval', function (node, callback) {
var undo = mock(domMutate, 'dispatchNodeRemoval', function (node, parentNode) {
assert.equal(node, child, 'Should pass the child being removed');
assert.equal(callback, undefined, 'Should not pass a callback');
assert.equal(parent, parentNode, 'Should pass the parent node');
assert.ok(!parent.contains(node), 'Node should be removed before dispatch is called');

@@ -261,5 +262,5 @@ undo();

var undoRemoval = mock(domMutate, 'dispatchNodeRemoval', function (node, callback) {
var undoRemoval = mock(domMutate, 'dispatchNodeRemoval', function (node, parentNode) {
assert.equal(node, sibling, 'Should pass the sibling being removed');
assert.equal(callback, undefined, 'Should not pass a callback');
assert.equal(parent, parentNode, 'Should pass the parent');
assert.ok(!parent.contains(node), 'Node should be removed before dispatch is called');

@@ -270,6 +271,6 @@ undoRemoval();

var undoInsertion = mock(domMutate, 'dispatchNodeInsertion', function (node, callback) {
var undoInsertion = mock(domMutate, 'dispatchNodeInsertion', function (node, parentNode) {
assert.ok(isSiblingRemoved, 'Sibling should be removed before the child is inserted (as far as dispatch order is concerned)');
assert.equal(node, child, 'Should pass the child being inserted');
assert.equal(callback, undefined, 'Should not pass a callback');
assert.equal(parentNode, parent, 'Should not pass a callback');
assert.ok(parent.contains(node), 'Node should be inserted before dispatch is called');

@@ -339,2 +340,22 @@ undoInsertion();

});
QUnit.test("connected should be called if element is inserted to a disconnected element and then the parent is inserted )#64", function(assert){
var done = assert.async();
var fixture = testUtils.getFixture();
var parent = document.createElement('div');
var child = document.createElement('div');
var undo = domMutate.onNodeConnected(child, function() {
assert.ok(true, 'this was called');
undo();
done();
});
node.appendChild.call(parent, child);
node.appendChild.call(fixture, parent);
});
};

@@ -359,3 +380,3 @@ moduleWithoutMutationObserver('can-dom-mutate/node with real document', getDocument(), withoutMutationObserverTests);

QUnit.test('appendChild should not call dispatchNodeInsertion', function (assert) {
QUnit.skip('appendChild should not call dispatchNodeInsertion', function (assert) {
assert.expect(1);

@@ -373,3 +394,3 @@ var doc = getDocument();

QUnit.test('insertBefore should not call dispatchNodeInsertion', function (assert) {
QUnit.skip('insertBefore should not call dispatchNodeInsertion', function (assert) {
assert.expect(1);

@@ -390,3 +411,3 @@ var doc = getDocument();

QUnit.test('removeChild should not call dispatchNodeRemoval', function (assert) {
QUnit.skip('removeChild should not call dispatchNodeRemoval', function (assert) {
assert.expect(1);

@@ -406,3 +427,3 @@ var doc = getDocument();

QUnit.test('replaceChild should not call dispatchNodeRemoval+Insertion', function (assert) {
QUnit.skip('replaceChild should not call dispatchNodeRemoval+Insertion', function (assert) {
assert.expect(2);

@@ -432,4 +453,6 @@ var doc = getDocument();

getDocument(doc1);
var undo = domMutate.onNodeDisconnected(doc1.documentElement, function() {
assert.ok(true, 'this was called');
getDocument(doc);
undo();

@@ -441,3 +464,3 @@ done();

node.removeChild.call(doc1, doc1.documentElement);
getDocument(doc);
});

@@ -444,0 +467,0 @@ }

@@ -10,27 +10,5 @@ 'use strict';

var contains = util.contains;
var isConnected = require("../-is-connected");
var isConnected;
function getIsConnectedFromNode(node) {
return node.isConnected;
}
function getIsConnectedFromDocument(node) {
var doc = node.ownerDocument;
// if node *is* the document, ownerDocument is null
// However, CanSimpleDom implements this incorrectly, and a document's ownerDocument is itself,
// so make both checks
return doc === null || doc === node || contains(doc, node);
}
function setIsConnected(doc) {
var node = doc.createTextNode("");
isConnected = 'isConnected' in node.constructor.prototype ?
getIsConnectedFromNode :
getIsConnectedFromDocument;
if(mutate) {
mutate.isConnected = isConnected;
}
}
setIsConnected(globals.getKeyValue("document"));
globals.onKeyValue("document", setIsConnected);
var compat = {

@@ -40,5 +18,5 @@ replaceChild: function (newChild, oldChild) {

var result = this.replaceChild(newChild, oldChild);
domMutate.dispatchNodeRemoval(oldChild, null, isConnected(this) && !isConnected(oldChild));
domMutate.dispatchNodeRemoval(oldChild, this);
for (var i = 0; i < newChildren.length; i++) {
domMutate.dispatchNodeInsertion(newChildren[i], null, isConnected(this));
domMutate.dispatchNodeInsertion(newChildren[i], this);
}

@@ -78,3 +56,3 @@ return result;

for (var i = 0; i < nodes.length; i++) {
domMutate[dispatchMethod](nodes[i], null, isConnected(this) && (pair[1] === 'Removal' ? !isConnected(nodes[i]) : true));
domMutate[dispatchMethod](nodes[i], this);
}

@@ -89,3 +67,3 @@ return result;

normal[methodName] = function () {
if(isConnected(this)) {
if(isConnected.isConnected(this)) {
return this[methodName].apply(this, arguments);

@@ -208,4 +186,4 @@ } else {

mutate.isConnected = isConnected;
//mutate.isConnected = isConnected;
module.exports = namespace.domMutateNode = domMutate.node = mutate;
{
"name": "can-dom-mutate",
"description": "Dispatch and listen for DOM mutations",
"version": "2.0.2",
"version": "2.0.3",
"author": {

@@ -25,3 +25,3 @@ "name": "DoneJS Team",

"jshint": "^2.9.1",
"steal": "^1.3.1",
"steal": "^2.0.0",
"steal-qunit": "^2.0.0",

@@ -28,0 +28,0 @@ "steal-tools": "^1.2.0",

@@ -209,8 +209,9 @@ var unit = require('steal-qunit');

var called = false;
domMutate.onNodeConnected(wrapper, function () {
var teardown = domMutate.onNodeConnected(wrapper, function () {
teardown();
called = true;
});
node.appendChild.call(parent, wrapper);
domMutate.flushRecords();

@@ -221,2 +222,87 @@ assert.ok(called, "insertion run immediately");

test('onDisconnected after onConnected', function(assert){
var done = assert.async();
var doc = globals.getKeyValue('document');
var parent = testUtils.getFixture();
var wrapper = doc.createElement("div");
var called = false;
var disconnectTeardown = domMutate.onNodeDisconnected(wrapper, function(){
assert.ok(called, "connected called before disconnected");
done();
disconnectTeardown();
});
var connectedTeardown = domMutate.onNodeConnected(wrapper, function () {
called = true;
assert.ok(true, "connected called");
connectedTeardown();
});
node.appendChild.call(parent, wrapper); // problem here is that it's removed
node.removeChild.call(parent, wrapper);
});
test('no double connected', function(assert){
assert.expect(1);
var done = assert.async();
var doc = globals.getKeyValue('document');
var outer = doc.createElement("div");
var inner = doc.createElement("div");
var connectedTeardown = domMutate.onNodeConnected(inner, function () {
assert.ok(true, "connected called");
setTimeout(function(){
connectedTeardown();
done();
},1);
});
var parent = testUtils.getFixture();
node.appendChild.call(parent, outer);
node.appendChild.call(outer, inner);
});
test("flushRecords while processing records issues changes in order", function(assert){
var done = assert.async();
var doc = globals.getKeyValue('document');
var parent = testUtils.getFixture();
var firstDiv = doc.createElement("div"),
secondDiv = doc.createElement("div"),
thirdDiv = doc.createElement("div");
var order = [];
var firstConnectedTeardown = domMutate.onNodeConnected(firstDiv, function () {
order.push("first");
node.appendChild.call(parent, thirdDiv);
domMutate.flushRecords();
firstConnectedTeardown();
});
var secondConnectedTeardown = domMutate.onNodeConnected(secondDiv, function () {
order.push("second");
secondConnectedTeardown();
});
var thirdConnectedTeardown = domMutate.onNodeConnected(thirdDiv, function () {
order.push("third");
assert.deepEqual(order, ["first","second","third"]);
order.push("third");
thirdConnectedTeardown();
done();
});
node.appendChild.call(parent, firstDiv);
node.appendChild.call(parent, secondDiv);
});
}

@@ -250,2 +336,1 @@

moduleMutationObserver('can-dom-mutate with SimpleDocument', makeSimpleDocument(), mutationObserverTests);

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
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc