riot-observable
Version:
Simple script to send and receive events
140 lines (120 loc) • 3.69 kB
JavaScript
;(function(window, undefined) {var observable = function(el) {
/**
* Extend the original object or create a new empty one
* @type { Object }
*/
el = el || {}
/**
* Private variables and methods
*/
var callbacks = {},
slice = Array.prototype.slice,
onEachEvent = function(e, fn) { e.replace(/\S+/g, fn) }
// extend the object adding the observable methods
Object.defineProperties(el, {
/**
* Listen to the given space separated list of `events` and execute the `callback` each time an event is triggered.
* @param { String } events - events ids
* @param { Function } fn - callback function
* @returns { Object } el
*/
on: {
value: function(events, fn) {
if (typeof fn != 'function') return el
onEachEvent(events, function(name, pos) {
(callbacks[name] = callbacks[name] || []).push(fn)
fn.typed = pos > 0
})
return el
},
enumerable: false,
writable: false,
configurable: false
},
/**
* Removes the given space separated list of `events` listeners
* @param { String } events - events ids
* @param { Function } fn - callback function
* @returns { Object } el
*/
off: {
value: function(events, fn) {
if (events == '*' && !fn) callbacks = {}
else {
onEachEvent(events, function(name) {
if (fn) {
var arr = callbacks[name]
for (var i = 0, cb; cb = arr && arr[i]; ++i) {
if (cb == fn) arr.splice(i--, 1)
}
} else delete callbacks[name]
})
}
return el
},
enumerable: false,
writable: false,
configurable: false
},
/**
* Listen to the given space separated list of `events` and execute the `callback` at most once
* @param { String } events - events ids
* @param { Function } fn - callback function
* @returns { Object } el
*/
one: {
value: function(events, fn) {
function on() {
el.off(events, on)
fn.apply(el, arguments)
}
return el.on(events, on)
},
enumerable: false,
writable: false,
configurable: false
},
/**
* Execute all callback functions that listen to the given space separated list of `events`
* @param { String } events - events ids
* @returns { Object } el
*/
trigger: {
value: function(events) {
// getting the arguments
var arglen = arguments.length - 1,
args = new Array(arglen),
fns
for (var i = 0; i < arglen; i++) {
args[i] = arguments[i + 1] // skip first argument
}
onEachEvent(events, function(name) {
fns = slice.call(callbacks[name] || [], 0)
for (var i = 0, fn; fn = fns[i]; ++i) {
if (fn.busy) return
fn.busy = 1
fn.apply(el, fn.typed ? [name].concat(args) : args)
if (fns[i] !== fn) { i-- }
fn.busy = 0
}
if (callbacks['*'] && name != '*')
el.trigger.apply(el, ['*', name].concat(args))
})
return el
},
enumerable: false,
writable: false,
configurable: false
}
})
return el
}
/* istanbul ignore next */
// support CommonJS, AMD & browser
if (typeof exports === 'object')
module.exports = observable
else if (typeof define === 'function' && define.amd)
define(function() { return observable })
else
window.observable = observable
})(typeof window != 'undefined' ? window : undefined);