Implement ChangeFlag.INSERTION notification to know when an item was inserted in a new parent inside the DOM.

This commit is contained in:
Jürg Lehni 2014-03-18 15:28:29 +01:00
parent 946e0d5b2c
commit aeeba4d58d
3 changed files with 43 additions and 21 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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);