Browse Source

remove flight

master
Stephanie Chung 12 years ago
parent
commit
42cfd17500
  1. 33
      js/libs/flight/.bower.json
  2. 19
      js/libs/flight/LICENSE
  3. 242
      js/libs/flight/README.md
  4. 22
      js/libs/flight/bower.json
  5. 69
      js/libs/flight/lib/advice.js
  6. 237
      js/libs/flight/lib/base.js
  7. 136
      js/libs/flight/lib/component.js
  8. 85
      js/libs/flight/lib/compose.js
  9. 165
      js/libs/flight/lib/debug.js
  10. 31
      js/libs/flight/lib/index.js
  11. 100
      js/libs/flight/lib/logger.js
  12. 228
      js/libs/flight/lib/registry.js
  13. 263
      js/libs/flight/lib/utils.js

33
js/libs/flight/.bower.json

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
{
"name": "flight",
"description": "Clientside component infrastructure",
"main": "lib/index.js",
"version": "1.1.4",
"ignore": [
"doc",
"tools",
"test",
".gitignore",
".travis.yml",
"CHANGELOG.md",
"CONTRIBUTING.md",
"Makefile",
"karma.conf.js",
"package.json"
],
"dependencies": {
"es5-shim": "2.0.0",
"jquery": ">=1.8.0"
},
"homepage": "https://github.com/flightjs/flight",
"_release": "1.1.4",
"_resolution": {
"type": "version",
"tag": "v1.1.4",
"commit": "5da831ba9026330b692ecf5668cad8832f1f19cd"
},
"_source": "git://github.com/flightjs/flight.git",
"_target": "~1.1.4",
"_originalSource": "flight",
"_direct": true
}

19
js/libs/flight/LICENSE

@ -1,19 +0,0 @@ @@ -1,19 +0,0 @@
Copyright (c) 2013-2014 Twitter, Inc and others
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.

242
js/libs/flight/README.md

