ares-ide
Version:
A browser-based code editor and UI designer for Enyo 2 projects
144 lines (135 loc) • 4.97 kB
JavaScript
(function (enyo) {
//*@public
/**
An _enyo.Mixin_ is a group of properties and/or methods to apply to a kind
or instance without requiring the kind to be subclassed. There are a few
things to keep in mind when creating an _enyo.Mixin_ for use with your
kinds:
- A property on a mixin will automatically override the same property on the
kind or instance it is being applied to, should it already exist.
- A method that already exists on the kind or instance will not
automatically call the super-method. If the intention is to extend the
kind's own method, make sure that you wrap the method with _enyo.inherit_.
- Mixins must have a name so they can be identified when applied; otherwise,
the same mixin may be applied multiple times to a given kind,
potentially resulting in an infinite loop.
An _enyo.Mixin_ is _not a kind_. It is simply a named collection of methods
and properties that may be reused with multiple kinds.
To create an _enyo.Mixin_, simply create a hash of methods and properties,
and assign it to a referenceable namespace.
To apply an _enyo.Mixin_ to a kind, simply add its name or a reference to it
in the special _mixins_ property in the kind definition. Alternatively, you
may call _extend()_ on the constructor for the kind, passing in the mixin
(or an array of mixins).
To apply an _enyo.Mixin_ to an instance of a kind, call the _extend()_
method on the instance and pass it the name of (or a reference to) the mixin,
or an array of mixins.
*/
//*@protected
/**
We add the feature that will execute last in the feature chain but will scan
for mixins and extend the kind accordingly, only applying any given mixin one time
to any kind base.
*/
var applyMixin = function (proto, props) {
var mx = proto._appliedMixins,
m = props, n;
// if the mixin is a string we have to try to resolve it to an object
if (enyo.isString(m)) {
m = enyo.getPath(m);
if (!m) {
enyo.warn("could not find the requested mixin " + props);
// could not find the mixin
return;
}
}
// we can't do anything if someone attempts to extend a kind with a mixin
// that does not have a name but all internal mixins should have names
if (m.name) {
if (!~enyo.indexOf(m.name, mx)) {
mx.push(m.name);
} else {
// we will not add the same mixin twice, but we throw the warning
// to alert the developer of the attempt so it can be tracked down
enyo.warn("attempt to add the same mixin more than once, " +
m.name + " onto -> " + proto.kindName);
return;
}
n = m.name;
delete m.name;
} else {
n = null;
}
var mc = enyo.clone(m);
// rename constructor to _constructor to work around IE8/Prototype problems
if (m.hasOwnProperty("constructor")) {
mc._constructor = m.constructor;
delete mc.constructor;
}
enyo.kind.statics.extend(mc, proto);
if (n) {
m.name = n;
}
};
var mixinsFeature = function (ctor, props) {
if (props.mixins) {
var cp = ctor.prototype || ctor,
pm = props.mixins;
cp._appliedMixins = cp._appliedMixins? enyo.cloneArray(cp._appliedMixins): [],
// prevent recursion
delete props.mixins;
for (var i=0, m; (m=pm[i]); ++i) {
applyMixin(cp, m);
}
}
};
enyo.kind.features.push(mixinsFeature);
var fn = enyo.concatHandler;
enyo.concatHandler = function (ctor, props) {
if (props.mixins) {
var p = ctor.prototype || ctor;
p.mixins = (p.mixins? p.mixins.concat(props.mixins): props.mixins.slice());
}
fn.apply(this, arguments);
};
enyo.kind.extendMethods(enyo.kind.statics, {
extend: enyo.inherit(function (sup) {
return function (props, target) {
var proto = target || this.prototype;
if (props.mixins) {
// cut-out the need for concatenated properties to handle
// this (and it won't be able to because we're removing the
// new mixins array)
proto.mixins = enyo.merge(proto.mixins, props.mixins);
mixinsFeature(proto, props);
}
return sup.apply(this, arguments);
};
})
}, true);
//*@public
enyo.MixinSupport = {
name: "MixinSupport",
/**
Takes a single parameter--a hash of properties to apply. To be considered
a _mixin_, it must have a _name_ property that is unique, but the method
will apply even non-mixins to the kind instance.
*/
extend: function (props) {
applyMixin(this, props);
},
/**
Extend the _importProps()_ method to ensure we can handle runtime additions
of the mixins' properties since they can be added at any time, even by other
mixins. This will only be executed against mixins applied after the kind
has already been evaluated and it is being initialized as an instance.
However, if a mixin applies more mixins at runtime, it will have no effect.
*/
importProps: enyo.inherit(function (sup) {
return function (props) {
if (props) { mixinsFeature(this, props); }
sup.apply(this, arguments);
};
})
};
}(enyo));