diff --git a/src/Container.js b/src/Container.js index 6e7bb039..1dc26989 100644 --- a/src/Container.js +++ b/src/Container.js @@ -43,21 +43,6 @@ child.index = children.length; child.parent = this; children.push(child); - var stage = child.getStage(); - - if(!stage) { - go._addTempNode(child); - } - else { - stage._addId(child); - stage._addName(child); - - /* - * pull in other nodes that are now linked - * to a stage - */ - go._pullNodes(stage); - } // chainable return this; @@ -99,14 +84,14 @@ return collection; }, _getNodeById: function(key) { - var stage = this.getStage(); - if(stage.ids[key] !== undefined && this.isAncestorOf(stage.ids[key])) { - return stage.ids[key]; + var stage = this.getStage(), go = Kinetic.Global, node = go.ids[key]; + if(node !== undefined && this.isAncestorOf(node)) { + return node; } return null; }, _getNodesByName: function(key) { - var arr = this.getStage().names[key] || []; + var go = Kinetic.Global, arr = go.names[key] || []; return this._getDescendants(arr); }, _get: function(selector) { diff --git a/src/Global.js b/src/Global.js index c20a55a1..c48f1ef8 100644 --- a/src/Global.js +++ b/src/Global.js @@ -28,8 +28,7 @@ /** * @namespace */ -var Kinetic = {}; -(function() { +var Kinetic = {}; (function() { Kinetic.version = '@version'; /** * @namespace @@ -39,7 +38,8 @@ var Kinetic = {}; Kinetic.Global = { stages: [], idCounter: 0, - tempNodes: {}, + ids: {}, + names: {}, //shapes hash. rgb keys and shape values shapes: {}, warn: function(str) { @@ -58,22 +58,39 @@ var Kinetic = {}; } } }, - _pullNodes: function(stage) { - var tempNodes = this.tempNodes; - for(var key in tempNodes) { - var node = tempNodes[key]; - if(node.getStage() !== undefined && node.getStage()._id === stage._id) { - stage._addId(node); - stage._addName(node); - this._removeTempNode(node); - } + _addId: function(node, id) { + if(id !== undefined) { + this.ids[id] = node; } }, - _addTempNode: function(node) { - this.tempNodes[node._id] = node; + _removeId: function(id) { + if(id !== undefined) { + delete this.ids[id]; + } }, - _removeTempNode: function(node) { - delete this.tempNodes[node._id]; + _addName: function(node, name) { + if(name !== undefined) { + if(this.names[name] === undefined) { + this.names[name] = []; + } + this.names[name].push(node); + } + }, + _removeName: function(name, _id) { + if(name !== undefined) { + var nodes = this.names[name]; + if(nodes !== undefined) { + for(var n = 0; n < nodes.length; n++) { + var no = nodes[n]; + if(no._id === _id) { + nodes.splice(n, 1); + } + } + if(nodes.length === 0) { + delete this.names[name]; + } + } + } } }; })(); diff --git a/src/Node.js b/src/Node.js index d6ce32f1..60ffe9e4 100644 --- a/src/Node.js +++ b/src/Node.js @@ -55,23 +55,6 @@ this.setDefaultAttrs(this.defaultNodeAttrs); this.eventListeners = {}; this.setAttrs(config); - - // bind events - var that = this; - this.on('idChange.kinetic', function(evt) { - var stage = that.getStage(); - if(stage) { - stage._removeId(evt.oldVal); - stage._addId(that); - } - }); - this.on('nameChange.kinetic', function(evt) { - var stage = that.getStage(); - if(stage) { - stage._removeName(evt.oldVal, that._id); - stage._addName(that); - } - }); }, /** * bind events to the node. KineticJS supports mouseover, mousemove, @@ -167,22 +150,18 @@ * @methodOf Kinetic.Node.prototype */ destroy: function() { + var parent = this.getParent(), stage = this.getStage(), dd = Kinetic.DD, go = Kinetic.Global; + + this.remove(); + // destroy children while(this.children && this.children.length > 0) { this.children[0].destroy(); } - var parent = this.getParent(), stage = this.getStage(), dd = Kinetic.DD; - this.remove(); - - // remove ids and names hashes - if(stage) { - stage._removeId(this.getId()); - stage._removeName(this.getName(), this._id); - } - - // remove from temp nodes - Kinetic.Global._removeTempNode(this); + // remove from ids and names hashes + go._removeId(this.getId()); + go._removeName(this.getName(), this._id); // remove from DD if(dd && dd.node && dd.node._id === this._id) { @@ -558,16 +537,8 @@ * @param {Container} newContainer */ moveTo: function(newContainer) { - var parent = this.parent; - // remove from parent's children - parent.children.splice(this.index, 1); - parent._setChildrenIndices(); - - // add to new parent - newContainer.children.push(this); - this.index = newContainer.children.length - 1; - this.parent = newContainer; - newContainer._setChildrenIndices(); + Kinetic.Node.prototype.remove.call(this); + newContainer.add(this); }, /** * convert Node into an object for serialization. Returns an object. @@ -892,6 +863,30 @@ newVal: newVal }); }, + /** + * set id + * @name setId + * @methodOf Kinetic.Node.prototype + * @param {String} id + */ + setId: function(id) { + var oldId = this.getId(), stage = this.getStage(), go = Kinetic.Global; + go._removeId(oldId); + go._addId(this, id); + this.setAttr('id', id); + }, + /** + * set name + * @name setName + * @methodOf Kinetic.Node.prototype + * @param {String} name + */ + setName: function(name) { + var oldName = this.getName(), stage = this.getStage(), go = Kinetic.Global; + go._removeName(oldName, this._id); + go._addName(this, name); + this.setAttr('name', name); + }, setAttr: function(key, val) { if(val !== undefined) { var oldVal = this.attrs[key]; @@ -1090,7 +1085,7 @@ return no; }; // add getters setters - Kinetic.Node.addGettersSetters(Kinetic.Node, ['x', 'y', 'opacity', 'name', 'id']); + Kinetic.Node.addGettersSetters(Kinetic.Node, ['x', 'y', 'opacity']); /** * set x position @@ -1115,20 +1110,6 @@ * @param {Object} opacity */ - /** - * set name - * @name setName - * @methodOf Kinetic.Node.prototype - * @param {String} name - */ - - /** - * set id - * @name setId - * @methodOf Kinetic.Node.prototype - * @param {String} id - */ - /** * get x position * @name getX @@ -1147,6 +1128,8 @@ * @methodOf Kinetic.Node.prototype */ + Kinetic.Node.addGetters(Kinetic.Node, ['name', 'id']); + /** * get name * @name getName diff --git a/src/Stage.js b/src/Stage.js index 9b2329a5..b8018ca8 100644 --- a/src/Stage.js +++ b/src/Stage.js @@ -46,8 +46,6 @@ this._buildDOM(); this._bindContentEvents(); Kinetic.Global.stages.push(this); - this._addId(this); - this._addName(this); if(Kinetic.DD) { this._initDragLayer(); @@ -283,12 +281,6 @@ return null; }, - _getNodeById: function(key) { - return this.ids[key] || null; - }, - _getNodesByName: function(key) { - return this.names[key] || []; - }, _resizeDOM: function() { if(this.content) { var width = this.attrs.width; @@ -582,41 +574,6 @@ this._resizeDOM(); }, - _addId: function(node) { - if(node.attrs.id !== undefined) { - this.ids[node.attrs.id] = node; - } - }, - _removeId: function(id) { - if(id !== undefined) { - delete this.ids[id]; - } - }, - _addName: function(node) { - var name = node.attrs.name; - if(name !== undefined) { - if(this.names[name] === undefined) { - this.names[name] = []; - } - this.names[name].push(node); - } - }, - _removeName: function(name, _id) { - if(name !== undefined) { - var nodes = this.names[name]; - if(nodes !== undefined) { - for(var n = 0; n < nodes.length; n++) { - var no = nodes[n]; - if(no._id === _id) { - nodes.splice(n, 1); - } - } - if(nodes.length === 0) { - delete this.names[name]; - } - } - } - }, /** * bind event listener to container DOM element * @param {String} typesStr @@ -640,13 +597,6 @@ this.clickStart = false; this.touchPos = undefined; this.tapStart = false; - - /* - * ids and names hash needs to be stored at the stage level to prevent - * id and name collisions between multiple stages in the document - */ - this.ids = {}; - this.names = {}; } }; Kinetic.Global.extend(Kinetic.Stage, Kinetic.Container); diff --git a/tests/js/manualTests.js b/tests/js/manualTests.js index 8b15bb8f..b8930365 100644 --- a/tests/js/manualTests.js +++ b/tests/js/manualTests.js @@ -798,7 +798,8 @@ Test.Modules.MANUAL = { x: 5, y: 5 }, - draggable: true + draggable: true, + name: 'star' }); layer.add(star); diff --git a/tests/js/unit/containerTests.js b/tests/js/unit/containerTests.js index 6e78fa64..53d5e150 100644 --- a/tests/js/unit/containerTests.js +++ b/tests/js/unit/containerTests.js @@ -236,7 +236,7 @@ Test.Modules.CONTAINER = { fill: 'green', stroke: 'black', strokeWidth: 4, - id: 'myCircle' + id: 'myCircle3' }); var rect = new Kinetic.Rect({ @@ -247,23 +247,25 @@ Test.Modules.CONTAINER = { fill: 'purple', stroke: 'black', strokeWidth: 4, - name: 'myRect' + name: 'myRect3' }); layer.add(circle); layer.add(rect); stage.add(layer); + + var go = Kinetic.Global; - test(stage.ids['myCircle'].getId() === 'myCircle', 'circle id not in ids hash'); - test(stage.names['myRect'][0].getName() === 'myRect', 'rect name not in names hash'); + test(go.ids['myCircle3'].getId() === 'myCircle3', 'circle id not in ids hash'); + test(go.names['myRect3'][0].getName() === 'myRect3', 'rect name not in names hash'); circle.setId('newCircleId'); - test(stage.ids['newCircleId'] !== undefined, 'circle not in ids hash'); - test(stage.ids['myCircle'] === undefined, 'old circle id key is still in ids hash'); + test(go.ids['newCircleId'] !== undefined, 'circle not in ids hash'); + test(go.ids['myCircle3'] === undefined, 'old circle id key is still in ids hash'); rect.setName('newRectName'); - test(stage.names['newRectName'][0] !== undefined, 'new rect name not in names hash'); - test(stage.names['myRect'] === undefined, 'old rect name is still in names hash'); + test(go.names['newRectName'][0] !== undefined, 'new rect name not in names hash'); + test(go.names['myRect3'] === undefined, 'old rect name is still in names hash'); }, 'add layer': function(containerId) { var stage = new Kinetic.Stage({ diff --git a/tests/js/unit/nodeTests.js b/tests/js/unit/nodeTests.js index 2d9d37c0..b969fbf0 100644 --- a/tests/js/unit/nodeTests.js +++ b/tests/js/unit/nodeTests.js @@ -2252,20 +2252,14 @@ Test.Modules.NODE = { var go = Kinetic.Global; - test(go.tempNodes[circle._id] === undefined, 'circle shouldn\'t be in the temp nodes hash'); - layer.add(circle); var node = stage.get('#myCircle')[0]; test(node === undefined, 'node should be undefined'); - test(go.tempNodes[circle._id].attrs.id === 'myCircle', 'circle should be in temp nodes'); - circle.destroy(); - test(go.tempNodes[circle._id] === undefined, 'circle shouldn\'t be in the temp nodes hash'); - }, 'destroy layer with shape': function(containerId) { var stage = new Kinetic.Stage({ @@ -2288,7 +2282,7 @@ Test.Modules.NODE = { layer.add(circle); stage.add(layer); - + test(stage.children.length === 1, 'stage should have 1 children'); test(stage.get('.myLayer')[0] !== undefined, 'layer should exist'); test(stage.get('.myCircle')[0] !== undefined, 'circle should exist'); @@ -2472,7 +2466,7 @@ Test.Modules.NODE = { fill: 'green', stroke: 'black', strokeWidth: 4, - id: 'myCircle' + id: 'myCircle2' }); var rect = new Kinetic.Rect({ @@ -2483,32 +2477,33 @@ Test.Modules.NODE = { fill: 'purple', stroke: 'black', strokeWidth: 4, - name: 'myRect' + name: 'myRect2' }); var circleColorKey = circle.colorKey; var rectColorKey = rect.colorKey; + var go = Kinetic.Global; layer.add(circle); layer.add(rect); stage.add(layer); - test(stage.ids.myCircle._id === circle._id, 'circle not in ids hash'); - test(stage.names.myRect[0]._id === rect._id, 'rect not in names hash'); + test(go.ids.myCircle2._id === circle._id, 'circle not in ids hash'); + test(go.names.myRect2[0]._id === rect._id, 'rect not in names hash'); test(Kinetic.Global.shapes[circleColorKey]._id === circle._id, 'circle color key should be in shapes hash'); test(Kinetic.Global.shapes[rectColorKey]._id === rect._id, 'rect color key should be in shapes hash'); circle.destroy(); - test(stage.ids.myCircle === undefined, 'circle still in hash'); - test(stage.names.myRect[0]._id === rect._id, 'rect not in names hash'); + test(go.ids.myCircle2 === undefined, 'circle still in hash'); + test(go.names.myRect2[0]._id === rect._id, 'rect not in names hash'); test(Kinetic.Global.shapes[circleColorKey] === undefined, 'circle color key should not be in shapes hash'); test(Kinetic.Global.shapes[rectColorKey]._id === rect._id, 'rect color key should be in shapes hash'); rect.destroy(); - test(stage.ids.myCircle === undefined, 'circle still in hash'); - test(stage.names.myRect === undefined, 'rect still in hash'); + test(go.ids.myCircle2 === undefined, 'circle still in hash'); + test(go.names.myRect2 === undefined, 'rect still in hash'); test(Kinetic.Global.shapes[circleColorKey] === undefined, 'circle color key should not be in shapes hash'); test(Kinetic.Global.shapes[rectColorKey] === undefined, 'rect color key should not be in shapes hash'); }