@ -1,242 +0,0 @@ @@ -1,242 +0,0 @@
# Flight
[![Build Status](https://travis-ci.org/flightjs/flight.png?branch=master)](http://travis-ci.org/flightjs/flight)
[Flight](http://flightjs.github.io/) is a lightweight, component-based,
event-driven JavaScript framework that maps behavior to DOM nodes. It was
created at Twitter, and is used by the [twitter.com](https://twitter.com/) and
[TweetDeck](https://web.tweetdeck.com/) web applications.
* [Website](http://flightjs.github.io/)
* [API documentation](doc/README.md)
* [Flight example app](http://flightjs.github.io/example-app/) ([Source](https://github.com/flightjs/example-app))
* [Flight's Google Group](https://groups.google.com/forum/?fromgroups#!forum/twitter-flight)
* [Flight on Twitter](https://twitter.com/flight)
## Why Flight?
Flight is only ~5K minified and gzipped. It's built upon jQuery, and has
first-class support for Asynchronous Module Definition (AMD) and [Bower](http://bower.io/).
Flight components are highly portable and easily testable. This is because a
Flight component (and its API) is entirely decoupled from other components.
Flight components communicate only by triggering and subscribing to events.
Flight also includes a simple and safe
[mixin](https://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/)
infrastructure, allowing components to be easily extended with minimal
boilerplate.
## Development tools
Flight has supporting projects that provide everything you need to setup,
write, and test your application.
* [Flight generator](https://github.com/flightjs/generator-flight/)
Recommended. One-step to setup everything you need to work with Flight.
* [Flight package generator](https://github.com/flightjs/generator-flight-package/)
Recommended. One-step to setup everything you need to write and test a
standalone Flight component.
* [Jasmine Flight](https://github.com/flightjs/jasmine-flight/)
Extensions for the Jasmine test framework.
* [Mocha Flight](https://github.com/flightjs/mocha-flight/)
Extensions for the Mocha test framework.
## Finding and writing standalone components
You can browse all the [Flight components](http://flight-components.jit.su)
available at this time. They can also be found by searching the Bower registry:
```
bower search flight
```
The easiest way to write a standalone Flight component is to use the [Flight
package generator](https://github.com/flightjs/generator-flight-package/):
```
yo flight-package foo
```
## Installation
If you prefer not to use the Flight generators, it's highly recommended that
you install Flight as an AMD package (including all the correct dependencies).
This is best done with [Bower](http://bower.io/), a package manager for the web.
```
npm install -g bower
bower install --save flight
```
You will have to reference Flight's installed dependencies –
[ES5-shim](https://github.com/kriskowal/es5-shim) and
[jQuery](http://jquery.com) – and use an AMD module loader like
[Require.js](http://requirejs.org/) or
[Loadrunner](https://github.com/danwrong/loadrunner).
```html
<script src="bower_components/es5-shim/es5-shim.js"></script>
<script src="bower_components/es5-shim/es5-sham.js"></script>
<script src="bower_components/jquery/dist/jquery.js"></script>
<script data-main="main.js" src="bower_components/requirejs/require.js"></script>
...
```
## Standalone version
Alternatively, you can manually install the [standalone
version](http://flightjs.github.io/release/latest/flight.js) of Flight, also
available on [cdnjs](http://cdnjs.com/). It exposes all of its modules as
properties of a global variable, `flight`:
```html
...
<script src="flight.js"></script>
<script>
var MyComponent = flight.component(function() {
//...
});
</script>
```
N.B. You will also need to manually install the correct versions of Flight's
dependencies: ES5 Shim and jQuery.
## Browser Support
Chrome, Firefox, Safari, Opera, IE 7+.
## Quick Overview
Here's a brief introduction to Flight's key concepts and syntax. Read the [API
documentation](doc) for a comprehensive overview.
### Example
A simple example of how to write and use a Flight component.
```js
define(function (require) {
var defineComponent = require('flight/lib/component');
// define the component
return defineComponent(inbox);
function inbox() {
// define custom functions here
this.doSomething = function() {
//...
}
this.doSomethingElse = function() {
//...
}
// now initialize the component
this.after('initialize', function() {
this.on('click', this.doSomething);
this.on('mouseover', this.doSomethingElse);
});
}
});
```
```js
/* attach an inbox component to a node with id 'inbox' */
define(function (require) {
var Inbox = require('inbox');
Inbox.attachTo('#inbox', {
'nextPageSelector': '#nextPage',
'previousPageSelector': '#previousPage',
});
});
```
### Components ([API](doc/component_api.md))
- A Component is nothing more than a constructor with properties mixed into its prototype.
- Every Component comes with a set of basic functionality such as event handling and component registration.
(see [Base API](doc/base_api.md))
- Additionally, each Component definition mixes in a set of custom properties which describe its behavior.
- When a component is attached to a DOM node, a new instance of that component is created. Each component
instance references the DOM node via its `node` property.
- Component instances cannot be referenced directly; they communicate with other components via events.
### Interacting with the DOM
Once attached, component instances have direct access to their node object via the `node` property. (There's
also a jQuery version of the node available via the `$node` property.)
### Events in Flight
Events are how Flight components interact. The Component prototype supplies methods for triggering events as
well as for subscribing to and unsubscribing from events. These Component event methods are actually just convenient
wrappers around regular event methods on DOM nodes.
### Mixins ([API](doc/mixin_api.md))
- In Flight, a mixin is a function which assigns properties to a target object (represented by the `this`
keyword).
- A typical mixin defines a set of functionality that will be useful to more than one component.
- One mixin can be applied to any number of [Component](#components) definitions.
- One Component definition can have any number of mixins applied to it.
- Each Component defines a [*core*](#core_mixin) mixin within its own module.
- A mixin can itself have mixins applied to it.
### Advice ([API](doc/advice_api.md))
In Flight, advice is a mixin (`'lib/advice.js'`) that defines `before`, `after` and `around` methods.
These can be used to modify existing functions by adding custom code. All Components have advice mixed in to
their prototype so that mixins can augment existing functions without requiring knowledge
of the original implementation. Moreover, since Component's are seeded with an empty `initialize` method,
Component definitions will typically use `after` to define custom `initialize` behavior.
### Debugging ([API](doc/debug_api.md))
Flight ships with a debug module which can help you trace the sequence of event triggering and binding. By default
console logging is turned off, but you can you can log `trigger`, `on` and `off` events by means of the following console
commands.
## Authors
+ [@angus-c](http://github.com/angus-c)
+ [@danwrong](http://github.com/danwrong)
+ [@kpk](http://github.com/kennethkufluk)
Thanks for assistance and contributions:
[@sayrer](https://github.com/sayrer),
[@shinypb](https://github.com/shinypb),
[@kloots](https://github.com/kloots),
[@marcelduran](https://github.com/marcelduran),
[@tbrd](https://github.com/tbrd),
[@necolas](https://github.com/necolas),
[@fat](https://github.com/fat),
[@mkuklis](https://github.com/mkuklis),
[@jrburke](https://github.com/jrburke),
[@garann](https://github.com/garann),
[@WebReflection](https://github.com/WebReflection),
[@coldhead](https://github.com/coldhead),
[@paulirish](https://github.com/paulirish),
[@nimbupani](https://github.com/nimbupani),
[@mootcycle](https://github.com/mootcycle).
Special thanks to the rest of the Twitter web team for their abundant
contributions and feedback.
## License
Copyright 2013 Twitter, Inc and other contributors.
Licensed under the MIT License

22
js/libs/flight/bower.json

@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
{
"name": "flight",
"description": "Clientside component infrastructure",
"main": "lib/index.js",
"version": "1.1.4",
"ignore": [
"doc",
"tools",
"test",
".gitignore",
".travis.yml",
"CHANGELOG.md",
"CONTRIBUTING.md",
"Makefile",
"karma.conf.js",
"package.json"
],
"dependencies": {
"es5-shim": "2.0.0",
"jquery": ">=1.8.0"
}
}

69
js/libs/flight/lib/advice.js

@ -1,69 +0,0 @@ @@ -1,69 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[
'./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;
};
},
// a mixin that allows other mixins to augment existing functions by adding additional
// code before, after or around.
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;
}
);

237
js/libs/flight/lib/base.js

@ -1,237 +0,0 @@ @@ -1,237 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[
'./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;
}
);

136
js/libs/flight/lib/component.js

@ -1,136 +0,0 @@ @@ -1,136 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[
'./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/*, options args */) {
// 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(/*mixins*/) {
// 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;
}
);

85
js/libs/flight/lib/compose.js

@ -1,85 +0,0 @@ @@ -1,85 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[
'./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
};
}
);

165
js/libs/flight/lib/debug.js

@ -1,165 +0,0 @@ @@ -1,165 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[],
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(/*actions*/) {
var actions = [].slice.call(arguments);
logFilter.eventNames.length || (logFilter.eventNames = ALL);
logFilter.actions = actions.length ? actions : ALL;
saveLogFilter();
}
function filterEventLogsByName(/*eventNames*/) {
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,
// Accepts any number of action args
// e.g. DEBUG.events.logByAction("on", "off")
logByAction: filterEventLogsByAction,
// Accepts any number of event name args (inc. regex or wildcards)
// e.g. DEBUG.events.logByName(/ui.*/, "*Thread*");
logByName: filterEventLogsByName,
logAll: showAllEventLogs,
logNone: hideAllEventLogs
}
};
}
);

31
js/libs/flight/lib/index.js

@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[
'./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
};
}
);

100
js/libs/flight/lib/logger.js

@ -1,100 +0,0 @@ @@ -1,100 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[
'./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;
}
);

228
js/libs/flight/lib/registry.js

@ -1,228 +0,0 @@ @@ -1,228 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[],
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(/*el, type, callback*/) {
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;
}
);

263
js/libs/flight/lib/utils.js

@ -1,263 +0,0 @@ @@ -1,263 +0,0 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[],
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);
},
// returns new object representing multiple objects merged together
// optional final argument is boolean which specifies if merge is recursive
// original objects are unmodified
//
// usage:
// var base = {a:2, b:6};
// var extra = {b:3, c:4};
// merge(base, extra); //{a:2, b:3, c:4}
// base; //{a:2, b:6}
//
// var base = {a:2, b:6};
// var extra = {b:3, c:4};
// var extraExtra = {a:4, d:9};
// merge(base, extra, extraExtra); //{a:4, b:3, c:4. d: 9}
// base; //{a:2, b:6}
//
// var base = {a:2, b:{bb:4, cc:5}};
// var extra = {a:4, b:{cc:7, dd:1}};
// merge(base, extra, true); //{a:4, b:{bb:4, cc:7, dd:1}}
// base; //{a:2, b:6}
merge: function(/*obj1, obj2,....deepCopy*/) {
// 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);
},
// updates base in place by copying properties of extra to it
// optionally clobber protected
// usage:
// var base = {a:2, b:6};
// var extra = {c:4};
// push(base, extra); //{a:2, b:6, c:4}
// base; //{a:2, b:6, c:4}
//
// var base = {a:2, b:6};
// var extra = {b: 4 c:4};
// push(base, extra, true); //Error ("utils.push attempted to overwrite 'b' while running in protected mode")
// base; //{a:2, b:6}
//
// objects with the same key will merge recursively when protect is false
// eg:
// var base = {a:16, b:{bb:4, cc:10}};
// var extra = {b:{cc:25, dd:19}, c:5};
// push(base, extra); //{a:16, {bb:4, cc:25, dd:19}, c:5}
//
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;
},
// build a function from other function(s)
// utils.compose(a,b,c) -> a(b(c()));
// implementation lifted from underscore.js (c) 2009-2012 Jeremy Ashkenas
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];
};
},
// Can only unique arrays of homogeneous primitives, e.g. an array of only strings, an array of only booleans, or an array of only numerics
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);
};
},
// ensures that a function will only be called once.
// usage:
// will only create the application once
// var initialize = utils.once(createApplication)
// initialize();
// initialize();
//
// will only delete a record once
// var myHanlder = function () {
// $.ajax({type: 'DELETE', url: 'someurl.com', data: {id: 1}});
// };
// this.on('click', utils.once(myHandler));
//
once: function(func) {
var ran, result;
return function() {
if (ran) {
return result;
}
ran = true;
result = func.apply(this, arguments);
return result;
};
}
};
return utils;
}
);
Loading…
Cancel
Save