Comparing version 0.5.1 to 0.6.0
{ | ||
"name": "eventi", | ||
"version": "0.5.1", | ||
"version": "0.6.0", | ||
"homepage": "https://github.com/nbubna/Eventi", | ||
@@ -13,3 +13,3 @@ "bugs": "https://github.com/nbubna/nbubna/issues", | ||
}, | ||
"main": "dist/Eventi.min.js", | ||
"main": "dist/eventi.min.js", | ||
"keywords": [ | ||
@@ -24,2 +24,4 @@ "event", | ||
"listener", | ||
"history", | ||
"location", | ||
"handler", | ||
@@ -26,0 +28,0 @@ "trigger", |
{ | ||
"name": "eventi", | ||
"repo": "nbubna/Eventi", | ||
"version": "0.5.1", | ||
"version": "0.6.0", | ||
"keywords": [ | ||
@@ -15,2 +15,4 @@ "event", | ||
"handler", | ||
"history", | ||
"location", | ||
"trigger", | ||
@@ -30,4 +32,4 @@ "dispatch", | ||
"src/component.js", | ||
"dist/Eventi.js" | ||
"dist/eventi.js" | ||
] | ||
} |
@@ -24,3 +24,3 @@ module.exports = function(grunt) { | ||
src: ['src/core.js','src/fire.js','src/on.js', | ||
'src/declare.js', 'src/singleton.js', 'src/key.js', | ||
'src/declare.js', 'src/singleton.js', 'src/key.js', 'src/location.js', | ||
'src/off.js', 'src/until.js', 'src/combo.js', 'src/signal.js'] | ||
@@ -35,3 +35,3 @@ }, | ||
src: ['src/core.js','src/fire.js','src/on.js', | ||
'src/declare.js', 'src/singleton.js','src/key.js'] | ||
'src/declare.js', 'src/singleton.js','src/key.js', 'src/location.js'] | ||
}, | ||
@@ -38,0 +38,0 @@ }, |
{ | ||
"name": "eventi", | ||
"title": "Eventi", | ||
"version": "0.5.1", | ||
"version": "0.6.0", | ||
"homepage": "https://github.com/nbubna/Eventi", | ||
@@ -49,2 +49,4 @@ "author": { | ||
"handler", | ||
"history", | ||
"location", | ||
"trigger", | ||
@@ -51,0 +53,0 @@ "dispatch", |
@@ -12,11 +12,8 @@ # Eventi | ||
## TODO | ||
* finish singleton tests | ||
* finish key tests | ||
* finish off tests | ||
* finish until tests | ||
* finish combo tests | ||
* finish signal tests | ||
* documentation | ||
* demo app/site | ||
* integrations (jQuery, Visual Event 2, etc) | ||
* integrations (jQuery, Visual Event 2, Capo, etc) | ||
@@ -40,4 +37,6 @@ ## Motive | ||
* Impressive visual and/or interactive demo (ideas, anyone?) | ||
* Three versions (tall, grande, venti): tall is frame/core/fire/on, grande adds declare/singleton/key, venti adds off/until/combo/signal | ||
* Venti will be the default version to encourage feature use/development. | ||
* Three versions (tall, grande, venti): tall is frame/core/fire/on, grande adds declare/singleton/key/location, venti adds off/until/combo/signal | ||
* Venti is the default version to encourage much event-based awesomeness for everyone. | ||
* Grande includes basic webapp tools. | ||
* Tall could be enough for lite server work. | ||
@@ -90,3 +89,3 @@ ## Code Plans | ||
* fire them so they're remembered: `Eventi.fire([target, ]'^type', fn)` | ||
* alias DOMContentLoaded to '^ready'? | ||
* alias DOMContentLoaded to '^ready' | ||
@@ -96,3 +95,7 @@ #### key.js (requires on.js) | ||
#### location.js (requires on.js and fire.js) | ||
* Eventi.on('location', '?view={view}'||regex, function(e, url, params){ console.log(params.view); }) | ||
* Eventi.fire('location', '?view={0}', ['foo']) | ||
#### off.js (requires on.js) | ||
@@ -99,0 +102,0 @@ * simple listener removal: `Eventi.off([target, ]['type', ][fn])` |
_.comboRE = /\+|>/; | ||
// overwrite fire.js' _.fireAll to watch for combo events | ||
_.combo_trigger = _.fireAll; | ||
_.fireAll = function(target, events, props, _resumeIndex) { | ||
@@ -37,21 +36,17 @@ var event, sequence; | ||
// wrap _.on's _.handler to watch for combo event listeners | ||
_.combo_handler = _.handler; | ||
_.handler = function(target, event, selector) { | ||
var handler = _.combo_handler.apply(this, arguments), | ||
joint = event.match(_.comboRE); | ||
Eventi.on(_, 'handler#new', function comboHandler(e, handler) { | ||
var text = handler.text, | ||
joint = text.match(_.comboRE); | ||
if (joint) { | ||
var types = event.split(joint[0]), | ||
fn = handler.comboFn = _.comboFn(joint[0]==='>', types, event); | ||
var types = text.split(joint[0]), | ||
fn = handler.comboFn = _.comboFn(joint[0]==='>', types, text); | ||
for (var i=0,m=types.length; i<m; i++) { | ||
// override full type with parsed, core type for comboFn's use | ||
types[i] = _.handler(target, types[i], selector, fn).type; | ||
types[i] = _.handler(handler.target, types[i], handler.selector, fn).type; | ||
} | ||
fn.reset(); | ||
} | ||
return handler; | ||
}; | ||
}); | ||
_.comboTimeout = 1000; | ||
_.comboFn = function(ordered, types, event) { | ||
_.comboFn = function(ordered, types, text) { | ||
var waitingFor, | ||
@@ -69,3 +64,3 @@ clear, | ||
if (!waitingFor.length) { | ||
_.fire(e.target, event); | ||
_.fire(e.target, text); | ||
reset(); | ||
@@ -79,11 +74,7 @@ } | ||
if (_.off) { | ||
// wrap _.off's _.cleaned to watch for handler.comboFn and remove sub-handlers | ||
_.combo_cleaned = _.cleaned; | ||
_.cleaned = function(handler) { | ||
_.combo_cleaned.apply(this, arguments); | ||
if (handler.comboFn) { | ||
_.off(handler.target, '', handler.comboFn); | ||
} | ||
}; | ||
} | ||
// watch for handler.comboFn and remove sub-handlers | ||
Eventi.on(_, 'handler#off', function cleanedHandler(e, handler) { | ||
if (handler.comboFn) { | ||
_.off(handler.target, '', handler.comboFn); | ||
} | ||
}); |
@@ -9,2 +9,3 @@ function Eventi(){ return _.create.apply(this, arguments); } | ||
}, | ||
async: global.setImmediate || function async(fn){ return setTimeout(fn, 0); }, | ||
resolveRE: /^([\w\$]+)?((\.[\w\$]+)|\[(\d+|'(\\'|[^'])+'|"(\\"|[^"])+")\])*$/, | ||
@@ -32,3 +33,2 @@ resolve: function(reference, context) { | ||
} | ||
event.stopImmediatePropagation = _.sIP;//TODO: consider prototype extension | ||
return event; | ||
@@ -38,6 +38,2 @@ }, | ||
prop: function(prop){ return prop; },// only an extension hook | ||
sIP: function() { | ||
this.immediatePropagationStopped = true; | ||
(Event.prototype.stopImmediatePropagation || _.noop).call(this); | ||
}, | ||
parse: function(type, props) { | ||
@@ -52,15 +48,22 @@ _.properties.forEach(function(property) { | ||
properties: [ | ||
/*nobubble*/[/^_/, function(){ this.bubbles = false; }], | ||
/*detail*/ [/\((.*)\)/, function(m, val) { | ||
try { | ||
this.detail = _.resolve(val) || JSON.parse(val); | ||
} catch (e) { | ||
this.detail = val; | ||
} | ||
}], | ||
/*tags*/ [/#(\w+)/g, function(m, tag) { | ||
(this.tags||(this.tags=[])).push(tag); | ||
this[tag] = true; | ||
}], | ||
/*category*/[/^(\w+):/, function(m, category){ this.category = category; }]// | ||
[/^_/, function nobubble() { | ||
this.bubbles = false; | ||
}], | ||
[/^\!/, function protect() {// | ||
this._protect = true; | ||
}], | ||
[/\((.*)\)/, function detail(m, val) { | ||
try { | ||
this.detail = _.resolve(val) || JSON.parse(val); | ||
} catch (e) { | ||
this.detail = val; | ||
} | ||
}], | ||
[/#(\w+)/g, function tags(m, tag) { | ||
(this.tags||(this.tags=[])).push(tag); | ||
this[tag] = true; | ||
}], | ||
[/^(\w+):/, function category(m, cat) {// | ||
this.category = cat; | ||
}] | ||
], | ||
@@ -67,0 +70,0 @@ |
@@ -21,8 +21,12 @@ _.fire = function(target, events, props, data) { | ||
}; | ||
_.dispatch = function(target, event) { | ||
(target.dispatchEvent || target[_._key] || _.noop).call(target, event); | ||
if (target.parentObject) { | ||
_.dispatch(target.parentObject, event); | ||
_.dispatch = function(target, event, objectBubbling) { | ||
(target.dispatchEvent || target[_key] || _.noop).call(target, event); | ||
if (target.parentObject && event.bubbles && !event.propagationStopped) { | ||
_.dispatch(target.parentObject, event, true); | ||
} | ||
// icky test/call, but lighter than wrapping or firing internal event | ||
if (!objectBubbling && event._singleton) { | ||
_.singleton(target, event); | ||
} | ||
}; | ||
Eventi.fire = _.wrap('fire', 3); |
_.off = function(target, events, fn) { | ||
var listener = target[_._key]; | ||
if (listener) { | ||
for (var i=0, m=events.length; i<m; i++) { | ||
var filter = { fn:fn }, | ||
type = _.parse(events[i], filter.match = {}); | ||
if (type) { | ||
_.clean(type, filter, listener, target); | ||
} else { | ||
for (type in listener.s) { | ||
_.clean(type, filter, listener, target); | ||
} | ||
} | ||
} | ||
if (_.empty(listener.s)) { | ||
delete target[_._key]; | ||
} | ||
} | ||
//TODO: support filtering by selector/location | ||
var listener = target[_key]; | ||
if (listener) { | ||
for (var i=0, m=events.length; i<m; i++) { | ||
var filter = { fn:fn, match:{} }, | ||
type = _.parse(events[i], filter.match); | ||
delete filter.match.tags;// superfluous for matching | ||
if (type) { | ||
_.clean(type, filter, listener, target); | ||
} else { | ||
for (type in listener.s) { | ||
_.clean(type, filter, listener, target); | ||
} | ||
} | ||
} | ||
if (_.empty(listener.s)) { | ||
delete target[_key]; | ||
} | ||
} | ||
}; | ||
_.unhandle = function off(handler) { | ||
_.off(handler.target, [handler.text], handler._fn||handler.fn); | ||
}; | ||
_.empty = function(o){ for (var k in o){ return !k; } return true; }; | ||
_.clean = function(type, filter, listener, target) { | ||
var handlers = listener.s[type]; | ||
if (handlers) { | ||
for (var i=0, m=handlers.length; i<m; i++) { | ||
if (_.cleans(handlers[i], filter)) { | ||
_.cleaned(handlers.splice(i--, 1)[0]); | ||
m--; | ||
} | ||
} | ||
if (!handlers.length) { | ||
if (target.removeEventListener) { | ||
target.removeEventListener(type, listener); | ||
} | ||
delete listener.s[type]; | ||
} | ||
} | ||
var handlers = listener.s[type]; | ||
if (handlers) { | ||
for (var i=0, m=handlers.length; i<m; i++) { | ||
if (_.cleans(handlers[i], filter)) { | ||
var cleaned = handlers.splice(i--, 1)[0]; | ||
if (target !== _) {// ignore internal events | ||
Eventi.fire(_, 'handler#off', cleaned); | ||
} | ||
m--; | ||
} | ||
} | ||
if (!handlers.length) { | ||
if (target.removeEventListener) { | ||
target.removeEventListener(type, listener); | ||
} | ||
delete listener.s[type]; | ||
} | ||
} | ||
}; | ||
_.cleans = function(handler, filter) { | ||
return _.matches(handler.match, filter.match) && (!filter.fn || handler.fn === filter.fn); | ||
return _.matches(handler.match, filter.match, true) && | ||
(!filter.fn || filter.fn === (handler._fn||handler.fn)); | ||
}; | ||
_.cleaned = _.noop;// extension hook (called with cleaned handler as arg) | ||
Eventi.off = _.wrap('off', 3); | ||
Eventi.off = _.wrap('off', 3); |
128
src/on.js
_.on = function(target, events, selector, fn, data) { | ||
// adjust for absence of selector | ||
if (typeof selector !== "string") { | ||
if (fn !== undefined) { | ||
data = data ? data.unshift(fn) && data : [fn]; | ||
} | ||
fn = selector; selector = null; | ||
} | ||
for (var i=0,m=events.length; i<m; i++) { | ||
_.handler(target, events[i], selector, fn, data); | ||
} | ||
// adjust for absence of selector | ||
if (typeof selector === "function") { | ||
if (fn !== undefined) { | ||
data = data ? data.unshift(fn) && data : [fn]; | ||
} | ||
fn = selector; selector = null; | ||
} | ||
for (var i=0,m=events.length; i<m; i++) { | ||
_.handler(target, events[i], selector, fn, data); | ||
} | ||
}; | ||
_.handler = function(target, text, selector, fn, data) { | ||
var handler = { target:target, selector:selector, fn:fn, data:data, text:text, match:{} }, | ||
listener = _.listener(target), | ||
type = _.parse(text, handler.match), | ||
handlers = listener.s[type]; | ||
delete handler.match.tags;// superfluous for matching | ||
if (!handlers) { | ||
handlers = listener.s[type] = []; | ||
if (target.addEventListener) { | ||
target.addEventListener(type, listener); | ||
} | ||
} | ||
handlers.push(handler); | ||
return handler; | ||
//TODO: consider moving selector into match, so we can specifically off delegates | ||
var handler = { target:target, selector:selector, fn:fn, data:data, text:text, match:{} }; | ||
_.parse(text, handler.match); | ||
delete handler.match.tags;// superfluous for matching | ||
if (target !== _) {// ignore internal events | ||
Eventi.fire(_, 'handler#new', handler); | ||
} | ||
// allow handler#new listeners to change these things | ||
if (handler.fn !== _.noop) { | ||
_.handlers(handler.target, handler.match.type).push(handler); | ||
} | ||
return handler; | ||
}; | ||
_._key = 'Eventi'+Math.random(); | ||
_.handlers = function(target, type) { | ||
var listener = _.listener(target), | ||
handlers = listener.s[type]; | ||
if (!handlers) { | ||
handlers = listener.s[type] = []; | ||
if (target.addEventListener) { | ||
target.addEventListener(type, listener); | ||
} | ||
} | ||
return handlers; | ||
}; | ||
var _key = _._key = '_eventi'+Date.now(); | ||
_.listener = function(target) { | ||
var listener = target[_._key]; | ||
var listener = target[_key]; | ||
if (!listener) { | ||
listener = function(event){ _.handle(event, listener.s[event.type]||[]); }; | ||
listener = function(event) { | ||
var handlers = listener.s[event.type]; | ||
if (handlers){ _.handle(event, handlers); } | ||
}; | ||
listener.s = {}; | ||
Object.defineProperty(target, _._key, { | ||
value:listener, writeable:false, configurable:true | ||
Object.defineProperty(target, _key, { | ||
value:listener, writeable:false, configurable:true | ||
}); | ||
@@ -42,33 +56,41 @@ } | ||
_.handle = function(event, handlers) { | ||
for (var i=0, m=handlers.length, handler, target; i<m; i++) { | ||
if (_.matches(event, (handler = handlers[i]).match)) { | ||
if (target = _.target(handler, event.target)) { | ||
_.execute(target, event, handler); | ||
if (event.immediatePropagationStopped){ i = m; } | ||
} | ||
} | ||
} | ||
for (var i=0, handler, target; i<handlers.length; i++) { | ||
if (_.matches(event, (handler = handlers[i]).match)) { | ||
if (target = _.target(handler, event.target)) { | ||
_.execute(target, event, handler); | ||
if (event.immediatePropagationStopped){ break; } | ||
} | ||
} | ||
} | ||
}; | ||
_.execute = function(target, event, handler) { | ||
var args = [event]; | ||
if (event.data){ args.push.apply(args, event.data); } | ||
if (handler.data){ args.push.apply(args, handler.data); } | ||
try { | ||
handler.fn.apply(target, args); | ||
} catch (e) { | ||
setTimeout(function(){ throw e; }, 0); | ||
} | ||
var args = [event]; | ||
if (event.data){ args.push.apply(args, event.data); } | ||
if (handler.data){ args.push.apply(args, handler.data); } | ||
try { | ||
handler.fn.apply(target, args); | ||
} catch (e) { | ||
_.async(function(){ throw e; }); | ||
} | ||
}; | ||
_.unhandle = function noop(handler){ handler.fn = _.noop; }; | ||
_.matches = function(event, match) { | ||
for (var key in match) { | ||
if (match[key] !== event[key]) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
_.matches = function(event, match, strict) { | ||
for (var key in match) { | ||
if (match[key] !== event[key] && (strict || key.charAt(0) !== '_')) { | ||
return false; | ||
} | ||
} | ||
if (strict) { | ||
for (key in event) { | ||
if (key.charAt(0) === '_' && event[key] !== match[key]) { | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
}; | ||
_.target = function(handler, target) { | ||
return handler.selector ? _.closest(target, handler.selector) : handler.target; | ||
return handler.selector ? _.closest(target, handler.selector) : handler.target; | ||
}; | ||
@@ -86,5 +108,5 @@ _.closest = function(el, selector) { | ||
aS = 'atchesSelector'; | ||
Object.defineProperty(Ep, 'matches', {value:Ep['webkitM'+aS]||Ep['mozM'+aS]||Ep['msM'+aS]}); | ||
Object.defineProperty(Ep, 'matches', {value:Ep['webkitM'+aS]||Ep['mozM'+aS]||Ep['msM'+aS]}); | ||
} | ||
Eventi.on = _.wrap('on', 4); |
@@ -6,3 +6,3 @@ // memoizes results | ||
index = this.index || 1; | ||
if (typeof target !== "object" || !(target.dispatchEvent || target[_._key])) { | ||
if (typeof target !== "object" || !(target.dispatchEvent || target[_key])) { | ||
index--; | ||
@@ -9,0 +9,0 @@ } |
// add singleton to _.parse's supported event properties | ||
_.singletonRE = /^_?\^/; | ||
_.properties.splice(1,0, [_.singletonRE, function(){ this.singleton = true; }]); | ||
_.properties.unshift([/^\^/, function singleton(){ this._singleton = true; }]); | ||
// wrap _.fire's _.dispatch to save singletons with node and all parents | ||
_.singleton_dispatch = _.dispatch; | ||
_.dispatch = function(target, event) { | ||
_.singleton_dispatch(target, event); | ||
if (event.singleton) { | ||
do { | ||
var saved = target[_._sKey]; | ||
if (saved) { | ||
saved.push(event); | ||
} else { | ||
Object.defineProperty(target, _._sKey, {value:[event],configurable:true}); | ||
} | ||
} while (target = target.parentNode); | ||
// _.fire's _.dispatch will call this when appropriate | ||
_.singleton = function(target, event) { | ||
_.remember(target, event); | ||
if (event.bubbles && !event.propagationStopped && target !== _.global) { | ||
_.singleton(target.parentNode || target.parentObject || _.global, event); | ||
} | ||
}; | ||
_._sKey = _._key+'s.e.'; | ||
var _skey = _._skey = '^'+_key; | ||
_.remember = function remember(target, event) { | ||
var saved = target[_skey] || []; | ||
if (!saved.length) { | ||
Object.defineProperty(target, _skey, {value:saved,configurable:true}); | ||
} | ||
event[_skey] = true; | ||
saved.push(event); | ||
}; | ||
// wrap _.on's _.handler to execute fired singletons immediately | ||
//TODO: ensure that combo.js wraps this _.handler instead of vice versa | ||
// combo events should be able to include singletons, but not be singletons | ||
_.singleton_handler = _.handler; | ||
_.handler = function(target, text, selector, fn) { | ||
var handler = _.singleton_handler.apply(this, arguments); | ||
if (handler.singleton) { | ||
handler.after = function after() { | ||
if (_.off){ _.off(target, text, fn); } | ||
handler.fn = _.noop; | ||
Eventi.on(_, 'handler#new', function singleton(e, handler) { | ||
if (handler.match._singleton) { | ||
var fn = handler._fn = handler.fn; | ||
handler.fn = function singleton(e) { | ||
_.unhandle(handler); | ||
if (!e[_skey]) {// remember this non-singleton as singleton for handler's sake | ||
_.remember(handler.target, e); | ||
} | ||
fn.apply(this, arguments); | ||
}; | ||
// search target's saved singletons, execute handler upon match | ||
var saved = target[_._sKey]; | ||
if (saved) { | ||
for (var i=0,m=saved.length; i<m; i++) { | ||
var event = saved[i]; | ||
if (_.handles(event, handler)) { | ||
if (target = _.target(handler, event.target)) { | ||
_.execute(target, event, handler); | ||
break; | ||
} | ||
var saved = handler.target[_skey]||[]; | ||
for (var i=0,m=saved.length; i<m; i++) { | ||
var event = saved[i]; | ||
if (_.matches(event, handler.match)) { | ||
var target = _.target(handler, event.target); | ||
if (target) { | ||
_.execute(target, event, handler); | ||
handler.fn = _.noop;// tell _.handler not to keep this | ||
break; | ||
} | ||
@@ -47,9 +46,8 @@ } | ||
} | ||
return handler; | ||
}; | ||
}); | ||
if (document) { | ||
Eventi.on('DOMContentLoaded', function ready(e) { | ||
_.fire(document.documentElement, ['^ready'], undefined, e); | ||
_.fire(document.documentElement, ['^ready'], undefined, [e]); | ||
}); | ||
} |
@@ -16,9 +16,6 @@ _.until = function(target, condition, events, selector, fn, data) { | ||
var stop = _.untilFn(handler, condition), | ||
fn = handler.fn; | ||
fn = handler._fn = handler.fn; | ||
handler.fn = function() { | ||
fn.apply(this, arguments); | ||
if (stop()) { | ||
if (_.off){ _.off(handler.target, handler.text, fn); } | ||
handler.fn = _.noop; | ||
} | ||
if (stop()){ _.unhandle(handler); } | ||
}; | ||
@@ -34,3 +31,3 @@ }; | ||
if (not){ condition = condition.substring(1); } | ||
return function() { | ||
return function until() { | ||
var value = _.resolve(condition, handler.target); | ||
@@ -37,0 +34,0 @@ if (value === undefined) { |
@@ -45,4 +45,4 @@ (function() { | ||
test('new Eventi("_category:type#tag#label(\'detail\')")', function() { | ||
var e = new Eventi("_category:type#tag#label(\"detail\")"); | ||
test('new Eventi("_!category:type#tag#label(\'detail\')")', function() { | ||
var e = new Eventi("_!category:type#tag#label(\"detail\")"); | ||
equal(e.bubbles, false, 'should not be set to bubble'); | ||
@@ -55,2 +55,3 @@ equal(e.category, 'category', 'should be in category'); | ||
equal(e.detail, 'detail', 'should have detail'); | ||
equal(e._protect, true, 'should be protected'); | ||
}); | ||
@@ -83,2 +84,3 @@ | ||
ok(_.copy, "_.copy"); | ||
ok(_.async, "_.async"); | ||
ok(_.resolveRE, "_.resolveRE"); | ||
@@ -88,3 +90,2 @@ ok(_.resolve, "_.resolve"); | ||
ok(_.prop, "_.prop"); | ||
ok(_.sIP, "_.sIP"); | ||
ok(_.parse, "_.parse"); | ||
@@ -114,2 +115,10 @@ ok(_.properties, "_.properties"); | ||
asyncTest('_.async', function() { | ||
var id = _.async(function() { | ||
ok(true, 'should be called'); | ||
start(); | ||
}); | ||
ok(id, 'should have id'); | ||
}); | ||
test('_.resolve', function() { | ||
@@ -116,0 +125,0 @@ equal(_.resolve('module()') || _.resolve('test;foo') || _.resolve('a b'), undefined, 'should not resolve non-reference strings'); |
@@ -87,3 +87,5 @@ (function() { | ||
el.remove = function() { | ||
this.parentNode.removeChild(this); | ||
if (this.parentNode) { | ||
this.parentNode.removeChild(this); | ||
} | ||
}; | ||
@@ -90,0 +92,0 @@ } |
@@ -6,4 +6,11 @@ (function() { | ||
test('3rd party/polyfill api presence', function() { | ||
ok(typeof CustomEvent === "function", "CustomEvent"); | ||
test('CustomEvent API/polyfill', function() { | ||
equal(typeof CustomEvent, "function", "CustomEvent"); | ||
var ce = new CustomEvent('foo', {bubbles:true}); | ||
equal(ce.type, 'foo', "CustomEvent type"); | ||
equal(typeof ce.timeStamp, "number", "CustomEvent timeStamp"); | ||
ok('detail' in ce, "CustomEvent detail"); | ||
equal(ce.bubbles, true, "CustomEvent bubbles"); | ||
equal(typeof ce.stopPropagation, "function", "CustomEvent stopPropagation"); | ||
equal(typeof ce.stopImmediatePropagation, "function", "CustomEvent stopImmediatePropagation"); | ||
}); | ||
@@ -10,0 +17,0 @@ |
145
test/off.js
@@ -34,10 +34,153 @@ (function() { | ||
test('Eventi.off(type)', function() { | ||
expect(1); | ||
Eventi.on("test", function() { | ||
ok(true, 'should only be called once'); | ||
}) | ||
.fire('test'); | ||
Eventi.off("test") | ||
.fire('test'); | ||
}); | ||
test('Eventi.off("category:")', function() { | ||
expect(2); | ||
Eventi.on("test:foo", function() { | ||
ok(true, 'should call foo once'); | ||
}) | ||
.on('test:bar', function() { | ||
ok(true, 'should call bar once'); | ||
}) | ||
.fire('test:foo test:bar'); | ||
Eventi.off("test:") | ||
.fire('test:foo test:bar'); | ||
}); | ||
test('Eventi.off("#tag")', function() { | ||
expect(2); | ||
Eventi.on("foo#test", function() { | ||
ok(true, 'should call foo once'); | ||
}) | ||
.on('bar#test', function() { | ||
ok(true, 'should call bar once'); | ||
}) | ||
.fire('foo#test bar#test'); | ||
Eventi.off("#test") | ||
.fire('foo#test bar#test'); | ||
}); | ||
test('Eventi.off(type,fn)', function() { | ||
expect(1); | ||
var fn = function() { | ||
ok(false, 'should not be called'); | ||
}, | ||
type = 'offfn'; | ||
Eventi.on(type, fn) | ||
.on(type, function() { | ||
ok(true, 'should be called once'); | ||
}) | ||
.off(type, fn) | ||
.fire(type); | ||
}); | ||
test('Eventi.off(target,type,fn)', function() { | ||
expect(2); | ||
var fn = function() { | ||
strictEqual(this, document, 'should only fire on document'); | ||
}, | ||
type = 'offtargetfn', | ||
other = {}, | ||
targets = [document, other]; | ||
Eventi.on(targets, type, fn) | ||
.on(other, type, function() { | ||
ok(true, 'should be called once'); | ||
}) | ||
.off(other, type, fn) | ||
.fire(targets, type); | ||
Eventi.off(document, type, fn) | ||
.off(other, type) | ||
.fire(targets, type); | ||
}); | ||
test('Eventi.off(target, type', function() { | ||
expect(1); | ||
var other = {}, | ||
type = 'offtarget', | ||
targets = [document, other]; | ||
Eventi.on(targets, type, function() { | ||
strictEqual(this, document, 'should only fire on document'); | ||
}) | ||
.off(other, type) | ||
.fire(targets, type); | ||
Eventi.off(document, type) | ||
.fire(targets, type); | ||
}); | ||
test('Eventi.off("!protected")', function() { | ||
expect(2); | ||
Eventi.on("!protected", function(e) { | ||
equal(e.type, 'protected'); | ||
equal(e._protect, undefined); | ||
}) | ||
.off("protected")// should fail to turn it off | ||
.fire("protected"); | ||
Eventi.off("!protected") | ||
.fire("protected"); | ||
}); | ||
test('Eventi.off within on nastiness', function() { | ||
expect(1); | ||
var type = 'bewarePrematureOptimization'; | ||
Eventi.on(type, function() { | ||
ok(true, 'should be called'); | ||
Eventi.off(type); | ||
}) | ||
.on(type, function() { | ||
ok(false, 'should not be called'); | ||
}) | ||
.fire(type); | ||
}); | ||
test('internal api presence', function() { | ||
ok(_.off, "_.off"); | ||
ok(_.unhandle, "_.unhandle"); | ||
ok(_.empty, "_.empty"); | ||
ok(_.clean, "_.clean"); | ||
ok(_.cleans, "_.cleans"); | ||
ok(_.cleaned, "_.cleaned"); | ||
}); | ||
test('handler#off event', function() { | ||
expect(4); | ||
var target = {}, | ||
type = 'offevent', | ||
fn = function(e, h) { | ||
if (h.match.type === type) { | ||
ok(e.off); | ||
equal(e.type, 'handler'); | ||
ok(h === handler, 'should pass off\'ed handler'); | ||
} | ||
}; | ||
Eventi.on(target, type, function(){}); | ||
var handler = target[_._key].s[type][0]; | ||
ok(handler, 'should be able to snag ref to handler'); | ||
Eventi.on(_, 'handler#off', fn) | ||
.off(target, type) | ||
.off(_, 'handler#off', fn); | ||
}); | ||
test('_.unhandle not just noop', function() { | ||
equal(_.unhandle.name, 'off', 'should override on.js\' noop version'); | ||
}); | ||
test('_.empty', function() { | ||
ok(_.empty({}), 'should be empty'); | ||
ok(!_.empty({foo:1}), 'should not be empty'); | ||
function A(){} | ||
A.prototype = { foo: 1 }; | ||
var a = new A(); | ||
ok(!_.empty(a), 'those with inherited props should not be empty'); | ||
var o = {}; | ||
Object.defineProperty(o, 'foo', {value:1}); | ||
ok(_.empty(o), 'non-enumerable defined props should keep things empty'); | ||
}); | ||
}()); |
@@ -119,2 +119,22 @@ (function() { | ||
test('handler#new event', function() { | ||
expect(4); | ||
var target = {}, | ||
type = 'onevent', | ||
passed, | ||
fn = function(e, h) { | ||
if (h.text === type) {// don't let problems with _.off bug us | ||
ok(e['new']); | ||
equal(e.type, 'handler'); | ||
passed = h; | ||
} | ||
}; | ||
Eventi.on(_, 'handler#new', fn) | ||
.on(target, type, function(){}) | ||
.off(_, 'handler#new', fn); | ||
var handler = target[_._key].s[type][0]; | ||
ok(handler, 'should get new handler directly'); | ||
ok(passed === handler, 'should pass new handler'); | ||
}); | ||
test('internal api presence', function() { | ||
@@ -126,2 +146,3 @@ ok(_.on, "_.on"); | ||
ok(_.execute, "_.execute"); | ||
ok(_.unhandle, "_.unhandle"); | ||
ok(_.matches, "_.matches"); | ||
@@ -128,0 +149,0 @@ ok(_.target, "_.target"); |
@@ -26,7 +26,96 @@ (function() { | ||
test('^ready - even when registered late', function() { | ||
expect(3); | ||
Eventi.on('^ready', function(e, oe) { | ||
equal(e.type, 'ready'); | ||
ok(e._singleton); | ||
equal(oe.type, 'DOMContentLoaded'); | ||
}); | ||
}); | ||
test('^once on once', function() { | ||
expect(5); | ||
var target = Eventi.fy({}); | ||
target.on('^once', function(e) {// early listener | ||
equal(e.type, 'once'); | ||
ok(!e._singleton); | ||
equal(e[_._skey], true); | ||
}); | ||
var first = target.fire('once#first'); | ||
target.fire('once#second'); | ||
target.on('^once', function(e) {// late listener | ||
strictEqual(e, first, 'should get first once in late listener'); | ||
first = null; | ||
}); | ||
ok(!first, 'late listener should have fired synchronously'); | ||
target.fire('once#third'); | ||
}); | ||
test('^sbubbles - parentNode and parentObject', function() { | ||
expect(2); | ||
var target = Eventi.fy({parentObject:{}}); | ||
target.fire('^sbubbles'); | ||
Eventi.on(target.parentObject, '^sbubbles', function(e) { | ||
equal(e.type, 'sbubbles'); | ||
}); | ||
target = document.getElementById('on'); | ||
Eventi.fire(target, '^sbubbles'); | ||
Eventi.on(document.body, '^sbubbles', function(e) { | ||
equal(e.type, 'sbubbles'); | ||
}); | ||
}); | ||
test('snobubble', function() { | ||
expect(2); | ||
var target = document.getElementById('on'); | ||
ok(target, 'should have target element'); | ||
Eventi.on(target, '^snobubble', function(e) { | ||
equal(e.type, 'snobubble'); | ||
}); | ||
Eventi.fire(target, '^_snobubble'); | ||
Eventi.on('^snobubble', function() { | ||
ok(false, 'should not see snobubble here'); | ||
}); | ||
}); | ||
test('internal api presence', function() { | ||
ok(_.singletonRE, "_.singletonRE"); | ||
equal(_.properties[1][0], _.singletonRE, '_.properties includes singleton parser'); | ||
var e = {}; | ||
_.properties[0][1].call(e); | ||
ok(e._singleton, '_.properties has singleton parser up front'); | ||
ok(_.singleton, '_.singleton'); | ||
ok(_._skey, '_._key'); | ||
ok(_.remember, '_.remember'); | ||
}); | ||
test('_.singleton bubbles', function() { | ||
var e = {type:'singletonbubbles',bubbles:true}; | ||
_.singleton(document.body, e); | ||
equal(document.body[_._skey].pop(), e, 'body should remember e'); | ||
equal(document[_._skey].pop(), e, 'document should remember e'); | ||
equal(_.global[_._skey].pop(), e, 'global should remember e'); | ||
}); | ||
test('_.singleton bubbles=false', function() { | ||
var e = {type:'singleton'}; | ||
_.singleton(document.body, e); | ||
equal(document.body[_._skey].pop(), e, 'body should remember e'); | ||
notEqual((document[_._skey]||[]).slice(-1), e, 'document should not remember e'); | ||
notEqual((_.global[_._skey]||[]).slice(-1), e, 'global should not remember e'); | ||
}); | ||
test('_.remember', function() { | ||
var target = {}, | ||
event = {}; | ||
equal(Object.keys(target).length, 0, 'target should have no keys'); | ||
_.remember(target, event); | ||
equal(Object.keys(target).length, 0, 'target should still have no keys'); | ||
var saved = target[_._skey]; | ||
ok(saved, 'target should have saved events array'); | ||
equal(saved[0], event, 'should have event saved'); | ||
_.remember(target, event); | ||
equal(saved.length, 2, 'should have two saved'); | ||
}); | ||
}()); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
284652
61
6255
141