mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-29 09:22:22 -05:00
Implement Base.readSupported() and improve argument reading in Shape
This commit is contained in:
parent
2b62eb5cfa
commit
dacfce0498
3 changed files with 82 additions and 34 deletions
|
@ -98,11 +98,13 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
arg0.width || 0, arg0.height || 0);
|
arg0.width || 0, arg0.height || 0);
|
||||||
read = 1;
|
read = 1;
|
||||||
} else if (arg0.from === undefined && arg0.to === undefined) {
|
} else if (arg0.from === undefined && arg0.to === undefined) {
|
||||||
// Use Base.filter() to support whatever property the rectangle
|
// Use `Base.readSupported()` to read and consume whatever
|
||||||
// can take, but handle from/to separately below.
|
// property the rectangle can receive, but handle `from` / `to`
|
||||||
|
// separately below.
|
||||||
this._set(0, 0, 0, 0);
|
this._set(0, 0, 0, 0);
|
||||||
Base.filter(this, arg0);
|
if (Base.readSupported(arguments, this)) {
|
||||||
read = 1;
|
read = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (read === undefined) {
|
if (read === undefined) {
|
||||||
|
@ -141,13 +143,13 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
||||||
}
|
}
|
||||||
this._set(x, y, width, height);
|
this._set(x, y, width, height);
|
||||||
read = arguments.__index;
|
read = arguments.__index;
|
||||||
// arguments.__filtered wouldn't survive the function call even if a
|
|
||||||
// previous arguments list was passed through Function#apply().
|
|
||||||
// Return it on the object instead, see Base.read()
|
|
||||||
var filtered = arguments.__filtered;
|
|
||||||
if (filtered)
|
|
||||||
this.__filtered = filtered;
|
|
||||||
}
|
}
|
||||||
|
// arguments.__filtered wouldn't survive the function call even if a
|
||||||
|
// previous arguments list was passed through Function#apply().
|
||||||
|
// Return it on the object instead, see Base.read()
|
||||||
|
var filtered = arguments.__filtered;
|
||||||
|
if (filtered)
|
||||||
|
this.__filtered = filtered;
|
||||||
if (this.__read)
|
if (this.__read)
|
||||||
this.__read = read;
|
this.__read = read;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -269,11 +269,11 @@ statics: /** @lends Base */{
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows using of Base.read() mechanism in combination with reading named
|
* Allows using of `Base.read()` mechanism in combination with reading named
|
||||||
* arguments form a passed property object literal. Calling Base.readNamed()
|
* arguments form a passed property object literal. Calling
|
||||||
* can read both from such named properties and normal unnamed arguments
|
* `Base.readNamed()` can read both from such named properties and normal
|
||||||
* through Base.read(). In use for example for the various
|
* unnamed arguments through `Base.read()`. In use for example for
|
||||||
* Path.Constructors.
|
* the various `Path` constructors in `Path.Constructors.js`.
|
||||||
*
|
*
|
||||||
* @param {Array} list the list to read from, either an arguments object or
|
* @param {Array} list the list to read from, either an arguments object or
|
||||||
* a normal array
|
* a normal array
|
||||||
|
@ -287,24 +287,68 @@ statics: /** @lends Base */{
|
||||||
*/
|
*/
|
||||||
readNamed: function(list, name, start, options, amount) {
|
readNamed: function(list, name, start, options, amount) {
|
||||||
var value = this.getNamed(list, name),
|
var value = this.getNamed(list, name),
|
||||||
hasObject = value !== undefined;
|
hasValue = value !== undefined;
|
||||||
if (hasObject) {
|
if (hasValue) {
|
||||||
// Create a _filtered object that inherits from list[0], and
|
// Create a _filtered object that inherits from `source`, and
|
||||||
// override all fields that were already read with undefined.
|
// override all fields that were already read with undefined.
|
||||||
var filtered = list.__filtered;
|
var filtered = list.__filtered;
|
||||||
if (!filtered) {
|
if (!filtered) {
|
||||||
filtered = list.__filtered = Base.create(list[0]);
|
var source = this.getSource(list);
|
||||||
// Point _unfiltered to the original so Base#_set() can
|
filtered = list.__filtered = Base.create(source);
|
||||||
// execute hasOwnProperty on it.
|
// Point __unfiltered to the original, so `Base.filter()` can
|
||||||
filtered.__unfiltered = list[0];
|
// use it to get all keys to iterate over.
|
||||||
|
filtered.__unfiltered = source;
|
||||||
}
|
}
|
||||||
// delete wouldn't work since the masked parent's value would
|
// delete wouldn't work since the masked parent's value would
|
||||||
// shine through.
|
// shine through.
|
||||||
filtered[name] = undefined;
|
filtered[name] = undefined;
|
||||||
}
|
}
|
||||||
var l = hasObject ? [value] : list,
|
return this.read(hasValue ? [value] : list, start, options, amount);
|
||||||
res = this.read(l, start, options, amount);
|
},
|
||||||
return res;
|
|
||||||
|
/**
|
||||||
|
* If `list[0]` is a source object, calls `Base.readNamed()` for each key in
|
||||||
|
* it that is supported on `dest`, consuming these values.
|
||||||
|
*
|
||||||
|
* @param {Array} list the list to read from, either an arguments object or
|
||||||
|
* a normal array
|
||||||
|
* @param {Object} dest the object on which to set the supported properties
|
||||||
|
* @return {Boolean} {@true if any property was read from the source object}
|
||||||
|
*/
|
||||||
|
readSupported: function(list, dest) {
|
||||||
|
var source = this.getSource(list),
|
||||||
|
that = this,
|
||||||
|
read = false;
|
||||||
|
if (source) {
|
||||||
|
// If `source` is a filtered object, we get the keys from the the
|
||||||
|
// original object (it's parent / prototype). See _filtered
|
||||||
|
// inheritance trick in the argument reading code.
|
||||||
|
Object.keys(source).forEach(function(key) {
|
||||||
|
if (key in dest) {
|
||||||
|
var value = that.readNamed(list, key);
|
||||||
|
// Due to the _filtered inheritance trick, undefined is used
|
||||||
|
// to mask already consumed named arguments.
|
||||||
|
if (value !== undefined) {
|
||||||
|
dest[key] = value;
|
||||||
|
}
|
||||||
|
read = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the arguments object if the list provides one at `list[0]`
|
||||||
|
*/
|
||||||
|
getSource: function(list) {
|
||||||
|
var source = list.__source;
|
||||||
|
if (source === undefined) {
|
||||||
|
var arg = list.length === 1 && list[0];
|
||||||
|
source = list.__source = arg && Base.isPlainObject(arg)
|
||||||
|
? arg : null;
|
||||||
|
}
|
||||||
|
return source;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -314,12 +358,11 @@ statics: /** @lends Base */{
|
||||||
* provided, it returns the whole arguments object
|
* provided, it returns the whole arguments object
|
||||||
*/
|
*/
|
||||||
getNamed: function(list, name) {
|
getNamed: function(list, name) {
|
||||||
var arg = list[0];
|
var source = this.getSource(list);
|
||||||
if (list._hasObject === undefined)
|
if (source) {
|
||||||
list._hasObject = list.length === 1 && Base.isPlainObject(arg);
|
|
||||||
if (list._hasObject)
|
|
||||||
// Return the whole arguments object if no name is provided.
|
// Return the whole arguments object if no name is provided.
|
||||||
return name ? arg[name] : list.__filtered || arg;
|
return name ? source[name] : list.__filtered || source;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -82,7 +82,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
||||||
setSize: function(/* size */) {
|
setSize: function(/* size */) {
|
||||||
var size = Size.read(arguments);
|
var size = Size.read(arguments);
|
||||||
if (!this._size) {
|
if (!this._size) {
|
||||||
// First time, e.g. whean reading from JSON...
|
// First time, e.g. when reading from JSON...
|
||||||
this._size = size.clone();
|
this._size = size.clone();
|
||||||
} else if (!this._size.equals(size)) {
|
} else if (!this._size.equals(size)) {
|
||||||
var type = this._type,
|
var type = this._type,
|
||||||
|
@ -101,8 +101,8 @@ var Shape = Item.extend(/** @lends Shape# */{
|
||||||
this._radius._set(width / 2, height / 2);
|
this._radius._set(width / 2, height / 2);
|
||||||
}
|
}
|
||||||
this._size._set(width, height);
|
this._size._set(width, height);
|
||||||
|
this._changed(/*#=*/Change.GEOMETRY);
|
||||||
}
|
}
|
||||||
this._changed(/*#=*/Change.GEOMETRY);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,7 +130,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
||||||
} else {
|
} else {
|
||||||
radius = Size.read(arguments);
|
radius = Size.read(arguments);
|
||||||
if (!this._radius) {
|
if (!this._radius) {
|
||||||
// First time, e.g. whean reading from JSON...
|
// First time, e.g. when reading from JSON...
|
||||||
this._radius = radius.clone();
|
this._radius = radius.clone();
|
||||||
} else {
|
} else {
|
||||||
if (this._radius.equals(radius))
|
if (this._radius.equals(radius))
|
||||||
|
@ -390,10 +390,13 @@ new function() { // Scope for _contains() and _hitTestSelf() code.
|
||||||
// Mess with indentation in order to get more line-space below:
|
// Mess with indentation in order to get more line-space below:
|
||||||
statics: new function() {
|
statics: new function() {
|
||||||
function createShape(type, point, size, radius, args) {
|
function createShape(type, point, size, radius, args) {
|
||||||
var item = new Shape(Base.getNamed(args), point);
|
// Use `Base.create()` to avoid calling `initialize()` until after the
|
||||||
|
// internal fields are set here, then call `_initialize()` directly:
|
||||||
|
var item = Base.create(Shape.prototype);
|
||||||
item._type = type;
|
item._type = type;
|
||||||
item._size = size;
|
item._size = size;
|
||||||
item._radius = radius;
|
item._radius = radius;
|
||||||
|
item._initialize(Base.getNamed(args), point);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue