Implement #insertAbove/Below using the new #insertChild, allowing the removal of one injection scope, and rearrange function sequence for documentation.

This commit is contained in:
Jürg Lehni 2011-06-17 17:35:26 +01:00
parent 69d7e026ba
commit ee0446fa4f

View file

@ -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}
*