mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-08 05:42:07 -05:00
Merge remote branch 'origin/master'
This commit is contained in:
commit
bbd2574cfd
1 changed files with 150 additions and 22 deletions
170
lib/bootstrap.js
vendored
170
lib/bootstrap.js
vendored
|
@ -12,19 +12,26 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Base = this.Base = new function() {
|
var Base = this.Base = new function() {
|
||||||
|
// Fix __proto__ for browsers where it is not implemented (IE and Opera).
|
||||||
var fix = !this.__proto__,
|
var fix = !this.__proto__,
|
||||||
hidden = /^(statics|generics|preserve|beans|enumerable|prototype|__proto__|toString|valueOf)$/,
|
hidden = /^(statics|generics|preserve|beans|enumerable|prototype|__proto__|toString|valueOf)$/,
|
||||||
proto = Object.prototype,
|
proto = Object.prototype,
|
||||||
|
toString = proto.toString,
|
||||||
|
/**
|
||||||
|
* Private function that checks if an object contains a given property.
|
||||||
|
* Naming it 'has' causes problems on Opera when defining
|
||||||
|
* Object.prototype.has, as the local version then seems to be overriden
|
||||||
|
* by that. Giving it a idfferent name fixes it.
|
||||||
|
*/
|
||||||
has = fix
|
has = fix
|
||||||
? function(name) {
|
? function(name) {
|
||||||
return name !== '__proto__' && this.hasOwnProperty(name);
|
return name !== '__proto__' && this.hasOwnProperty(name);
|
||||||
}
|
}
|
||||||
: proto.hasOwnProperty,
|
: proto.hasOwnProperty,
|
||||||
toString = proto.toString,
|
proto = Array.prototype,
|
||||||
isArray = Array.isArray = Array.isArray || function(obj) {
|
isArray = Array.isArray = Array.isArray || function(obj) {
|
||||||
return toString.call(obj) === '[object Array]';
|
return toString.call(obj) === '[object Array]';
|
||||||
},
|
},
|
||||||
proto = Array.prototype,
|
|
||||||
slice = proto.slice,
|
slice = proto.slice,
|
||||||
forEach = proto.forEach = proto.forEach || function(iter, bind) {
|
forEach = proto.forEach = proto.forEach || function(iter, bind) {
|
||||||
for (var i = 0, l = this.length; i < l; i++)
|
for (var i = 0, l = this.length; i < l; i++)
|
||||||
|
@ -32,13 +39,18 @@ var Base = this.Base = new function() {
|
||||||
},
|
},
|
||||||
forIn = function(iter, bind) {
|
forIn = function(iter, bind) {
|
||||||
for (var i in this)
|
for (var i in this)
|
||||||
if (has.call(this, i))
|
if (this.hasOwnProperty(i))
|
||||||
iter.call(bind, this[i], i, this);
|
iter.call(bind, this[i], i, this);
|
||||||
},
|
},
|
||||||
_define = Object.defineProperty,
|
_define = Object.defineProperty,
|
||||||
_describe = Object.getOwnPropertyDescriptor;
|
_describe = Object.getOwnPropertyDescriptor;
|
||||||
|
|
||||||
|
// Support a mixed environment of some ECMAScript 5 features present,
|
||||||
|
// along with __defineGetter/Setter__ functions, as found in browsers today.
|
||||||
function define(obj, name, desc) {
|
function define(obj, name, desc) {
|
||||||
|
// Unfortunately Safari seems to ignore configurable: true and
|
||||||
|
// does not override existing properties, so we need to delete
|
||||||
|
// first:
|
||||||
if (_define) {
|
if (_define) {
|
||||||
try {
|
try {
|
||||||
delete obj[name];
|
delete obj[name];
|
||||||
|
@ -70,13 +82,31 @@ var Base = this.Base = new function() {
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private function that injects functions from src into dest, overriding
|
||||||
|
* (and inherinting from) base.
|
||||||
|
*/
|
||||||
function inject(dest, src, enumerable, base, preserve, generics) {
|
function inject(dest, src, enumerable, base, preserve, generics) {
|
||||||
var beans, bean;
|
var beans, bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private function that injects one field with given name and checks if
|
||||||
|
* the field is a function that needs to be wrapped for calls of base().
|
||||||
|
* This is only needed if the function in base is different from the one
|
||||||
|
* in src, and if the one in src is actually calling base through base.
|
||||||
|
* The string of the function is parsed for this.base to detect calls.
|
||||||
|
*/
|
||||||
function field(name, val, dontCheck, generics) {
|
function field(name, val, dontCheck, generics) {
|
||||||
|
// This does even work for prop: 0, as it will just be looked up
|
||||||
|
// again through describe.
|
||||||
var val = val || (val = describe(src, name))
|
var val = val || (val = describe(src, name))
|
||||||
&& (val.get ? val : val.value),
|
&& (val.get ? val : val.value),
|
||||||
func = typeof val === 'function', res = val,
|
func = typeof val === 'function',
|
||||||
|
res = val,
|
||||||
|
// Only lookup previous value if we preserve or define a
|
||||||
|
// function that might need it for this.base(). If we're
|
||||||
|
// defining a getter, don't lookup previous value, but look if
|
||||||
|
// the property exists (name in dest) and store result in prev
|
||||||
prev = preserve || func
|
prev = preserve || func
|
||||||
? (val && val.get ? name in dest : dest[name]) : null;
|
? (val && val.get ? name in dest : dest[name]) : null;
|
||||||
if (generics && func && (!preserve || !generics[name])) {
|
if (generics && func && (!preserve || !generics[name])) {
|
||||||
|
@ -110,16 +140,24 @@ var Base = this.Base = new function() {
|
||||||
return val.valueOf();
|
return val.valueOf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Only add getter beans if they do not expect arguments
|
// Produce bean properties if getters are specified. This
|
||||||
// Functions that should function both with optional
|
// does not produce properties for setter-only properties.
|
||||||
// arguments and as beans should not declare the parameters
|
// Just collect beans for now, and look them up in dest at
|
||||||
// and use the arguments array internally instead.
|
// the end of fields injection. This ensures this.base()
|
||||||
|
// works in beans too, and inherits setters for redefined
|
||||||
|
// getters in subclasses. Only add getter beans if they do
|
||||||
|
// not expect arguments. Functions that should function both
|
||||||
|
// with optional arguments and as beans should not declare
|
||||||
|
// the parameters and use the arguments array internally
|
||||||
|
// instead.
|
||||||
if (beans && val.length == 0
|
if (beans && val.length == 0
|
||||||
&& (bean = name.match(/^(get|is)(([A-Z])(.*))$/)))
|
&& (bean = name.match(/^(get|is)(([A-Z])(.*))$/)))
|
||||||
beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]);
|
beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]);
|
||||||
}
|
}
|
||||||
if (!res || func || !res.get && !res.set)
|
if (!res || func || !res.get && !res.set)
|
||||||
res = { value: res, writable: true };
|
res = { value: res, writable: true };
|
||||||
|
// Only set/change configurable and enumerable if this field is
|
||||||
|
// configurable
|
||||||
if ((describe(dest, name)
|
if ((describe(dest, name)
|
||||||
|| { configurable: true }).configurable) {
|
|| { configurable: true }).configurable) {
|
||||||
res.configurable = true;
|
res.configurable = true;
|
||||||
|
@ -128,13 +166,20 @@ var Base = this.Base = new function() {
|
||||||
define(dest, name, res);
|
define(dest, name, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Iterate through all definitions in src now and call field() for each.
|
||||||
if (src) {
|
if (src) {
|
||||||
beans = src.beans && [];
|
beans = src.beans && [];
|
||||||
for (var name in src)
|
for (var name in src)
|
||||||
if (has.call(src, name) && !hidden.test(name))
|
if (has.call(src, name) && !hidden.test(name))
|
||||||
field(name, null, true, generics);
|
field(name, null, true, generics);
|
||||||
|
// IE (and some other browsers?) never enumerate these, even if
|
||||||
|
// they are simply set on an object. Force their creation. Do not
|
||||||
|
// create generics for these, and check them for not being defined
|
||||||
|
// (by passing undefined for dontCheck).
|
||||||
field('toString');
|
field('toString');
|
||||||
field('valueOf');
|
field('valueOf');
|
||||||
|
// Now finally define beans as well. Look up methods on dest, for
|
||||||
|
// support of this.base() (See above).
|
||||||
for (var i = 0, l = beans && beans.length; i < l; i++)
|
for (var i = 0, l = beans && beans.length; i < l; i++)
|
||||||
try {
|
try {
|
||||||
var bean = beans[i], part = bean[1];
|
var bean = beans[i], part = bean[1];
|
||||||
|
@ -147,19 +192,37 @@ var Base = this.Base = new function() {
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private function that creates a constructor to extend the given object.
|
||||||
|
* When this constructor is called through new, a new object is craeted
|
||||||
|
* that inherits all from obj.
|
||||||
|
*/
|
||||||
function extend(obj) {
|
function extend(obj) {
|
||||||
|
// Create the constructor for the new prototype that calls initialize
|
||||||
|
// if it is defined.
|
||||||
var ctor = function(dont) {
|
var ctor = function(dont) {
|
||||||
|
// Fix __proto__
|
||||||
if (fix) define(this, '__proto__', { value: obj });
|
if (fix) define(this, '__proto__', { value: obj });
|
||||||
|
// Call the constructor function, if defined and we are not
|
||||||
|
// inheriting, in which case ctor.dont would be set, see bellow.
|
||||||
if (this.initialize && dont !== ctor.dont)
|
if (this.initialize && dont !== ctor.dont)
|
||||||
return this.initialize.apply(this, arguments);
|
return this.initialize.apply(this, arguments);
|
||||||
}
|
}
|
||||||
ctor.prototype = obj;
|
ctor.prototype = obj;
|
||||||
|
// Add a toString function that delegates to initialize if possible
|
||||||
ctor.toString = function() {
|
ctor.toString = function() {
|
||||||
return (this.prototype.initialize || function() {}).toString();
|
return (this.prototype.initialize || function() {}).toString();
|
||||||
}
|
}
|
||||||
return ctor;
|
return ctor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the argument to an iterator function. If none is specified, the
|
||||||
|
* identity function is returned.
|
||||||
|
* This supports normal functions, which are returned unmodified, and values
|
||||||
|
* to compare to. Wherever this function is used in the Enumerable
|
||||||
|
* functions, a value, a Function or null may be passed.
|
||||||
|
*/
|
||||||
function iterator(iter) {
|
function iterator(iter) {
|
||||||
return !iter
|
return !iter
|
||||||
? function(val) { return val }
|
? function(val) { return val }
|
||||||
|
@ -168,10 +231,10 @@ var Base = this.Base = new function() {
|
||||||
: iter;
|
: iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
function each(iter, bind, asArray) {
|
function each(obj, iter, bind, asArray) {
|
||||||
try {
|
try {
|
||||||
(asArray || asArray === undefined && isArray(this) ? forEach : forIn)
|
(asArray || asArray === undefined && isArray(obj) ? forEach : forIn)
|
||||||
.call(this, iterator(iter), bind = bind || this);
|
.call(obj, iterator(iter), bind = bind || obj);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e !== Base.stop) throw e;
|
if (e !== Base.stop) throw e;
|
||||||
}
|
}
|
||||||
|
@ -179,14 +242,14 @@ var Base = this.Base = new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function clone(obj) {
|
function clone(obj) {
|
||||||
return each.call(obj, function(val, i) {
|
return each(obj, function(val, i) {
|
||||||
this[i] = val;
|
this[i] = val;
|
||||||
}, new obj.constructor());
|
}, new obj.constructor());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject into new ctor object that's passed to inject(), and then returned
|
// Inject into new ctor object that's passed to inject(), and then returned
|
||||||
return inject(function() {}, {
|
return inject(function() {}, {
|
||||||
inject: function(src) {
|
inject: function(src/* , ... */) {
|
||||||
if (src) {
|
if (src) {
|
||||||
var proto = this.prototype,
|
var proto = this.prototype,
|
||||||
base = proto.__proto__ && proto.__proto__.constructor,
|
base = proto.__proto__ && proto.__proto__.constructor,
|
||||||
|
@ -196,43 +259,98 @@ var Base = this.Base = new function() {
|
||||||
if (statics != src)
|
if (statics != src)
|
||||||
inject(proto, src, src.enumerable, base && base.prototype,
|
inject(proto, src, src.enumerable, base && base.prototype,
|
||||||
src.preserve, src.generics && this);
|
src.preserve, src.generics && this);
|
||||||
|
// Define new static fields as enumerable, and inherit from
|
||||||
|
// base. enumerable is necessary so they can be copied over from
|
||||||
|
// base, and it does not disturb to be enumerable in the
|
||||||
|
// constructor. Use the preserve setting in src.preserve for
|
||||||
|
// statics too, not their own.
|
||||||
inject(this, statics, true, base, src.preserve);
|
inject(this, statics, true, base, src.preserve);
|
||||||
}
|
}
|
||||||
|
// If there are more than one argument, loop through them and call
|
||||||
|
// inject again. Do not simple inline the above code in one loop,
|
||||||
|
// since each of the passed objects might override this.inject.
|
||||||
for (var i = 1, l = arguments.length; i < l; i++)
|
for (var i = 1, l = arguments.length; i < l; i++)
|
||||||
this.inject(arguments[i]);
|
this.inject(arguments[i]);
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
extend: function(src) {
|
extend: function(src/* , ... */) {
|
||||||
var proto = new this(this.dont), ctor = extend(proto);
|
// The new prototype extends the constructor on which extend is
|
||||||
|
// called. Fix constructor.
|
||||||
|
// TODO: Consider using Object.create instead of using this.dont if
|
||||||
|
// available?
|
||||||
|
var proto = new this(this.dont),
|
||||||
|
ctor = extend(proto);
|
||||||
define(proto, 'constructor',
|
define(proto, 'constructor',
|
||||||
{ value: ctor, writable: true, configurable: true });
|
{ value: ctor, writable: true, configurable: true });
|
||||||
|
// Define an object to be passed as the first parameter in
|
||||||
|
// constructors when initialize should not be called.
|
||||||
ctor.dont = {};
|
ctor.dont = {};
|
||||||
|
// Copy over static fields, as prototype-like inheritance
|
||||||
|
// is not possible for static fields. Mark them as enumerable
|
||||||
|
// so they can be copied over again.
|
||||||
inject(ctor, this, true);
|
inject(ctor, this, true);
|
||||||
|
// Inject all the definitions in src. Use the new inject instead of
|
||||||
|
// the one in ctor, in case it was overriden. this is needed when
|
||||||
|
// overriding the static .inject(). But only inject if there's
|
||||||
|
// something to actually inject.
|
||||||
return arguments.length ? this.inject.apply(ctor, arguments) : ctor;
|
return arguments.length ? this.inject.apply(ctor, arguments) : ctor;
|
||||||
}
|
}
|
||||||
// Pass true for enumerable, so inject() and extend() can be passed on
|
// Pass true for enumerable, so inject() and extend() can be passed on
|
||||||
// to subclasses of Base through Base.inject() / extend().
|
// to subclasses of Base through Base.inject() / extend().
|
||||||
}, true).inject({
|
}, true).inject({
|
||||||
|
/**
|
||||||
|
* Returns true if the object contains a property with the given name,
|
||||||
|
* false otherwise.
|
||||||
|
* Just like in .each, objects only contained in the prototype(s) are
|
||||||
|
* filtered.
|
||||||
|
*/
|
||||||
has: has,
|
has: has,
|
||||||
each: each,
|
each: each,
|
||||||
|
|
||||||
inject: function() {
|
/**
|
||||||
|
* Injects the fields from the given object, adding this.base()
|
||||||
|
* functionality
|
||||||
|
*/
|
||||||
|
inject: function(/* src, ... */) {
|
||||||
for (var i = 0, l = arguments.length; i < l; i++)
|
for (var i = 0, l = arguments.length; i < l; i++)
|
||||||
inject(this, arguments[i]);
|
inject(this, arguments[i]);
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
extend: function() {
|
/**
|
||||||
|
* Returns a new object that inherits all properties from "this",
|
||||||
|
* through proper JS inheritance, not copying.
|
||||||
|
* Optionally, src and hide parameters can be passed to fill in the
|
||||||
|
* newly created object just like in inject(), to copy the behavior
|
||||||
|
* of Function.prototype.extend.
|
||||||
|
*/
|
||||||
|
extend: function(/* src, ... */) {
|
||||||
|
// Notice the "new" here: the private extend returns a constructor
|
||||||
|
// as it's used for Function.prototype.extend as well. But when
|
||||||
|
// extending objects, we want to return a new object that inherits
|
||||||
|
// from "this". In that case, the constructor is never used again,
|
||||||
|
// its just created to create a new object with the proper
|
||||||
|
// inheritance set and is garbage collected right after.
|
||||||
var res = new (extend(this));
|
var res = new (extend(this));
|
||||||
return res.inject.apply(res, arguments);
|
return res.inject.apply(res, arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
each: function(iter, bind) {
|
||||||
|
return each(this, iter, bind);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new object of the same type and copies over all
|
||||||
|
* name / value pairs from this object.
|
||||||
|
*/
|
||||||
clone: function() {
|
clone: function() {
|
||||||
return clone(this);
|
return clone(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
statics: {
|
statics: {
|
||||||
|
// Expose some local privates as Base generics.
|
||||||
|
each: each,
|
||||||
clone: clone,
|
clone: clone,
|
||||||
define: define,
|
define: define,
|
||||||
describe: describe,
|
describe: describe,
|
||||||
|
@ -242,10 +360,6 @@ var Base = this.Base = new function() {
|
||||||
return has.call(obj, name);
|
return has.call(obj, name);
|
||||||
},
|
},
|
||||||
|
|
||||||
each: function(obj, iter, bind) {
|
|
||||||
return each.call(obj, iter, bind);
|
|
||||||
},
|
|
||||||
|
|
||||||
type: function(obj) {
|
type: function(obj) {
|
||||||
return (obj || obj === 0) && (obj._type || typeof obj) || null;
|
return (obj || obj === 0) && (obj._type || typeof obj) || null;
|
||||||
},
|
},
|
||||||
|
@ -254,6 +368,11 @@ var Base = this.Base = new function() {
|
||||||
return !!(obj || obj === 0);
|
return !!(obj || obj === 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first argument that is defined.
|
||||||
|
* Null is counted as defined too, since !== undefined is used for
|
||||||
|
* comparisons. In this it differs from Mootools!
|
||||||
|
*/
|
||||||
pick: function() {
|
pick: function() {
|
||||||
for (var i = 0, l = arguments.length; i < l; i++)
|
for (var i = 0, l = arguments.length; i < l; i++)
|
||||||
if (arguments[i] !== undefined)
|
if (arguments[i] !== undefined)
|
||||||
|
@ -261,6 +380,15 @@ var Base = this.Base = new function() {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special constant, to be thrown by closures passed to each()
|
||||||
|
*
|
||||||
|
* $continue / Base.next is not implemented, as the same
|
||||||
|
* functionality can achieved by using return in the closure.
|
||||||
|
* In prototype, the implementation of $continue also leads to a
|
||||||
|
* huge speed decrease, as the closure is wrapped in another closure
|
||||||
|
* that does nothing else than handling $continue.
|
||||||
|
*/
|
||||||
stop: {}
|
stop: {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue