twitter-flight-rails 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +50 -0
- data/Rakefile +1 -0
- data/lib/twitter-flight-rails/version.rb +7 -0
- data/lib/twitter-flight-rails.rb +10 -0
- data/twitter-flight-rails.gemspec +25 -0
- data/vendor/assets/javascripts/twitter/flight/advice.js +75 -0
- data/vendor/assets/javascripts/twitter/flight/component.js +262 -0
- data/vendor/assets/javascripts/twitter/flight/compose.js +86 -0
- data/vendor/assets/javascripts/twitter/flight/index.js +30 -0
- data/vendor/assets/javascripts/twitter/flight/logger.js +93 -0
- data/vendor/assets/javascripts/twitter/flight/registry.js +234 -0
- data/vendor/assets/javascripts/twitter/flight/utils.js +228 -0
- data/vendor/assets/javascripts/twitter/flight.js +1 -0
- metadata +126 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Yousef Ourabi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Twitter Flight framework for Rails
|
2
|
+
|
3
|
+
This asset gem packages the [twitter flight](https://github.com/twitter/flight/) framework for the Rails asset pipeline.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'twitter-flight-rails'
|
10
|
+
|
11
|
+
or
|
12
|
+
|
13
|
+
gem 'twitter-flight-rails', :git => "git@github.com:yourabi/twitter-flight-rails.git"
|
14
|
+
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install twitter-flight-rails
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
To start using the twitter flight fraemwork in your rails app enable it via the asset pipeline (app/assets/javascripts/application.js).
|
27
|
+
|
28
|
+
Add the folllwing:
|
29
|
+
|
30
|
+
```js
|
31
|
+
|
32
|
+
//= require twitter/flight
|
33
|
+
|
34
|
+
```
|
35
|
+
|
36
|
+
Currently this version tracks flight master [commit e07b90c78d](https://github.com/twitter/flight/commit/e07b90c78d416549455354cbcd3e7f8a001c4fdf) and may support release tags in the future.
|
37
|
+
|
38
|
+
## Dependencies
|
39
|
+
|
40
|
+
Flight uses [ES5-shim](https://github.com/kriskowal/es5-shim) to polyfill ES5 support for older browsers and [JQuery](http://jquery.com) for DOM manipulation API.
|
41
|
+
|
42
|
+
Note: as of version 0.0.2 the es5-shim dependency is not handled.
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
1. Fork it
|
47
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
48
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
49
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
50
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'twitter-flight-rails/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "twitter-flight-rails"
|
8
|
+
gem.version = Twitter::Flight::Rails::VERSION
|
9
|
+
gem.authors = ["Yousef Ourabi"]
|
10
|
+
gem.email = ["yourabi@gmail.com"]
|
11
|
+
gem.description = %q{twitter-flight-rails flight framework for Rails asset pipeline}
|
12
|
+
gem.summary = %q{twitter-flight-rails packages the flight framework into an asset gem}
|
13
|
+
gem.homepage = "https://github.com/yourabi/twitter-flight-rails"
|
14
|
+
|
15
|
+
gem.add_dependency 'railties', '>= 3.1'
|
16
|
+
gem.add_dependency 'actionpack', '>= 3.1'
|
17
|
+
gem.add_dependency 'jquery-rails'
|
18
|
+
|
19
|
+
gem.add_development_dependency 'rails', '>= 3.1'
|
20
|
+
|
21
|
+
gem.files = `git ls-files`.split($/)
|
22
|
+
# gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
23
|
+
# gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
24
|
+
gem.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
// ==========================================
|
2
|
+
// Copyright 2013 Twitter, Inc
|
3
|
+
// Licensed under The MIT License
|
4
|
+
// http://opensource.org/licenses/MIT
|
5
|
+
// ==========================================
|
6
|
+
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
define(
|
10
|
+
|
11
|
+
[
|
12
|
+
'./utils',
|
13
|
+
'./compose'
|
14
|
+
],
|
15
|
+
|
16
|
+
function (util, compose) {
|
17
|
+
|
18
|
+
var advice = {
|
19
|
+
|
20
|
+
around: function(base, wrapped) {
|
21
|
+
return function() {
|
22
|
+
var args = util.toArray(arguments);
|
23
|
+
return wrapped.apply(this, [base.bind(this)].concat(args));
|
24
|
+
}
|
25
|
+
},
|
26
|
+
|
27
|
+
before: function(base, before) {
|
28
|
+
return this.around(base, function() {
|
29
|
+
var args = util.toArray(arguments),
|
30
|
+
orig = args.shift(),
|
31
|
+
beforeFn;
|
32
|
+
|
33
|
+
beforeFn = (typeof before == 'function') ? before : before.obj[before.fnName];
|
34
|
+
beforeFn.apply(this, args);
|
35
|
+
return (orig).apply(this, args);
|
36
|
+
});
|
37
|
+
},
|
38
|
+
|
39
|
+
after: function(base, after) {
|
40
|
+
return this.around(base, function() {
|
41
|
+
var args = util.toArray(arguments),
|
42
|
+
orig = args.shift(),
|
43
|
+
afterFn;
|
44
|
+
|
45
|
+
// this is a separate statement for debugging purposes.
|
46
|
+
var res = (orig.unbound || orig).apply(this, args);
|
47
|
+
|
48
|
+
afterFn = (typeof after == 'function') ? after : after.obj[after.fnName];
|
49
|
+
afterFn.apply(this, args);
|
50
|
+
return res;
|
51
|
+
});
|
52
|
+
},
|
53
|
+
|
54
|
+
// a mixin that allows other mixins to augment existing functions by adding additional
|
55
|
+
// code before, after or around.
|
56
|
+
withAdvice: function() {
|
57
|
+
['before', 'after', 'around'].forEach(function(m) {
|
58
|
+
this[m] = function(method, fn) {
|
59
|
+
|
60
|
+
compose.unlockProperty(this, method, function() {
|
61
|
+
if (typeof this[method] == 'function') {
|
62
|
+
return this[method] = advice[m](this[method], fn);
|
63
|
+
} else {
|
64
|
+
return this[method] = fn;
|
65
|
+
}
|
66
|
+
});
|
67
|
+
|
68
|
+
};
|
69
|
+
}, this);
|
70
|
+
}
|
71
|
+
};
|
72
|
+
|
73
|
+
return advice;
|
74
|
+
}
|
75
|
+
);
|
@@ -0,0 +1,262 @@
|
|
1
|
+
// ==========================================
|
2
|
+
// Copyright 2013 Twitter, Inc
|
3
|
+
// Licensed under The MIT License
|
4
|
+
// http://opensource.org/licenses/MIT
|
5
|
+
// ==========================================
|
6
|
+
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
define(
|
10
|
+
|
11
|
+
[
|
12
|
+
'./advice',
|
13
|
+
'./utils',
|
14
|
+
'./compose',
|
15
|
+
'./registry'
|
16
|
+
],
|
17
|
+
|
18
|
+
function(advice, utils, compose, registry) {
|
19
|
+
|
20
|
+
function teardownInstance(instanceInfo){
|
21
|
+
instanceInfo.events.slice().forEach(function(event) {
|
22
|
+
var args = [event.type];
|
23
|
+
|
24
|
+
event.element && args.unshift(event.element);
|
25
|
+
(typeof event.callback == 'function') && args.push(event.callback);
|
26
|
+
|
27
|
+
this.off.apply(this, args);
|
28
|
+
}, instanceInfo.instance);
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
function teardown() {
|
33
|
+
this.trigger("componentTearDown");
|
34
|
+
teardownInstance(registry.findInstanceInfo(this));
|
35
|
+
}
|
36
|
+
|
37
|
+
//teardown for all instances of this constructor
|
38
|
+
function teardownAll() {
|
39
|
+
var componentInfo = registry.findComponentInfo(this);
|
40
|
+
|
41
|
+
componentInfo && componentInfo.instances.slice().forEach(function(info) {
|
42
|
+
info.instance.teardown();
|
43
|
+
});
|
44
|
+
}
|
45
|
+
|
46
|
+
//common mixin allocates basic functionality - used by all component prototypes
|
47
|
+
//callback context is bound to component
|
48
|
+
function withBaseComponent() {
|
49
|
+
|
50
|
+
// delegate trigger, bind and unbind to an element
|
51
|
+
// if $element not supplied, use component's node
|
52
|
+
// other arguments are passed on
|
53
|
+
this.trigger = function() {
|
54
|
+
var $element, type, data;
|
55
|
+
var args = utils.toArray(arguments);
|
56
|
+
|
57
|
+
if (typeof args[args.length - 1] != "string") {
|
58
|
+
data = args.pop();
|
59
|
+
}
|
60
|
+
|
61
|
+
$element = (args.length == 2) ? $(args.shift()) : this.$node;
|
62
|
+
type = args[0];
|
63
|
+
|
64
|
+
if (window.DEBUG && window.postMessage) {
|
65
|
+
try {
|
66
|
+
window.postMessage(data, '*');
|
67
|
+
} catch(e) {
|
68
|
+
console.log('unserializable data for event',type,':',data);
|
69
|
+
throw new Error(
|
70
|
+
["The event", event.type, "on component", this.describe, "was triggered with non-serializable data"].join(" ")
|
71
|
+
);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
if (typeof this.attr.eventData === 'object') {
|
76
|
+
data = $.extend(true, {}, this.attr.eventData, data);
|
77
|
+
}
|
78
|
+
|
79
|
+
return $element.trigger(type, data);
|
80
|
+
};
|
81
|
+
|
82
|
+
this.on = function() {
|
83
|
+
var $element, type, callback, originalCb;
|
84
|
+
var args = utils.toArray(arguments);
|
85
|
+
|
86
|
+
if (typeof args[args.length - 1] == "object") {
|
87
|
+
//delegate callback
|
88
|
+
originalCb = utils.delegate(
|
89
|
+
this.resolveDelegateRules(args.pop())
|
90
|
+
);
|
91
|
+
} else {
|
92
|
+
originalCb = args.pop();
|
93
|
+
}
|
94
|
+
|
95
|
+
callback = originalCb && originalCb.bind(this);
|
96
|
+
callback.target = originalCb;
|
97
|
+
|
98
|
+
// if the original callback is already branded by jQuery's guid, copy it to the context-bound version
|
99
|
+
if (originalCb.guid) {
|
100
|
+
callback.guid = originalCb.guid;
|
101
|
+
}
|
102
|
+
|
103
|
+
$element = (args.length == 2) ? $(args.shift()) : this.$node;
|
104
|
+
type = args[0];
|
105
|
+
|
106
|
+
if (typeof callback == 'undefined') {
|
107
|
+
throw new Error("Unable to bind to '" + type + "' because the given callback is undefined");
|
108
|
+
}
|
109
|
+
|
110
|
+
$element.on(type, callback);
|
111
|
+
|
112
|
+
// get jquery's guid from our bound fn, so unbinding will work
|
113
|
+
originalCb.guid = callback.guid;
|
114
|
+
|
115
|
+
return callback;
|
116
|
+
};
|
117
|
+
|
118
|
+
this.off = function() {
|
119
|
+
var $element, type, callback;
|
120
|
+
var args = utils.toArray(arguments);
|
121
|
+
|
122
|
+
if (typeof args[args.length - 1] == "function") {
|
123
|
+
callback = args.pop();
|
124
|
+
}
|
125
|
+
|
126
|
+
$element = (args.length == 2) ? $(args.shift()) : this.$node;
|
127
|
+
type = args[0];
|
128
|
+
|
129
|
+
return $element.off(type, callback);
|
130
|
+
};
|
131
|
+
|
132
|
+
this.resolveDelegateRules = function(ruleInfo) {
|
133
|
+
var rules = {};
|
134
|
+
|
135
|
+
Object.keys(ruleInfo).forEach(
|
136
|
+
function(r) {
|
137
|
+
if (!this.attr.hasOwnProperty(r)) {
|
138
|
+
throw new Error('Component "' + this.describe + '" wants to listen on "' + r + '" but no such attribute was defined.');
|
139
|
+
}
|
140
|
+
rules[this.attr[r]] = ruleInfo[r];
|
141
|
+
},
|
142
|
+
this
|
143
|
+
);
|
144
|
+
|
145
|
+
return rules;
|
146
|
+
};
|
147
|
+
|
148
|
+
this.defaultAttrs = function(defaults) {
|
149
|
+
utils.push(this.defaults, defaults, true) || (this.defaults = defaults);
|
150
|
+
};
|
151
|
+
|
152
|
+
this.select = function(attributeKey) {
|
153
|
+
return this.$node.find(this.attr[attributeKey]);
|
154
|
+
};
|
155
|
+
|
156
|
+
this.initialize = $.noop;
|
157
|
+
this.teardown = teardown;
|
158
|
+
}
|
159
|
+
|
160
|
+
function attachTo(selector/*, options args */) {
|
161
|
+
if (!selector) {
|
162
|
+
throw new Error("Component needs to be attachTo'd a jQuery object, native node or selector string");
|
163
|
+
}
|
164
|
+
|
165
|
+
var options = utils.merge.apply(utils, utils.toArray(arguments, 1));
|
166
|
+
|
167
|
+
$(selector).each(function(i, node) {
|
168
|
+
new this(node, options);
|
169
|
+
}.bind(this));
|
170
|
+
}
|
171
|
+
|
172
|
+
// define the constructor for a custom component type
|
173
|
+
// takes an unlimited number of mixin functions as arguments
|
174
|
+
// typical api call with 3 mixins: define(timeline, withTweetCapability, withScrollCapability);
|
175
|
+
function define(/*mixins*/) {
|
176
|
+
var mixins = utils.toArray(arguments);
|
177
|
+
|
178
|
+
Component.toString = function() {
|
179
|
+
var prettyPrintMixins = mixins.map(function(mixin) {
|
180
|
+
if ($.browser.msie) {
|
181
|
+
var m = mixin.toString().match(/function (.*?)\s?\(/);
|
182
|
+
return (m && m[1]) ? m[1] : "";
|
183
|
+
} else {
|
184
|
+
return mixin.name;
|
185
|
+
}
|
186
|
+
}).join(', ').replace(/\s\,/g,'');//weed out no-named mixins
|
187
|
+
|
188
|
+
return prettyPrintMixins;
|
189
|
+
};
|
190
|
+
|
191
|
+
Component.describe = Component.toString();
|
192
|
+
|
193
|
+
//'options' is optional hash to be merged with 'defaults' in the component definition
|
194
|
+
function Component(node, options) {
|
195
|
+
var fnCache = {}, uuid = 0;
|
196
|
+
|
197
|
+
if (!node) {
|
198
|
+
throw new Error("Component needs a node");
|
199
|
+
}
|
200
|
+
|
201
|
+
if (node.jquery) {
|
202
|
+
this.node = node[0];
|
203
|
+
this.$node = node;
|
204
|
+
} else {
|
205
|
+
this.node = node;
|
206
|
+
this.$node = $(node);
|
207
|
+
}
|
208
|
+
|
209
|
+
this.describe = this.constructor.describe;
|
210
|
+
|
211
|
+
this.bind = function(func) {
|
212
|
+
var bound;
|
213
|
+
|
214
|
+
if (func.uuid && (bound = fnCache[func.uuid])) {
|
215
|
+
return bound;
|
216
|
+
}
|
217
|
+
|
218
|
+
var bindArgs = utils.toArray(arguments, 1);
|
219
|
+
bindArgs.unshift(this); //prepend context
|
220
|
+
|
221
|
+
bound = func.bind.apply(func, bindArgs);
|
222
|
+
bound.target = func;
|
223
|
+
func.uuid = uuid++;
|
224
|
+
fnCache[func.uuid] = bound;
|
225
|
+
|
226
|
+
return bound;
|
227
|
+
};
|
228
|
+
|
229
|
+
//merge defaults with supplied options
|
230
|
+
this.attr = utils.merge(this.defaults, options);
|
231
|
+
this.defaults && Object.keys(this.defaults).forEach(function(key) {
|
232
|
+
if (this.defaults[key] === null && this.attr[key] === null) {
|
233
|
+
throw new Error('Required attribute "' + key + '" not specified in attachTo for component "' + this.describe + '".');
|
234
|
+
}
|
235
|
+
}, this);
|
236
|
+
|
237
|
+
this.initialize.call(this, options || {});
|
238
|
+
|
239
|
+
this.trigger('componentInitialized');
|
240
|
+
}
|
241
|
+
|
242
|
+
Component.attachTo = attachTo;
|
243
|
+
Component.teardownAll = teardownAll;
|
244
|
+
|
245
|
+
// prepend common mixins to supplied list, then mixin all flavors
|
246
|
+
mixins.unshift(withBaseComponent, advice.withAdvice, registry.withRegistration);
|
247
|
+
|
248
|
+
compose.mixin(Component.prototype, mixins);
|
249
|
+
|
250
|
+
return Component;
|
251
|
+
}
|
252
|
+
|
253
|
+
define.teardownAll = function() {
|
254
|
+
registry.components.slice().forEach(function(c) {
|
255
|
+
c.component.teardownAll();
|
256
|
+
});
|
257
|
+
registry.reset();
|
258
|
+
};
|
259
|
+
|
260
|
+
return define;
|
261
|
+
}
|
262
|
+
);
|
@@ -0,0 +1,86 @@
|
|
1
|
+
// ==========================================
|
2
|
+
// Copyright 2013 Twitter, Inc
|
3
|
+
// Licensed under The MIT License
|
4
|
+
// http://opensource.org/licenses/MIT
|
5
|
+
// ==========================================
|
6
|
+
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
define(
|
10
|
+
|
11
|
+
[
|
12
|
+
'./utils',
|
13
|
+
'../tools/debug/debug'
|
14
|
+
],
|
15
|
+
|
16
|
+
function(util, debug) {
|
17
|
+
|
18
|
+
//enumerables are shims - getOwnPropertyDescriptor shim doesn't work
|
19
|
+
var canWriteProtect = debug.enabled && !util.isEnumerable(Object, 'getOwnPropertyDescriptor');
|
20
|
+
//whitelist of unlockable property names
|
21
|
+
var dontLock = ['mixedIn'];
|
22
|
+
|
23
|
+
if (canWriteProtect) {
|
24
|
+
//IE8 getOwnPropertyDescriptor is built-in but throws exeption on non DOM objects
|
25
|
+
try {
|
26
|
+
Object.getOwnPropertyDescriptor(Object, 'keys');
|
27
|
+
} catch(e) {
|
28
|
+
canWriteProtect = false;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
function setPropertyWritability(obj, isWritable) {
|
33
|
+
if (!canWriteProtect) {
|
34
|
+
return;
|
35
|
+
}
|
36
|
+
|
37
|
+
var props = Object.create(null);
|
38
|
+
|
39
|
+
Object.keys(obj).forEach(
|
40
|
+
function (key) {
|
41
|
+
if (dontLock.indexOf(key) < 0) {
|
42
|
+
var desc = Object.getOwnPropertyDescriptor(obj, key);
|
43
|
+
desc.writable = isWritable;
|
44
|
+
props[key] = desc;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
);
|
48
|
+
|
49
|
+
Object.defineProperties(obj, props);
|
50
|
+
}
|
51
|
+
|
52
|
+
function unlockProperty(obj, prop, op) {
|
53
|
+
var writable;
|
54
|
+
|
55
|
+
if (!canWriteProtect || !obj.hasOwnProperty(prop)) {
|
56
|
+
op.call(obj);
|
57
|
+
return;
|
58
|
+
}
|
59
|
+
|
60
|
+
writable = Object.getOwnPropertyDescriptor(obj, prop).writable;
|
61
|
+
Object.defineProperty(obj, prop, { writable: true });
|
62
|
+
op.call(obj);
|
63
|
+
Object.defineProperty(obj, prop, { writable: writable });
|
64
|
+
}
|
65
|
+
|
66
|
+
function mixin(base, mixins) {
|
67
|
+
base.mixedIn = base.hasOwnProperty('mixedIn') ? base.mixedIn : [];
|
68
|
+
|
69
|
+
mixins.forEach(function(mixin) {
|
70
|
+
if (base.mixedIn.indexOf(mixin) == -1) {
|
71
|
+
setPropertyWritability(base, false);
|
72
|
+
mixin.call(base);
|
73
|
+
base.mixedIn.push(mixin);
|
74
|
+
}
|
75
|
+
});
|
76
|
+
|
77
|
+
setPropertyWritability(base, true);
|
78
|
+
}
|
79
|
+
|
80
|
+
return {
|
81
|
+
mixin: mixin,
|
82
|
+
unlockProperty: unlockProperty
|
83
|
+
};
|
84
|
+
|
85
|
+
}
|
86
|
+
);
|
@@ -0,0 +1,30 @@
|
|
1
|
+
// ==========================================
|
2
|
+
// Copyright 2013 Twitter, Inc
|
3
|
+
// Licensed under The MIT License
|
4
|
+
// http://opensource.org/licenses/MIT
|
5
|
+
// ==========================================
|
6
|
+
|
7
|
+
define(
|
8
|
+
|
9
|
+
[
|
10
|
+
'./advice',
|
11
|
+
'./component',
|
12
|
+
'./compose',
|
13
|
+
'./logger',
|
14
|
+
'./registry',
|
15
|
+
'./utils'
|
16
|
+
],
|
17
|
+
|
18
|
+
function (advice, component, compose, logger, registry, utils) {
|
19
|
+
|
20
|
+
return {
|
21
|
+
advice: advice,
|
22
|
+
component: component,
|
23
|
+
compose: compose,
|
24
|
+
logger: logger,
|
25
|
+
registry: registry,
|
26
|
+
utils: utils
|
27
|
+
};
|
28
|
+
|
29
|
+
}
|
30
|
+
);
|
@@ -0,0 +1,93 @@
|
|
1
|
+
// ==========================================
|
2
|
+
// Copyright 2013 Twitter, Inc
|
3
|
+
// Licensed under The MIT License
|
4
|
+
// http://opensource.org/licenses/MIT
|
5
|
+
// ==========================================
|
6
|
+
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
define(
|
10
|
+
|
11
|
+
[
|
12
|
+
'./compose',
|
13
|
+
'./utils'
|
14
|
+
],
|
15
|
+
|
16
|
+
function (compose, util) {
|
17
|
+
|
18
|
+
var actionSymbols = {
|
19
|
+
on:'<-',
|
20
|
+
trigger: '->',
|
21
|
+
off: 'x '
|
22
|
+
};
|
23
|
+
|
24
|
+
function elemToString(elem) {
|
25
|
+
var tagStr = elem.tagName ? elem.tagName.toLowerCase() : elem.toString();
|
26
|
+
var classStr = elem.className ? "." + (elem.className) : "";
|
27
|
+
var result = tagStr + classStr;
|
28
|
+
return elem.tagName ? ['\'', '\''].join(result) : result;
|
29
|
+
}
|
30
|
+
|
31
|
+
function log(action, component, eventArgs) {
|
32
|
+
|
33
|
+
var name, elem, fn, fnName, logFilter, toRegExp, actionLoggable, nameLoggable;
|
34
|
+
|
35
|
+
if (typeof eventArgs[eventArgs.length-1] == 'function') {
|
36
|
+
fn = eventArgs.pop();
|
37
|
+
fn = fn.unbound || fn; //use unbound version if any (better info)
|
38
|
+
}
|
39
|
+
|
40
|
+
if (typeof eventArgs[eventArgs.length - 1] == 'object') {
|
41
|
+
eventArgs.pop(); //trigger data arg - not logged right now
|
42
|
+
}
|
43
|
+
|
44
|
+
if (eventArgs.length == 2) {
|
45
|
+
elem = eventArgs[0];
|
46
|
+
name = eventArgs[1];
|
47
|
+
} else {
|
48
|
+
elem = component.$node[0];
|
49
|
+
name = eventArgs[0];
|
50
|
+
}
|
51
|
+
|
52
|
+
if (window.DEBUG) {
|
53
|
+
logFilter = DEBUG.events.logFilter;
|
54
|
+
|
55
|
+
// no regex for you, actions...
|
56
|
+
actionLoggable = logFilter.actions=="all" || (logFilter.actions.indexOf(action) > -1);
|
57
|
+
// event name filter allow wildcards or regex...
|
58
|
+
toRegExp = function(expr) {
|
59
|
+
return expr.test ? expr : new RegExp("^" + expr.replace(/\*/g, ".*") + "$");
|
60
|
+
};
|
61
|
+
nameLoggable =
|
62
|
+
logFilter.eventNames=="all" ||
|
63
|
+
logFilter.eventNames.some(function(e) {return toRegExp(e).test(name)});
|
64
|
+
|
65
|
+
if (actionLoggable && nameLoggable) {
|
66
|
+
console.info(
|
67
|
+
actionSymbols[action],
|
68
|
+
action,
|
69
|
+
'[' + name + ']',
|
70
|
+
elemToString(elem),
|
71
|
+
component.constructor.describe,
|
72
|
+
fn && (fnName = fn.name || fn.displayName) && '-> ' + fnName
|
73
|
+
);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
|
79
|
+
function withLogging() {
|
80
|
+
this.before('trigger', function() {
|
81
|
+
log('trigger', this, util.toArray(arguments));
|
82
|
+
});
|
83
|
+
this.before('on', function() {
|
84
|
+
log('on', this, util.toArray(arguments));
|
85
|
+
});
|
86
|
+
this.before('off', function(eventArgs) {
|
87
|
+
log('off', this, util.toArray(arguments));
|
88
|
+
});
|
89
|
+
}
|
90
|
+
|
91
|
+
return withLogging;
|
92
|
+
}
|
93
|
+
);
|
@@ -0,0 +1,234 @@
|
|
1
|
+
// ==========================================
|
2
|
+
// Copyright 2013 Twitter, Inc
|
3
|
+
// Licensed under The MIT License
|
4
|
+
// http://opensource.org/licenses/MIT
|
5
|
+
// ==========================================
|
6
|
+
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
define(
|
10
|
+
|
11
|
+
[
|
12
|
+
'./utils'
|
13
|
+
],
|
14
|
+
|
15
|
+
function (util) {
|
16
|
+
|
17
|
+
function parseEventArgs(instance, args) {
|
18
|
+
var element, type, callback;
|
19
|
+
|
20
|
+
args = util.toArray(args);
|
21
|
+
|
22
|
+
if (typeof args[args.length-1] === 'function') {
|
23
|
+
callback = args.pop();
|
24
|
+
}
|
25
|
+
|
26
|
+
if (typeof args[args.length-1] === 'object') {
|
27
|
+
args.pop();
|
28
|
+
}
|
29
|
+
|
30
|
+
if (args.length == 2) {
|
31
|
+
element = args[0];
|
32
|
+
type = args[1];
|
33
|
+
} else {
|
34
|
+
element = instance.node;
|
35
|
+
type = args[0];
|
36
|
+
}
|
37
|
+
|
38
|
+
return {
|
39
|
+
element: element,
|
40
|
+
type: type,
|
41
|
+
callback: callback
|
42
|
+
};
|
43
|
+
}
|
44
|
+
|
45
|
+
function matchEvent(a, b) {
|
46
|
+
return (
|
47
|
+
(a.element == b.element) &&
|
48
|
+
(a.type == b.type) &&
|
49
|
+
(b.callback == null || (a.callback == b.callback))
|
50
|
+
);
|
51
|
+
}
|
52
|
+
|
53
|
+
function Registry() {
|
54
|
+
|
55
|
+
var registry = this;
|
56
|
+
|
57
|
+
(this.reset = function() {
|
58
|
+
this.components = [];
|
59
|
+
this.allInstances = [];
|
60
|
+
this.events = [];
|
61
|
+
}).call(this);
|
62
|
+
|
63
|
+
function ComponentInfo(component) {
|
64
|
+
this.component = component;
|
65
|
+
this.instances = [];
|
66
|
+
|
67
|
+
this.addInstance = function(instance) {
|
68
|
+
this.throwIfInstanceExistsOnNode(instance);
|
69
|
+
|
70
|
+
var instanceInfo = new InstanceInfo(instance);
|
71
|
+
this.instances.push(instanceInfo);
|
72
|
+
|
73
|
+
return instanceInfo;
|
74
|
+
}
|
75
|
+
|
76
|
+
this.throwIfInstanceExistsOnNode = function(instance) {
|
77
|
+
this.instances.forEach(function (instanceInfo) {
|
78
|
+
if (instanceInfo.instance.$node[0] === instance.$node[0]) {
|
79
|
+
throw new Error('Instance of ' + instance.constructor + ' already exists on node ' + instance.$node[0]);
|
80
|
+
}
|
81
|
+
});
|
82
|
+
}
|
83
|
+
|
84
|
+
this.removeInstance = function(instance) {
|
85
|
+
var instanceInfo = this.instances.filter(function(instanceInfo) {
|
86
|
+
return instanceInfo.instance == instance;
|
87
|
+
})[0];
|
88
|
+
|
89
|
+
var index = this.instances.indexOf(instanceInfo);
|
90
|
+
|
91
|
+
(index > -1) && this.instances.splice(index, 1);
|
92
|
+
|
93
|
+
if (!this.instances.length) {
|
94
|
+
//if I hold no more instances remove me from registry
|
95
|
+
registry.removeComponentInfo(this);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
function InstanceInfo(instance) {
|
101
|
+
this.instance = instance;
|
102
|
+
this.events = [];
|
103
|
+
|
104
|
+
this.addTrigger = function() {};
|
105
|
+
|
106
|
+
this.addBind = function(event) {
|
107
|
+
this.events.push(event);
|
108
|
+
registry.events.push(event);
|
109
|
+
};
|
110
|
+
|
111
|
+
this.removeBind = function(event) {
|
112
|
+
for (var i = 0, e; e = this.events[i]; i++) {
|
113
|
+
if (matchEvent(e, event)) {
|
114
|
+
this.events.splice(i, 1);
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
this.addInstance = function(instance) {
|
121
|
+
var component = this.findComponentInfo(instance);
|
122
|
+
|
123
|
+
if (!component) {
|
124
|
+
component = new ComponentInfo(instance.constructor);
|
125
|
+
this.components.push(component);
|
126
|
+
}
|
127
|
+
|
128
|
+
var inst = component.addInstance(instance);
|
129
|
+
|
130
|
+
this.allInstances.push(inst);
|
131
|
+
|
132
|
+
return component;
|
133
|
+
};
|
134
|
+
|
135
|
+
this.removeInstance = function(instance) {
|
136
|
+
var index, instInfo = this.findInstanceInfo(instance);
|
137
|
+
|
138
|
+
//remove from component info
|
139
|
+
var componentInfo = this.findComponentInfo(instance);
|
140
|
+
componentInfo.removeInstance(instance);
|
141
|
+
|
142
|
+
//remove from registry
|
143
|
+
var index = this.allInstances.indexOf(instInfo);
|
144
|
+
(index > -1) && this.allInstances.splice(index, 1);
|
145
|
+
};
|
146
|
+
|
147
|
+
this.removeComponentInfo = function(componentInfo) {
|
148
|
+
var index = this.components.indexOf(componentInfo);
|
149
|
+
(index > -1) && this.components.splice(index, 1);
|
150
|
+
};
|
151
|
+
|
152
|
+
this.findComponentInfo = function(which) {
|
153
|
+
var component = which.attachTo ? which : which.constructor;
|
154
|
+
|
155
|
+
for (var i = 0, c; c = this.components[i]; i++) {
|
156
|
+
if (c.component === component) {
|
157
|
+
return c;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
return null;
|
162
|
+
};
|
163
|
+
|
164
|
+
this.findInstanceInfo = function(which) {
|
165
|
+
var testFn;
|
166
|
+
|
167
|
+
if (which.node) {
|
168
|
+
//by instance (returns matched instance)
|
169
|
+
testFn = function(inst) {return inst.instance === which};
|
170
|
+
} else {
|
171
|
+
//by node (returns array of matches)
|
172
|
+
testFn = function(inst) {return inst.instance.node === which};
|
173
|
+
}
|
174
|
+
|
175
|
+
var matches = this.allInstances.filter(testFn);
|
176
|
+
if (!matches.length) {
|
177
|
+
return which.node ? null : [];
|
178
|
+
}
|
179
|
+
return which.node ? matches[0] : matches;
|
180
|
+
};
|
181
|
+
|
182
|
+
this.trigger = function() {
|
183
|
+
var event = parseEventArgs(this, arguments),
|
184
|
+
instance = registry.findInstanceInfo(this);
|
185
|
+
|
186
|
+
if (instance) {
|
187
|
+
instance.addTrigger(event);
|
188
|
+
}
|
189
|
+
};
|
190
|
+
|
191
|
+
this.on = function(componentOn) {
|
192
|
+
var otherArgs = util.toArray(arguments, 1);
|
193
|
+
var instance = registry.findInstanceInfo(this);
|
194
|
+
var boundCallback;
|
195
|
+
|
196
|
+
if (instance) {
|
197
|
+
boundCallback = componentOn.apply(null, otherArgs);
|
198
|
+
if(boundCallback) {
|
199
|
+
otherArgs[otherArgs.length-1] = boundCallback;
|
200
|
+
}
|
201
|
+
var event = parseEventArgs(this, otherArgs);
|
202
|
+
instance.addBind(event);
|
203
|
+
}
|
204
|
+
};
|
205
|
+
|
206
|
+
this.off = function(el, type, callback) {
|
207
|
+
var event = parseEventArgs(this, arguments),
|
208
|
+
instance = registry.findInstanceInfo(this);
|
209
|
+
|
210
|
+
if (instance) {
|
211
|
+
instance.removeBind(event);
|
212
|
+
}
|
213
|
+
};
|
214
|
+
|
215
|
+
this.teardown = function() {
|
216
|
+
registry.removeInstance(this);
|
217
|
+
};
|
218
|
+
|
219
|
+
this.withRegistration = function() {
|
220
|
+
this.before('initialize', function() {
|
221
|
+
registry.addInstance(this);
|
222
|
+
});
|
223
|
+
|
224
|
+
this.after('trigger', registry.trigger);
|
225
|
+
this.around('on', registry.on);
|
226
|
+
this.after('off', registry.off);
|
227
|
+
this.after('teardown', {obj:registry, fnName:'teardown'});
|
228
|
+
};
|
229
|
+
|
230
|
+
}
|
231
|
+
|
232
|
+
return new Registry;
|
233
|
+
}
|
234
|
+
);
|
@@ -0,0 +1,228 @@
|
|
1
|
+
// ==========================================
|
2
|
+
// Copyright 2013 Twitter, Inc
|
3
|
+
// Licensed under The MIT License
|
4
|
+
// http://opensource.org/licenses/MIT
|
5
|
+
// ==========================================
|
6
|
+
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
define(
|
10
|
+
|
11
|
+
[],
|
12
|
+
|
13
|
+
function () {
|
14
|
+
|
15
|
+
var arry = [];
|
16
|
+
var DEFAULT_INTERVAL = 100;
|
17
|
+
|
18
|
+
var utils = {
|
19
|
+
|
20
|
+
isDomObj: function(obj) {
|
21
|
+
return !!(obj.nodeType || (obj === window));
|
22
|
+
},
|
23
|
+
|
24
|
+
toArray: function(obj, from) {
|
25
|
+
return arry.slice.call(obj, from);
|
26
|
+
},
|
27
|
+
|
28
|
+
// returns new object representing multiple objects merged together
|
29
|
+
// optional final argument is boolean which specifies if merge is recursive
|
30
|
+
// original objects are unmodified
|
31
|
+
//
|
32
|
+
// usage:
|
33
|
+
// var base = {a:2, b:6};
|
34
|
+
// var extra = {b:3, c:4};
|
35
|
+
// merge(base, extra); //{a:2, b:3, c:4}
|
36
|
+
// base; //{a:2, b:6}
|
37
|
+
//
|
38
|
+
// var base = {a:2, b:6};
|
39
|
+
// var extra = {b:3, c:4};
|
40
|
+
// var extraExtra = {a:4, d:9};
|
41
|
+
// merge(base, extra, extraExtra); //{a:4, b:3, c:4. d: 9}
|
42
|
+
// base; //{a:2, b:6}
|
43
|
+
//
|
44
|
+
// var base = {a:2, b:{bb:4, cc:5}};
|
45
|
+
// var extra = {a:4, b:{cc:7, dd:1}};
|
46
|
+
// merge(base, extra, true); //{a:4, b:{bb:4, cc:7, dd:1}}
|
47
|
+
// base; //{a:2, b:6}
|
48
|
+
|
49
|
+
merge: function(/*obj1, obj2,....deepCopy*/) {
|
50
|
+
var args = this.toArray(arguments);
|
51
|
+
|
52
|
+
//start with empty object so a copy is created
|
53
|
+
args.unshift({});
|
54
|
+
|
55
|
+
if (args[args.length - 1] === true) {
|
56
|
+
//jquery extend requires deep copy as first arg
|
57
|
+
args.pop();
|
58
|
+
args.unshift(true);
|
59
|
+
}
|
60
|
+
|
61
|
+
return $.extend.apply(undefined, args);
|
62
|
+
},
|
63
|
+
|
64
|
+
// updates base in place by copying properties of extra to it
|
65
|
+
// optionally clobber protected
|
66
|
+
// usage:
|
67
|
+
// var base = {a:2, b:6};
|
68
|
+
// var extra = {c:4};
|
69
|
+
// push(base, extra); //{a:2, b:6, c:4}
|
70
|
+
// base; //{a:2, b:6, c:4}
|
71
|
+
//
|
72
|
+
// var base = {a:2, b:6};
|
73
|
+
// var extra = {b: 4 c:4};
|
74
|
+
// push(base, extra, true); //Error ("utils.push attempted to overwrite 'b' while running in protected mode")
|
75
|
+
// base; //{a:2, b:6}
|
76
|
+
//
|
77
|
+
// objects with the same key will merge recursively when protect is false
|
78
|
+
// eg:
|
79
|
+
// var base = {a:16, b:{bb:4, cc:10}};
|
80
|
+
// var extra = {b:{cc:25, dd:19}, c:5};
|
81
|
+
// push(base, extra); //{a:16, {bb:4, cc:25, dd:19}, c:5}
|
82
|
+
//
|
83
|
+
push: function(base, extra, protect) {
|
84
|
+
if (base) {
|
85
|
+
Object.keys(extra || {}).forEach(function(key) {
|
86
|
+
if (base[key] && protect) {
|
87
|
+
throw Error("utils.push attempted to overwrite '" + key + "' while running in protected mode");
|
88
|
+
}
|
89
|
+
|
90
|
+
if (typeof base[key] == "object" && typeof extra[key] == "object") {
|
91
|
+
//recurse
|
92
|
+
this.push(base[key], extra[key]);
|
93
|
+
} else {
|
94
|
+
//no protect, so extra wins
|
95
|
+
base[key] = extra[key];
|
96
|
+
}
|
97
|
+
}, this);
|
98
|
+
}
|
99
|
+
|
100
|
+
return base;
|
101
|
+
},
|
102
|
+
|
103
|
+
isEnumerable: function(obj, property) {
|
104
|
+
return Object.keys(obj).indexOf(property) > -1;
|
105
|
+
},
|
106
|
+
|
107
|
+
//build a function from other function(s)
|
108
|
+
//util.compose(a,b,c) -> a(b(c()));
|
109
|
+
//implementation lifted from underscore.js (c) 2009-2012 Jeremy Ashkenas
|
110
|
+
compose: function() {
|
111
|
+
var funcs = arguments;
|
112
|
+
|
113
|
+
return function() {
|
114
|
+
var args = arguments;
|
115
|
+
|
116
|
+
for (var i = funcs.length-1; i >= 0; i--) {
|
117
|
+
args = [funcs[i].apply(this, args)];
|
118
|
+
}
|
119
|
+
|
120
|
+
return args[0];
|
121
|
+
};
|
122
|
+
},
|
123
|
+
|
124
|
+
// 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
|
125
|
+
uniqueArray: function(array) {
|
126
|
+
var u = {}, a = [];
|
127
|
+
|
128
|
+
for (var i = 0, l = array.length; i < l; ++i) {
|
129
|
+
if (u.hasOwnProperty(array[i])) {
|
130
|
+
continue;
|
131
|
+
}
|
132
|
+
|
133
|
+
a.push(array[i]);
|
134
|
+
u[array[i]] = 1;
|
135
|
+
}
|
136
|
+
|
137
|
+
return a;
|
138
|
+
},
|
139
|
+
|
140
|
+
debounce: function(func, wait, immediate) {
|
141
|
+
if (typeof wait != 'number') {
|
142
|
+
wait = DEFAULT_INTERVAL;
|
143
|
+
}
|
144
|
+
|
145
|
+
var timeout, result;
|
146
|
+
|
147
|
+
return function() {
|
148
|
+
var context = this, args = arguments;
|
149
|
+
var later = function() {
|
150
|
+
timeout = null;
|
151
|
+
if (!immediate) {
|
152
|
+
result = func.apply(context, args);
|
153
|
+
}
|
154
|
+
};
|
155
|
+
var callNow = immediate && !timeout;
|
156
|
+
|
157
|
+
clearTimeout(timeout);
|
158
|
+
timeout = setTimeout(later, wait);
|
159
|
+
|
160
|
+
if (callNow) {
|
161
|
+
result = func.apply(context, args);
|
162
|
+
}
|
163
|
+
|
164
|
+
return result;
|
165
|
+
};
|
166
|
+
},
|
167
|
+
|
168
|
+
throttle: function(func, wait) {
|
169
|
+
if (typeof wait != 'number') {
|
170
|
+
wait = DEFAULT_INTERVAL;
|
171
|
+
}
|
172
|
+
|
173
|
+
var context, args, timeout, throttling, more, result;
|
174
|
+
var whenDone = this.debounce(function(){
|
175
|
+
more = throttling = false;
|
176
|
+
}, wait);
|
177
|
+
|
178
|
+
return function() {
|
179
|
+
context = this; args = arguments;
|
180
|
+
var later = function() {
|
181
|
+
timeout = null;
|
182
|
+
if (more) {
|
183
|
+
result = func.apply(context, args);
|
184
|
+
}
|
185
|
+
whenDone();
|
186
|
+
};
|
187
|
+
|
188
|
+
if (!timeout) {
|
189
|
+
timeout = setTimeout(later, wait);
|
190
|
+
}
|
191
|
+
|
192
|
+
if (throttling) {
|
193
|
+
more = true;
|
194
|
+
} else {
|
195
|
+
throttling = true;
|
196
|
+
result = func.apply(context, args);
|
197
|
+
}
|
198
|
+
|
199
|
+
whenDone();
|
200
|
+
return result;
|
201
|
+
};
|
202
|
+
},
|
203
|
+
|
204
|
+
countThen: function(num, base) {
|
205
|
+
return function() {
|
206
|
+
if (!--num) { return base.apply(this, arguments); }
|
207
|
+
};
|
208
|
+
},
|
209
|
+
|
210
|
+
delegate: function(rules) {
|
211
|
+
return function(e, data) {
|
212
|
+
var target = $(e.target), parent;
|
213
|
+
|
214
|
+
Object.keys(rules).forEach(function(selector) {
|
215
|
+
if ((parent = target.closest(selector)).length) {
|
216
|
+
data = data || {};
|
217
|
+
data.el = parent[0];
|
218
|
+
return rules[selector].apply(this, [e, data]);
|
219
|
+
}
|
220
|
+
}, this);
|
221
|
+
};
|
222
|
+
}
|
223
|
+
|
224
|
+
};
|
225
|
+
|
226
|
+
return utils;
|
227
|
+
}
|
228
|
+
);
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_directory twitter/flight
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twitter-flight-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Yousef Ourabi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: railties
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.1'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.1'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: actionpack
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.1'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.1'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: jquery-rails
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rails
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.1'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '3.1'
|
78
|
+
description: twitter-flight-rails flight framework for Rails asset pipeline
|
79
|
+
email:
|
80
|
+
- yourabi@gmail.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- .travis.yml
|
87
|
+
- Gemfile
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- lib/twitter-flight-rails.rb
|
92
|
+
- lib/twitter-flight-rails/version.rb
|
93
|
+
- twitter-flight-rails.gemspec
|
94
|
+
- vendor/assets/javascripts/twitter/flight.js
|
95
|
+
- vendor/assets/javascripts/twitter/flight/advice.js
|
96
|
+
- vendor/assets/javascripts/twitter/flight/component.js
|
97
|
+
- vendor/assets/javascripts/twitter/flight/compose.js
|
98
|
+
- vendor/assets/javascripts/twitter/flight/index.js
|
99
|
+
- vendor/assets/javascripts/twitter/flight/logger.js
|
100
|
+
- vendor/assets/javascripts/twitter/flight/registry.js
|
101
|
+
- vendor/assets/javascripts/twitter/flight/utils.js
|
102
|
+
homepage: https://github.com/yourabi/twitter-flight-rails
|
103
|
+
licenses: []
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 1.8.23
|
123
|
+
signing_key:
|
124
|
+
specification_version: 3
|
125
|
+
summary: twitter-flight-rails packages the flight framework into an asset gem
|
126
|
+
test_files: []
|