-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Viktor Tomilin
committed
Feb 2, 2013
1 parent
b725ef3
commit 6521b1c
Showing
11 changed files
with
1,022 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
require "rails" | ||
require "flight-rails/version" | ||
|
||
module Flight | ||
module Rails | ||
# Your code goes here... | ||
require "flight-rails/engine" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module Flight | ||
class Engine < ::Rails::Engine | ||
initializer 'flight-rails-setup', group: :all | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// ========================================== | ||
// Copyright 2013 Twitter, Inc | ||
// Licensed under The MIT License | ||
// http://opensource.org/licenses/MIT | ||
// ========================================== | ||
|
||
"use strict"; | ||
|
||
define( | ||
|
||
[ | ||
'./utils', | ||
'./compose' | ||
], | ||
|
||
function (util, compose) { | ||
|
||
var advice = { | ||
|
||
around: function(base, wrapped) { | ||
return function() { | ||
var args = util.toArray(arguments); | ||
return wrapped.apply(this, [base.bind(this)].concat(args)); | ||
} | ||
}, | ||
|
||
before: function(base, before) { | ||
return this.around(base, function() { | ||
var args = util.toArray(arguments), | ||
orig = args.shift(), | ||
beforeFn; | ||
|
||
beforeFn = (typeof before == 'function') ? before : before.obj[before.fnName]; | ||
beforeFn.apply(this, args); | ||
return (orig).apply(this, args); | ||
}); | ||
}, | ||
|
||
after: function(base, after) { | ||
return this.around(base, function() { | ||
var args = util.toArray(arguments), | ||
orig = args.shift(), | ||
afterFn; | ||
|
||
// this is a separate statement for debugging purposes. | ||
var res = (orig.unbound || orig).apply(this, args); | ||
|
||
afterFn = (typeof after == 'function') ? after : after.obj[after.fnName]; | ||
afterFn.apply(this, args); | ||
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') { | ||
return this[method] = advice[m](this[method], fn); | ||
} else { | ||
return this[method] = fn; | ||
} | ||
}); | ||
|
||
}; | ||
}, this); | ||
} | ||
}; | ||
|
||
return advice; | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
// ========================================== | ||
// Copyright 2013 Twitter, Inc | ||
// Licensed under The MIT License | ||
// http://opensource.org/licenses/MIT | ||
// ========================================== | ||
|
||
"use strict"; | ||
|
||
define( | ||
|
||
[ | ||
'./advice', | ||
'./utils', | ||
'./compose', | ||
'./registry' | ||
], | ||
|
||
function(advice, utils, compose, registry) { | ||
|
||
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 teardown() { | ||
this.trigger("componentTearDown"); | ||
teardownInstance(registry.findInstanceInfo(this)); | ||
} | ||
|
||
//teardown for all instances of this constructor | ||
function teardownAll() { | ||
var componentInfo = registry.findComponentInfo(this); | ||
|
||
componentInfo && componentInfo.instances.slice().forEach(function(info) { | ||
info.instance.teardown(); | ||
}); | ||
} | ||
|
||
//common mixin allocates basic functionality - used by all component prototypes | ||
//callback context is bound to component | ||
function withBaseComponent() { | ||
|
||
// delegate trigger, bind and unbind to an element | ||
// if $element not supplied, use component's node | ||
// other arguments are passed on | ||
this.trigger = function() { | ||
var $element, type, data; | ||
var args = utils.toArray(arguments); | ||
|
||
if (typeof args[args.length - 1] != "string") { | ||
data = args.pop(); | ||
} | ||
|
||
$element = (args.length == 2) ? $(args.shift()) : this.$node; | ||
type = args[0]; | ||
|
||
if (window.DEBUG && window.postMessage) { | ||
try { | ||
window.postMessage(data, '*'); | ||
} catch(e) { | ||
console.log('unserializable data for event',type,':',data); | ||
throw new Error( | ||
["The event", event.type, "on component", this.describe, "was triggered with non-serializable data"].join(" ") | ||
); | ||
} | ||
} | ||
|
||
if (typeof this.attr.eventData === 'object') { | ||
data = $.extend(true, {}, this.attr.eventData, data); | ||
} | ||
|
||
return $element.trigger(type, data); | ||
}; | ||
|
||
this.on = function() { | ||
var $element, type, callback, originalCb; | ||
var args = utils.toArray(arguments); | ||
|
||
if (typeof args[args.length - 1] == "object") { | ||
//delegate callback | ||
originalCb = utils.delegate( | ||
this.resolveDelegateRules(args.pop()) | ||
); | ||
} else { | ||
originalCb = args.pop(); | ||
} | ||
|
||
callback = originalCb && originalCb.bind(this); | ||
callback.target = originalCb; | ||
|
||
$element = (args.length == 2) ? $(args.shift()) : this.$node; | ||
type = args[0]; | ||
|
||
if (typeof callback == 'undefined') { | ||
throw new Error("Unable to bind to '" + type + "' because the given callback is undefined"); | ||
} | ||
|
||
$element.on(type, callback); | ||
|
||
// get jquery's guid from our bound fn, so unbinding will work | ||
originalCb.guid = callback.guid; | ||
|
||
return callback; | ||
}; | ||
|
||
this.off = function() { | ||
var $element, type, callback; | ||
var args = utils.toArray(arguments); | ||
|
||
if (typeof args[args.length - 1] == "function") { | ||
callback = args.pop(); | ||
} | ||
|
||
$element = (args.length == 2) ? $(args.shift()) : this.$node; | ||
type = args[0]; | ||
|
||
return $element.off(type, callback); | ||
}; | ||
|
||
this.resolveDelegateRules = function(ruleInfo) { | ||
var rules = {}; | ||
|
||
Object.keys(ruleInfo).forEach( | ||
function(r) { | ||
if (!this.attr.hasOwnProperty(r)) { | ||
throw new Error('Component "' + this.describe + '" wants to listen on "' + r + '" but no such attribute was defined.'); | ||
} | ||
rules[this.attr[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 = $.noop; | ||
this.teardown = teardown; | ||
} | ||
|
||
function attachTo(selector/*, options args */) { | ||
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, utils.toArray(arguments, 1)); | ||
|
||
$(selector).each(function(i, node) { | ||
new this(node, options); | ||
}.bind(this)); | ||
} | ||
|
||
// 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*/) { | ||
var mixins = utils.toArray(arguments); | ||
|
||
Component.toString = function() { | ||
var prettyPrintMixins = mixins.map(function(mixin) { | ||
if ($.browser.msie) { | ||
var m = mixin.toString().match(/function (.*?)\s?\(/); | ||
return (m && m[1]) ? m[1] : ""; | ||
} else { | ||
return mixin.name; | ||
} | ||
}).join(', ').replace(/\s\,/g,'');//weed out no-named mixins | ||
|
||
return prettyPrintMixins; | ||
}; | ||
|
||
Component.describe = Component.toString(); | ||
|
||
//'options' is optional hash to be merged with 'defaults' in the component definition | ||
function Component(node, options) { | ||
var fnCache = {}, uuid = 0; | ||
|
||
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); | ||
} | ||
|
||
this.describe = this.constructor.describe; | ||
|
||
this.bind = function(func) { | ||
var bound; | ||
|
||
if (func.uuid && (bound = fnCache[func.uuid])) { | ||
return bound; | ||
} | ||
|
||
var bindArgs = utils.toArray(arguments, 1); | ||
bindArgs.unshift(this); //prepend context | ||
|
||
bound = func.bind.apply(func, bindArgs); | ||
bound.target = func; | ||
func.uuid = uuid++; | ||
fnCache[func.uuid] = bound; | ||
|
||
return bound; | ||
}; | ||
|
||
//merge defaults with supplied options | ||
this.attr = utils.merge(this.defaults, options); | ||
this.defaults && 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.describe + '".'); | ||
} | ||
}, this); | ||
|
||
this.initialize.call(this, options || {}); | ||
|
||
this.trigger('componentInitialized'); | ||
} | ||
|
||
Component.attachTo = attachTo; | ||
Component.teardownAll = teardownAll; | ||
|
||
// prepend common mixins to supplied list, then mixin all flavors | ||
mixins.unshift(withBaseComponent, 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; | ||
} | ||
); |
Oops, something went wrong.