mirror of
https://github.com/wahyd4/cdnjs.git
synced 2026-08-09 04:46:00 +10:00
add old versions(before v0.6.1) of eddy
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function v(e,t,n){w(this,e,t,n)}function m(){S.call(this),this._stopImmediatePropagation()}function g(e){return{configurable:!0,value:e}}function y(e){return function(){return s(this,u&&"dispatchEvent"in this?l:c)[e].apply(this,arguments)}}function b(e,t,n){t in e||(e[t]=n)}function w(e,t,n,r){b(e,"timeStamp",Date.now());for(var i in r)e[i]=r[i];b(e,"type",n),b(e,"currentTarget",t),b(e,"target",t),r&&b(e,"data",r)}function E(e){return e._active=!0,e._stopImmediatePropagation=e.stopImmediatePropagation,e.stopImmediatePropagation=m,e}function S(){i(this,"_active",h)}function x(e,t,n){typeof e=="function"?e.apply(t,n):e.handleEvent.apply(e,n)}function T(e,t,n){typeof e=="function"?e.call(t,n):e.handleEvent(n)}function N(e){return T(e,this.target,this),this._active}function C(e){e.apply(this.context,this.arguments)}function k(e){return T(e,this.context,this.event),this.event._active}if(e.eddy)return;var t="_@eddy:"+Math.random(),n=e.Object,r=n.create,i=n.defineProperty,s=n.defineProperties,o=e.Node||e.Element||e.HTMLElement,u=!!o,a=g(function(n){var i=this[t]||d.get(this)||(d.set(this,r(null)),d.get(this)),s=i[t]||(i[t]={m:[],b:[]}),o=s.m.indexOf(n);return o<0?s.b[s.m.push(n)-1]=n.bind(this):s.b[o]}),f=g(function(t,n,r){var i=this;return i.on(t,function s(){i.off(t,s,r),x(n,i,arguments)},r)}),l={boundTo:a,off:g(function(t,n,r){return this.removeEventListener(t,n,!!r),this}),on:g(function(t,n,r){return this.addEventListener(t,n,!!r),this}),once:f,trigger:g(function(n,r){var i=typeof n=="string",s=i?n:(r=n).type,o=(this.ownerDocument||this.document||e.document).createEvent("Event");return o.initEvent(s,r&&r.bubbles||1,r&&r.cancelable||1),w(o,this,s,i&&r),this.dispatchEvent(o),this})},c={boundTo:a,emit:g(function(n){var r=this[t][n];return r&&r.forEach(C,{arguments:(r.shift.call(arguments),arguments),context:this}),this}),off:g(function(n,r){var i=this[t],s=i[n],o;return s&&(o=s.indexOf(r),-1<o&&(s.splice(o,1),s.length||delete i[n])),this}),on:g(function(n,r){var i=this[t],s=i[n]||(i[n]=[]);return s.indexOf(r)<0&&s.push(r),this}),once:f,trigger:g(function(n,r){var i=this[t],s=typeof n=="string",o=i[s?n:n.type];return o&&o.every(k,{event:s?new v(this,n,r):E(n),context:this}),this})},h={value:!1},p=e.WeakMap,d;u&&(d=p?new p:{get:function(e){return e[t]},set:function(e,n){i(e,t,g(n))}}),s(v.prototype,{_active:g(!0),stopImmediatePropagation:g(S)}),i(c,t,{enumerable:!0,get:function(){return{value:r(null)}}}),s(n.prototype,{boundTo:g(y("boundTo")),emit:g(y("emit")),handleEvent:g(y("trigger")),off:g(y("off")),on:g(y("on")),once:g(y("once")),trigger:g(y("trigger"))}),i(e,"eddy",{value:!0})})(typeof global=="undefined"?window:global);
|
||||
@@ -0,0 +1,326 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function(global){
|
||||
'use strict';
|
||||
if (global.eddy) return;
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
var
|
||||
uid = '_@eddy:' + Math.random(),
|
||||
Object = global.Object,
|
||||
create = Object.create,
|
||||
defineProperty = Object.defineProperty,
|
||||
defineProperties = Object.defineProperties,
|
||||
DOM = global.Node || global.Element || global.HTMLElement,
|
||||
hasDOM = !!DOM,
|
||||
boundTo = commonDescriptor(
|
||||
function boundTo(method) {
|
||||
var
|
||||
listeners = this[uid] || DOMWM.get(this) || (
|
||||
DOMWM.set(this, create(null)),
|
||||
DOMWM.get(this)
|
||||
),
|
||||
bound = listeners[uid] || (
|
||||
listeners[uid] = {
|
||||
m: [],
|
||||
b: []
|
||||
}
|
||||
),
|
||||
i = bound.m.indexOf(method);
|
||||
return i < 0 ?
|
||||
bound.b[bound.m.push(method) - 1] = method.bind(this) :
|
||||
bound.b[i];
|
||||
}
|
||||
),
|
||||
once = commonDescriptor(
|
||||
function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once() {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(handler, self, arguments);
|
||||
}, capture);
|
||||
}
|
||||
),
|
||||
DOMDescriptor = {
|
||||
boundTo: boundTo,
|
||||
off: commonDescriptor(
|
||||
function DOMOff(type, handler, capture) {
|
||||
this.removeEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function DOMOn(type, handler, capture) {
|
||||
this.addEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function DOMTrigger(evt, data) {
|
||||
var
|
||||
stringEvent = typeof evt === 'string',
|
||||
type = stringEvent ? evt : (data = evt).type,
|
||||
e = (
|
||||
this.ownerDocument || this.document || global.document
|
||||
).createEvent('Event');
|
||||
e.initEvent(
|
||||
type,
|
||||
data && data.bubbles || 1,
|
||||
data && data.cancelable || 1
|
||||
);
|
||||
initEvent(e, this, type, stringEvent && data);
|
||||
this.dispatchEvent(e);
|
||||
return this;
|
||||
}
|
||||
)
|
||||
},
|
||||
JSDescriptor = {
|
||||
boundTo: boundTo,
|
||||
emit: commonDescriptor(
|
||||
function JSemit(type) {
|
||||
var array = this[uid][type];
|
||||
if (array) {
|
||||
array.forEach(
|
||||
emitJS,
|
||||
{
|
||||
arguments: (
|
||||
array.shift.call(arguments),
|
||||
arguments
|
||||
),
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
off: commonDescriptor(
|
||||
function JSOff(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type],
|
||||
i;
|
||||
if (array) {
|
||||
i = array.indexOf(handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function JSOn(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type] || (listeners[type] = []);
|
||||
if (array.indexOf(handler) < 0) {
|
||||
array.push(handler);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function JSTrigger(evt, data) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
isNotEvent = typeof evt === 'string',
|
||||
array = listeners[isNotEvent ? evt : evt.type];
|
||||
if (array) {
|
||||
array.every(
|
||||
triggerJS,
|
||||
{
|
||||
event: isNotEvent ?
|
||||
new Event(this, evt, data) :
|
||||
injectActiveStatus(evt),
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
)
|
||||
},
|
||||
stoppedPropagation = {
|
||||
value: false
|
||||
},
|
||||
WM = global.WeakMap,
|
||||
DOMWM
|
||||
;
|
||||
function Event(target, type, data) {
|
||||
initEvent(this, target, type, data);
|
||||
}
|
||||
function _stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
stopImmediatePropagation.call(this);
|
||||
this._stopImmediatePropagation();
|
||||
}
|
||||
function commonDescriptor(value) {
|
||||
return {
|
||||
configurable: true,
|
||||
value: value
|
||||
};
|
||||
}
|
||||
function defineCommonMethod(name) {
|
||||
return function () {
|
||||
/*jshint validthis:true */
|
||||
return defineProperties(
|
||||
this,
|
||||
hasDOM && ('dispatchEvent' in this) ?
|
||||
DOMDescriptor :
|
||||
JSDescriptor
|
||||
)[name].apply(this, arguments);
|
||||
};
|
||||
}
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!(key in e)) e[key] = value;
|
||||
}
|
||||
function initEvent(e, target, type, data) {
|
||||
ifNotPresent(e, 'timeStamp', Date.now());
|
||||
for(var key in data) e[key] = data[key];
|
||||
ifNotPresent(e, 'type', type);
|
||||
ifNotPresent(e, 'currentTarget', target);
|
||||
ifNotPresent(e, 'target', target);
|
||||
if (data) ifNotPresent(e, 'data', data);
|
||||
}
|
||||
function injectActiveStatus(evt) {
|
||||
evt._active = true;
|
||||
evt._stopImmediatePropagation = evt.stopImmediatePropagation;
|
||||
evt.stopImmediatePropagation = _stopImmediatePropagation;
|
||||
return evt;
|
||||
}
|
||||
function stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
defineProperty(
|
||||
this,
|
||||
'_active',
|
||||
stoppedPropagation
|
||||
);
|
||||
}
|
||||
function triggerEvent(handler, context, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
function triggerAny(handler, context, e) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.call(context, e);
|
||||
} else {
|
||||
handler.handleEvent(e);
|
||||
}
|
||||
}
|
||||
function triggerDOM(handler) {
|
||||
/*jshint validthis:true */
|
||||
triggerAny(handler, this.target, this);
|
||||
return this._active;
|
||||
}
|
||||
function emitJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
handler.apply(this.context, this.arguments);
|
||||
}
|
||||
function triggerJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
triggerAny(handler, this.context, this.event);
|
||||
return this.event._active;
|
||||
}
|
||||
if (hasDOM) {
|
||||
DOMWM = WM ? new WM() : {
|
||||
get: function (node) {
|
||||
return node[uid];
|
||||
},
|
||||
set: function (node, value) {
|
||||
defineProperty(
|
||||
node,
|
||||
uid,
|
||||
commonDescriptor(value)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
defineProperties(
|
||||
Event.prototype,
|
||||
{
|
||||
_active: commonDescriptor(true),
|
||||
stopImmediatePropagation: commonDescriptor(stopImmediatePropagation)
|
||||
}
|
||||
);
|
||||
// this property is used as
|
||||
// defineProperties descriptor
|
||||
// for all JS objects
|
||||
// In order to grant a fresh new
|
||||
// object as event handler
|
||||
// and without leaks
|
||||
// a new descriptor is returned
|
||||
// per each call
|
||||
defineProperty(
|
||||
JSDescriptor,
|
||||
uid,
|
||||
{
|
||||
enumerable: true,
|
||||
get: function get() {
|
||||
return {
|
||||
value: create(null)
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
// all must be configurable
|
||||
// so other prototypes can work too
|
||||
defineProperties(
|
||||
Object.prototype,
|
||||
{
|
||||
boundTo: commonDescriptor(
|
||||
defineCommonMethod('boundTo')
|
||||
),
|
||||
emit: commonDescriptor(
|
||||
defineCommonMethod('emit')
|
||||
),
|
||||
handleEvent: commonDescriptor(
|
||||
defineCommonMethod('trigger')
|
||||
),
|
||||
off: commonDescriptor(
|
||||
defineCommonMethod('off')
|
||||
),
|
||||
on: commonDescriptor(
|
||||
defineCommonMethod('on')
|
||||
),
|
||||
once: commonDescriptor(
|
||||
defineCommonMethod('once')
|
||||
),
|
||||
trigger: commonDescriptor(
|
||||
defineCommonMethod('trigger')
|
||||
)
|
||||
}
|
||||
);
|
||||
defineProperty(global, 'eddy', {
|
||||
value: true
|
||||
});
|
||||
}(
|
||||
typeof global == 'undefined' ? window : global
|
||||
));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function v(e,t,n){w(this,e,t,n)}function m(){S.call(this),this._stopImmediatePropagation()}function g(e){return{configurable:!0,value:e}}function y(e){return function(){return s(this,u&&"dispatchEvent"in this?l:c)[e].apply(this,arguments)}}function b(e,t,n){t in e||(e[t]=n)}function w(e,t,n,r){b(e,"timeStamp",Date.now());for(var i in r)e[i]=r[i];b(e,"type",n),b(e,"currentTarget",t),b(e,"target",t),r&&b(e,"data",r)}function E(e){return e._active=!0,e._stopImmediatePropagation=e.stopImmediatePropagation,e.stopImmediatePropagation=m,e}function S(){i(this,"_active",h)}function x(e,t,n){typeof e=="function"?e.apply(t,n):e.handleEvent.apply(e,n)}function T(e,t,n){typeof e=="function"?e.call(t,n):e.handleEvent(n)}function N(e){return T(e,this.target,this),this._active}function C(e){e.apply(this.context,this.arguments)}function k(e){return T(e,this.context,this.event),this.event._active}if(e.eddy)return;var t="_@eddy:"+Math.random(),n=e.Object,r=n.create,i=n.defineProperty,s=n.defineProperties,o=e.Node||e.Element||e.HTMLElement,u=!!o,a=g(function(n){var i=this[t]||d.get(this)||(d.set(this,r(null)),d.get(this)),s=i[t]||(i[t]={m:[],b:[]}),o=typeof n=="string"?this[n]:n,u=s.m.indexOf(o);return u<0?s.b[s.m.push(o)-1]=o.bind(this):s.b[u]}),f=g(function(t,n,r){var i=this;return i.on(t,function s(){i.off(t,s,r),x(n,i,arguments)},r)}),l={boundTo:a,off:g(function(t,n,r){return this.removeEventListener(t,n,!!r),this}),on:g(function(t,n,r){return this.addEventListener(t,n,!!r),this}),once:f,trigger:g(function(n,r){var i=typeof n=="string",s=i?n:(r=n).type,o=(this.ownerDocument||this.document||e.document).createEvent("Event");return o.initEvent(s,r&&r.bubbles||1,r&&r.cancelable||1),w(o,this,s,i&&r),this.dispatchEvent(o),this})},c={boundTo:a,emit:g(function(n){var r=this[t][n];return r&&r.forEach(C,{arguments:(r.shift.call(arguments),arguments),context:this}),this}),off:g(function(n,r){var i=this[t],s=i[n],o;return s&&(o=s.indexOf(r),-1<o&&(s.splice(o,1),s.length||delete i[n])),this}),on:g(function(n,r){var i=this[t],s=i[n]||(i[n]=[]);return s.indexOf(r)<0&&s.push(r),this}),once:f,trigger:g(function(n,r){var i=this[t],s=typeof n=="string",o=i[s?n:n.type];return o&&o.every(k,{event:s?new v(this,n,r):E(n),context:this}),this})},h={value:!1},p=e.WeakMap,d;u&&(d=p?new p:{get:function(e){return e[t]},set:function(e,n){i(e,t,g(n))}}),s(v.prototype,{_active:g(!0),stopImmediatePropagation:g(S)}),i(c,t,{enumerable:!0,get:function(){return{value:r(null)}}}),s(n.prototype,{boundTo:g(y("boundTo")),emit:g(y("emit")),handleEvent:g(y("trigger")),off:g(y("off")),on:g(y("on")),once:g(y("once")),trigger:g(y("trigger"))}),i(e,"eddy",{value:!0})})(typeof global=="undefined"?window:global);
|
||||
@@ -0,0 +1,328 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function(global){
|
||||
'use strict';
|
||||
if (global.eddy) return;
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
var
|
||||
uid = '_@eddy:' + Math.random(),
|
||||
Object = global.Object,
|
||||
create = Object.create,
|
||||
defineProperty = Object.defineProperty,
|
||||
defineProperties = Object.defineProperties,
|
||||
DOM = global.Node || global.Element || global.HTMLElement,
|
||||
hasDOM = !!DOM,
|
||||
boundTo = commonDescriptor(
|
||||
function boundTo(method) {
|
||||
var
|
||||
listeners = this[uid] || DOMWM.get(this) || (
|
||||
DOMWM.set(this, create(null)),
|
||||
DOMWM.get(this)
|
||||
),
|
||||
bound = listeners[uid] || (
|
||||
listeners[uid] = {
|
||||
m: [],
|
||||
b: []
|
||||
}
|
||||
),
|
||||
fn = typeof method === 'string' ?
|
||||
this[method] : method,
|
||||
i = bound.m.indexOf(fn);
|
||||
return i < 0 ?
|
||||
bound.b[bound.m.push(fn) - 1] = fn.bind(this) :
|
||||
bound.b[i];
|
||||
}
|
||||
),
|
||||
once = commonDescriptor(
|
||||
function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once() {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(handler, self, arguments);
|
||||
}, capture);
|
||||
}
|
||||
),
|
||||
DOMDescriptor = {
|
||||
boundTo: boundTo,
|
||||
off: commonDescriptor(
|
||||
function DOMOff(type, handler, capture) {
|
||||
this.removeEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function DOMOn(type, handler, capture) {
|
||||
this.addEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function DOMTrigger(evt, data) {
|
||||
var
|
||||
stringEvent = typeof evt === 'string',
|
||||
type = stringEvent ? evt : (data = evt).type,
|
||||
e = (
|
||||
this.ownerDocument || this.document || global.document
|
||||
).createEvent('Event');
|
||||
e.initEvent(
|
||||
type,
|
||||
data && data.bubbles || 1,
|
||||
data && data.cancelable || 1
|
||||
);
|
||||
initEvent(e, this, type, stringEvent && data);
|
||||
this.dispatchEvent(e);
|
||||
return this;
|
||||
}
|
||||
)
|
||||
},
|
||||
JSDescriptor = {
|
||||
boundTo: boundTo,
|
||||
emit: commonDescriptor(
|
||||
function JSemit(type) {
|
||||
var array = this[uid][type];
|
||||
if (array) {
|
||||
array.forEach(
|
||||
emitJS,
|
||||
{
|
||||
arguments: (
|
||||
array.shift.call(arguments),
|
||||
arguments
|
||||
),
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
off: commonDescriptor(
|
||||
function JSOff(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type],
|
||||
i;
|
||||
if (array) {
|
||||
i = array.indexOf(handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function JSOn(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type] || (listeners[type] = []);
|
||||
if (array.indexOf(handler) < 0) {
|
||||
array.push(handler);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function JSTrigger(evt, data) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
isNotEvent = typeof evt === 'string',
|
||||
array = listeners[isNotEvent ? evt : evt.type];
|
||||
if (array) {
|
||||
array.every(
|
||||
triggerJS,
|
||||
{
|
||||
event: isNotEvent ?
|
||||
new Event(this, evt, data) :
|
||||
injectActiveStatus(evt),
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
)
|
||||
},
|
||||
stoppedPropagation = {
|
||||
value: false
|
||||
},
|
||||
WM = global.WeakMap,
|
||||
DOMWM
|
||||
;
|
||||
function Event(target, type, data) {
|
||||
initEvent(this, target, type, data);
|
||||
}
|
||||
function _stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
stopImmediatePropagation.call(this);
|
||||
this._stopImmediatePropagation();
|
||||
}
|
||||
function commonDescriptor(value) {
|
||||
return {
|
||||
configurable: true,
|
||||
value: value
|
||||
};
|
||||
}
|
||||
function defineCommonMethod(name) {
|
||||
return function () {
|
||||
/*jshint validthis:true */
|
||||
return defineProperties(
|
||||
this,
|
||||
hasDOM && ('dispatchEvent' in this) ?
|
||||
DOMDescriptor :
|
||||
JSDescriptor
|
||||
)[name].apply(this, arguments);
|
||||
};
|
||||
}
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!(key in e)) e[key] = value;
|
||||
}
|
||||
function initEvent(e, target, type, data) {
|
||||
ifNotPresent(e, 'timeStamp', Date.now());
|
||||
for(var key in data) e[key] = data[key];
|
||||
ifNotPresent(e, 'type', type);
|
||||
ifNotPresent(e, 'currentTarget', target);
|
||||
ifNotPresent(e, 'target', target);
|
||||
if (data) ifNotPresent(e, 'data', data);
|
||||
}
|
||||
function injectActiveStatus(evt) {
|
||||
evt._active = true;
|
||||
evt._stopImmediatePropagation = evt.stopImmediatePropagation;
|
||||
evt.stopImmediatePropagation = _stopImmediatePropagation;
|
||||
return evt;
|
||||
}
|
||||
function stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
defineProperty(
|
||||
this,
|
||||
'_active',
|
||||
stoppedPropagation
|
||||
);
|
||||
}
|
||||
function triggerEvent(handler, context, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
function triggerAny(handler, context, e) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.call(context, e);
|
||||
} else {
|
||||
handler.handleEvent(e);
|
||||
}
|
||||
}
|
||||
function triggerDOM(handler) {
|
||||
/*jshint validthis:true */
|
||||
triggerAny(handler, this.target, this);
|
||||
return this._active;
|
||||
}
|
||||
function emitJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
handler.apply(this.context, this.arguments);
|
||||
}
|
||||
function triggerJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
triggerAny(handler, this.context, this.event);
|
||||
return this.event._active;
|
||||
}
|
||||
if (hasDOM) {
|
||||
DOMWM = WM ? new WM() : {
|
||||
get: function (node) {
|
||||
return node[uid];
|
||||
},
|
||||
set: function (node, value) {
|
||||
defineProperty(
|
||||
node,
|
||||
uid,
|
||||
commonDescriptor(value)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
defineProperties(
|
||||
Event.prototype,
|
||||
{
|
||||
_active: commonDescriptor(true),
|
||||
stopImmediatePropagation: commonDescriptor(stopImmediatePropagation)
|
||||
}
|
||||
);
|
||||
// this property is used as
|
||||
// defineProperties descriptor
|
||||
// for all JS objects
|
||||
// In order to grant a fresh new
|
||||
// object as event handler
|
||||
// and without leaks
|
||||
// a new descriptor is returned
|
||||
// per each call
|
||||
defineProperty(
|
||||
JSDescriptor,
|
||||
uid,
|
||||
{
|
||||
enumerable: true,
|
||||
get: function get() {
|
||||
return {
|
||||
value: create(null)
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
// all must be configurable
|
||||
// so other prototypes can work too
|
||||
defineProperties(
|
||||
Object.prototype,
|
||||
{
|
||||
boundTo: commonDescriptor(
|
||||
defineCommonMethod('boundTo')
|
||||
),
|
||||
emit: commonDescriptor(
|
||||
defineCommonMethod('emit')
|
||||
),
|
||||
handleEvent: commonDescriptor(
|
||||
defineCommonMethod('trigger')
|
||||
),
|
||||
off: commonDescriptor(
|
||||
defineCommonMethod('off')
|
||||
),
|
||||
on: commonDescriptor(
|
||||
defineCommonMethod('on')
|
||||
),
|
||||
once: commonDescriptor(
|
||||
defineCommonMethod('once')
|
||||
),
|
||||
trigger: commonDescriptor(
|
||||
defineCommonMethod('trigger')
|
||||
)
|
||||
}
|
||||
);
|
||||
defineProperty(global, 'eddy', {
|
||||
value: true
|
||||
});
|
||||
}(
|
||||
typeof global == 'undefined' ? window : global
|
||||
));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function m(e,t,n){E(this,e,t,n)}function g(){x.call(this),this._stopImmediatePropagation()}function y(e){return{configurable:!0,value:e}}function b(e){return function(){return s(this,a&&"dispatchEvent"in this?c:h)[e].apply(this,arguments)}}function w(e,t,n){t in e||(e[t]=n)}function E(e,t,n,r){w(e,"timeStamp",Date.now());for(var i in r)w(e,i,r[i]);w(e,"type",n),w(e,"target",t),r&&w(e,"data",r)}function S(e){return e._active=!0,e._stopImmediatePropagation=e.stopImmediatePropagation,e.stopImmediatePropagation=g,e}function x(){i(this,"_active",p)}function T(e,t,n){typeof e=="function"?e.apply(t,n):e.handleEvent.apply(e,n)}function N(e,t,n){typeof e=="function"?e.call(t,n):e.handleEvent(n)}function C(e){T(e,this.context,this.arguments)}function k(e){return C.call(this,e),this.arguments[0]._active}if(e.eddy)return;var t="_@eddy:"+Math.random(),n=e.Object,r=n.create,i=n.defineProperty,s=n.defineProperties,o=Array.prototype.slice,u=e.Node||e.Element||e.HTMLElement,a=!!u,f=y(function(n){var i=a?v.get(this)||(v.set(this,r(null)),v.get(this)):this[t],s=i[t]||(i[t]={m:[],b:[]}),o=typeof n=="string"?this[n]:n,u=s.m.indexOf(o);return u<0?s.b[s.m.push(o)-1]=o.bind(this):s.b[u]}),l=y(function(t,n,r){var i=this;return i.on(t,function s(){i.off(t,s,r),T(n,i,arguments)},r)}),c={boundTo:f,emit:y(function(t){return this.trigger(t,{data:o.call(arguments,1)})}),off:y(function(t,n,r){return this.removeEventListener(t,n,!!r),this}),on:y(function(t,n,r){return this.addEventListener(t,n,!!r),this}),once:l,trigger:y(function(n,r){var i=typeof n=="string",s=i?n:(r=n).type,o=(this.ownerDocument||this.document||e.document).createEvent("Event");return o.initEvent(s,r&&r.bubbles||1,r&&r.cancelable||1),E(o,this,s,i&&r),this.dispatchEvent(o),this})},h={boundTo:f,emit:y(function(n){var r=this[t][n];return r&&r.forEach(C,{arguments:(r.shift.call(arguments),arguments),context:this}),this}),off:y(function(n,r){var i=this[t],s=i[n],o;return s&&(o=s.indexOf(r),-1<o&&(s.splice(o,1),s.length||delete i[n])),this}),on:y(function(n,r){var i=this[t],s=i[n]||(i[n]=[]);return s.indexOf(r)<0&&s.push(r),this}),once:l,trigger:y(function(n,r){var i=this[t],s=typeof n=="string",o=i[s?n:n.type];return o&&o.every(k,{arguments:[s?new m(this,n,r):n instanceof m?n:S(n)],context:this}),this})},p={value:!1},d=e.WeakMap,v;a&&(v=d?new d:{get:function(e){return e[t]},set:function(e,n){i(e,t,y(n))}}),s(m.prototype,{_active:y(!0),stopImmediatePropagation:y(x)}),i(h,t,{enumerable:!0,get:function(){return{value:r(null)}}}),s(n.prototype,{boundTo:y(b("boundTo")),emit:y(b("emit")),off:y(b("off")),on:y(b("on")),once:y(b("once")),trigger:y(b("trigger"))}),i(String.prototype,"toLocaleString",y(function(){var e={}.hasOwnProperty,t=/\$\{([^}]+?)\}/g,n=function(e,t){return o[t]},s=r(null),o;return i(String,"setLocale",y(function(n){for(var r in n)e.call(n,r)&&(s[r]=n[r]);return n})),function u(e){var r;return o=e,r=(s[this]||this).replace(t,n),o=null,r}}())),i(e,"eddy",{value:!0})})(typeof global=="undefined"?window:global);
|
||||
@@ -0,0 +1,370 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function(global){
|
||||
'use strict';
|
||||
if (global.eddy) return;
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
var
|
||||
uid = '_@eddy:' + Math.random(),
|
||||
Object = global.Object,
|
||||
create = Object.create,
|
||||
defineProperty = Object.defineProperty,
|
||||
defineProperties = Object.defineProperties,
|
||||
slice = Array.prototype.slice,
|
||||
DOM = global.Node || global.Element || global.HTMLElement,
|
||||
hasDOM = !!DOM,
|
||||
boundTo = commonDescriptor(
|
||||
function boundTo(method) {
|
||||
var
|
||||
listeners = hasDOM ? DOMWM.get(this) || (
|
||||
DOMWM.set(this, create(null)),
|
||||
DOMWM.get(this)
|
||||
) : this[uid],
|
||||
bound = listeners[uid] || (
|
||||
listeners[uid] = {
|
||||
m: [],
|
||||
b: []
|
||||
}
|
||||
),
|
||||
fn = typeof method === 'string' ?
|
||||
this[method] : method,
|
||||
i = bound.m.indexOf(fn);
|
||||
return i < 0 ?
|
||||
bound.b[bound.m.push(fn) - 1] = fn.bind(this) :
|
||||
bound.b[i];
|
||||
}
|
||||
),
|
||||
once = commonDescriptor(
|
||||
function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once() {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(handler, self, arguments);
|
||||
}, capture);
|
||||
}
|
||||
),
|
||||
DOMDescriptor = {
|
||||
boundTo: boundTo,
|
||||
emit: commonDescriptor(
|
||||
function DOMemit(type) {
|
||||
return this.trigger(
|
||||
type,
|
||||
{
|
||||
data: slice.call(arguments, 1)
|
||||
}
|
||||
);
|
||||
}
|
||||
),
|
||||
off: commonDescriptor(
|
||||
function DOMOff(type, handler, capture) {
|
||||
this.removeEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function DOMOn(type, handler, capture) {
|
||||
this.addEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function DOMTrigger(evt, data) {
|
||||
var
|
||||
stringEvent = typeof evt === 'string',
|
||||
type = stringEvent ? evt : (data = evt).type,
|
||||
e = (
|
||||
this.ownerDocument || this.document || global.document
|
||||
).createEvent('Event');
|
||||
e.initEvent(
|
||||
type,
|
||||
data && data.bubbles || 1,
|
||||
data && data.cancelable || 1
|
||||
);
|
||||
initEvent(e, this, type, stringEvent && data);
|
||||
this.dispatchEvent(e);
|
||||
return this;
|
||||
}
|
||||
)
|
||||
},
|
||||
JSDescriptor = {
|
||||
boundTo: boundTo,
|
||||
emit: commonDescriptor(
|
||||
function JSemit(type) {
|
||||
var array = this[uid][type];
|
||||
if (array) {
|
||||
array.forEach(
|
||||
emitJS,
|
||||
{
|
||||
arguments: (
|
||||
array.shift.call(arguments),
|
||||
arguments
|
||||
),
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
off: commonDescriptor(
|
||||
function JSOff(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type],
|
||||
i;
|
||||
if (array) {
|
||||
i = array.indexOf(handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function JSOn(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type] || (listeners[type] = []);
|
||||
if (array.indexOf(handler) < 0) {
|
||||
array.push(handler);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function JSTrigger(evt, data) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
isNotEvent = typeof evt === 'string',
|
||||
array = listeners[isNotEvent ? evt : evt.type];
|
||||
if (array) {
|
||||
array.every(
|
||||
triggerJS,
|
||||
{
|
||||
arguments: [isNotEvent ?
|
||||
new Event(this, evt, data) :
|
||||
(evt instanceof Event ?
|
||||
evt : injectActiveStatus(evt))],
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
)
|
||||
},
|
||||
stoppedPropagation = {
|
||||
value: false
|
||||
},
|
||||
WM = global.WeakMap,
|
||||
DOMWM
|
||||
;
|
||||
function Event(target, type, data) {
|
||||
initEvent(this, target, type, data);
|
||||
}
|
||||
function _stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
stopImmediatePropagation.call(this);
|
||||
this._stopImmediatePropagation();
|
||||
}
|
||||
function commonDescriptor(value) {
|
||||
return {
|
||||
// writable: true,
|
||||
configurable: true,
|
||||
value: value
|
||||
};
|
||||
}
|
||||
function defineCommonMethod(name) {
|
||||
return function () {
|
||||
/*jshint validthis:true */
|
||||
return defineProperties(
|
||||
this,
|
||||
hasDOM && ('dispatchEvent' in this) ?
|
||||
DOMDescriptor :
|
||||
JSDescriptor
|
||||
)[name].apply(this, arguments);
|
||||
};
|
||||
}
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!(key in e)) e[key] = value;
|
||||
}
|
||||
function initEvent(e, target, type, data) {
|
||||
ifNotPresent(e, 'timeStamp', Date.now());
|
||||
for(var key in data) ifNotPresent(e, key, data[key]);
|
||||
ifNotPresent(e, 'type', type);
|
||||
ifNotPresent(e, 'target', target);
|
||||
if (data) ifNotPresent(e, 'data', data);
|
||||
}
|
||||
function injectActiveStatus(evt) {
|
||||
evt._active = true;
|
||||
evt._stopImmediatePropagation = evt.stopImmediatePropagation;
|
||||
evt.stopImmediatePropagation = _stopImmediatePropagation;
|
||||
return evt;
|
||||
}
|
||||
function stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
defineProperty(
|
||||
this,
|
||||
'_active',
|
||||
stoppedPropagation
|
||||
);
|
||||
}
|
||||
function triggerEvent(handler, context, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
function triggerAny(handler, context, e) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.call(context, e);
|
||||
} else {
|
||||
handler.handleEvent(e);
|
||||
}
|
||||
}
|
||||
function emitJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
triggerEvent(handler, this.context, this.arguments);
|
||||
}
|
||||
function triggerJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
emitJS.call(this, handler);
|
||||
return this.arguments[0]._active;
|
||||
}
|
||||
if (hasDOM) {
|
||||
DOMWM = WM ? new WM() : {
|
||||
get: function (node) {
|
||||
return node[uid];
|
||||
},
|
||||
set: function (node, value) {
|
||||
defineProperty(
|
||||
node,
|
||||
uid,
|
||||
commonDescriptor(value)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
defineProperties(
|
||||
Event.prototype,
|
||||
{
|
||||
_active: commonDescriptor(true),
|
||||
stopImmediatePropagation: commonDescriptor(stopImmediatePropagation)
|
||||
}
|
||||
);
|
||||
// this property is used as
|
||||
// defineProperties descriptor
|
||||
// for all JS objects
|
||||
// In order to grant a fresh new
|
||||
// object as event handler
|
||||
// and without leaks
|
||||
// a new descriptor is returned
|
||||
// per each call
|
||||
defineProperty(
|
||||
JSDescriptor,
|
||||
uid,
|
||||
{
|
||||
enumerable: true,
|
||||
get: function get() {
|
||||
return {
|
||||
value: create(null)
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
// all must be configurable
|
||||
// so other prototypes can work too
|
||||
defineProperties(
|
||||
Object.prototype,
|
||||
{
|
||||
boundTo: commonDescriptor(
|
||||
defineCommonMethod('boundTo')
|
||||
),
|
||||
emit: commonDescriptor(
|
||||
defineCommonMethod('emit')
|
||||
),
|
||||
/*
|
||||
handleEvent: commonDescriptor(
|
||||
defineCommonMethod('handleEvent')
|
||||
),
|
||||
*/
|
||||
off: commonDescriptor(
|
||||
defineCommonMethod('off')
|
||||
),
|
||||
on: commonDescriptor(
|
||||
defineCommonMethod('on')
|
||||
),
|
||||
once: commonDescriptor(
|
||||
defineCommonMethod('once')
|
||||
),
|
||||
trigger: commonDescriptor(
|
||||
defineCommonMethod('trigger')
|
||||
)
|
||||
}
|
||||
);
|
||||
defineProperty(
|
||||
String.prototype,
|
||||
'toLocaleString',
|
||||
commonDescriptor((function(){
|
||||
var
|
||||
hasOwnProperty = {}.hasOwnProperty,
|
||||
re = /\$\{([^}]+?)\}/g,
|
||||
place = function ($0, $1) {
|
||||
return current[$1];
|
||||
},
|
||||
locale = create(null),
|
||||
current;
|
||||
defineProperty(
|
||||
String,
|
||||
'setLocale',
|
||||
commonDescriptor(function setLocale(language){
|
||||
for (var key in language) {
|
||||
if (hasOwnProperty.call(language, key)) {
|
||||
locale[key] = language[key];
|
||||
}
|
||||
}
|
||||
return language;
|
||||
})
|
||||
);
|
||||
return function toLocaleString(object) {
|
||||
var result;
|
||||
current = object;
|
||||
result = (locale[this] || this).replace(re, place);
|
||||
current = null;
|
||||
return result;
|
||||
};
|
||||
}()))
|
||||
);
|
||||
defineProperty(global, 'eddy', {
|
||||
value: true
|
||||
});
|
||||
}(
|
||||
typeof global == 'undefined' ? window : global
|
||||
));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function m(e,t,n){E(this,e,t,n)}function g(){x.call(this),this._stopImmediatePropagation()}function y(e){return{configurable:!0,value:e}}function b(e){return function(){return s(this,a&&"dispatchEvent"in this?c:h)[e].apply(this,arguments)}}function w(e,t,n){t in e||(e[t]=n)}function E(e,t,n,r){w(e,"timeStamp",Date.now());for(var i in r)w(e,i,r[i]);w(e,"type",n),w(e,"target",t),r&&w(e,"data",r)}function S(e){return e._active=!0,e._stopImmediatePropagation=e.stopImmediatePropagation,e.stopImmediatePropagation=g,e}function x(){i(this,"_active",p)}function T(e,t,n){typeof e=="function"?e.apply(t,n):e.handleEvent.apply(e,n)}function N(e,t,n){typeof e=="function"?e.call(t,n):e.handleEvent(n)}function C(e){T(e,this.context,this.arguments)}function k(e){return C.call(this,e),this.arguments[0]._active}if(e.eddy)return;var t="_@eddy:"+Math.random(),n=e.Object,r=n.create,i=n.defineProperty,s=n.defineProperties,o=Array.prototype.slice,u=e.Node||e.Element||e.HTMLElement,a=!!u,f=y(function(n){var i=a?v.get(this)||(v.set(this,r(null)),v.get(this)):this[t],s=i[t]||(i[t]={m:[],b:[]}),o=typeof n=="string"?this[n]:n,u=s.m.indexOf(o);return u<0?s.b[s.m.push(o)-1]=o.bind(this):s.b[u]}),l=y(function(t,n,r){var i=this;return i.on(t,function s(){i.off(t,s,r),T(n,i,arguments)},r)}),c={boundTo:f,emit:y(function(t){return this.trigger(t,{data:o.call(arguments,1)})}),off:y(function(t,n,r){return this.removeEventListener(t,n,!!r),this}),on:y(function(t,n,r){return this.addEventListener(t,n,!!r),this}),once:l,trigger:y(function(n,r){var i=typeof n=="string",s=i?n:(r=n).type,o=(this.ownerDocument||this.document||e.document).createEvent("Event");return o.initEvent(s,r&&r.bubbles||1,r&&r.cancelable||1),E(o,this,s,i&&r),this.dispatchEvent(o),this})},h={boundTo:f,emit:y(function(n){var r=this[t][n],i=!!r;return i&&r.forEach(C,{arguments:(r.shift.call(arguments),arguments),context:this}),i}),off:y(function(n,r){var i=this[t],s=i[n],o;return s&&(o=s.indexOf(r),-1<o&&(s.splice(o,1),s.length||delete i[n])),this}),on:y(function(n,r){var i=this[t],s=i[n]||(i[n]=[]);return s.indexOf(r)<0&&s.push(r),this}),once:l,trigger:y(function(n,r){var i=this[t],s=typeof n=="string",o=i[s?n:n.type];return o&&o.every(k,{arguments:[s?new m(this,n,r):n instanceof m?n:S(n)],context:this}),this})},p={value:!1},d=e.WeakMap,v;a&&(v=d?new d:{get:function(e){return e[t]},set:function(e,n){i(e,t,y(n))}}),s(m.prototype,{_active:y(!0),stopImmediatePropagation:y(x)}),i(h,t,{enumerable:!0,get:function(){return{value:r(null)}}}),s(n.prototype,{boundTo:y(b("boundTo")),emit:y(b("emit")),off:y(b("off")),on:y(b("on")),once:y(b("once")),trigger:y(b("trigger"))}),i(e,"eddy",{value:!0})})(typeof global=="undefined"?window:global);
|
||||
@@ -0,0 +1,368 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function(global){
|
||||
'use strict';
|
||||
if (global.eddy) return;
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
var
|
||||
uid = '_@eddy:' + Math.random(),
|
||||
Object = global.Object,
|
||||
create = Object.create,
|
||||
defineProperty = Object.defineProperty,
|
||||
defineProperties = Object.defineProperties,
|
||||
slice = Array.prototype.slice,
|
||||
DOM = global.Node || global.Element || global.HTMLElement,
|
||||
hasDOM = !!DOM,
|
||||
boundTo = commonDescriptor(
|
||||
function boundTo(method) {
|
||||
var
|
||||
listeners = hasDOM ? DOMWM.get(this) || (
|
||||
DOMWM.set(this, create(null)),
|
||||
DOMWM.get(this)
|
||||
) : this[uid],
|
||||
bound = listeners[uid] || (
|
||||
listeners[uid] = {
|
||||
m: [],
|
||||
b: []
|
||||
}
|
||||
),
|
||||
fn = typeof method === 'string' ?
|
||||
this[method] : method,
|
||||
i = bound.m.indexOf(fn);
|
||||
return i < 0 ?
|
||||
bound.b[bound.m.push(fn) - 1] = fn.bind(this) :
|
||||
bound.b[i];
|
||||
}
|
||||
),
|
||||
once = commonDescriptor(
|
||||
function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once() {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(handler, self, arguments);
|
||||
}, capture);
|
||||
}
|
||||
),
|
||||
DOMDescriptor = {
|
||||
boundTo: boundTo,
|
||||
emit: commonDescriptor(
|
||||
function DOMemit(type) {
|
||||
return this.trigger(
|
||||
type,
|
||||
{
|
||||
data: slice.call(arguments, 1)
|
||||
}
|
||||
);
|
||||
}
|
||||
),
|
||||
off: commonDescriptor(
|
||||
function DOMOff(type, handler, capture) {
|
||||
this.removeEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function DOMOn(type, handler, capture) {
|
||||
this.addEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function DOMTrigger(evt, data) {
|
||||
var
|
||||
stringEvent = typeof evt === 'string',
|
||||
type = stringEvent ? evt : (data = evt).type,
|
||||
e = (
|
||||
this.ownerDocument || this.document || global.document
|
||||
).createEvent('Event');
|
||||
e.initEvent(
|
||||
type,
|
||||
data && data.bubbles || 1,
|
||||
data && data.cancelable || 1
|
||||
);
|
||||
initEvent(e, this, type, stringEvent && data);
|
||||
this.dispatchEvent(e);
|
||||
return this;
|
||||
}
|
||||
)
|
||||
},
|
||||
JSDescriptor = {
|
||||
boundTo: boundTo,
|
||||
emit: commonDescriptor(
|
||||
function JSemit(type) {
|
||||
var array = this[uid][type],
|
||||
emitted = !!array;
|
||||
if (emitted) {
|
||||
array.forEach(
|
||||
emitJS,
|
||||
{
|
||||
arguments: (
|
||||
array.shift.call(arguments),
|
||||
arguments
|
||||
),
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return emitted;
|
||||
}
|
||||
),
|
||||
off: commonDescriptor(
|
||||
function JSOff(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type],
|
||||
i;
|
||||
if (array) {
|
||||
i = array.indexOf(handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function JSOn(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type] || (listeners[type] = []);
|
||||
if (array.indexOf(handler) < 0) {
|
||||
array.push(handler);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function JSTrigger(evt, data) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
isNotEvent = typeof evt === 'string',
|
||||
array = listeners[isNotEvent ? evt : evt.type];
|
||||
if (array) {
|
||||
array.every(
|
||||
triggerJS,
|
||||
{
|
||||
arguments: [isNotEvent ?
|
||||
new Event(this, evt, data) :
|
||||
(evt instanceof Event ?
|
||||
evt : injectActiveStatus(evt))],
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
)
|
||||
},
|
||||
stoppedPropagation = {
|
||||
value: false
|
||||
},
|
||||
WM = global.WeakMap,
|
||||
DOMWM
|
||||
;
|
||||
function Event(target, type, data) {
|
||||
initEvent(this, target, type, data);
|
||||
}
|
||||
function _stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
stopImmediatePropagation.call(this);
|
||||
this._stopImmediatePropagation();
|
||||
}
|
||||
function commonDescriptor(value) {
|
||||
return {
|
||||
// writable: true,
|
||||
configurable: true,
|
||||
value: value
|
||||
};
|
||||
}
|
||||
function defineCommonMethod(name) {
|
||||
return function () {
|
||||
/*jshint validthis:true */
|
||||
return defineProperties(
|
||||
this,
|
||||
hasDOM && ('dispatchEvent' in this) ?
|
||||
DOMDescriptor :
|
||||
JSDescriptor
|
||||
)[name].apply(this, arguments);
|
||||
};
|
||||
}
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!(key in e)) e[key] = value;
|
||||
}
|
||||
function initEvent(e, target, type, data) {
|
||||
ifNotPresent(e, 'timeStamp', Date.now());
|
||||
for(var key in data) ifNotPresent(e, key, data[key]);
|
||||
ifNotPresent(e, 'type', type);
|
||||
ifNotPresent(e, 'target', target);
|
||||
if (data) ifNotPresent(e, 'data', data);
|
||||
}
|
||||
function injectActiveStatus(evt) {
|
||||
evt._active = true;
|
||||
evt._stopImmediatePropagation = evt.stopImmediatePropagation;
|
||||
evt.stopImmediatePropagation = _stopImmediatePropagation;
|
||||
return evt;
|
||||
}
|
||||
function stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
defineProperty(
|
||||
this,
|
||||
'_active',
|
||||
stoppedPropagation
|
||||
);
|
||||
}
|
||||
function triggerEvent(handler, context, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
function triggerAny(handler, context, e) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.call(context, e);
|
||||
} else {
|
||||
handler.handleEvent(e);
|
||||
}
|
||||
}
|
||||
function emitJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
triggerEvent(handler, this.context, this.arguments);
|
||||
}
|
||||
function triggerJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
emitJS.call(this, handler);
|
||||
return this.arguments[0]._active;
|
||||
}
|
||||
if (hasDOM) {
|
||||
DOMWM = WM ? new WM() : {
|
||||
get: function (node) {
|
||||
return node[uid];
|
||||
},
|
||||
set: function (node, value) {
|
||||
defineProperty(
|
||||
node,
|
||||
uid,
|
||||
commonDescriptor(value)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
defineProperties(
|
||||
Event.prototype,
|
||||
{
|
||||
_active: commonDescriptor(true),
|
||||
stopImmediatePropagation: commonDescriptor(stopImmediatePropagation)
|
||||
}
|
||||
);
|
||||
// this property is used as
|
||||
// defineProperties descriptor
|
||||
// for all JS objects
|
||||
// In order to grant a fresh new
|
||||
// object as event handler
|
||||
// and without leaks
|
||||
// a new descriptor is returned
|
||||
// per each call
|
||||
defineProperty(
|
||||
JSDescriptor,
|
||||
uid,
|
||||
{
|
||||
enumerable: true,
|
||||
get: function get() {
|
||||
return {
|
||||
value: create(null)
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
// all must be configurable
|
||||
// so other prototypes can work too
|
||||
defineProperties(
|
||||
Object.prototype,
|
||||
{
|
||||
boundTo: commonDescriptor(
|
||||
defineCommonMethod('boundTo')
|
||||
),
|
||||
emit: commonDescriptor(
|
||||
defineCommonMethod('emit')
|
||||
),
|
||||
off: commonDescriptor(
|
||||
defineCommonMethod('off')
|
||||
),
|
||||
on: commonDescriptor(
|
||||
defineCommonMethod('on')
|
||||
),
|
||||
once: commonDescriptor(
|
||||
defineCommonMethod('once')
|
||||
),
|
||||
trigger: commonDescriptor(
|
||||
defineCommonMethod('trigger')
|
||||
)
|
||||
}
|
||||
);
|
||||
/* abandoned right now ...
|
||||
defineProperty(
|
||||
String.prototype,
|
||||
'toLocaleString',
|
||||
commonDescriptor((function(){
|
||||
var
|
||||
hasOwnProperty = {}.hasOwnProperty,
|
||||
re = /\$\{([^}]+?)\}/g,
|
||||
place = function ($0, $1) {
|
||||
return current[$1];
|
||||
},
|
||||
locale = create(null),
|
||||
current;
|
||||
defineProperty(
|
||||
String,
|
||||
'setLocale',
|
||||
commonDescriptor(function setLocale(language){
|
||||
for (var key in language) {
|
||||
if (hasOwnProperty.call(language, key)) {
|
||||
locale[key] = language[key];
|
||||
}
|
||||
}
|
||||
return language;
|
||||
})
|
||||
);
|
||||
return function toLocaleString(object) {
|
||||
var result;
|
||||
current = object;
|
||||
result = (locale[this] || this).replace(re, place);
|
||||
current = null;
|
||||
return result;
|
||||
};
|
||||
}()))
|
||||
);
|
||||
// */
|
||||
defineProperty(global, 'eddy', {
|
||||
value: true
|
||||
});
|
||||
}(
|
||||
typeof global == 'undefined' ? window : global
|
||||
));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function v(e,t,n){E(this,e,t,n)}function m(){x.call(this),this._stopImmediatePropagation()}function g(e){return{enumerable:!1,writable:!0,configurable:!0,value:e}}function y(e,n,r){var i=n[t]||(n[t]={m:[],b:[]}),s=typeof r=="string"?e[r]:r,o=i.m.indexOf(s);return o<0?i.b[i.m.push(s)-1]=s.bind(e):i.b[o]}function b(e){return function(){return s(this,a&&"dispatchEvent"in this?l:c)[e].apply(this,arguments)}}function w(e,t,n){t in e||(e[t]=n)}function E(e,t,n,r){w(e,"timeStamp",Date.now());for(var i in r)w(e,i,r[i]);w(e,"type",n),w(e,"target",t),r&&w(e,"data",r)}function S(e){return e._active=!0,e._stopImmediatePropagation=e.stopImmediatePropagation,e.stopImmediatePropagation=m,e}function x(){i(this,"_active",h)}function T(e,t,n){typeof e=="function"?e.apply(t,n):e.handleEvent.apply(e,n)}function N(e,t,n){typeof e=="function"?e.call(t,n):e.handleEvent(n)}function C(e){T(e,this.context,this.arguments)}function k(e){return C.call(this,e),this.arguments[0]._active}if(e.eddy)return;var t="_@eddy:"+Math.random(),n=e.Object,r=n.create,i=n.defineProperty,s=n.defineProperties,o=Array.prototype.slice,u=e.Node||e.Element||e.HTMLElement,a=!!u,f=g(function(t,n,r){var i=this;return i.on(t,function s(){i.off(t,s,r),T(n,i,arguments)},r)}),l={boundTo:g(function(e){return y(this,d.get(this)||(d.set(this,r(null)),d.get(this)),e)}),emit:g(function(t){return this.trigger(t,{data:o.call(arguments,1)})}),off:g(function(t,n,r){return this.removeEventListener(t,n,!!r),this}),on:g(function(t,n,r){return this.addEventListener(t,n,!!r),this}),once:f,trigger:g(function(n,r){var i=typeof n=="string",s=i?n:(r=n).type,o=(this.ownerDocument||this.document||e.document).createEvent("Event");return o.initEvent(s,r&&r.bubbles||1,r&&r.cancelable||1),E(o,this,s,i&&r),this.dispatchEvent(o)})},c={boundTo:g(function(e){return y(this,this[t],e)}),emit:g(function(n){var r=this[t][n],i=!!r;return i&&r.forEach(C,{arguments:(r.shift.call(arguments),arguments),context:this}),i}),off:g(function(n,r){var i=this[t],s=i[n],o;return s&&(o=s.indexOf(r),-1<o&&(s.splice(o,1),s.length||delete i[n])),this}),on:g(function(n,r){var i=this[t],s=i[n]||(i[n]=[]);return s.indexOf(r)<0&&s.push(r),this}),once:f,trigger:g(function(n,r){var i=this[t],s=typeof n=="string",o=i[s?n:n.type];return o?o.every(k,{arguments:[s?new v(this,n,r):n instanceof v?n:S(n)],context:this}):!0})},h={value:!1},p=e.WeakMap,d;a&&(d=p?new p:{get:function(e){return e[t]},set:function(e,n){i(e,t,g(n))}}),s(v.prototype,{_active:g(!0),stopImmediatePropagation:g(x)}),i(c,t,{enumerable:!0,get:function(){return{value:r(null)}}}),s(n.prototype,{boundTo:g(b("boundTo")),emit:g(b("emit")),off:g(b("off")),on:g(b("on")),once:g(b("once")),trigger:g(b("trigger"))}),i(e,"eddy",{value:!0})})(typeof global=="undefined"?window:global);
|
||||
@@ -0,0 +1,335 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function(global){
|
||||
'use strict';
|
||||
if (global.eddy) return;
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
var
|
||||
uid = '_@eddy:' + Math.random(),
|
||||
Object = global.Object,
|
||||
create = Object.create,
|
||||
defineProperty = Object.defineProperty,
|
||||
defineProperties = Object.defineProperties,
|
||||
slice = Array.prototype.slice,
|
||||
DOM = global.Node || global.Element || global.HTMLElement,
|
||||
hasDOM = !!DOM,
|
||||
once = commonDescriptor(
|
||||
function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once() {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(handler, self, arguments);
|
||||
}, capture);
|
||||
}
|
||||
),
|
||||
DOMDescriptor = {
|
||||
boundTo: commonDescriptor(function(method){
|
||||
return boundTo(
|
||||
this,
|
||||
DOMWM.get(this) || (
|
||||
DOMWM.set(this, create(null)),
|
||||
DOMWM.get(this)
|
||||
),
|
||||
method
|
||||
);
|
||||
}),
|
||||
emit: commonDescriptor(
|
||||
function DOMemit(type) {
|
||||
return this.trigger(
|
||||
type,
|
||||
{
|
||||
data: slice.call(arguments, 1)
|
||||
}
|
||||
);
|
||||
}
|
||||
),
|
||||
off: commonDescriptor(
|
||||
function DOMOff(type, handler, capture) {
|
||||
this.removeEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function DOMOn(type, handler, capture) {
|
||||
this.addEventListener(type, handler, !!capture);
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function DOMTrigger(evt, data) {
|
||||
var
|
||||
stringEvent = typeof evt === 'string',
|
||||
type = stringEvent ? evt : (data = evt).type,
|
||||
e = (
|
||||
this.ownerDocument || this.document || global.document
|
||||
).createEvent('Event');
|
||||
e.initEvent(
|
||||
type,
|
||||
data && data.bubbles || 1,
|
||||
data && data.cancelable || 1
|
||||
);
|
||||
initEvent(e, this, type, stringEvent && data);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
)
|
||||
},
|
||||
JSDescriptor = {
|
||||
boundTo: commonDescriptor(function(method){
|
||||
return boundTo(this, this[uid], method);
|
||||
}),
|
||||
emit: commonDescriptor(
|
||||
function JSemit(type) {
|
||||
var array = this[uid][type],
|
||||
emitted = !!array;
|
||||
if (emitted) {
|
||||
array.forEach(
|
||||
emitJS,
|
||||
{
|
||||
arguments: (
|
||||
array.shift.call(arguments),
|
||||
arguments
|
||||
),
|
||||
context: this
|
||||
}
|
||||
);
|
||||
}
|
||||
return emitted;
|
||||
}
|
||||
),
|
||||
off: commonDescriptor(
|
||||
function JSOff(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type],
|
||||
i;
|
||||
if (array) {
|
||||
i = array.indexOf(handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
on: commonDescriptor(
|
||||
function JSOn(type, handler) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
array = listeners[type] || (listeners[type] = []);
|
||||
if (array.indexOf(handler) < 0) {
|
||||
array.push(handler);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
),
|
||||
once: once,
|
||||
trigger: commonDescriptor(
|
||||
function JSTrigger(evt, data) {
|
||||
var
|
||||
listeners = this[uid],
|
||||
isNotEvent = typeof evt === 'string',
|
||||
array = listeners[isNotEvent ? evt : evt.type];
|
||||
return array ? array.every(
|
||||
triggerJS,
|
||||
{
|
||||
arguments: [isNotEvent ?
|
||||
new Event(this, evt, data) :
|
||||
(evt instanceof Event ?
|
||||
evt : injectActiveStatus(evt))],
|
||||
context: this
|
||||
}
|
||||
) : true;
|
||||
}
|
||||
)
|
||||
},
|
||||
stoppedPropagation = {
|
||||
value: false
|
||||
},
|
||||
WM = global.WeakMap,
|
||||
DOMWM
|
||||
;
|
||||
function Event(target, type, data) {
|
||||
initEvent(this, target, type, data);
|
||||
}
|
||||
function _stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
stopImmediatePropagation.call(this);
|
||||
this._stopImmediatePropagation();
|
||||
}
|
||||
function commonDescriptor(value) {
|
||||
return {
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: value
|
||||
};
|
||||
}
|
||||
function boundTo(self, listeners, method) {
|
||||
var
|
||||
bound = listeners[uid] || (
|
||||
listeners[uid] = {
|
||||
m: [],
|
||||
b: []
|
||||
}
|
||||
),
|
||||
fn = typeof method === 'string' ?
|
||||
self[method] : method,
|
||||
i = bound.m.indexOf(fn);
|
||||
return i < 0 ?
|
||||
bound.b[bound.m.push(fn) - 1] = fn.bind(self) :
|
||||
bound.b[i];
|
||||
}
|
||||
function defineCommonMethod(name) {
|
||||
return function () {
|
||||
/*jshint validthis:true */
|
||||
return defineProperties(
|
||||
this,
|
||||
hasDOM && ('dispatchEvent' in this) ?
|
||||
DOMDescriptor :
|
||||
JSDescriptor
|
||||
)[name].apply(this, arguments);
|
||||
};
|
||||
}
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!(key in e)) e[key] = value;
|
||||
}
|
||||
function initEvent(e, target, type, data) {
|
||||
ifNotPresent(e, 'timeStamp', Date.now());
|
||||
for(var key in data) ifNotPresent(e, key, data[key]);
|
||||
ifNotPresent(e, 'type', type);
|
||||
ifNotPresent(e, 'target', target);
|
||||
if (data) ifNotPresent(e, 'data', data);
|
||||
}
|
||||
function injectActiveStatus(evt) {
|
||||
evt._active = true;
|
||||
evt._stopImmediatePropagation = evt.stopImmediatePropagation;
|
||||
evt.stopImmediatePropagation = _stopImmediatePropagation;
|
||||
return evt;
|
||||
}
|
||||
function stopImmediatePropagation() {
|
||||
/*jshint validthis:true */
|
||||
defineProperty(
|
||||
this,
|
||||
'_active',
|
||||
stoppedPropagation
|
||||
);
|
||||
}
|
||||
function triggerEvent(handler, context, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
function triggerAny(handler, context, e) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.call(context, e);
|
||||
} else {
|
||||
handler.handleEvent(e);
|
||||
}
|
||||
}
|
||||
function emitJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
triggerEvent(handler, this.context, this.arguments);
|
||||
}
|
||||
function triggerJS(handler) {
|
||||
/*jshint validthis:true */
|
||||
emitJS.call(this, handler);
|
||||
return this.arguments[0]._active;
|
||||
}
|
||||
if (hasDOM) {
|
||||
DOMWM = WM ? new WM() : {
|
||||
get: function (node) {
|
||||
return node[uid];
|
||||
},
|
||||
set: function (node, value) {
|
||||
defineProperty(
|
||||
node,
|
||||
uid,
|
||||
commonDescriptor(value)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
defineProperties(
|
||||
Event.prototype,
|
||||
{
|
||||
_active: commonDescriptor(true),
|
||||
stopImmediatePropagation: commonDescriptor(stopImmediatePropagation)
|
||||
}
|
||||
);
|
||||
// this property is used as
|
||||
// defineProperties descriptor
|
||||
// for all JS objects
|
||||
// In order to grant a fresh new
|
||||
// object as event handler
|
||||
// and without leaks
|
||||
// a new descriptor is returned
|
||||
// per each call
|
||||
defineProperty(
|
||||
JSDescriptor,
|
||||
uid,
|
||||
{
|
||||
enumerable: true,
|
||||
get: function get() {
|
||||
return {
|
||||
value: create(null)
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
// all must be configurable
|
||||
// so other prototypes can work too
|
||||
defineProperties(
|
||||
Object.prototype,
|
||||
{
|
||||
boundTo: commonDescriptor(
|
||||
defineCommonMethod('boundTo')
|
||||
),
|
||||
emit: commonDescriptor(
|
||||
defineCommonMethod('emit')
|
||||
),
|
||||
off: commonDescriptor(
|
||||
defineCommonMethod('off')
|
||||
),
|
||||
on: commonDescriptor(
|
||||
defineCommonMethod('on')
|
||||
),
|
||||
once: commonDescriptor(
|
||||
defineCommonMethod('once')
|
||||
),
|
||||
trigger: commonDescriptor(
|
||||
defineCommonMethod('trigger')
|
||||
)
|
||||
}
|
||||
);
|
||||
defineProperty(global, 'eddy', {
|
||||
value: true
|
||||
});
|
||||
}(
|
||||
typeof global == 'undefined' ? window : global
|
||||
));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function b(){return{l:{},m:[],b:[]}}function w(e,t,n){s.call(e,t)||(e[t]=n)}function E(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function S(e,t,n){w(this,"timeStamp",m());for(var r in n)s.call(n,r)&&w(this,r,n[r]);w(this,"type",t),w(this,"target",e),n&&w(this,"data",n)}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=S.prototype,i=e.defineProperty,s=n.hasOwnProperty,o=t.push,u=t.slice,a=t.unshift,f="toLocaleString",l={toLocaleString:1}.propertyIsEnumerable(f)?"_@eddy"+Math.random():f,c=l===f,h=c||(e.create||e)(null),p=c?function(e){return e[l]=b(),e[l]}:function(e){var t=b();return h.value=t,i(e,l,h),h.value=null,t},d=e.bind||function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now?function(){return Date.now()}:function(){return(new Date).getTime()},g={boundTo:function(t){var n=s.call(this,l)?this[l]:p(this),r=n.m,i=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?i[o.call(r,u)-1]=d.call(u,this):i[a]},emit:function(t){var n=s.call(this,l),r=n&&this[l].l,i=n&&s.call(r,t),o=i&&r[t],a=i&&u.call(arguments,1),f=0,c=i?o.length:f;while(f<c)E(this,o[f++],a);return i},off:function(t,n){var r=s.call(this,l),i=r&&this[l].l,o=r&&s.call(i,t)&&i[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete i[t])),this},on:function(t,n,r){var i=s.call(this,l),u=(i?this[l]:p(this)).l,f=i&&s.call(u,t)?u[t]:u[t]=[];return v.call(f,n)<0&&(r?a:o).call(f,n),this},once:function(t,n,r){var i=this;return i.on(t,function s(e){i.off(t,s,r),E(i,n,arguments)},r)},trigger:function(t,n){var i=s.call(this,l),o=i&&this[l].l,u=typeof t=="string",a=u?t:t.type,f=i&&s.call(o,a),c=f&&o[a],h=u?new S(this,a,n):t,p=[h],d=0,v=f?c.length:d,m=!(h instanceof S),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation);while(h._active&&d<v)E(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},y;r._active=!0,r.stopImmediatePropagation=function(){this._active=!1},function(){function u(e){var t=n.toString,r=g[e],i=o[e];return function(){return(t.call(this)=="[object Object]"?r:i).apply(this,arguments)}}function a(e,t){return typeof t=="function"?e.boundTo(t):t.boundTo(t.handleEvent)}var e=!("addEventListener"in window),t=e?function(e){var t=document.createEventObject();return t.eventType=e,t}:function(e){var t=document.createEvent("Event");return t.initEvent(e,!0,!0),t},r=e?function(e,t){var n=e.fireEvent(t.eventType,t);return n||e.fireEvent("on"+t.eventType,t)}:function(e,t){return e.dispatchEvent(t)},o={boundTo:g.boundTo,emit:function(n){return r(this,t(n))},off:e?function(e,t,n){var r=a(this,t);return this.detachEvent(e,r),this.detachEvent("on"+e,r),this}:function(e,t,n){return this.removeEventListener(e,t,n),this},on:e?function(e,t,n){var r=a(this,t);return this.attachEvent(e,r),this.attachEvent("on"+e,r),this}:function(e,t,n){return this.addEventListener(e,t,n),this},once:function(n,r,i){var s=this;return s.on(n,function o(t){s.off(n,o,i),(e?a(s,r):r).call(s,t)},i)},trigger:function(n,i){var s=typeof n=="string",o=s?n:n.type,u=t(o);return S.call(u,this,o,s&&i),r(this,u)}};for(var f in g)s.call(g,f)&&(c?n[f]=u(f):i(n,f,{enumerable:!1,configurable:!0,writable:!0,value:u(f)}))}()})(Object);
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function b(){return{l:{},m:[],b:[]}}function w(e,t,n){s.call(e,t)||(e[t]=n)}function E(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function S(e,t,n){w(this,"timeStamp",m());for(var r in n)s.call(n,r)&&w(this,r,n[r]);w(this,"type",t),w(this,"target",e),n&&w(this,"data",n)}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=S.prototype,i=e.defineProperty,s=n.hasOwnProperty,o=t.push,u=t.slice,a=t.unshift,f="toLocaleString",l={toLocaleString:1}.propertyIsEnumerable(f)?"_@eddy"+Math.random():f,c=l===f,h=c||(e.create||e)(null),p=c?function(e){return e[l]=b(),e[l]}:function(e){var t=b();return h.value=t,i(e,l,h),h.value=null,t},d=e.bind||function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now?function(){return Date.now()}:function(){return(new Date).getTime()},g={boundTo:function(t){var n=s.call(this,l)?this[l]:p(this),r=n.m,i=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?i[o.call(r,u)-1]=d.call(u,this):i[a]},emit:function(t){var n=s.call(this,l),r=n&&this[l].l,i=n&&s.call(r,t),o=i&&r[t],a=i&&u.call(arguments,1),f=0,c=i?o.length:f;while(f<c)E(this,o[f++],a);return i},off:function(t,n){var r=s.call(this,l),i=r&&this[l].l,o=r&&s.call(i,t)&&i[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete i[t])),this},on:function(t,n,r){var i=s.call(this,l),u=(i?this[l]:p(this)).l,f=i&&s.call(u,t)?u[t]:u[t]=[];return v.call(f,n)<0&&(r?a:o).call(f,n),this},once:function(t,n,r){var i=this;return i.on(t,function s(e){i.off(t,s,r),E(i,n,arguments)},r)},trigger:function(t,n){var i=s.call(this,l),o=i&&this[l].l,u=typeof t=="string",a=u?t:t.type,f=i&&s.call(o,a),c=f&&o[a],h=u?new S(this,a,n):t,p=[h],d=0,v=f?c.length:d,m=!(h instanceof S),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation);while(h._active&&d<v)E(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},y;r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(y in g)s.call(g,y)&&(c?n[y]=g[y]:i(n,y,{enumerable:!1,configurable:!0,writable:!0,value:g[y]}))})(Object);
|
||||
@@ -0,0 +1,363 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
defineProperty = Object.defineProperty,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 hs this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = IE || (Object.create || Object)(null),
|
||||
setAndGet = IE ?
|
||||
function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
} :
|
||||
function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
bind = Object.bind || function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var self = this;
|
||||
return function () {
|
||||
return self.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now ?
|
||||
function () {
|
||||
return Date.now();
|
||||
} :
|
||||
function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once(e) {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
}, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
// assign properties only if not there already
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
}
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
if (IE) {
|
||||
ObjectPrototype[key] = eddy[key];
|
||||
} else {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function y(){return{l:{},m:[],b:[]}}function b(e,t,n){i.call(e,t)||(e[t]=n)}function w(e){var t=y();return c.value=t,h(e,f,c),c.value=null,t}function E(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function S(e,t,n){b(this,"timeStamp",v());for(var r in n)i.call(n,r)&&b(this,r,n[r]);b(this,"type",t),b(this,"target",e),n&&b(this,"data",n)}function T(e,t,n){var r=document.createEvent("Event");return r.initEvent(e,t,n),r}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=S.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:w(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)E(this,u[l++],a);return s},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:w(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=this;return i.on(t,function s(e){i.off(t,s,r),E(i,n,arguments)},r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a],h=u?new S(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof S),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)E(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g;r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(g in m)i.call(m,g)&&h(n,g,{enumerable:!1,configurable:!0,writable:!0,value:m[g]});var x={boundTo:m.boundTo,emit:function(n){var r=T(n,!1,!1);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:function(t,n,r){var i=this;return i.on(t,function s(e){i.off(t,s,r),E(i,n,arguments)},r)},trigger:function(t,n){var r=typeof t=="string",s=r?t:t.type,o=r?n||r:t,u=T(s,i.call(o,"bubbles")?o.bubbles:!0,i.call(o,"cancelable")?o.cancelable:!0);return S.call(u,this,s,r&&n),this.dispatchEvent(u)}};(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o,u;for(o in x)i.call(x,o)&&(u={enumerable:!1,configurable:!0,writable:!0,value:x[o]},h(n,o,u),h(r,o,u),h(s,o,u))})(window)})(Object);
|
||||
@@ -0,0 +1,438 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once(e) {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
}, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
// assign properties only if not there already
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
emit: function emit(type) {
|
||||
var e = createEvent(type, false, false);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once(e) {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
}, capture);
|
||||
},
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
opt = isString ? (data || isString) : evt,
|
||||
e = createEvent(
|
||||
type,
|
||||
hasOwnProperty.call(opt, 'bubbles') ?
|
||||
opt.bubbles : true,
|
||||
hasOwnProperty.call(opt, 'cancelable') ?
|
||||
opt.cancelable : true
|
||||
)
|
||||
;
|
||||
Event.call(e, this, type, isString && data);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
function createEvent(type, bubbles, cancelable) {
|
||||
var e = document.createEvent('Event');
|
||||
e.initEvent(type, bubbles, cancelable);
|
||||
return e;
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function y(){return{l:{},m:[],b:[]}}function b(e,t,n){i.call(e,t)||(e[t]=n)}function w(e){var t=y();return c.value=t,h(e,f,c),c.value=null,t}function E(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function S(e,t,n){b(this,"timeStamp",v());for(var r in n)i.call(n,r)&&b(this,r,n[r]);b(this,"type",t),b(this,"target",e),n&&b(this,"data",n)}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=S.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:w(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)E(this,u[l++],a);return s},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:w(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=this;return i.on(t,function s(e){i.off(t,s,r),E(i,n,arguments)},r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a],h=u?new S(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof S),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)E(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g;r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(g in m)i.call(m,g)&&h(n,g,{enumerable:!1,configurable:!0,writable:!0,value:m[g]})})(Object);
|
||||
@@ -0,0 +1,359 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var self = this;
|
||||
return self.on(type, function once(e) {
|
||||
self.off(type, once, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
}, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
// assign properties only if not there already
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function y(){return{l:{},m:[],b:[]}}function b(e,t,n){i.call(e,t)||(e[t]=n)}function w(e){var t=y();return c.value=t,h(e,f,c),c.value=null,t}function E(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function S(e,t,n){b(this,"timeStamp",v());for(var r in n)i.call(n,r)&&b(this,r,n[r]);b(this,"type",t),b(this,"target",e),n&&b(this,"data",n)}function T(e,t,n){var r=document.createEvent("Event");return r.initEvent(e,t,n),r}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=S.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:w(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)E(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:w(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),E(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),h=u?new S(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof S),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)E(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g;r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(g in m)i.call(m,g)&&h(n,g,{enumerable:!1,configurable:!0,writable:!0,value:m[g]});var x={boundTo:m.boundTo,emit:function(n){var r=T(n,!1,!1);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:m.once,trigger:function(t,n){var r=typeof t=="string",s=r?t:t.type,o=r?n||r:t,u=T(s,i.call(o,"bubbles")?o.bubbles:!0,i.call(o,"cancelable")?o.cancelable:!0);return S.call(u,this,s,r&&n),this.dispatchEvent(u)}};(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o,u;for(o in x)i.call(x,o)&&(u={enumerable:!1,configurable:!0,writable:!0,value:x[o]},h(n,o,u),h(r,o,u),h(s,o,u))})(window)})(Object);
|
||||
@@ -0,0 +1,454 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
// assign properties only if not there already
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
emit: function emit(type) {
|
||||
var e = createEvent(type, false, false);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
opt = isString ? (data || isString) : evt,
|
||||
e = createEvent(
|
||||
type,
|
||||
hasOwnProperty.call(opt, 'bubbles') ?
|
||||
opt.bubbles : true,
|
||||
hasOwnProperty.call(opt, 'cancelable') ?
|
||||
opt.cancelable : true
|
||||
)
|
||||
;
|
||||
Event.call(e, this, type, isString && data);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
function createEvent(type, bubbles, cancelable) {
|
||||
var e = document.createEvent('Event');
|
||||
e.initEvent(type, bubbles, cancelable);
|
||||
return e;
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function y(){return{l:{},m:[],b:[]}}function b(e,t,n){i.call(e,t)||(e[t]=n)}function w(e){var t=y();return c.value=t,h(e,f,c),c.value=null,t}function E(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function S(e,t,n){b(this,"timeStamp",v());for(var r in n)i.call(n,r)&&b(this,r,n[r]);b(this,"type",t),b(this,"target",e),n&&b(this,"data",n)}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=S.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:w(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)E(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:w(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),E(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),h=u?new S(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof S),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)E(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g;r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(g in m)i.call(m,g)&&h(n,g,{enumerable:!1,configurable:!0,writable:!0,value:m[g]})})(Object);
|
||||
@@ -0,0 +1,378 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
// assign properties only if not there already
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function y(){return{l:{},m:[],b:[]}}function b(e,t,n){i.call(e,t)||(e[t]=n)}function w(e){var t=y();return c.value=t,h(e,f,c),c.value=null,t}function E(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function S(e,t,n){b(this,"timeStamp",v());for(var r in n)i.call(n,r)&&b(this,r,n[r]);b(this,"type",t),b(this,"target",e),n&&b(this,"data",n)}function T(e,t,n){var r=document.createEvent("Event");return r.initEvent(e,t,n),r}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=S.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:w(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)E(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:w(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),E(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),h=u?new S(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof S),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)E(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g;r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(g in m)i.call(m,g)&&h(n,g,{enumerable:!1,configurable:!0,writable:!0,value:m[g]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in m)m.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&h(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var x={boundTo:m.boundTo,emit:function(n){var r=T(n,!1,!1);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:m.once,trigger:function(t,n){var r=typeof t=="string",s=r?t:t.type,o=r?n||r:t,u=T(s,i.call(o,"bubbles")?o.bubbles:!0,i.call(o,"cancelable")?o.cancelable:!0);return S.call(u,this,s,r&&n),this.dispatchEvent(u)}};(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o,u;for(o in x)i.call(x,o)&&(u={enumerable:!1,configurable:!0,writable:!0,value:x[o]},h(n,o,u),h(r,o,u),h(s,o,u))})(window)})(Object);
|
||||
@@ -0,0 +1,482 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
// assign properties only if not there already
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
emit: function emit(type) {
|
||||
var e = createEvent(type, false, false);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
opt = isString ? (data || isString) : evt,
|
||||
e = createEvent(
|
||||
type,
|
||||
hasOwnProperty.call(opt, 'bubbles') ?
|
||||
opt.bubbles : true,
|
||||
hasOwnProperty.call(opt, 'cancelable') ?
|
||||
opt.cancelable : true
|
||||
)
|
||||
;
|
||||
Event.call(e, this, type, isString && data);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
function createEvent(type, bubbles, cancelable) {
|
||||
var e = document.createEvent('Event');
|
||||
e.initEvent(type, bubbles, cancelable);
|
||||
return e;
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function y(){return{l:{},m:[],b:[]}}function b(e,t,n){i.call(e,t)||(e[t]=n)}function w(e){var t=y();return c.value=t,h(e,f,c),c.value=null,t}function E(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function S(e,t,n){b(this,"timeStamp",v());for(var r in n)i.call(n,r)&&b(this,r,n[r]);b(this,"type",t),b(this,"target",e),n&&b(this,"data",n)}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=S.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:w(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)E(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:w(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),E(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),h=u?new S(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof S),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)E(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g;r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(g in m)i.call(m,g)&&h(n,g,{enumerable:!1,configurable:!0,writable:!0,value:m[g]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in m)m.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&h(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,406 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
// assign properties only if not there already
|
||||
function ifNotPresent(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function w(){return{l:{},m:[],b:[]}}function S(e){var t=w();return c.value=t,h(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){y(this,"timeStamp",v());for(var r in n)i.call(n,r)&&y(this,r,n[r]);y(this,"type",t),y(this,"target",e),n&&y(this,"data",n)}function C(e,t,n){var r=document.createEvent("Event");return r.initEvent(e,t,n),r}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),h=u?new T(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof T),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)x(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g=!1,y,b;try{document.createEvent("Event").target=document,y=function(e,t,n){i.call(e,t)||(e[t]=n)}}catch(E){g=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(b in m)i.call(m,b)&&h(n,b,{enumerable:!1,configurable:!0,writable:!0,value:m[b]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in m)m.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&h(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:m.boundTo,emit:function(n){var r=C(n,!1,!1);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:m.once,trigger:function(t,n){var r=typeof t=="string",s=r?t:t.type,o=r?n||r:t,u=C(s,i.call(o,"bubbles")?o.bubbles:!0,i.call(o,"cancelable")?o.cancelable:!0);return T.call(u,this,s,r&&n),this.dispatchEvent(u)}};(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o,u;for(o in N)i.call(N,o)&&(u={enumerable:!1,configurable:!0,writable:!0,value:N[o]},h(n,o,u),h(r,o,u),h(s,o,u))})(window)})(Object);
|
||||
@@ -0,0 +1,497 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
ifNotPresent,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
};
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
emit: function emit(type) {
|
||||
var e = createEvent(type, false, false);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
opt = isString ? (data || isString) : evt,
|
||||
e = createEvent(
|
||||
type,
|
||||
hasOwnProperty.call(opt, 'bubbles') ?
|
||||
opt.bubbles : true,
|
||||
hasOwnProperty.call(opt, 'cancelable') ?
|
||||
opt.cancelable : true
|
||||
)
|
||||
;
|
||||
Event.call(e, this, type, isString && data);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
function createEvent(type, bubbles, cancelable) {
|
||||
var e = document.createEvent('Event');
|
||||
e.initEvent(type, bubbles, cancelable);
|
||||
return e;
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function w(){return{l:{},m:[],b:[]}}function S(e){var t=w();return c.value=t,h(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){y(this,"timeStamp",v());for(var r in n)i.call(n,r)&&y(this,r,n[r]);y(this,"type",t),y(this,"target",e),n&&y(this,"data",n)}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),h=u?new T(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof T),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)x(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g=!1,y,b;try{document.createEvent("Event").target=document,y=function(e,t,n){i.call(e,t)||(e[t]=n)}}catch(E){g=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(b in m)i.call(m,b)&&h(n,b,{enumerable:!1,configurable:!0,writable:!0,value:m[b]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in m)m.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&h(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,421 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
ifNotPresent,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
};
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function w(){return{l:{},m:[],b:[]}}function S(e){var t=w();return c.value=t,h(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){y(this,"timeStamp",v());for(var r in n)i.call(n,r)&&y(this,r,n[r]);y(this,"type",t),y(this,"target",e),n&&y(this,"data",n)}function C(e,t,n){var r=document.createEvent("Event");return r.initEvent(e,t,n),r}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),h=u?new T(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof T),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)x(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g=!1,y,b;try{document.createEvent("Event").target=document,y=function(e,t,n){i.call(e,t)||(e[t]=n)}}catch(E){g=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(b in m)i.call(m,b)&&h(n,b,{enumerable:!1,configurable:!0,writable:!0,value:m[b]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in m)m.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&h(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:m.boundTo,emit:function(n){var r=C(n,!1,!1);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:m.once,trigger:function(t,n){var r=typeof t=="string",s=r?t:t.type,o=r?n||r:t,u=C(s,i.call(o,"bubbles")?o.bubbles:!0,i.call(o,"cancelable")?o.cancelable:!0);return T.call(u,this,s,r&&n),this.dispatchEvent(u)}};(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o,u;for(o in N)i.call(N,o)&&(u={enumerable:!1,configurable:!0,writable:!0,value:N[o]},h(n,o,u),h(r,o,u),h(s,o,u))})(window)})(Object);
|
||||
@@ -0,0 +1,497 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
ifNotPresent,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
};
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
emit: function emit(type) {
|
||||
var e = createEvent(type, false, false);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
opt = isString ? (data || isString) : evt,
|
||||
e = createEvent(
|
||||
type,
|
||||
hasOwnProperty.call(opt, 'bubbles') ?
|
||||
opt.bubbles : true,
|
||||
hasOwnProperty.call(opt, 'cancelable') ?
|
||||
opt.cancelable : true
|
||||
)
|
||||
;
|
||||
Event.call(e, this, type, isString && data);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
function createEvent(type, bubbles, cancelable) {
|
||||
var e = document.createEvent('Event');
|
||||
e.initEvent(type, bubbles, cancelable);
|
||||
return e;
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function w(){return{l:{},m:[],b:[]}}function S(e){var t=w();return c.value=t,h(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){y(this,"timeStamp",v());for(var r in n)i.call(n,r)&&y(this,r,n[r]);y(this,"type",t),y(this,"target",e),n&&y(this,"data",n)}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=l?function(e,t,n){e[t]=n.value}:e.defineProperty,p=function(e){var t=this;return function(){return t.apply(e,arguments)}},d=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},v=Date.now||function(){return(new Date).getTime()},m={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=d.call(r,u);return a<0?o[s.call(r,u)-1]=p.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=d.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return d.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),h=u?new T(this,a,n):t,p=[h],d=0,v=l?c.length:d,m=!(h instanceof T),g,y;m&&(h._active=!0,h.stopImmediatePropagation=r.stopImmediatePropagation),h.currentTarget=this;while(h._active&&d<v)x(this,c[d++],p);return g=!!h._active,m&&(delete h._active,delete h.stopImmediatePropagation),g}},g=!1,y,b;try{document.createEvent("Event").target=document,y=function(e,t,n){i.call(e,t)||(e[t]=n)}}catch(E){g=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}r._active=!0,r.stopImmediatePropagation=function(){this._active=!1};for(b in m)i.call(m,b)&&h(n,b,{enumerable:!1,configurable:!0,writable:!0,value:m[b]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in m)m.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&h(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,421 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler wil be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* target object the original object that triggered
|
||||
* data [any] optional argument passed through
|
||||
* eventually copied over the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.data === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional data object to pass through
|
||||
* and/or copy over the event object
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, data) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, data) : evt,
|
||||
args = [event],
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event),
|
||||
result,
|
||||
current;
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
result = !!event._active;
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
ifNotPresent,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
};
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, data) {
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
for (var key in data) {
|
||||
if (hasOwnProperty.call(data, key)) {
|
||||
ifNotPresent(this, key, data[key]);
|
||||
}
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
if (data) ifNotPresent(this, 'data', data);
|
||||
}
|
||||
EventPrototype._active = true;
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:g.boundTo,emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:g.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)}};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){b=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o,u;for(o in N)i.call(N,o)&&(u={enumerable:!1,configurable:!0,writable:!0,value:N[o]},p(n,o,u),p(r,o,u),p(s,o,u))})(window)})(Object);
|
||||
@@ -0,0 +1,493 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,406 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:g.boundTo,data:function k(e,t){var n="dataset"in this;return arguments.length<2?n?this.dataset[e]:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?void 0:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:g.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)}};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){b=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o,u;for(o in N)i.call(N,o)&&(u={enumerable:!1,configurable:!0,writable:!0,value:N[o]},p(n,o,u),p(r,o,u),p(s,o,u))})(window)})(Object);
|
||||
@@ -0,0 +1,529 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
this.dataset[key] :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void 0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,406 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:g.boundTo,data:function k(e,t){var n="dataset"in this;return arguments.length<2?n?this.dataset[e]:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?void 0:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:g.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)}};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){b=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o=(e.XMLHttpRequest||function(){}).prototype,u,a;for(u in N)i.call(N,u)&&(a={enumerable:!1,configurable:!0,writable:!0,value:N[u]},p(n,u,a),p(r,u,a),p(s,u,a),u!=="data"&&p(o,u,a))})(window)})(Object);
|
||||
@@ -0,0 +1,537 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
this.dataset[key] :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void 0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,406 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:g.boundTo,data:function k(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:g.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)}};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){b=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o=(e.XMLHttpRequest||function(){}).prototype,u,a;for(u in N)i.call(N,u)&&(a={enumerable:!1,configurable:!0,writable:!0,value:N[u]},p(n,u,a),p(r,u,a),p(s,u,a),u!=="data"&&p(o,u,a))})(window)})(Object);
|
||||
@@ -0,0 +1,538 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,406 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:g.boundTo,data:function k(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:g.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)}};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){b=!0,y=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o=(e.XMLHttpRequest||function(){}).prototype,u,a;for(u in N)i.call(N,u)&&(a={enumerable:!1,configurable:!0,writable:!0,value:N[u]},p(r,u,a),u!=="data"&&(p(n,u,a),p(s,u,a),p(o,u,a)))})(window)})(Object);
|
||||
@@ -0,0 +1,538 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: eddy.boundTo,
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function E(){return{l:{},m:[],b:[]}}function S(e){var t=E();return c.value=t,p(e,f,c),c.value=null,t}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&y(this,"detail",n),y(this,"type",t),y(this,"target",e),y(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g={boundTo:function(t){var n=i.call(this,f)?this[f]:S(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t],a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:S(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented}},y=function(e,t,n){i.call(e,t)||(e[t]=n)},b=!1,w;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(w in g)i.call(g,w)&&p(n,w,{enumerable:!1,configurable:!0,writable:!0,value:g[w]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in g)g.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,406 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type],
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
function setAndGet(self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t){var n=i.call(this,f)?this[f]:g(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:function(e){try{e.call(document.createElement("div"),function(){})}catch(t){g=function(e){return e[f]=S(),e[f]}}return e}(y.boundTo),data:function k(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:y.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)},when:y.when};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){w=!0,b=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(e){var t=e.Window,n=t?t.prototype:e,r=(e.Node||e.Element||e.HTMLElement).prototype,s=(e.Document||e.HTMLDocument).prototype,o=(e.XMLHttpRequest||function(){}).prototype,u,a;for(u in N)i.call(N,u)&&(a={enumerable:!1,configurable:!0,writable:!0,value:N[u]},p(r,u,a),u!=="data"&&(p(n,u,a),p(s,u,a),p(o,u,a)))})(window)})(Object);
|
||||
@@ -0,0 +1,597 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t){var n=i.call(this,f)?this[f]:g(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,453 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t){var n=i.call(this,f)?this[f]:g(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:function(e){try{e.call(document.createElement("div"),function(){})}catch(t){g=function(e){return e[f]=S(),e[f]}}return e}(y.boundTo),data:function k(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:y.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)},when:y.when};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){w=!0,b=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(t){var n=t.Window,r=n?n.prototype:t,s=(t.Node||t.Element||t.HTMLElement).prototype,o=(t.Document||t.HTMLDocument).prototype,u=(t.XMLHttpRequest||function(){}).prototype,a=function(){f.trigger("ready")},f=t.document,l,c;for(l in N)i.call(N,l)&&(c={enumerable:!1,configurable:!0,writable:!0,value:N[l]},p(s,l,c),l!=="data"&&(p(r,l,c),p(o,l,c),p(u,l,c)));f.when("ready",e),/loaded|complete/.test(f.readyState)?a():f.once("DOMContentLoaded",a,!0)})(window)})(Object);
|
||||
@@ -0,0 +1,607 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
ready = function() {
|
||||
document.trigger('ready');
|
||||
},
|
||||
document = window.document,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.when('ready', Object);
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
ready();
|
||||
} else {
|
||||
document.once('DOMContentLoaded', ready, true);
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t){var n=i.call(this,f)?this[f]:g(this),r=n.m,o=n.b,u=typeof t=="string"?this[t]:t,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,453 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? this[method] : method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?typeof n===void 0||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:function(e){try{e.call(document.createElement("div"),function(){})}catch(t){g=function(e){return e[f]=S(),e[f]}}return e}(y.boundTo),data:function k(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:y.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)},when:y.when};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){w=!0,b=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(t){var n=t.Window,r=n?n.prototype:t,s=(t.Node||t.Element||t.HTMLElement).prototype,o=(t.Document||t.HTMLDocument).prototype,u=(t.XMLHttpRequest||function(){}).prototype,a=function(){f.trigger("ready")},f=t.document,l,c;for(l in N)i.call(N,l)&&(c={enumerable:!1,configurable:!0,writable:!0,value:N[l]},p(s,l,c),l!=="data"&&(p(r,l,c),p(o,l,c),p(u,l,c)));f.when("ready",e),/loaded|complete/.test(f.readyState)?a():f.once("DOMContentLoaded",a,!0)})(window)})(Object);
|
||||
@@ -0,0 +1,622 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
typeof callback === void 0 ||
|
||||
hasOwnProperty.call(this, method) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
ready = function() {
|
||||
document.trigger('ready');
|
||||
},
|
||||
document = window.document,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.when('ready', Object);
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
ready();
|
||||
} else {
|
||||
document.once('DOMContentLoaded', ready, true);
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?typeof n===void 0||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,468 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
typeof callback === void 0 ||
|
||||
hasOwnProperty.call(this, method) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?typeof n===void 0||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:function(e){try{e.call(document.createElement("div"),function(){})}catch(t){g=function(e){return e[f]=S(),e[f]}}return e}(y.boundTo),data:function k(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:y.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)},when:y.when};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){w=!0,b=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(t){var n=t.Window,r=n?n.prototype:t,s=(t.Node||t.Element||t.HTMLElement).prototype,o=(t.Document||t.HTMLDocument).prototype,u=(t.XMLHttpRequest||function(){}).prototype,a=function(){f.trigger("ready")},f=t.document,l,c;for(l in N)i.call(N,l)&&(c={enumerable:!1,configurable:!0,writable:!0,value:N[l]},p(s,l,c),l!=="data"&&(p(r,l,c),p(o,l,c),p(u,l,c)));f.when("ready",e),/loaded|complete/.test(f.readyState)?(t.setImmediate||setTimeout)(a):f.once("DOMContentLoaded",a,!0)})(window)})(Object);
|
||||
@@ -0,0 +1,622 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
typeof callback === void 0 ||
|
||||
hasOwnProperty.call(this, method) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
ready = function() {
|
||||
document.trigger('ready');
|
||||
},
|
||||
document = window.document,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.when('ready', Object);
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
(window.setImmediate || setTimeout)(ready);
|
||||
} else {
|
||||
document.once('DOMContentLoaded', ready, true);
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?typeof n===void 0||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,468 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
typeof callback === void 0 ||
|
||||
hasOwnProperty.call(this, method) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function k(e,t){var n=i.call(this,f)?this[f]:g(this),r=n.m,o=n.b,u=typeof e=="string"?typeof t===void 0||i.call(this,e)?this[e]:this[e]=t:e,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function L(e){var t=i.call(this,f),n=t&&this[f].l,r=t&&i.call(n,e),s=r&&n[e].slice(0),u=r&&o.call(arguments,1),a=0,l=r?s.length:a;while(a<l)x(this,s[a++],u);return r},listeners:function A(e){return i.call(this,f)&&i.call(this[f].l,e)&&this[f].l[e].slice()||[]},off:function O(e,t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,e)&&r[e],o;return s&&(o=v.call(s,t),-1<o&&(s.splice(o,1),s.length||delete r[e])),this},on:function M(e,t,n){var r=i.call(this,f),o=(r?this[f]:g(this)).l,a=r&&i.call(o,e)?o[e]:o[e]=[];return v.call(a,t)<0&&(n?u:s).call(a,t),this},once:function _(e,t,n){var r=function(s){i.off(e,r,n),x(i,t,arguments)},i=this;return i.on(e,r,n)},trigger:function D(e,t){var n=i.call(this,f),s=n&&this[f].l,o=typeof e=="string",u=o?e:e.type,a=n&&i.call(s,u),l=a&&s[u].slice(0),c=o?new T(this,u,t):e,p=0,d=a?l.length:p,v=!(c instanceof T);v&&(c._active=!0,c.stopImmediatePropagation=r.stopImmediatePropagation),c.currentTarget=this,h[0]=c;while(c._active&&p<d)x(this,l[p++],h);return v&&(delete c._active,delete c.stopImmediatePropagation),!c.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:function(e){try{e.call(document.createElement("div"),function(){})}catch(t){g=function(e){return e[f]=S(),e[f]}}return e}(y.boundTo),data:function P(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(P.gre||(P.gre=/-[a-z]/g),P.gplace||(P.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(P.sre||(P.sre=/([a-z])([A-Z])/g,P.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(P.sre,P.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function H(e){var n=new CustomEvent(e);return n.arguments=t.slice.call(arguments,1),this.dispatchEvent(n)},listeners:function B(e){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:y.once,trigger:function j(e,t){var n=typeof e=="string",r=n?e:e.type,i=n?new CustomEvent(r,(c.detail=t,c)):e;return c.detail=null,T.call(i,this,r),this.dispatchEvent(i)},when:y.when};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){w=!0,b=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(t){var n=t.Window,r=n?n.prototype:t,s=(t.Node||t.Element||t.HTMLElement).prototype,o=(t.Document||t.HTMLDocument).prototype,u=(t.XMLHttpRequest||function(){}).prototype,a=function(){f.trigger("ready")},f=t.document,l,c;for(l in N)i.call(N,l)&&(c={enumerable:!1,configurable:!0,writable:!0,value:N[l]},p(s,l,c),l!=="data"&&(p(r,l,c),p(o,l,c),p(u,l,c)));f.when("ready",e),/loaded|complete/.test(f.readyState)?(t.setImmediate||setTimeout)(a):f.once("DOMContentLoaded",a,!0)})(window)})(Object);
|
||||
@@ -0,0 +1,622 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
typeof callback === void 0 ||
|
||||
hasOwnProperty.call(this, method) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
ready = function() {
|
||||
document.trigger('ready');
|
||||
},
|
||||
document = window.document,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.when('ready', Object);
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
(window.setImmediate || setTimeout)(ready);
|
||||
} else {
|
||||
document.once('DOMContentLoaded', ready, true);
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function N(e,t){var n=i.call(this,f)?this[f]:g(this),r=n.m,o=n.b,u=typeof e=="string"?typeof t===void 0||i.call(this,e)?this[e]:this[e]=t:e,a=v.call(r,u);return a<0?o[s.call(r,u)-1]=d.call(u,this):o[a]},emit:function C(e){var t=i.call(this,f),n=t&&this[f].l,r=t&&i.call(n,e),s=r&&n[e].slice(0),u=r&&o.call(arguments,1),a=0,l=r?s.length:a;while(a<l)x(this,s[a++],u);return r},listeners:function k(e){return i.call(this,f)&&i.call(this[f].l,e)&&this[f].l[e].slice()||[]},off:function L(e,t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,e)&&r[e],o;return s&&(o=v.call(s,t),-1<o&&(s.splice(o,1),s.length||delete r[e])),this},on:function A(e,t,n){var r=i.call(this,f),o=(r?this[f]:g(this)).l,a=r&&i.call(o,e)?o[e]:o[e]=[];return v.call(a,t)<0&&(n?u:s).call(a,t),this},once:function O(e,t,n){var r=function(s){i.off(e,r,n),x(i,t,arguments)},i=this;return i.on(e,r,n)},trigger:function M(e,t){var n=i.call(this,f),s=n&&this[f].l,o=typeof e=="string",u=o?e:e.type,a=n&&i.call(s,u),l=a&&s[u].slice(0),c=o?new T(this,u,t):e,p=0,d=a?l.length:p,v=!(c instanceof T);v&&(c._active=!0,c.stopImmediatePropagation=r.stopImmediatePropagation),c.currentTarget=this,h[0]=c;while(c._active&&p<d)x(this,l[p++],h);return v&&(delete c._active,delete c.stopImmediatePropagation),!c.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,468 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
typeof callback === void 0 ||
|
||||
hasOwnProperty.call(this, method) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?n==null||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach);var N={boundTo:function(e){try{e.call(document.createElement("div"),function(){})}catch(t){g=function(e){return e[f]=S(),e[f]}}return e}(y.boundTo),data:function k(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?!this.removeAttribute(e):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:y.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)},when:y.when};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){w=!0,b=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(t){var n=t.Window,r=n?n.prototype:t,s=(t.Node||t.Element||t.HTMLElement).prototype,o=(t.Document||t.HTMLDocument).prototype,u=(t.XMLHttpRequest||function(){}).prototype,a=function(){f.trigger("ready")},f=t.document,l,c;for(l in N)i.call(N,l)&&(c={enumerable:!1,configurable:!0,writable:!0,value:N[l]},p(s,l,c),l!=="data"&&(p(r,l,c),p(o,l,c),p(u,l,c)));f.when("ready",e),/loaded|complete/.test(f.readyState)?(t.setImmediate||setTimeout)(a):f.once("DOMContentLoaded",a,!0)})(window)})(Object);
|
||||
@@ -0,0 +1,621 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
(callback == null || hasOwnProperty.call(this, method)) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return !this.removeAttribute(key);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
ready = function() {
|
||||
document.trigger('ready');
|
||||
},
|
||||
document = window.document,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.when('ready', Object);
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
(window.setImmediate || setTimeout)(ready);
|
||||
} else {
|
||||
document.once('DOMContentLoaded', ready, true);
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?n==null||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach)})(Object);
|
||||
@@ -0,0 +1,467 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
(callback == null || hasOwnProperty.call(this, method)) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach));
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?n==null||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach||function(e,t){var n=this,r=0;while(r<n.length)r in n&&e.call(t,n[r],r,n),r++});var N={boundTo:function(e){try{e.call(document.createElement("div"),function(){})}catch(t){g=function(e){return e[f]=S(),e[f]}}return e}(y.boundTo),data:function k(e,t){var n="dataset"in this,r;return arguments.length<2?n?e in this.dataset?this.dataset[e]:r:(t=this.getAttribute("data-"+e.replace(k.gre||(k.gre=/-[a-z]/g),k.gplace||(k.gplace=function(e,t){return t.toUpperCase()}))))==null?r:t:n?t==null?delete this.dataset[e]:(this.dataset[e]=t,t):(k.sre||(k.sre=/([a-z])([A-Z])/g,k.splace=function(e,t,n){return t+"-"+n.toLowerCase()}),e="data-"+e.replace(k.sre,k.splace),t==null?(this.removeAttribute(e),!0):(this.setAttribute(e,t),t))},emit:function(n){var r=new CustomEvent(n);return r.arguments=t.slice.call(arguments,1),this.dispatchEvent(r)},listeners:function(t){return[]},off:function(e,t,n){return this.removeEventListener(e,t,n),this},on:function(e,t,n){return this.addEventListener(e,t,n),this},once:y.once,trigger:function(t,n){var r=typeof t=="string",i=r?t:t.type,s=r?new CustomEvent(i,(c.detail=n,c)):t;return c.detail=null,T.call(s,this,i),this.dispatchEvent(s)},when:y.when};c.cancelable=!0,c.bubbles=!0;try{document.createEvent("Event").target=document}catch(C){w=!0,b=function(e,t,n){if(!i.call(e,t))try{e[t]=n}catch(r){}}}(function(t){var n=t.Window,r=n?n.prototype:t,s=(t.Node||t.Element||t.HTMLElement).prototype,o=(t.Document||t.HTMLDocument).prototype,u=(t.XMLHttpRequest||function(){}).prototype,a=function(){f.trigger("ready")},f=t.document,l,c;for(l in N)i.call(N,l)&&(c={enumerable:!1,configurable:!0,writable:!0,value:N[l]},p(s,l,c),l!=="data"&&(p(r,l,c),p(o,l,c),p(u,l,c)));f.when("ready",e),/loaded|complete/.test(f.readyState)?(t.setImmediate||setTimeout)(a):f.once("DOMContentLoaded",a,!0)})(window)})(Object);
|
||||
@@ -0,0 +1,630 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
/*jshint eqnull:true */
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
(callback == null || hasOwnProperty.call(this, method)) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach || function (callback, self) {
|
||||
var array = this, i = 0;
|
||||
while (i < array.length) {
|
||||
if (i in array) {
|
||||
callback.call(self, array[i], i, array);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function data(key, value) {
|
||||
/*jshint eqnull:true */
|
||||
var hasDataset = 'dataset' in this,
|
||||
void0;
|
||||
if (arguments.length < 2) {
|
||||
return hasDataset ?
|
||||
(key in this.dataset ? this.dataset[key] : void0) :
|
||||
(value = this.getAttribute(
|
||||
'data-' + key.replace(
|
||||
data.gre || (data.gre = /-[a-z]/g),
|
||||
data.gplace || (data.gplace = function(m, c) {
|
||||
return c.toUpperCase();
|
||||
})
|
||||
)
|
||||
)) == null ? void0 : value
|
||||
;
|
||||
}
|
||||
if (hasDataset) {
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} else {
|
||||
if (!data.sre) {
|
||||
data.sre = /([a-z])([A-Z])/g;
|
||||
data.splace = function(m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
};
|
||||
}
|
||||
key = 'data-' + key.replace(data.sre, data.splace);
|
||||
if (value == null) {
|
||||
return (this.removeAttribute(key), true);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
},
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
ready = function() {
|
||||
document.trigger('ready');
|
||||
},
|
||||
document = window.document,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.when('ready', Object);
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
(window.setImmediate || setTimeout)(ready);
|
||||
} else {
|
||||
document.once('DOMContentLoaded', ready, true);
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?n==null||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach||function(e,t){var n=this,r=0;while(r<n.length)r in n&&e.call(t,n[r],r,n),r++})})(Object);
|
||||
@@ -0,0 +1,476 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
/*jshint eqnull:true */
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
(callback == null || hasOwnProperty.call(this, method)) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach || function (callback, self) {
|
||||
var array = this, i = 0;
|
||||
while (i < array.length) {
|
||||
if (i in array) {
|
||||
callback.call(self, array[i], i, array);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}));
|
||||
}(Object));
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,679 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
/*jshint eqnull:true */
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
(callback == null || hasOwnProperty.call(this, method)) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach || function (callback, self) {
|
||||
var array = this, i = 0;
|
||||
while (i < array.length) {
|
||||
if (i in array) {
|
||||
callback.call(self, array[i], i, array);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function (hasDataset) {
|
||||
var
|
||||
dash = hasDataset ?
|
||||
/-([a-z])/g :
|
||||
/([a-z])([A-Z])/g,
|
||||
camel = hasDataset ?
|
||||
function (m, c) {
|
||||
return c.toUpperCase();
|
||||
} :
|
||||
function (m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
}
|
||||
;
|
||||
function transform(key) {
|
||||
return key.replace(dash, camel);
|
||||
}
|
||||
return hasDataset ?
|
||||
function data(key, value) {
|
||||
key = transform(key);
|
||||
if (arguments.length < 2) {
|
||||
return this.dataset[key];
|
||||
}
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} :
|
||||
function data(key, value) {
|
||||
key = 'data-' + transform(key);
|
||||
if (arguments.length < 2) {
|
||||
value = this.getAttribute(key);
|
||||
return value == null ? void 0 : value;
|
||||
}
|
||||
if (value == null) {
|
||||
return (this.removeAttribute(key), true);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
;
|
||||
}('dataset' in document.documentElement),
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
ready = function() {
|
||||
document.trigger('ready');
|
||||
},
|
||||
document = window.document,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Opera Mini
|
||||
if (!XMLHttpRequestPrototype.addEventListener) {
|
||||
XMLHttpRequestPrototype.addEventListener =
|
||||
function addEventListener(type, handler) {
|
||||
var
|
||||
self = this,
|
||||
handlers = self['_' + type] || (self['_' + type] = [])
|
||||
;
|
||||
if (indexOf.call(handlers, handler) < 0) {
|
||||
handlers.push(handler);
|
||||
if (!self['on' + type]) {
|
||||
self['on' + type] = function (e) {
|
||||
for (var
|
||||
evt = e || {
|
||||
currentTarget: self,
|
||||
type: type
|
||||
},
|
||||
i = 0,
|
||||
current;
|
||||
i < handlers.length;
|
||||
i++
|
||||
) {
|
||||
current = handlers[i];
|
||||
if (typeof current === 'function') {
|
||||
current.call(self, evt);
|
||||
} else {
|
||||
current.handleEvent(evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
XMLHttpRequestPrototype.removeEventListener =
|
||||
function removeEventListener(type, handler) {
|
||||
var handlers = self['_' + type] || [],
|
||||
i = indexOf.call(handlers, handler);
|
||||
if (-1 < i) {
|
||||
handlers.splice(i, 1);
|
||||
if (!handlers.length) {
|
||||
self['on' + type] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
document.when('ready', Object);
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
(window.setImmediate || setTimeout)(ready);
|
||||
} else {
|
||||
document.once('DOMContentLoaded', ready, true);
|
||||
}
|
||||
}(window));
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?n==null||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach||function(e,t){var n=this,r=0;while(r<n.length)r in n&&e.call(t,n[r],r,n),r++})})(Object);
|
||||
@@ -0,0 +1,476 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
/*jshint eqnull:true */
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
(callback == null || hasOwnProperty.call(this, method)) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach || function (callback, self) {
|
||||
var array = this, i = 0;
|
||||
while (i < array.length) {
|
||||
if (i in array) {
|
||||
callback.call(self, array[i], i, array);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}));
|
||||
}(Object));
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,698 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
/*jshint eqnull:true */
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
/*jshint eqnull:true */
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
(callback == null || hasOwnProperty.call(this, method)) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach || function (callback, self) {
|
||||
var array = this, i = 0;
|
||||
while (i < array.length) {
|
||||
if (i in array) {
|
||||
callback.call(self, array[i], i, array);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}));
|
||||
var dom = {
|
||||
boundTo: function(boundTo){
|
||||
// UC Browser might not support Object.defineProperty on DOM nodes
|
||||
try {
|
||||
boundTo.call(document.createElement('div'), function(){});
|
||||
} catch(o_O) {
|
||||
setAndGet = function (self) {
|
||||
self[SECRET] = createSecret();
|
||||
return self[SECRET];
|
||||
};
|
||||
}
|
||||
return boundTo;
|
||||
}(eddy.boundTo),
|
||||
data: function (hasDataset) {
|
||||
var
|
||||
dash = hasDataset ?
|
||||
/-([a-z])/g :
|
||||
/([a-z])([A-Z])/g,
|
||||
camel = hasDataset ?
|
||||
function (m, c) {
|
||||
return c.toUpperCase();
|
||||
} :
|
||||
function (m, l, U) {
|
||||
return l + '-' + U.toLowerCase();
|
||||
}
|
||||
;
|
||||
function transform(key) {
|
||||
return key.replace(dash, camel);
|
||||
}
|
||||
return hasDataset ?
|
||||
function data(key, value) {
|
||||
key = transform(key);
|
||||
if (arguments.length < 2) {
|
||||
return this.dataset[key];
|
||||
}
|
||||
if (value == null) {
|
||||
return delete this.dataset[key];
|
||||
}
|
||||
this.dataset[key] = value;
|
||||
return value;
|
||||
} :
|
||||
function data(key, value) {
|
||||
key = 'data-' + transform(key);
|
||||
if (arguments.length < 2) {
|
||||
value = this.getAttribute(key);
|
||||
return value == null ? void 0 : value;
|
||||
}
|
||||
if (value == null) {
|
||||
return (this.removeAttribute(key), true);
|
||||
}
|
||||
return this.setAttribute(key, value), value;
|
||||
}
|
||||
;
|
||||
}('dataset' in document.documentElement),
|
||||
emit: function emit(type) {
|
||||
var e = new CustomEvent(type);
|
||||
e.arguments = ArrayPrototype.slice.call(arguments, 1);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
listeners: function listeners(type) {
|
||||
return [];
|
||||
},
|
||||
off: function (type, handler, capture) {
|
||||
this.removeEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
on: function (type, handler, capture) {
|
||||
this.addEventListener(type, handler, capture);
|
||||
return this;
|
||||
},
|
||||
once: eddy.once,
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
e = isString ? new CustomEvent(
|
||||
type,
|
||||
(
|
||||
commonDescriptor.detail = detail,
|
||||
commonDescriptor
|
||||
)
|
||||
) : evt
|
||||
;
|
||||
commonDescriptor.detail = null;
|
||||
Event.call(e, this, type);
|
||||
return this.dispatchEvent(e);
|
||||
},
|
||||
when: eddy.when
|
||||
};
|
||||
|
||||
commonDescriptor.cancelable = true;
|
||||
commonDescriptor.bubbles = true;
|
||||
|
||||
// assign properties only if not there already
|
||||
try {
|
||||
document.createEvent('Event').target = document;
|
||||
} catch(Nokia_Xpress) {
|
||||
WTF = true;
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
try {
|
||||
e[key] = value;
|
||||
} catch(Nokia_Xpress) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
(function(window){
|
||||
var
|
||||
Window = window.Window,
|
||||
WindowPrototype = Window ? Window.prototype : window,
|
||||
ElementPrototype = (
|
||||
window.Node || window.Element || window.HTMLElement
|
||||
).prototype,
|
||||
DocumentPrototype = (
|
||||
window.Document || window.HTMLDocument
|
||||
).prototype,
|
||||
XMLHttpRequestPrototype = (
|
||||
window.XMLHttpRequest || function(){}
|
||||
).prototype,
|
||||
ready = function() {
|
||||
document.trigger('ready');
|
||||
},
|
||||
document = window.document,
|
||||
key,
|
||||
current
|
||||
;
|
||||
for (key in dom) {
|
||||
if (hasOwnProperty.call(dom, key)) {
|
||||
current = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[key]
|
||||
};
|
||||
defineProperty(
|
||||
ElementPrototype, key, current
|
||||
);
|
||||
if (key !== 'data') {
|
||||
defineProperty(
|
||||
WindowPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
DocumentPrototype, key, current
|
||||
);
|
||||
defineProperty(
|
||||
XMLHttpRequestPrototype, key, current
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Opera Mini
|
||||
if (!XMLHttpRequestPrototype.addEventListener) {
|
||||
XMLHttpRequestPrototype.addEventListener =
|
||||
function addEventListener(type, handler) {
|
||||
var
|
||||
self = this,
|
||||
handlers = self['_' + type] || (self['_' + type] = [])
|
||||
;
|
||||
if (indexOf.call(handlers, handler) < 0) {
|
||||
handlers.push(handler);
|
||||
if (!self['on' + type]) {
|
||||
self['on' + type] = function (e) {
|
||||
for (var
|
||||
evt = e || {
|
||||
currentTarget: self,
|
||||
type: type
|
||||
},
|
||||
i = 0,
|
||||
current;
|
||||
i < handlers.length;
|
||||
i++
|
||||
) {
|
||||
current = handlers[i];
|
||||
if (typeof current === 'function') {
|
||||
current.call(self, evt);
|
||||
} else {
|
||||
current.handleEvent(evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
XMLHttpRequestPrototype.removeEventListener =
|
||||
function removeEventListener(type, handler) {
|
||||
var handlers = self['_' + type] || [],
|
||||
i = indexOf.call(handlers, handler);
|
||||
if (-1 < i) {
|
||||
handlers.splice(i, 1);
|
||||
if (!handlers.length) {
|
||||
self['on' + type] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
document.when('ready', Object);
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
(window.setImmediate || setTimeout)(ready);
|
||||
} else {
|
||||
document.once('DOMContentLoaded', ready, true);
|
||||
}
|
||||
}(window));
|
||||
|
||||
if (!('$' in window)) defineProperty(window, '$', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
// @link http://webreflection.blogspot.com/2014/05/134-bytes-for-optimized-and-very-basic.html
|
||||
value: function $(CSS, parentNode) {
|
||||
var el = parentNode || document,
|
||||
length = CSS.length - 6,
|
||||
first = CSS.lastIndexOf(':first') === length,
|
||||
query = first ?
|
||||
el.querySelector(CSS.slice(0, length)) :
|
||||
el.querySelectorAll(CSS);
|
||||
return first ?
|
||||
(query ? [query] : []) :
|
||||
ArrayPrototype.slice.call(query);
|
||||
}
|
||||
});
|
||||
|
||||
}(Object));
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! (C) Andrea Giammarchi Mit Style License */
|
||||
/*jshint eqnull:true */(function(e){"use strict";function S(){return{w:{},l:{},m:[],b:[]}}function x(e,t,n){typeof t=="function"?t.apply(e,n):t.handleEvent.apply(t,n)}function T(e,t,n){n!==void 0&&b(this,"detail",n),b(this,"type",t),b(this,"target",e),b(this,"timeStamp",m())}if(e.eddy)return;e.eddy=!0;var t=Array.prototype,n=e.prototype,r=T.prototype,i=n.hasOwnProperty,s=t.push,o=t.slice,u=t.unshift,a="toLocaleString",f={toLocaleString:1}.propertyIsEnumerable(a)?"_@eddy"+Math.random():a,l=f===a,c=(e.create||e)(null),h=[],p=l?function(e,t,n){e[t]=n.value}:e.defineProperty,d=function(e){var t=this;return function(){return t.apply(e,arguments)}},v=t.indexOf||function(e){var t=this.length;while(t--&&this[t]!==e);return t},m=Date.now||function(){return(new Date).getTime()},g=function(e){var t=S();return c.value=t,p(e,f,c),c.value=null,t},y={boundTo:function(t,n){var r=i.call(this,f)?this[f]:g(this),o=r.m,u=r.b,a=typeof t=="string"?n==null||i.call(this,t)?this[t]:this[t]=n:t,l=v.call(o,a);return l<0?u[s.call(o,a)-1]=d.call(a,this):u[l]},emit:function(t){var n=i.call(this,f),r=n&&this[f].l,s=n&&i.call(r,t),u=s&&r[t].slice(0),a=s&&o.call(arguments,1),l=0,c=s?u.length:l;while(l<c)x(this,u[l++],a);return s},listeners:function(t){return i.call(this,f)&&i.call(this[f].l,t)&&this[f].l[t].slice()||[]},off:function(t,n){var r=i.call(this,f),s=r&&this[f].l,o=r&&i.call(s,t)&&s[t],u;return o&&(u=v.call(o,n),-1<u&&(o.splice(u,1),o.length||delete s[t])),this},on:function(t,n,r){var o=i.call(this,f),a=(o?this[f]:g(this)).l,l=o&&i.call(a,t)?a[t]:a[t]=[];return v.call(l,n)<0&&(r?u:s).call(l,n),this},once:function(t,n,r){var i=function(e){s.off(t,i,r),x(s,n,arguments)},s=this;return s.on(t,i,r)},trigger:function(t,n){var s=i.call(this,f),o=s&&this[f].l,u=typeof t=="string",a=u?t:t.type,l=s&&i.call(o,a),c=l&&o[a].slice(0),p=u?new T(this,a,n):t,d=0,v=l?c.length:d,m=!(p instanceof T);m&&(p._active=!0,p.stopImmediatePropagation=r.stopImmediatePropagation),p.currentTarget=this,h[0]=p;while(p._active&&d<v)x(this,c[d++],h);return m&&(delete p._active,delete p.stopImmediatePropagation),!p.defaultPrevented},when:function(e,t){var n=i.call(this,f),r=(n?this[f]:g(this)).w,s=n&&i.call(r,e);return s?(x(this,t,r[e]),this):this.once(e,function(){i.call(r,e)||(r[e]=arguments)},!0).once(e,t)}},b=function(e,t,n){i.call(e,t)||(e[t]=n)},w=!1,E;r.defaultPrevented=!1,r._active=r.cancelable=!0,r.preventDefault=function(){this.defaultPrevented=!0},r.stopImmediatePropagation=function(){this._active=!1};for(E in y)i.call(y,E)&&p(n,E,{enumerable:!1,configurable:!0,writable:!0,value:y[E]});(function(e){function n(t){function n(e){e[t].apply(e,this)}return function(){return e.call(this,n,arguments),this}}for(var r in y)y.hasOwnProperty(r)&&!/^listeners|boundTo$/.test(r)&&p(t,r,{enumerable:!1,configurable:!0,writable:!0,value:n(r)})})(t.forEach||function(e,t){var n=this,r=0;while(r<n.length)r in n&&e.call(t,n[r],r,n),r++})})(Object);
|
||||
@@ -0,0 +1,477 @@
|
||||
/*!
|
||||
Copyright (C) 2013 by Andrea Giammarchi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
/*jshint eqnull:true */
|
||||
(function (Object) {
|
||||
'use strict';
|
||||
// probably the very first script you want to load in any project
|
||||
// do not redefine same stuff twice anyway
|
||||
if (Object.eddy) return;
|
||||
Object.eddy = true;
|
||||
|
||||
// all private variables
|
||||
var /*! (C) Andrea Giammarchi Mit Style License */
|
||||
ArrayPrototype = Array.prototype,
|
||||
ObjectPrototype = Object.prototype,
|
||||
EventPrototype = Event.prototype,
|
||||
hasOwnProperty = ObjectPrototype.hasOwnProperty,
|
||||
push = ArrayPrototype.push,
|
||||
slice = ArrayPrototype.slice,
|
||||
unshift = ArrayPrototype.unshift,
|
||||
// IE < 9 has this problem which makes
|
||||
// eddy.js able to implement its features!
|
||||
// this would not have been possible in other
|
||||
// non ES5 compatible browsers so ... thanks IE!
|
||||
IE_WONT_ENUMERATE_THIS = 'toLocaleString',
|
||||
SECRET = {toLocaleString:1}.propertyIsEnumerable(
|
||||
IE_WONT_ENUMERATE_THIS
|
||||
) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
|
||||
IE = SECRET === IE_WONT_ENUMERATE_THIS,
|
||||
// used in all ES5 compatible browsers (all but IE < 9)
|
||||
commonDescriptor = (Object.create || Object)(null),
|
||||
recycledArguments = [],
|
||||
defineProperty = IE ?
|
||||
function (self, property, descriptor) {
|
||||
self[property] = descriptor.value;
|
||||
} :
|
||||
Object.defineProperty,
|
||||
// http://jsperf.com/bind-no-args bind is still freaking slow so...
|
||||
bind = /* Object.bind || */ function (context) {
|
||||
// this is not a fully specd replacemenet for Function#bind
|
||||
// but works specifically for this use case like a charm
|
||||
var fn = this;
|
||||
return function () {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
},
|
||||
indexOf = ArrayPrototype.indexOf || function (value) {
|
||||
// if you want more standard indexOf use a proper polyfill
|
||||
// and include it before eddy.js
|
||||
var i = this.length;
|
||||
while (i-- && this[i] !== value) {}
|
||||
return i;
|
||||
},
|
||||
// every triggered even has a timeStamp
|
||||
now = Date.now || function () {
|
||||
return new Date().getTime();
|
||||
},
|
||||
setAndGet = function (self) {
|
||||
var value = createSecret();
|
||||
commonDescriptor.value = value;
|
||||
defineProperty(self, SECRET, commonDescriptor);
|
||||
commonDescriptor.value = null;
|
||||
return value;
|
||||
},
|
||||
// for ES3+ and JScript native Objects
|
||||
// no hosted objects are considered here
|
||||
// see eddy.dom.js for that
|
||||
eddy = {
|
||||
/**
|
||||
* Returns a bound version of the specified method.
|
||||
* If called again with same method, the initial bound
|
||||
* object will be returned instead of creating a new one.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* obj.boundTo('method') === obj.boundTo('method')
|
||||
* // same as
|
||||
* obj.boundTo(obj.method) === obj.boundTo(obj.method)
|
||||
* // same as
|
||||
* obj.boundTo('method') === obj.boundTo(obj.method)
|
||||
*
|
||||
* It is also able to set once a method at runtime and
|
||||
* always return the initial one, if any.
|
||||
* This will make the following assertion always true:
|
||||
*
|
||||
* @example
|
||||
* var fn = function(){return this};
|
||||
* obj.boundTo('test', fn) === obj.boundTo('test', function(){})
|
||||
* obj.boundTo('test', fn)() === obj
|
||||
* obj.test === fn
|
||||
*
|
||||
* Bear in mind no arguments can be bound once, only the context.
|
||||
* Method could be either a function or a string.
|
||||
* In latter case, be aware Google Closure Compiler
|
||||
* might change methods name if compiled with
|
||||
* ADVANCED_OPTION resulting in a broken code.
|
||||
* Use methods instead of strings if you use such option.
|
||||
* @param method string|Function the method name to bind
|
||||
* @return Object the callable bound function/method.
|
||||
*/
|
||||
boundTo: function boundTo(method, callback) {
|
||||
/*jshint eqnull:true */
|
||||
var
|
||||
all = hasOwnProperty.call(this, SECRET) ?
|
||||
this[SECRET] : setAndGet(this),
|
||||
m = all.m,
|
||||
b = all.b,
|
||||
fn = typeof method === 'string' ? (
|
||||
(callback == null || hasOwnProperty.call(this, method)) ?
|
||||
this[method] : (this[method] = callback)
|
||||
) :
|
||||
method,
|
||||
i = indexOf.call(m, fn);
|
||||
return i < 0 ?
|
||||
(b[push.call(m, fn) - 1] = bind.call(fn, this)) :
|
||||
b[i];
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function(arg1, arg2, argN){
|
||||
* console.log(arg1, arg2, argN);
|
||||
* }).emit('evt', 1, 2, 3);
|
||||
* // {'0': 1, '1': 2, '2': 3}
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] one or more arguments to pass through
|
||||
* @return boolean true if the event was emitted
|
||||
*/
|
||||
emit: function emit(type) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
args = loop && slice.call(arguments, 1),
|
||||
i = 0,
|
||||
length = loop ? array.length : i;
|
||||
while (i < length) {
|
||||
triggerEvent(this, array[i++], args);
|
||||
}
|
||||
return loop;
|
||||
},
|
||||
/**
|
||||
* Borrowed from node.js, it does exactly what node.js does.
|
||||
*
|
||||
* @example
|
||||
* {}.on('evt', function a(){}).listeners('evt');
|
||||
* // [ function a(){} ]
|
||||
*
|
||||
* @param type string the optional event name to emit
|
||||
*/
|
||||
listeners: function listeners(type) {
|
||||
return hasOwnProperty.call(this, SECRET) &&
|
||||
hasOwnProperty.call(this[SECRET].l, type) &&
|
||||
this[SECRET].l[type].slice() || [];
|
||||
},
|
||||
/**
|
||||
* Counter part of `.on(type, handler)`
|
||||
* The equivalent of `removeListener` or `removeEventListener`.
|
||||
* It removes an event if already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var obj = {}.on('evt', console.boundTo('log'));
|
||||
* obj.emit('evt', 'OK'); // "OK" true
|
||||
* obj
|
||||
* .off('evt', console.boundTo('log'))
|
||||
* .emit('evt')
|
||||
* ; // false
|
||||
*
|
||||
* @param type string the event name to un-listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.off()`
|
||||
*/
|
||||
off: function off(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
array = has && hasOwnProperty.call(listeners, type) &&
|
||||
listeners[type],
|
||||
i
|
||||
;
|
||||
if (array) {
|
||||
i = indexOf.call(array, handler);
|
||||
if (-1 < i) {
|
||||
array.splice(i, 1);
|
||||
if (!array.length) {
|
||||
delete listeners[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* The equivalent of `addListener` or `addEventListener`.
|
||||
* It adds an event if not already added and return same object
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* function genericEvent() {
|
||||
* console.log(++i);
|
||||
* }
|
||||
* var obj = {};
|
||||
* obj
|
||||
* .on('evt', genericEvent)
|
||||
* .on('evt', genericEvent)
|
||||
* ;
|
||||
* obj.emit('evt'); // 1
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.on()`
|
||||
*/
|
||||
on: function on(type, handler, capture) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).l,
|
||||
array = has && hasOwnProperty.call(listeners, type) ?
|
||||
listeners[type] : listeners[type] = []
|
||||
;
|
||||
if (indexOf.call(array, handler) < 0) {
|
||||
(capture ? unshift : push).call(array, handler);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Assigns an event that will be dropped the very first time
|
||||
* it will be triggered/emitted/fired.
|
||||
*
|
||||
* @example
|
||||
* var i = 0;
|
||||
* var obj = {}.once('increment', function(){
|
||||
* console.log(++i);
|
||||
* });
|
||||
* obj.emit('increment'); // 1 true
|
||||
* obj.emit('increment'); // false
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @param [optional, **reserved**] boolean unshift instead of push
|
||||
* @return Object the chained object that called `.once()`
|
||||
*/
|
||||
once: function once(type, handler, capture) {
|
||||
var
|
||||
// IE8 has duplicated expression/declaration bug
|
||||
// could not self.on(type, function once(){}, ...);
|
||||
cb = function(e) {
|
||||
self.off(type, cb, capture);
|
||||
triggerEvent(self, handler, arguments);
|
||||
},
|
||||
self = this
|
||||
;
|
||||
return self.on(type, cb, capture);
|
||||
},
|
||||
/**
|
||||
* Triggers an event in a *DOMish* way.
|
||||
* The handler will be invoked with a single object
|
||||
* argument as event with at least a method called
|
||||
* `stopImmediatePropagation()` able to break the
|
||||
* method invocation loop.
|
||||
*
|
||||
* The event object will have always at least these properties:
|
||||
* type string the name of the event
|
||||
* timeStamp number when the event has been triggered
|
||||
* currentTarget object the original object that triggered
|
||||
* target object same as DOMish currentTarget
|
||||
* detail [any] optional argument passed through
|
||||
* eventually assigned to the event
|
||||
*
|
||||
* @example
|
||||
* var o = {}.on('evt', function(e){
|
||||
* console.log(e.type);
|
||||
* console.log(e.detail === RegExp);
|
||||
* });
|
||||
* o.trigger('evt', RegExp);
|
||||
* // "evt" true
|
||||
*
|
||||
* @param type string the event name to emit
|
||||
* @param [any=any] optional detail data
|
||||
* used as Event.detail property
|
||||
* @return boolean true if the event was triggered
|
||||
*/
|
||||
trigger: function trigger(evt, detail) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = has && this[SECRET].l,
|
||||
isString = typeof evt == 'string',
|
||||
type = isString ? evt : evt.type,
|
||||
loop = has && hasOwnProperty.call(listeners, type),
|
||||
array = loop && listeners[type].slice(0),
|
||||
event = isString ?
|
||||
new Event(this, type, detail) : evt,
|
||||
i = 0,
|
||||
length = loop ? array.length : i,
|
||||
isNotAnEventInstance = !(event instanceof Event);
|
||||
if (isNotAnEventInstance) {
|
||||
event._active = true;
|
||||
event.stopImmediatePropagation =
|
||||
EventPrototype.stopImmediatePropagation;
|
||||
}
|
||||
event.currentTarget = this;
|
||||
recycledArguments[0] = event;
|
||||
while (event._active && i < length) {
|
||||
triggerEvent(this, array[i++], recycledArguments);
|
||||
}
|
||||
if (isNotAnEventInstance) {
|
||||
delete event._active;
|
||||
delete event.stopImmediatePropagation;
|
||||
}
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
/**
|
||||
* Attach an event in a Promise_ish_ way.
|
||||
* The handler will be invoked instantly
|
||||
* if the event has fired already, it will
|
||||
* listen once otherwise.
|
||||
*
|
||||
* @example
|
||||
* // DOM example
|
||||
* window.when('DOMContentLoaded', initApp);
|
||||
*
|
||||
* // JS example
|
||||
* user.when('authenticated', function(info) {
|
||||
* alert('Hello ' + info.name);
|
||||
* });
|
||||
* app.once('login', function(info) {
|
||||
* user.emit('authenticated', info);
|
||||
* });
|
||||
*
|
||||
* @param type string the event name to listen to
|
||||
* @param handler Function|Object the handler used initially
|
||||
* @return Object the chained object that called `.when()`
|
||||
*/
|
||||
when: function(type, handler) {
|
||||
var
|
||||
has = hasOwnProperty.call(this, SECRET),
|
||||
listeners = (has ? this[SECRET] : setAndGet(this)).w,
|
||||
triggered = has && hasOwnProperty.call(listeners, type)
|
||||
;
|
||||
return triggered ? (
|
||||
// instantly resolved with first-time args
|
||||
triggerEvent(this, handler, listeners[type]),
|
||||
this
|
||||
) : this.
|
||||
once(type, function() {
|
||||
// only the first time this gets called
|
||||
if (!hasOwnProperty.call(listeners, type)) {
|
||||
// store the very first time arguments are retrieved
|
||||
// through the when .. it could be either DOM
|
||||
// events or custom emit()
|
||||
listeners[type] = arguments;
|
||||
}
|
||||
// a new callback each time is not optimal
|
||||
// however, this solves pretty quickly so
|
||||
// no real side effects should be introduced
|
||||
}, true).
|
||||
once(type, handler);
|
||||
}
|
||||
},
|
||||
ifNotPresent = function(e, key, value) {
|
||||
if (!hasOwnProperty.call(e, key)) {
|
||||
e[key] = value;
|
||||
}
|
||||
},
|
||||
WTF = false,
|
||||
key;
|
||||
|
||||
/* eddy.js private helpers/shortcuts */
|
||||
// the object used to trap listeners and bound functions
|
||||
function createSecret() {
|
||||
return {
|
||||
w: {},
|
||||
l: {},
|
||||
m: [],
|
||||
b: []
|
||||
};
|
||||
}
|
||||
|
||||
// check if the handler is a function OR an object
|
||||
// in latter case invoke `handler.handleEvent(args)`
|
||||
// compatible with DOM event handlers
|
||||
function triggerEvent(context, handler, args) {
|
||||
if (typeof handler == 'function') {
|
||||
handler.apply(context, args);
|
||||
} else {
|
||||
handler.handleEvent.apply(handler, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* the basic eddy.js Event class */
|
||||
function Event(target, type, detail) {
|
||||
if (detail !== void 0) {
|
||||
ifNotPresent(this, 'detail', detail);
|
||||
}
|
||||
ifNotPresent(this, 'type', type);
|
||||
ifNotPresent(this, 'target', target);
|
||||
ifNotPresent(this, 'timeStamp', now());
|
||||
}
|
||||
EventPrototype.defaultPrevented = false;
|
||||
EventPrototype._active = EventPrototype.cancelable = true;
|
||||
EventPrototype.preventDefault = function () {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
EventPrototype.stopImmediatePropagation = function () {
|
||||
this._active = false;
|
||||
};
|
||||
|
||||
// assign in the least obtrusive way eddy properties
|
||||
for (key in eddy) {
|
||||
if (hasOwnProperty.call(eddy, key)) {
|
||||
defineProperty(ObjectPrototype, key, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: eddy[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
(function(forEach){
|
||||
function fn(key) {
|
||||
function callback(value) {
|
||||
/*jshint validthis:true */
|
||||
value[key].apply(value, this);
|
||||
}
|
||||
return function () {
|
||||
forEach.call(this, callback, arguments);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
for(var key in eddy) {
|
||||
if (
|
||||
eddy.hasOwnProperty(key) &&
|
||||
!/^listeners|boundTo$/.test(key)
|
||||
) {
|
||||
defineProperty(
|
||||
ArrayPrototype,
|
||||
key,
|
||||
{
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: fn(key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}(ArrayPrototype.forEach || function (callback, self) {
|
||||
var array = this, i = 0;
|
||||
while (i < array.length) {
|
||||
if (i in array) {
|
||||
callback.call(self, array[i], i, array);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}));
|
||||
}(Object));
|
||||
Reference in New Issue
Block a user