From ee0446fa4f3ecfc7f1130b0417ccb648ccc09687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Fri, 17 Jun 2011 17:35:26 +0100 Subject: [PATCH] Implement #insertAbove/Below using the new #insertChild, allowing the removal of one injection scope, and rearrange function sequence for documentation. --- src/item/Item.js | 458 +++++++++++++++++++++++------------------------ 1 file changed, 222 insertions(+), 236 deletions(-) diff --git a/src/item/Item.js b/src/item/Item.js index 66b5c6c9..904b602c 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -510,6 +510,216 @@ var Item = this.Item = Base.extend({ return this._index; }, + /** + * Clones the item within the same project and places the copy above the + * item. + * + * @return {Item} the newly cloned item + * + * @example {@paperscript} + * // Cloning items: + * var circle = new Path.Circle(new Point(50, 50), 10); + * circle.fillColor = 'red'; + * + * // Make 20 copies of the circle: + * for (var i = 0; i < 20; i++) { + * var copy = circle.clone(); + * + * // Distribute the copies horizontally, so we can see them: + * copy.position.x += i * copy.bounds.width; + * } + */ + clone: function() { + return this._clone(new this.constructor()); + }, + + _clone: function(copy) { + // Copy over style + copy.setStyle(this._style); + // If this item has children, clone and append each of them: + if (this._children) { + for (var i = 0, l = this._children.length; i < l; i++) + copy.addChild(this._children[i].clone()); + } + // Only copy over these fields if they are actually defined in 'this' + // TODO: Consider moving this to Base once it's useful in more than one + // place + var keys = ['locked', 'visible', 'opacity', 'blendMode', '_clipMask', + '_selected']; + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + if (this.hasOwnProperty(key)) + copy[key] = this[key]; + } + // Insert the clone above the original, at the same position. + copy.insertAbove(this); + // Only set name once the copy is moved, to avoid setting and unsettting + // name related structures. + if (this._name) + copy.setName(this._name); + return copy; + }, + + /** + * When passed a project, copies the item to the project, + * or duplicates it within the same project. When passed an item, + * copies the item into the specified item. + * + * @param {Project|Layer|Group|CompoundPath} item the item or project to + * copy the item to + * @return {Item} the new copy of the item + */ + copyTo: function(itemOrProject) { + var copy = this.clone(); + if (itemOrProject.layers) { + itemOrProject.activeLayer.addChild(copy); + } else { + itemOrProject.addChild(copy); + } + return copy; + }, + + /** + * Rasterizes the item into a newly created Raster object. The item itself + * is not removed after rasterization. + * + * @param {Number} [resolution=72] the resolution of the raster in dpi + * @return {Raster} the newly created raster item + * + * @example {@paperscript} + * // Rasterizing an item: + * var circle = new Path.Circle(new Point(80, 50), 5); + * circle.fillColor = 'red'; + * + * // Create a rasterized version of the path: + * var raster = circle.rasterize(); + * + * // Move it 100pt to the right: + * raster.position.x += 100; + * + * // Scale the path and the raster by 300%, so we can compare them: + * circle.scale(5); + * raster.scale(5); + */ + rasterize: function(resolution) { + // TODO: why would we want to pass a size to rasterize? Seems to produce + // weird results on Scriptographer. Also we can't use antialiasing, since + // Canvas doesn't support it yet. Project colorMode is also out of the + // question for now. + var bounds = this.getStrokeBounds(), + scale = (resolution || 72) / 72, + canvas = CanvasProvider.getCanvas(bounds.getSize().multiply(scale)), + ctx = canvas.getContext('2d'), + matrix = new Matrix().scale(scale).translate(-bounds.x, -bounds.y); + matrix.applyToContext(ctx); + this.draw(ctx, {}); + var raster = new Raster(canvas); + raster.setPosition(this.getPosition()); + raster.scale(1 / scale); + return raster; + }, + + /** + * {@grouptitle Hierarchy Operations} + * Adds the specified item as a child of the item at the end of the + * its children list. You can use this function for groups, compound + * paths and layers. + * + * @param {Item} item The item that will be added as a child + */ + addChild: function(item) { + return this.insertChild(undefined, item); + }, + + /** + * Inserts the specified item as a child of the item at the specified + * index in its {@link #children} list. You can use this function for + * groups, compound paths and layers. + * + * @param {Number} index + * @param {Item} item The item that will be appended as a child + */ + insertChild: function(index, item) { + if (this._children) { + item._removeFromParent(); + Base.splice(this._children, [item], index, 0); + item._parent = this; + item._setProject(this._project); + if (item._name) + item.setName(item._name); + return true; + } + return false; + }, + + /** + * Inserts this item above the specified item. + * + * @param {Item} item The item above which it should be moved + * @return {Boolean} {@true it was inserted} + */ + insertAbove: function(item) { + return item._parent && item._parent.insertChild( + item._index + 1, this); + }, + + /** + * Inserts this item below the specified item. + * + * @param {Item} item The item above which it should be moved + * @return {Boolean} {@true it was inserted} + */ + insertBelow: function(item) { + return item._parent && item._parent.insertChild( + item._index - 1, this); + }, + + /** + * Inserts the specified item as a child of the item by appending it to + * the list of children and moving it above all other children. You can + * use this function for groups, compound paths and layers. + * + * @param {Item} item The item that will be appended as a child + * @deprecated use {@link #addChild(item)} instead. + */ + appendTop: function(item) { + return this.addChild(item); + }, + + /** + * Inserts the specified item as a child of this item by appending it to + * the list of children and moving it below all other children. You can + * use this function for groups, compound paths and layers. + * + * @param {Item} item The item that will be appended as a child + * @deprecated use {@link #insertChild(index, item)} instead. + */ + appendBottom: function(item) { + return this.insertChild(0, item); + }, + + /** + * Moves this item above the specified item. + * + * @param {Item} item The item above which it should be moved + * @return {Boolean} {@true it was moved} + * @deprecated use {@link #insertAbove(item)} instead. + */ + moveAbove: function(item) { + return this.insertAbove(item); + }, + + /** + * Moves the item below the specified item. + * + * @param {Item} item the item below which it should be moved + * @return {Boolean} {@true it was moved} + * @deprecated use {@link #insertBelow(item)} instead. + */ + moveBelow: function(item) { + return this.insertBelow(item); + }, + _removeFromNamed: function() { var children = this._parent._children, namedChildren = this._parent._namedChildren, @@ -573,75 +783,6 @@ var Item = this.Item = Base.extend({ return removed; }, - /** - * When passed a project, copies the item to the project, - * or duplicates it within the same project. When passed an item, - * copies the item into the specified item. - * - * @param {Project|Layer|Group|CompoundPath} item the item or project to - * copy the item to - * @return {Item} the new copy of the item - */ - copyTo: function(itemOrProject) { - var copy = this.clone(); - if (itemOrProject.layers) { - itemOrProject.activeLayer.addChild(copy); - } else { - itemOrProject.addChild(copy); - } - return copy; - }, - - /** - * Clones the item within the same project and places the copy above the - * item. - * - * @return {Item} the newly cloned item - * - * @example {@paperscript} - * // Cloning items: - * var circle = new Path.Circle(new Point(50, 50), 10); - * circle.fillColor = 'red'; - * - * // Make 20 copies of the circle: - * for (var i = 0; i < 20; i++) { - * var copy = circle.clone(); - * - * // Distribute the copies horizontally, so we can see them: - * copy.position.x += i * copy.bounds.width; - * } - */ - clone: function() { - return this._clone(new this.constructor()); - }, - - _clone: function(copy) { - // Copy over style - copy.setStyle(this._style); - // If this item has children, clone and append each of them: - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - copy.addChild(this._children[i].clone()); - } - // Only copy over these fields if they are actually defined in 'this' - // TODO: Consider moving this to Base once it's useful in more than one - // place - var keys = ['locked', 'visible', 'opacity', 'blendMode', '_clipMask', - '_selected']; - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - if (this.hasOwnProperty(key)) - copy[key] = this[key]; - } - // Insert the clone above the original, at the same position. - copy.insertAbove(this); - // Only set name once the copy is moved, to avoid setting and unsettting - // name related structures. - if (this._name) - copy.setName(this._name); - return copy; - }, - /** * Reverses the order of the item's children */ @@ -654,59 +795,10 @@ var Item = this.Item = Base.extend({ } }, - /** - * Rasterizes the item into a newly created Raster object. The item itself - * is not removed after rasterization. - * - * @param {Number} [resolution=72] the resolution of the raster in dpi - * @return {Raster} the newly created raster item - * - * @example {@paperscript} - * // Rasterizing an item: - * var circle = new Path.Circle(new Point(80, 50), 5); - * circle.fillColor = 'red'; - * - * // Create a rasterized version of the path: - * var raster = circle.rasterize(); - * - * // Move it 100pt to the right: - * raster.position.x += 100; - * - * // Scale the path and the raster by 300%, so we can compare them: - * circle.scale(5); - * raster.scale(5); - */ - rasterize: function(resolution) { - // TODO: why would we want to pass a size to rasterize? Seems to produce - // weird results on Scriptographer. Also we can't use antialiasing, since - // Canvas doesn't support it yet. Project colorMode is also out of the - // question for now. - var bounds = this.getStrokeBounds(), - scale = (resolution || 72) / 72, - canvas = CanvasProvider.getCanvas(bounds.getSize().multiply(scale)), - ctx = canvas.getContext('2d'), - matrix = new Matrix().scale(scale).translate(-bounds.x, -bounds.y); - matrix.applyToContext(ctx); - this.draw(ctx, {}); - var raster = new Raster(canvas); - raster.setPosition(this.getPosition()); - raster.scale(1 / scale); - return raster; - }, - - /** - * {@grouptitle Tests} - * Checks if the item contains any children items. - * - * @return {Boolean} {@true it has one or more children} - */ - hasChildren: function() { - return this._children && this._children.length > 0; - }, - // TODO: Item#isEditable is currently ignored in the documentation, as // locking an item currently has no effect /** + * {@grouptitle Tests} * Checks whether the item is editable. * * @return {Boolean} {@true when neither the item, nor its parents are @@ -756,6 +848,17 @@ var Item = this.Item = Base.extend({ return 0; }, + /** + * {@grouptitle Hierarchy Tests} + * + * Checks if the item contains any children items. + * + * @return {Boolean} {@true it has one or more children} + */ + hasChildren: function() { + return this._children && this._children.length > 0; + }, + /** * Checks if this item is above the specified item in the stacking order * of the project. @@ -779,7 +882,6 @@ var Item = this.Item = Base.extend({ }, /** - * {@grouptitle Hierarchy Tests} * Checks whether the specified item is the parent of the item. * * @param {Item} item The item to check against @@ -1372,122 +1474,6 @@ var Item = this.Item = Base.extend({ } } }, new function() { - - function move(above) { - return function(item) { - // first remove the item from its parent's children list - if (item._parent && this._removeFromParent()) { - Base.splice(item._parent._children, [this], - item._index + (above ? 1 : -1), 0); - this._parent = item._parent; - this._setProject(item._project); - if (item._name) - item.setName(item._name); - return true; - } - return false; - }; - } - - return { - /** @lends Item# */ - - /** - * {@grouptitle Hierarchy Operations} - * Adds the specified item as a child of the item at the end of the - * its children list. You can use this function for groups, compound - * paths and layers. - * - * @param {Item} item The item that will be added as a child - */ - addChild: function(item) { - return this.insertChild(undefined, item); - }, - - /** - * Inserts the specified item as a child of the item at the specified - * index in its {@link #children} list. You can use this function for - * groups, compound paths and layers. - * - * @param {Number} index - * @param {Item} item The item that will be appended as a child - */ - insertChild: function(index, item) { - if (this._children) { - item._removeFromParent(); - Base.splice(this._children, [item], index, 0); - item._parent = this; - item._setProject(this._project); - if (item._name) - item.setName(item._name); - return true; - } - return false; - }, - - /** - * Inserts this item above the specified item. - * - * @function - * @param {Item} item The item above which it should be moved - * @return {Boolean} {@true it was inserted} - */ - insertAbove: move(true), - - /** - * Inserts this item below the specified item. - * - * @function - * @param {Item} item The item above which it should be moved - * @return {Boolean} {@true it was inserted} - */ - insertBelow: move(false), - - /** - * Inserts the specified item as a child of the item by appending it to - * the list of children and moving it above all other children. You can - * use this function for groups, compound paths and layers. - * - * @param {Item} item The item that will be appended as a child - * @deprecated use {@link #addChild(item)} instead. - */ - appendTop: function(item) { - return this.addChild(item); - }, - - /** - * Inserts the specified item as a child of this item by appending it to - * the list of children and moving it below all other children. You can - * use this function for groups, compound paths and layers. - * - * @param {Item} item The item that will be appended as a child - * @deprecated use {@link #insertChild(index, item)} instead. - */ - appendBottom: function(item) { - return this.insertChild(0, item); - }, - - /** - * Moves this item above the specified item. - * - * @function - * @param {Item} item The item above which it should be moved - * @return {Boolean} {@true it was moved} - * @deprecated use {@link #insertAbove(item)} instead. - */ - moveAbove: move(true), - - /** - * Moves the item below the specified item. - * - * @function - * @param {Item} item the item below which it should be moved - * @return {Boolean} {@true it was moved} - * @deprecated use {@link #insertBelow(item)} instead. - */ - moveBelow: move(false) - }; -}, new function() { /** * {@grouptitle Remove On Event} *