You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.4 KiB
136 lines
4.4 KiB
// ========================================== |
|
// 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; |
|
} |
|
);
|
|
|