From aeeba4d58db862595a3219c308c89057c8167628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Tue, 18 Mar 2014 15:28:29 +0100 Subject: [PATCH] Implement ChangeFlag.INSERTION notification to know when an item was inserted in a new parent inside the DOM. --- src/item/ChangeFlag.js | 24 ++++++++++++++---------- src/item/Item.js | 38 ++++++++++++++++++++++++++++---------- src/item/Layer.js | 2 +- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/item/ChangeFlag.js b/src/item/ChangeFlag.js index 00ed7e30..cd6b9591 100644 --- a/src/item/ChangeFlag.js +++ b/src/item/ChangeFlag.js @@ -14,25 +14,27 @@ var ChangeFlag = { // Anything affecting the appearance of an item, including GEOMETRY, // STROKE, STYLE and ATTRIBUTE (except for the invisible ones: locked, name) APPEARANCE: 0x1, - // Change in item hierarchy + // A change in the item's children CHILDREN: 0x2, + // A change in the item's place in the DOM (removed, inserted, moved). + INSERTION: 0x4, // Item geometry (path, bounds) - GEOMETRY: 0x4, - // Only segment(s) have changed, and affected curves have alredy been + GEOMETRY: 0x8, + // Only segment(s) have changed, and affected curves have already been // notified. This is to implement an optimization in _changed() calls. - SEGMENTS: 0x8, + SEGMENTS: 0x10, // Stroke geometry (excluding color) - STROKE: 0x10, + STROKE: 0x20, // Fill style or stroke color / dash - STYLE: 0x20, + STYLE: 0x40, // Item attributes: visible, blendMode, locked, name, opacity, clipMask ... - ATTRIBUTE: 0x40, + ATTRIBUTE: 0x80, // Text content - CONTENT: 0x80, + CONTENT: 0x100, // Raster pixels - PIXELS: 0x100, + PIXELS: 0x200, // Clipping in one of the child items - CLIPPING: 0x200 + CLIPPING: 0x400 }; // Shortcuts to often used ChangeFlag values including APPEARANCE @@ -40,6 +42,8 @@ var Change = { // CHILDREN also changes GEOMETRY, since removing children from groups // changes bounds. CHILDREN: ChangeFlag.CHILDREN | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE, + // Changing the insertion can change the appearance through parent's matrix. + INSERTION: ChangeFlag.INSERTION | ChangeFlag.APPEARANCE, GEOMETRY: ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE, SEGMENTS: ChangeFlag.SEGMENTS | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE, STROKE: ChangeFlag.STROKE | ChangeFlag.STYLE | ChangeFlag.APPEARANCE, diff --git a/src/item/Item.js b/src/item/Item.js index a355dcf0..7b1fdc8c 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -2006,10 +2006,15 @@ var Item = Base.extend(Callback, /** @lends Item# */{ if (_proto && !(item instanceof _proto)) { items.splice(i, 1); } else { - item._remove(true); + // Notify parent of change. Don't notify item itself yet, + // as we're doing so when adding it to the new parent below. + item._remove(false, true); } } Base.splice(children, items, index, 0); + var project = this._project, + // See #_remove() for an explanation of this: + notifySelf = project && project._changes; for (var i = 0, l = items.length; i < l; i++) { var item = items[i]; item._parent = this; @@ -2018,6 +2023,8 @@ var Item = Base.extend(Callback, /** @lends Item# */{ // are kept in sync. if (item._name) item.setName(item._name); + if (notifySelf) + this._changed(/*#=*/ Change.INSERTION); } this._changed(/*#=*/ Change.CHILDREN); } else { @@ -2164,16 +2171,24 @@ var Item = Base.extend(Callback, /** @lends Item# */{ /** * Removes the item from its parent's children list. */ - _remove: function(notify) { - if (this._parent) { + _remove: function(notifySelf, notifyParent) { + var parent = this._parent; + if (parent) { if (this._name) this._removeNamed(); if (this._index != null) - Base.splice(this._parent._children, null, this._index, 1); + Base.splice(parent._children, null, this._index, 1); this._installEvents(false); - // Notify parent of changed hierarchy - if (notify) - this._parent._changed(/*#=*/ Change.CHILDREN); + // Notify self of the insertion change. We only need this + // notification if we're tracking changes for now. + if (notifySelf) { + var project = this._project; + if (project && project._changes) + this._changed(/*#=*/ Change.INSERTION); + } + // Notify parent of changed children + if (notifyParent) + parent._changed(/*#=*/ Change.CHILDREN); this._parent = null; return true; } @@ -2187,7 +2202,8 @@ var Item = Base.extend(Callback, /** @lends Item# */{ * @return {Boolean} {@true if the item was removed} */ remove: function() { - return this._remove(true); + // Notify self and parent of change: + return this._remove(true, true); }, /** @@ -2217,8 +2233,10 @@ var Item = Base.extend(Callback, /** @lends Item# */{ // deletes it for the removed items. Calling #_remove() afterwards is // fine, since it only calls Base.splice() if #_index is set. var removed = Base.splice(this._children, null, from, to - from); - for (var i = removed.length - 1; i >= 0; i--) - removed[i]._remove(false); + for (var i = removed.length - 1; i >= 0; i--) { + // Don't notify parent each time, notify it separately after. + removed[i]._remove(true, false); + } if (removed.length > 0) this._changed(/*#=*/ Change.CHILDREN); return removed; diff --git a/src/item/Layer.js b/src/item/Layer.js index e4d6424e..fd4855fb 100644 --- a/src/item/Layer.js +++ b/src/item/Layer.js @@ -131,7 +131,7 @@ var Layer = Group.extend(/** @lends Layer# */{ // If the item is a layer and contained within Project#layers, use // our own version of move(). if (item instanceof Layer && !item._parent) { - this._remove(true); + this._remove(true, true); Base.splice(item._project.layers, [this], item._index + (above ? 1 : 0), 0); this._setProject(item._project, true);