From 080726fd2cc369d8faa967bb50c9f4ed77387c7c Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Fri, 3 Jan 2020 18:27:44 -0500 Subject: [PATCH 1/5] Restore live binding on placeholders that have been disconnected and reconnected --- lib/helpers.js | 47 +++++++++++++++++++++++++++++---------- lib/html.js | 6 +---- test/html-test.js | 56 +++++++++++++++++++++++++++++++++++++++++++++++ test/text-test.js | 53 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 17 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index 4dec395..3b3b7f6 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -9,13 +9,18 @@ var canDev = require("can-log/dev/dev"); var setElementSymbol = canSymbol.for("can.setElement"); var elementSymbol = canSymbol.for("can.element"); -function ListenUntilRemovedAndInitialize(observable, handler, placeholder, queueName, handlerName, afterTeardownNodeRemoved) { +function ListenUntilRemovedAndInitialize( + observable, + handler, + placeholder, + queueName, + handlerName +) { this.observable = observable; this.handler = handler; this.placeholder = placeholder; this.queueName = queueName; this.handler[elementSymbol] = placeholder; - this.afterTeardownNodeRemoved = afterTeardownNodeRemoved; if( observable[setElementSymbol] ) { observable[setElementSymbol](placeholder); @@ -40,24 +45,42 @@ function ListenUntilRemovedAndInitialize(observable, handler, placeholder, queue value: handlerName, }); - canReflectDeps.addMutatedBy(placeholder, observable); } //!steal-remove-end - this.teardownNodeRemoved = domMutate.onNodeRemoved(placeholder, + this.setup(); +} +ListenUntilRemovedAndInitialize.prototype.setup = function() { + // reinsertion case, not applicable during initial setup + if(this.setupNodeReinserted) { + // do not set up again if disconnected + if(!this.placeholder.isConnected) { + return; + } + this.setupNodeReinserted(); + } + this.teardownNodeRemoved = domMutate.onNodeRemoved(this.placeholder, this.teardown.bind(this)); - canReflect.onValue(observable, handler, queueName); - // data = live.listen(parentNode, compute, liveHTMLUpdateHTML); - handler( canReflect.getValue(observable) ); -} -ListenUntilRemovedAndInitialize.prototype.teardown = function(){ - this.teardownNodeRemoved(); + //!steal-remove-start + if(process.env.NODE_ENV !== 'production') { + canReflectDeps.addMutatedBy(this.placeholder, this.observable); + } + //!steal-remove-end + + canReflect.onValue(this.observable, this.handler, this.queueName); + this.handler( canReflect.getValue(this.observable) ); - if (this.afterTeardownNodeRemoved) { - this.afterTeardownNodeRemoved(); +}; +ListenUntilRemovedAndInitialize.prototype.teardown = function(){ + // do not teardown if still connected. + if(this.placeholder.isConnected) { + return; } + this.teardownNodeRemoved(); + this.setupNodeReinserted = domMutate.onNodeInserted(this.placeholder, + this.setup.bind(this)); //!steal-remove-start if(process.env.NODE_ENV !== 'production') { diff --git a/lib/html.js b/lib/html.js index e4ebb72..db2abed 100644 --- a/lib/html.js +++ b/lib/html.js @@ -65,10 +65,6 @@ module.exports = function(el, compute, viewInsertSymbolOptions) { } //!steal-remove-end - var doNotUpdateRange = function() { - queues.domQueue.dequeue(updateRange); - }; - if (el.nodeType !== Node.COMMENT_NODE) { var commentFrag = makeCommentFragment(observableName); var startCommentNode = commentFrag.firstChild; @@ -109,6 +105,6 @@ module.exports = function(el, compute, viewInsertSymbolOptions) { }, range.start, "dom", - "live.html replace::" + observableName, doNotUpdateRange); + "live.html replace::" + observableName); }; diff --git a/test/html-test.js b/test/html-test.js index 359969c..062507e 100644 --- a/test/html-test.js +++ b/test/html-test.js @@ -10,9 +10,23 @@ var canSymbol = require('can-symbol'); var fragment = require("can-fragment"); var queues = require("can-queues"); var domMutateNode = require("can-dom-mutate/node/node"); +var canGlobals = require("can-globals"); QUnit.module("can-view-live.html"); +var afterMutation = function(cb) { + var doc = canGlobals.getKeyValue("document"); + var div = doc.createElement("div"); + var insertionDisposal = domMutate.onNodeInsertion(div, function(){ + insertionDisposal(); + doc.body.removeChild(div); + setTimeout(cb, 5); + }); + setTimeout(function(){ + domMutateNode.appendChild.call(doc.body, div); + }, 10); + }; + QUnit.test('basics', function(assert) { var div = document.createElement('div'), span = document.createElement('span'); @@ -274,3 +288,45 @@ QUnit.test("tearing down a .html inside another .html works", function(assert) { assert.deepEqual(ifPersonFrag.childNodes.length, 3, "nodes torn down correctly"); assert.deepEqual(ifPersonFrag.childNodes[1].textContent, "", "placeholder text node correct"); }); + +QUnit.test('Live binding is restored when the placeholder is reconnected', function(assert) { + var done = assert.async(); + + var div = document.createElement('div'), + span = document.createElement('span'); + document.getElementById("qunit-fixture").appendChild(div); + + div.appendChild(span); + var items = new DefineList([ + 'one', + 'two' + ]); + + var html = new Observation(function itemsHTML() { + var html = ''; + items.forEach(function (item) { + html += ''; + }); + return html; + }); + live.html(span, html); + assert.equal(div.getElementsByTagName('label').length, 2); + var commentChildren = Array.from(div.childNodes).filter(function(node) { + return node.nodeType === Node.COMMENT_NODE; + }); + div.removeChild(commentChildren[0]); + div.removeChild(commentChildren[1]); + + afterMutation(function() { + items.push('three'); + + div.insertBefore(commentChildren[0], div.firstChild); + div.appendChild(commentChildren[1]); + + afterMutation(function() { + console.log( document.getElementById("qunit-fixture").innerHTML); + assert.equal(div.getElementsByTagName('label').length, 3); + done(); + }) + }); +}); diff --git a/test/text-test.js b/test/text-test.js index 20ecd23..6ada748 100644 --- a/test/text-test.js +++ b/test/text-test.js @@ -15,6 +15,18 @@ QUnit.module("can-view-live.text", { } }); +var afterMutation = function(cb) { + var doc = canGlobals.getKeyValue("document"); + var div = doc.createElement("div"); + var insertionDisposal = domMutate.onNodeInsertion(div, function(){ + insertionDisposal(); + doc.body.removeChild(div); + setTimeout(cb, 5); + }); + setTimeout(function(){ + domMutateNode.appendChild.call(doc.body, div); + }, 10); + }; var esc = function(str) { return str.replace(/ Date: Fri, 3 Jan 2020 18:29:17 -0500 Subject: [PATCH 2/5] placate linter --- lib/html.js | 1 - test/html-test.js | 2 +- test/text-test.js | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/html.js b/lib/html.js index db2abed..749f345 100644 --- a/lib/html.js +++ b/lib/html.js @@ -3,7 +3,6 @@ var makeFragment = require('can-fragment'); var canReflect = require('can-reflect'); var canSymbol = require("can-symbol"); -var queues = require("can-queues"); var helpers = require('./helpers'); var getDocument = require('can-globals/document/document'); diff --git a/test/html-test.js b/test/html-test.js index 062507e..18d0ccd 100644 --- a/test/html-test.js +++ b/test/html-test.js @@ -327,6 +327,6 @@ QUnit.test('Live binding is restored when the placeholder is reconnected', funct console.log( document.getElementById("qunit-fixture").innerHTML); assert.equal(div.getElementsByTagName('label').length, 3); done(); - }) + }); }); }); diff --git a/test/text-test.js b/test/text-test.js index 6ada748..d02199a 100644 --- a/test/text-test.js +++ b/test/text-test.js @@ -165,7 +165,7 @@ QUnit.test('Live binding is restored when the text node is reconnected', functio assert.equal(div.innerHTML, 'four'); done(); - }) + }); }); }); }); From eb103ad9df3e2c403b0e00c6e55ba7d865c1bead Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Fri, 3 Jan 2020 18:46:50 -0500 Subject: [PATCH 3/5] Use isConnected from can-dom-mutate for IE compat --- lib/helpers.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index 3b3b7f6..bb755a7 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -5,6 +5,7 @@ var canReflect = require("can-reflect"); var canReflectDeps = require('can-reflect-dependencies'); var parser = require('can-view-parser'); var canDev = require("can-log/dev/dev"); +var isConnected = require("can-dom-mutate/-is-connected"); var setElementSymbol = canSymbol.for("can.setElement"); var elementSymbol = canSymbol.for("can.element"); @@ -54,7 +55,7 @@ ListenUntilRemovedAndInitialize.prototype.setup = function() { // reinsertion case, not applicable during initial setup if(this.setupNodeReinserted) { // do not set up again if disconnected - if(!this.placeholder.isConnected) { + if(!isConnected.isConnected(this.placeholder)) { return; } this.setupNodeReinserted(); @@ -75,7 +76,7 @@ ListenUntilRemovedAndInitialize.prototype.setup = function() { }; ListenUntilRemovedAndInitialize.prototype.teardown = function(){ // do not teardown if still connected. - if(this.placeholder.isConnected) { + if(isConnected.isConnected(this.placeholder)) { return; } this.teardownNodeRemoved(); From c1472f9f655b7b83a4a90714c67d8e53f4435faf Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Fri, 3 Jan 2020 18:51:56 -0500 Subject: [PATCH 4/5] Use Array.prototype.slice instead of Array.from for IE --- test/html-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/html-test.js b/test/html-test.js index 18d0ccd..48a7e6c 100644 --- a/test/html-test.js +++ b/test/html-test.js @@ -311,7 +311,7 @@ QUnit.test('Live binding is restored when the placeholder is reconnected', funct }); live.html(span, html); assert.equal(div.getElementsByTagName('label').length, 2); - var commentChildren = Array.from(div.childNodes).filter(function(node) { + var commentChildren = [].slice.call(div.childNodes, 0).filter(function(node) { return node.nodeType === Node.COMMENT_NODE; }); div.removeChild(commentChildren[0]); From 0d970dc3b2c03ba43058e707c4ba4249a970aed6 Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Mon, 6 Jan 2020 13:28:53 -0500 Subject: [PATCH 5/5] update can-dom-mutate for IE11 fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6674489..b5f546d 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "can-attribute-observable": "^2.0.0", "can-child-nodes": "^1.0.0", "can-diff": "^1.5.0", - "can-dom-mutate": "^2.0.0", + "can-dom-mutate": "^2.0.8", "can-fragment": "^1.0.0", "can-observation": "^4.2.0", "can-queues": "^1.3.0",