diff --git a/lib/helpers.js b/lib/helpers.js index 4dec395..bb755a7 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -5,17 +5,23 @@ 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"); -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 +46,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(!isConnected.isConnected(this.placeholder)) { + 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(isConnected.isConnected(this.placeholder)) { + 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..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'); @@ -65,10 +64,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 +104,6 @@ module.exports = function(el, compute, viewInsertSymbolOptions) { }, range.start, "dom", - "live.html replace::" + observableName, doNotUpdateRange); + "live.html replace::" + observableName); }; 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", diff --git a/test/html-test.js b/test/html-test.js index 359969c..48a7e6c 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 = [].slice.call(div.childNodes, 0).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..d02199a 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(/