rizzo-next
Version:
The next generation of Lonely Planet's style guide and pattern library.
193 lines (174 loc) • 6.63 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var each = require("lodash/each"),
_once = require("lodash/once"),
keys = require("lodash/keys"),
isEmpty = require("lodash/isEmpty"),
uniqueId = require("lodash/uniqueId"),
slice = Array.prototype.slice;
// Regular expression used to split event strings.
var eventSplitter = /\s+/;
// Implement fancy features of the Events API such as multiple event
// names `"change blur"` and jQuery-style event maps `{change: action}`
// in terms of the existing API.
function eventsApi(obj, action, name, rest) {
if (!name) return true;
// Handle event maps.
if ((typeof name === "undefined" ? "undefined" : _typeof(name)) === "object") {
for (var key in name) {
obj[action].apply(obj, [key, name[key]].concat(rest));
}
return false;
}
// Handle space separated event names.
if (eventSplitter.test(name)) {
var names = name.split(eventSplitter);
for (var i = 0, l = names.length; i < l; i++) {
obj[action].apply(obj, [names[i]].concat(rest));
}
return false;
}
return true;
}
// A difficult-to-believe, but optimized internal dispatch function for
// triggering events. Tries to keep the usual cases speedy (most internal
// Backbone events have 3 arguments).
function triggerEvents(events, args) {
var ev = void 0,
i = -1,
l = events.length,
a1 = args[0],
a2 = args[1],
a3 = args[2];
switch (args.length) {
case 0:
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx);
}return;
case 1:
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx, a1);
}return;
case 2:
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx, a1, a2);
}return;
case 3:
while (++i < l) {
(ev = events[i]).callback.call(ev.ctx, a1, a2, a3);
}return;
default:
while (++i < l) {
(ev = events[i]).callback.apply(ev.ctx, args);
}return;
}
}
var Events = {
// Bind an event to a `callback` function. Passing `"all"` will bind
// the callback to all events fired.
on: function on(name, callback, context) {
if (!eventsApi(this, "on", name, [callback, context]) || !callback) return this;
this._events || (this._events = {});
var events = this._events[name] || (this._events[name] = []);
events.push({ callback: callback, context: context, ctx: context || this });
return this;
},
// Bind an event to only be triggered a single time. After the first time
// the callback is invoked, it will be removed.
once: function once(name, callback, context) {
if (!eventsApi(this, "once", name, [callback, context]) || !callback) return this;
var self = this;
var onced = _once(function () {
self.off(name, _once);
callback.apply(this, arguments);
});
onced._callback = callback;
return this.on(name, onced, context);
},
// Remove one or many callbacks. If `context` is null, removes all
// callbacks with that function. If `callback` is null, removes all
// callbacks for the event. If `name` is null, removes all bound
// callbacks for all events.
off: function off(name, callback, context) {
var retain = void 0,
ev = void 0,
events = void 0,
names = void 0,
i = void 0,
l = void 0,
j = void 0,
k = void 0;
if (!this._events || !eventsApi(this, "off", name, [callback, context])) return this;
if (!name && !callback && !context) {
this._events = void 0;
return this;
}
names = name ? [name] : keys(this._events);
for (i = 0, l = names.length; i < l; i++) {
name = names[i];
if (events = this._events[name]) {
this._events[name] = retain = [];
if (callback || context) {
for (j = 0, k = events.length; j < k; j++) {
ev = events[j];
if (callback && callback !== ev.callback && callback !== ev.callback._callback || context && context !== ev.context) {
retain.push(ev);
}
}
}
if (!retain.length) delete this._events[name];
}
}
return this;
},
// Trigger one or many events, firing all bound callbacks. Callbacks are
// passed the same arguments as `trigger` is, apart from the event name
// (unless you're listening on `"all"`, which will cause your callback to
// receive the true name of the event as the first argument).
trigger: function trigger(name) {
if (!this._events) return this;
var args = slice.call(arguments, 1);
if (!eventsApi(this, "trigger", name, args)) return this;
var events = this._events[name];
var allEvents = this._events.all;
if (events) triggerEvents(events, args);
if (allEvents) triggerEvents(allEvents, arguments);
return this;
},
// Tell this object to stop listening to either specific events ... or
// to every object it's currently listening to.
stopListening: function stopListening(obj, name, callback) {
var listeningTo = this._listeningTo;
if (!listeningTo) return this;
var remove = !name && !callback;
if (!callback && (typeof name === "undefined" ? "undefined" : _typeof(name)) === "object") callback = this;
if (obj) (listeningTo = {})[obj._listenId] = obj;
for (var id in listeningTo) {
obj = listeningTo[id];
obj.off(name, callback, this);
if (remove || isEmpty(obj._events)) delete this._listeningTo[id];
}
return this;
}
};
var listenMethods = { listenTo: "on", listenToOnce: "once" };
// Inversion-of-control versions of `on` and `once`. Tell *this* object to
// listen to an event in another object ... keeping track of what it's
// listening to.
each(listenMethods, function (implementation, method) {
Events[method] = function (obj, name, callback) {
var listeningTo = this._listeningTo || (this._listeningTo = {});
var id = obj._listenId || (obj._listenId = uniqueId("l"));
listeningTo[id] = obj;
if (!callback && (typeof name === "undefined" ? "undefined" : _typeof(name)) === "object") callback = this;
obj[implementation](name, callback, this);
return this;
};
});
// Aliases for backwards compatibility.
Events.bind = Events.on;
Events.unbind = Events.off;
exports.default = Events;