summaryrefslogtreecommitdiffstats
path: root/third_party/webkit/PerformanceTests/Speedometer/resources/flightjs-example-app/components/flight/lib/component.js
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/webkit/PerformanceTests/Speedometer/resources/flightjs-example-app/components/flight/lib/component.js')
-rw-r--r--third_party/webkit/PerformanceTests/Speedometer/resources/flightjs-example-app/components/flight/lib/component.js308
1 files changed, 308 insertions, 0 deletions
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/flightjs-example-app/components/flight/lib/component.js b/third_party/webkit/PerformanceTests/Speedometer/resources/flightjs-example-app/components/flight/lib/component.js
new file mode 100644
index 0000000000..d9a5077ac9
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/Speedometer/resources/flightjs-example-app/components/flight/lib/component.js
@@ -0,0 +1,308 @@
+// ==========================================
+// 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) {
+
+ var functionNameRegEx = /function (.*?)\s?\(/;
+ 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 teardown() {
+ teardownInstance(registry.findInstanceInfo(this));
+ }
+
+ //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];
+ 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(" ")
+ );
+ }
+ }
+
+ //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
+ // 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 (window.DEBUG && window.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 {
+ 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;
+
+ // if the original callback is already branded by jQuery's guid, copy it to the context-bound version
+ if (originalCb.guid) {
+ callback.guid = originalCb.guid;
+ }
+
+ $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 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];
+ }
+
+ 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]] = 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 */) {
+ // 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);
+
+ $(selector).each(function(i, node) {
+ var rawNode = node.jQuery ? node[0] : node;
+ var componentInfo = registry.findComponentInfo(this)
+ if (componentInfo && componentInfo.isAttachedTo(rawNode)) {
+ //already attached
+ return;
+ }
+
+ 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*/) {
+ // 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];
+
+ Component.toString = function() {
+ var prettyPrintMixins = mixins.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 != "withBaseComponent") ? mixin.name : "";
+ }
+ }).filter(Boolean).join(', ');
+ return prettyPrintMixins;
+ };
+
+ if (window.DEBUG && window.DEBUG.enabled) {
+ Component.describe = Component.toString();
+ }
+
+ //'options' is optional hash to be merged with 'defaults' in the component definition
+ function Component(node, options) {
+ options = options || {};
+ 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);
+ }
+
+ this.toString = Component.toString;
+ if (window.DEBUG && window.DEBUG.enabled) {
+ this.describe = this.toString();
+ }
+
+ //merge defaults with supplied options
+ //put options in attr.__proto__ to avoid merge overhead
+ var attr = Object.create(options);
+ for (var key in this.defaults) {
+ if (!options.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);
+
+ this.initialize.call(this, options);
+ }
+
+ 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;
+ }
+);