From a8336f71def9da15bcacb2cbedab270121dff365 Mon Sep 17 00:00:00 2001 From: Stephanie Chung Date: Fri, 9 May 2014 23:46:56 -0700 Subject: [PATCH] adding standalone twitter flight --- js/libs/flight.js | 1112 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1112 insertions(+) create mode 100644 js/libs/flight.js diff --git a/js/libs/flight.js b/js/libs/flight.js new file mode 100644 index 0000000..b2b09e1 --- /dev/null +++ b/js/libs/flight.js @@ -0,0 +1,1112 @@ +/*! Flight v1.1.4 | (c) Twitter, Inc. | MIT License */ +(function(context) { + var factories = {}, loaded = {}; + var isArray = Array.isArray || function(obj) { + return obj.constructor == Array; + }; + + var map = Array.map || function(arr, fn, scope) { + for (var i = 0, len = arr.length, result = []; i < len; i++) { + result.push(fn.call(scope, arr[i])); + } + return result; + }; + + function define() { + var args = Array.prototype.slice.call(arguments), dependencies = [], id, factory; + if (typeof args[0] == 'string') { + id = args.shift(); + } + if (isArray(args[0])) { + dependencies = args.shift(); + } + factory = args.shift(); + factories[id] = [dependencies, factory]; + } + + function require(id) { + function resolve(dep) { + var relativeParts = id.split('/'), depParts = dep.split('/'), relative = false; + relativeParts.pop(); + while (depParts[0] == '..' && relativeParts.length) { + relativeParts.pop(); + depParts.shift(); + relative = true; + } + if (depParts[0] == '.') { + depParts.shift(); + relative = true; + } + if (relative) { + depParts = relativeParts.concat(depParts); + } + return depParts.join('/'); + } + + var unresolved, factory, dependencies; + if (typeof loaded[id] == 'undefined') { + unresolved = factories[id]; + if (unresolved) { + dependencies = unresolved[0]; + factory = unresolved[1]; + loaded[id] = factory.apply(undefined, map(dependencies, function(id) { + return require(resolve(id)); + })); + } + } + + return loaded[id]; + } + +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/utils', [], function () { + 'use strict'; + var arry = []; + var DEFAULT_INTERVAL = 100; + var utils = { + isDomObj: function (obj) { + return !!(obj.nodeType || obj === window); + }, + toArray: function (obj, from) { + return arry.slice.call(obj, from); + }, + merge: function () { + // unpacking arguments by hand benchmarked faster + var l = arguments.length, i = 0, args = new Array(l + 1); + for (; i < l; i++) + args[i + 1] = arguments[i]; + if (l === 0) { + return {}; + } + //start with empty object so a copy is created + args[0] = {}; + if (args[args.length - 1] === true) { + //jquery extend requires deep copy as first arg + args.pop(); + args.unshift(true); + } + return $.extend.apply(undefined, args); + }, + push: function (base, extra, protect) { + if (base) { + Object.keys(extra || {}).forEach(function (key) { + if (base[key] && protect) { + throw new Error('utils.push attempted to overwrite "' + key + '" while running in protected mode'); + } + if (typeof base[key] == 'object' && typeof extra[key] == 'object') { + // recurse + this.push(base[key], extra[key]); + } else { + // no protect, so extra wins + base[key] = extra[key]; + } + }, this); + } + return base; + }, + isEnumerable: function (obj, property) { + return Object.keys(obj).indexOf(property) > -1; + }, + compose: function () { + var funcs = arguments; + return function () { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }, + uniqueArray: function (array) { + var u = {}, a = []; + for (var i = 0, l = array.length; i < l; ++i) { + if (u.hasOwnProperty(array[i])) { + continue; + } + a.push(array[i]); + u[array[i]] = 1; + } + return a; + }, + debounce: function (func, wait, immediate) { + if (typeof wait != 'number') { + wait = DEFAULT_INTERVAL; + } + var timeout, result; + return function () { + var context = this, args = arguments; + var later = function () { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + } + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + } + return result; + }; + }, + throttle: function (func, wait) { + if (typeof wait != 'number') { + wait = DEFAULT_INTERVAL; + } + var context, args, timeout, throttling, more, result; + var whenDone = this.debounce(function () { + more = throttling = false; + }, wait); + return function () { + context = this; + args = arguments; + var later = function () { + timeout = null; + if (more) { + result = func.apply(context, args); + } + whenDone(); + }; + if (!timeout) { + timeout = setTimeout(later, wait); + } + if (throttling) { + more = true; + } else { + throttling = true; + result = func.apply(context, args); + } + whenDone(); + return result; + }; + }, + countThen: function (num, base) { + return function () { + if (!--num) { + return base.apply(this, arguments); + } + }; + }, + delegate: function (rules) { + return function (e, data) { + var target = $(e.target), parent; + Object.keys(rules).forEach(function (selector) { + if (!e.isPropagationStopped() && (parent = target.closest(selector)).length) { + data = data || {}; + data.el = parent[0]; + return rules[selector].apply(this, [ + e, + data + ]); + } + }, this); + }; + }, + once: function (func) { + var ran, result; + return function () { + if (ran) { + return result; + } + ran = true; + result = func.apply(this, arguments); + return result; + }; + } + }; + return utils; +}); +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/debug', [], function () { + 'use strict'; + // ========================================== + // Search object model + // ========================================== + function traverse(util, searchTerm, options) { + options = options || {}; + var obj = options.obj || window; + var path = options.path || (obj == window ? 'window' : ''); + var props = Object.keys(obj); + props.forEach(function (prop) { + if ((tests[util] || util)(searchTerm, obj, prop)) { + console.log([ + path, + '.', + prop + ].join(''), '->', [ + '(', + typeof obj[prop], + ')' + ].join(''), obj[prop]); + } + if (Object.prototype.toString.call(obj[prop]) == '[object Object]' && obj[prop] != obj && path.split('.').indexOf(prop) == -1) { + traverse(util, searchTerm, { + obj: obj[prop], + path: [ + path, + prop + ].join('.') + }); + } + }); + } + function search(util, expected, searchTerm, options) { + if (!expected || typeof searchTerm == expected) { + traverse(util, searchTerm, options); + } else { + console.error([ + searchTerm, + 'must be', + expected + ].join(' ')); + } + } + var tests = { + 'name': function (searchTerm, obj, prop) { + return searchTerm == prop; + }, + 'nameContains': function (searchTerm, obj, prop) { + return prop.indexOf(searchTerm) > -1; + }, + 'type': function (searchTerm, obj, prop) { + return obj[prop] instanceof searchTerm; + }, + 'value': function (searchTerm, obj, prop) { + return obj[prop] === searchTerm; + }, + 'valueCoerced': function (searchTerm, obj, prop) { + return obj[prop] == searchTerm; + } + }; + function byName(searchTerm, options) { + search('name', 'string', searchTerm, options); + } + function byNameContains(searchTerm, options) { + search('nameContains', 'string', searchTerm, options); + } + function byType(searchTerm, options) { + search('type', 'function', searchTerm, options); + } + function byValue(searchTerm, options) { + search('value', null, searchTerm, options); + } + function byValueCoerced(searchTerm, options) { + search('valueCoerced', null, searchTerm, options); + } + function custom(fn, options) { + traverse(fn, null, options); + } + // ========================================== + // Event logging + // ========================================== + var ALL = 'all'; + //no filter + //log nothing by default + var logFilter = { + eventNames: [], + actions: [] + }; + function filterEventLogsByAction() { + var actions = [].slice.call(arguments); + logFilter.eventNames.length || (logFilter.eventNames = ALL); + logFilter.actions = actions.length ? actions : ALL; + saveLogFilter(); + } + function filterEventLogsByName() { + var eventNames = [].slice.call(arguments); + logFilter.actions.length || (logFilter.actions = ALL); + logFilter.eventNames = eventNames.length ? eventNames : ALL; + saveLogFilter(); + } + function hideAllEventLogs() { + logFilter.actions = []; + logFilter.eventNames = []; + saveLogFilter(); + } + function showAllEventLogs() { + logFilter.actions = ALL; + logFilter.eventNames = ALL; + saveLogFilter(); + } + function saveLogFilter() { + try { + if (window.localStorage) { + localStorage.setItem('logFilter_eventNames', logFilter.eventNames); + localStorage.setItem('logFilter_actions', logFilter.actions); + } + } catch (ignored) { + } + ; + } + function retrieveLogFilter() { + var eventNames, actions; + try { + eventNames = window.localStorage && localStorage.getItem('logFilter_eventNames'); + actions = window.localStorage && localStorage.getItem('logFilter_actions'); + } catch (ignored) { + return; + } + eventNames && (logFilter.eventNames = eventNames); + actions && (logFilter.actions = actions); + // reconstitute arrays in place + Object.keys(logFilter).forEach(function (k) { + var thisProp = logFilter[k]; + if (typeof thisProp == 'string' && thisProp !== ALL) { + logFilter[k] = thisProp ? thisProp.split(',') : []; + } + }); + } + return { + enable: function (enable) { + this.enabled = !!enable; + if (enable && window.console) { + console.info('Booting in DEBUG mode'); + console.info('You can configure event logging with DEBUG.events.logAll()/logNone()/logByName()/logByAction()'); + } + retrieveLogFilter(); + window.DEBUG = this; + }, + find: { + byName: byName, + byNameContains: byNameContains, + byType: byType, + byValue: byValue, + byValueCoerced: byValueCoerced, + custom: custom + }, + events: { + logFilter: logFilter, + logByAction: filterEventLogsByAction, + logByName: filterEventLogsByName, + logAll: showAllEventLogs, + logNone: hideAllEventLogs + } + }; +}); +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/compose', [ + './utils', + './debug' +], function (utils, debug) { + 'use strict'; + //enumerables are shims - getOwnPropertyDescriptor shim doesn't work + var canWriteProtect = debug.enabled && !utils.isEnumerable(Object, 'getOwnPropertyDescriptor'); + //whitelist of unlockable property names + var dontLock = ['mixedIn']; + if (canWriteProtect) { + //IE8 getOwnPropertyDescriptor is built-in but throws exeption on non DOM objects + try { + Object.getOwnPropertyDescriptor(Object, 'keys'); + } catch (e) { + canWriteProtect = false; + } + } + function setPropertyWritability(obj, isWritable) { + if (!canWriteProtect) { + return; + } + var props = Object.create(null); + Object.keys(obj).forEach(function (key) { + if (dontLock.indexOf(key) < 0) { + var desc = Object.getOwnPropertyDescriptor(obj, key); + desc.writable = isWritable; + props[key] = desc; + } + }); + Object.defineProperties(obj, props); + } + function unlockProperty(obj, prop, op) { + var writable; + if (!canWriteProtect || !obj.hasOwnProperty(prop)) { + op.call(obj); + return; + } + writable = Object.getOwnPropertyDescriptor(obj, prop).writable; + Object.defineProperty(obj, prop, { writable: true }); + op.call(obj); + Object.defineProperty(obj, prop, { writable: writable }); + } + function mixin(base, mixins) { + base.mixedIn = base.hasOwnProperty('mixedIn') ? base.mixedIn : []; + for (var i = 0; i < mixins.length; i++) { + if (base.mixedIn.indexOf(mixins[i]) == -1) { + setPropertyWritability(base, false); + mixins[i].call(base); + base.mixedIn.push(mixins[i]); + } + } + setPropertyWritability(base, true); + } + return { + mixin: mixin, + unlockProperty: unlockProperty + }; +}); +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/advice', ['./compose'], function (compose) { + 'use strict'; + var advice = { + around: function (base, wrapped) { + return function composedAround() { + // unpacking arguments by hand benchmarked faster + var i = 0, l = arguments.length, args = new Array(l + 1); + args[0] = base.bind(this); + for (; i < l; i++) + args[i + 1] = arguments[i]; + return wrapped.apply(this, args); + }; + }, + before: function (base, before) { + var beforeFn = typeof before == 'function' ? before : before.obj[before.fnName]; + return function composedBefore() { + beforeFn.apply(this, arguments); + return base.apply(this, arguments); + }; + }, + after: function (base, after) { + var afterFn = typeof after == 'function' ? after : after.obj[after.fnName]; + return function composedAfter() { + var res = (base.unbound || base).apply(this, arguments); + afterFn.apply(this, arguments); + return res; + }; + }, + withAdvice: function () { + [ + 'before', + 'after', + 'around' + ].forEach(function (m) { + this[m] = function (method, fn) { + compose.unlockProperty(this, method, function () { + if (typeof this[method] == 'function') { + this[method] = advice[m](this[method], fn); + } else { + this[method] = fn; + } + return this[method]; + }); + }; + }, this); + } + }; + return advice; +}); +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/registry', [], function () { + 'use strict'; + function parseEventArgs(instance, args) { + var element, type, callback; + var end = args.length; + if (typeof args[end - 1] === 'function') { + end -= 1; + callback = args[end]; + } + if (typeof args[end - 1] === 'object') { + end -= 1; + } + if (end == 2) { + element = args[0]; + type = args[1]; + } else { + element = instance.node; + type = args[0]; + } + return { + element: element, + type: type, + callback: callback + }; + } + function matchEvent(a, b) { + return a.element == b.element && a.type == b.type && (b.callback == null || a.callback == b.callback); + } + function Registry() { + var registry = this; + (this.reset = function () { + this.components = []; + this.allInstances = {}; + this.events = []; + }).call(this); + function ComponentInfo(component) { + this.component = component; + this.attachedTo = []; + this.instances = {}; + this.addInstance = function (instance) { + var instanceInfo = new InstanceInfo(instance); + this.instances[instance.identity] = instanceInfo; + this.attachedTo.push(instance.node); + return instanceInfo; + }; + this.removeInstance = function (instance) { + delete this.instances[instance.identity]; + var indexOfNode = this.attachedTo.indexOf(instance.node); + indexOfNode > -1 && this.attachedTo.splice(indexOfNode, 1); + if (!Object.keys(this.instances).length) { + //if I hold no more instances remove me from registry + registry.removeComponentInfo(this); + } + }; + this.isAttachedTo = function (node) { + return this.attachedTo.indexOf(node) > -1; + }; + } + function InstanceInfo(instance) { + this.instance = instance; + this.events = []; + this.addBind = function (event) { + this.events.push(event); + registry.events.push(event); + }; + this.removeBind = function (event) { + for (var i = 0, e; e = this.events[i]; i++) { + if (matchEvent(e, event)) { + this.events.splice(i, 1); + } + } + }; + } + this.addInstance = function (instance) { + var component = this.findComponentInfo(instance); + if (!component) { + component = new ComponentInfo(instance.constructor); + this.components.push(component); + } + var inst = component.addInstance(instance); + this.allInstances[instance.identity] = inst; + return component; + }; + this.removeInstance = function (instance) { + var index, instInfo = this.findInstanceInfo(instance); + //remove from component info + var componentInfo = this.findComponentInfo(instance); + componentInfo && componentInfo.removeInstance(instance); + //remove from registry + delete this.allInstances[instance.identity]; + }; + this.removeComponentInfo = function (componentInfo) { + var index = this.components.indexOf(componentInfo); + index > -1 && this.components.splice(index, 1); + }; + this.findComponentInfo = function (which) { + var component = which.attachTo ? which : which.constructor; + for (var i = 0, c; c = this.components[i]; i++) { + if (c.component === component) { + return c; + } + } + return null; + }; + this.findInstanceInfo = function (instance) { + return this.allInstances[instance.identity] || null; + }; + this.getBoundEventNames = function (instance) { + return this.findInstanceInfo(instance).events.map(function (ev) { + return ev.type; + }); + }; + this.findInstanceInfoByNode = function (node) { + var result = []; + Object.keys(this.allInstances).forEach(function (k) { + var thisInstanceInfo = this.allInstances[k]; + if (thisInstanceInfo.instance.node === node) { + result.push(thisInstanceInfo); + } + }, this); + return result; + }; + this.on = function (componentOn) { + var instance = registry.findInstanceInfo(this), boundCallback; + // unpacking arguments by hand benchmarked faster + var l = arguments.length, i = 1; + var otherArgs = new Array(l - 1); + for (; i < l; i++) + otherArgs[i - 1] = arguments[i]; + if (instance) { + boundCallback = componentOn.apply(null, otherArgs); + if (boundCallback) { + otherArgs[otherArgs.length - 1] = boundCallback; + } + var event = parseEventArgs(this, otherArgs); + instance.addBind(event); + } + }; + this.off = function () { + var event = parseEventArgs(this, arguments), instance = registry.findInstanceInfo(this); + if (instance) { + instance.removeBind(event); + } + //remove from global event registry + for (var i = 0, e; e = registry.events[i]; i++) { + if (matchEvent(e, event)) { + registry.events.splice(i, 1); + } + } + }; + // debug tools may want to add advice to trigger + registry.trigger = function () { + }; + this.teardown = function () { + registry.removeInstance(this); + }; + this.withRegistration = function () { + this.after('initialize', function () { + registry.addInstance(this); + }); + this.around('on', registry.on); + this.after('off', registry.off); + //debug tools may want to add advice to trigger + window.DEBUG && DEBUG.enabled && this.after('trigger', registry.trigger); + this.after('teardown', { + obj: registry, + fnName: 'teardown' + }); + }; + } + return new Registry(); +}); +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/base', [ + './utils', + './registry', + './debug' +], function (utils, registry, debug) { + 'use strict'; + // common mixin allocates basic functionality - used by all component prototypes + // callback context is bound to component + var componentId = 0; + function teardownInstance(instanceInfo) { + instanceInfo.events.slice().forEach(function (event) { + var args = [event.type]; + event.element && args.unshift(event.element); + typeof event.callback == 'function' && args.push(event.callback); + this.off.apply(this, args); + }, instanceInfo.instance); + } + function checkSerializable(type, data) { + try { + window.postMessage(data, '*'); + } catch (e) { + console.log('unserializable data for event', type, ':', data); + throw new Error([ + 'The event', + type, + 'on component', + this.toString(), + 'was triggered with non-serializable data' + ].join(' ')); + } + } + function proxyEventTo(targetEvent) { + return function (e, data) { + $(e.target).trigger(targetEvent, data); + }; + } + function withBase() { + // delegate trigger, bind and unbind to an element + // if $element not supplied, use component's node + // other arguments are passed on + // event can be either a string specifying the type + // of the event, or a hash specifying both the type + // and a default function to be called. + this.trigger = function () { + var $element, type, data, event, defaultFn; + var lastIndex = arguments.length - 1, lastArg = arguments[lastIndex]; + if (typeof lastArg != 'string' && !(lastArg && lastArg.defaultBehavior)) { + lastIndex--; + data = lastArg; + } + if (lastIndex == 1) { + $element = $(arguments[0]); + event = arguments[1]; + } else { + $element = this.$node; + event = arguments[0]; + } + if (event.defaultBehavior) { + defaultFn = event.defaultBehavior; + event = $.Event(event.type); + } + type = event.type || event; + if (debug.enabled && window.postMessage) { + checkSerializable.call(this, type, data); + } + if (typeof this.attr.eventData === 'object') { + data = $.extend(true, {}, this.attr.eventData, data); + } + $element.trigger(event || type, data); + if (defaultFn && !event.isDefaultPrevented()) { + (this[defaultFn] || defaultFn).call(this); + } + return $element; + }; + this.on = function () { + var $element, type, callback, originalCb; + var lastIndex = arguments.length - 1, origin = arguments[lastIndex]; + if (typeof origin == 'object') { + //delegate callback + originalCb = utils.delegate(this.resolveDelegateRules(origin)); + } else if (typeof origin == 'string') { + originalCb = proxyEventTo(origin); + } else { + originalCb = origin; + } + if (lastIndex == 2) { + $element = $(arguments[0]); + type = arguments[1]; + } else { + $element = this.$node; + type = arguments[0]; + } + if (typeof originalCb != 'function' && typeof originalCb != 'object') { + throw new Error('Unable to bind to "' + type + '" because the given callback is not a function or an object'); + } + callback = originalCb.bind(this); + callback.target = originalCb; + callback.context = this; + $element.on(type, callback); + // store every bound version of the callback + originalCb.bound || (originalCb.bound = []); + originalCb.bound.push(callback); + return callback; + }; + this.off = function () { + var $element, type, callback; + var lastIndex = arguments.length - 1; + if (typeof arguments[lastIndex] == 'function') { + callback = arguments[lastIndex]; + lastIndex -= 1; + } + if (lastIndex == 1) { + $element = $(arguments[0]); + type = arguments[1]; + } else { + $element = this.$node; + type = arguments[0]; + } + if (callback) { + //this callback may be the original function or a bound version + var boundFunctions = callback.target ? callback.target.bound : callback.bound || []; + //set callback to version bound against this instance + boundFunctions && boundFunctions.some(function (fn, i, arr) { + if (fn.context && this.identity == fn.context.identity) { + arr.splice(i, 1); + callback = fn; + return true; + } + }, this); + } + return $element.off(type, callback); + }; + this.resolveDelegateRules = function (ruleInfo) { + var rules = {}; + Object.keys(ruleInfo).forEach(function (r) { + if (!(r in this.attr)) { + throw new Error('Component "' + this.toString() + '" wants to listen on "' + r + '" but no such attribute was defined.'); + } + rules[this.attr[r]] = typeof ruleInfo[r] == 'string' ? proxyEventTo(ruleInfo[r]) : ruleInfo[r]; + }, this); + return rules; + }; + this.defaultAttrs = function (defaults) { + utils.push(this.defaults, defaults, true) || (this.defaults = defaults); + }; + this.select = function (attributeKey) { + return this.$node.find(this.attr[attributeKey]); + }; + this.initialize = function (node, attrs) { + attrs || (attrs = {}); + //only assign identity if there isn't one (initialize can be called multiple times) + this.identity || (this.identity = componentId++); + if (!node) { + throw new Error('Component needs a node'); + } + if (node.jquery) { + this.node = node[0]; + this.$node = node; + } else { + this.node = node; + this.$node = $(node); + } + // merge defaults with supplied options + // put options in attr.__proto__ to avoid merge overhead + var attr = Object.create(attrs); + for (var key in this.defaults) { + if (!attrs.hasOwnProperty(key)) { + attr[key] = this.defaults[key]; + } + } + this.attr = attr; + Object.keys(this.defaults || {}).forEach(function (key) { + if (this.defaults[key] === null && this.attr[key] === null) { + throw new Error('Required attribute "' + key + '" not specified in attachTo for component "' + this.toString() + '".'); + } + }, this); + return this; + }; + this.teardown = function () { + teardownInstance(registry.findInstanceInfo(this)); + }; + } + return withBase; +}); +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/logger', ['./utils'], function (utils) { + 'use strict'; + var actionSymbols = { + on: '<-', + trigger: '->', + off: 'x ' + }; + function elemToString(elem) { + var tagStr = elem.tagName ? elem.tagName.toLowerCase() : elem.toString(); + var classStr = elem.className ? '.' + elem.className : ''; + var result = tagStr + classStr; + return elem.tagName ? [ + '\'', + '\'' + ].join(result) : result; + } + function log(action, component, eventArgs) { + if (!window.DEBUG || !window.DEBUG.enabled) + return; + var name, eventType, elem, fn, payload, logFilter, toRegExp, actionLoggable, nameLoggable, info; + if (typeof eventArgs[eventArgs.length - 1] == 'function') { + fn = eventArgs.pop(); + fn = fn.unbound || fn; // use unbound version if any (better info) + } + if (eventArgs.length == 1) { + elem = component.$node[0]; + eventType = eventArgs[0]; + } else if (eventArgs.length == 2 && typeof eventArgs[1] == 'object' && !eventArgs[1].type) { + //2 args, first arg is not elem + elem = component.$node[0]; + eventType = eventArgs[0]; + if (action == 'trigger') { + payload = eventArgs[1]; + } + } else { + //2+ args, first arg is elem + elem = eventArgs[0]; + eventType = eventArgs[1]; + if (action == 'trigger') { + payload = eventArgs[2]; + } + } + name = typeof eventType == 'object' ? eventType.type : eventType; + logFilter = DEBUG.events.logFilter; + // no regex for you, actions... + actionLoggable = logFilter.actions == 'all' || logFilter.actions.indexOf(action) > -1; + // event name filter allow wildcards or regex... + toRegExp = function (expr) { + return expr.test ? expr : new RegExp('^' + expr.replace(/\*/g, '.*') + '$'); + }; + nameLoggable = logFilter.eventNames == 'all' || logFilter.eventNames.some(function (e) { + return toRegExp(e).test(name); + }); + if (actionLoggable && nameLoggable) { + info = [ + actionSymbols[action], + action, + '[' + name + ']' + ]; + payload && info.push(payload); + info.push(elemToString(elem)); + info.push(component.constructor.describe.split(' ').slice(0, 3).join(' ')); + console.groupCollapsed && action == 'trigger' && console.groupCollapsed(action, name); + console.info.apply(console, info); + } + } + function withLogging() { + this.before('trigger', function () { + log('trigger', this, utils.toArray(arguments)); + }); + if (console.groupCollapsed) { + this.after('trigger', function () { + console.groupEnd(); + }); + } + this.before('on', function () { + log('on', this, utils.toArray(arguments)); + }); + this.before('off', function () { + log('off', this, utils.toArray(arguments)); + }); + } + return withLogging; +}); +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/component', [ + './advice', + './utils', + './compose', + './base', + './registry', + './logger', + './debug' +], function (advice, utils, compose, withBase, registry, withLogging, debug) { + 'use strict'; + var functionNameRegEx = /function (.*?)\s?\(/; + // teardown for all instances of this constructor + function teardownAll() { + var componentInfo = registry.findComponentInfo(this); + componentInfo && Object.keys(componentInfo.instances).forEach(function (k) { + var info = componentInfo.instances[k]; + // It's possible that a previous teardown caused another component to teardown, + // so we can't assume that the instances object is as it was. + if (info && info.instance) { + info.instance.teardown(); + } + }); + } + function checkSerializable(type, data) { + try { + window.postMessage(data, '*'); + } catch (e) { + console.log('unserializable data for event', type, ':', data); + throw new Error([ + 'The event', + type, + 'on component', + this.toString(), + 'was triggered with non-serializable data' + ].join(' ')); + } + } + function attachTo(selector) { + // unpacking arguments by hand benchmarked faster + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) + args[i - 1] = arguments[i]; + if (!selector) { + throw new Error('Component needs to be attachTo\'d a jQuery object, native node or selector string'); + } + var options = utils.merge.apply(utils, args); + var componentInfo = registry.findComponentInfo(this); + $(selector).each(function (i, node) { + if (componentInfo && componentInfo.isAttachedTo(node)) { + // already attached + return; + } + new this().initialize(node, options); + }.bind(this)); + } + function prettyPrintMixins() { + //could be called from constructor or constructor.prototype + var mixedIn = this.mixedIn || this.prototype.mixedIn || []; + return mixedIn.map(function (mixin) { + if (mixin.name == null) { + // function name property not supported by this browser, use regex + var m = mixin.toString().match(functionNameRegEx); + return m && m[1] ? m[1] : ''; + } else { + return mixin.name != 'withBase' ? mixin.name : ''; + } + }).filter(Boolean).join(', '); + } + ; + // define the constructor for a custom component type + // takes an unlimited number of mixin functions as arguments + // typical api call with 3 mixins: define(timeline, withTweetCapability, withScrollCapability); + function define() { + // unpacking arguments by hand benchmarked faster + var l = arguments.length; + var mixins = new Array(l); + for (var i = 0; i < l; i++) + mixins[i] = arguments[i]; + var Component = function () { + }; + Component.toString = Component.prototype.toString = prettyPrintMixins; + if (debug.enabled) { + Component.describe = Component.prototype.describe = Component.toString(); + } + // 'options' is optional hash to be merged with 'defaults' in the component definition + Component.attachTo = attachTo; + // enables extension of existing "base" Components + Component.mixin = function () { + var newComponent = define(); + //TODO: fix pretty print + var newPrototype = Object.create(Component.prototype); + newPrototype.mixedIn = [].concat(Component.prototype.mixedIn); + compose.mixin(newPrototype, arguments); + newComponent.prototype = newPrototype; + newComponent.prototype.constructor = newComponent; + return newComponent; + }; + Component.teardownAll = teardownAll; + // prepend common mixins to supplied list, then mixin all flavors + if (debug.enabled) { + mixins.unshift(withLogging); + } + mixins.unshift(withBase, advice.withAdvice, registry.withRegistration); + compose.mixin(Component.prototype, mixins); + return Component; + } + define.teardownAll = function () { + registry.components.slice().forEach(function (c) { + c.component.teardownAll(); + }); + registry.reset(); + }; + return define; +}); +// ========================================== +// Copyright 2013 Twitter, Inc +// Licensed under The MIT License +// http://opensource.org/licenses/MIT +// ========================================== +define('lib/index', [ + './advice', + './component', + './compose', + './logger', + './registry', + './utils' +], function (advice, component, compose, logger, registry, utils) { + 'use strict'; + return { + advice: advice, + component: component, + compose: compose, + logger: logger, + registry: registry, + utils: utils + }; +}); + + context.flight = require('lib/index'); +}(this));