Commit 82a5bac3 authored by Kostantinos Margaritis's avatar Kostantinos Margaritis Committed by Kostantinos Margaritis

Fix demo application link and twitter handle (README included). Add articles,...

Fix demo application link and twitter handle (README included). Add articles, guides, videos and community links. Add debug mode. Upgrade depot, flight, jQuery, requirejs and dev deps. Sync bower since some deps are aready upgraded but not depicted to bower.json. Adjust flight attributes to new api. Enabled debug mode for event 'visualisation' and ensuring only serialisable data are passed to components. Moved app to page folder. Introduced new paths for cleaner deps. Upgrade karma and deps. Update karma conf according to new dependencies. Replay paths to test-main and spec-dep paths. Update specs to new jasmine-flight api. Upgrade bower components.
parent c717579f
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
define([ define([
'flight/lib/component', 'flight/lib/component',
'../store' 'app/store'
], function (defineComponent, dataStore) { ], function (defineComponent, dataStore) {
function stats() { function stats() {
this.defaultAttrs({ this.attributes({
dataStore: dataStore dataStore: dataStore
}); });
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
define([ define([
'flight/lib/component', 'flight/lib/component',
'../store' 'app/store'
], function (defineComponent, dataStore) { ], function (defineComponent, dataStore) {
function todos() { function todos() {
var filter; var filter;
this.defaultAttrs({ this.attributes({
dataStore: dataStore dataStore: dataStore
}); });
......
/*global DEBUG */
'use strict'; 'use strict';
require.config({ require.config({
baseUrl: './', baseUrl: './',
paths: { paths: {
jquery: 'bower_components/jquery/jquery', jquery: 'bower_components/jquery/dist/jquery',
es5shim: 'bower_components/es5-shim/es5-shim', es5shim: 'bower_components/es5-shim/es5-shim',
es5sham: 'bower_components/es5-shim/es5-sham', es5sham: 'bower_components/es5-shim/es5-sham',
text: 'bower_components/requirejs-text/text', text: 'bower_components/requirejs-text/text',
flight: 'bower_components/flight', flight: 'bower_components/flight',
depot: 'bower_components/depot/depot' depot: 'bower_components/depot/depot',
app: 'app/js',
templates: 'app/templates',
ui: 'app/js/ui',
data: 'app/js/data',
}, },
shim: { shim: {
'app/js/app': { 'app/page/app': {
deps: ['jquery', 'es5shim', 'es5sham'] deps: ['jquery', 'es5shim', 'es5sham']
} }
} }
}); });
require(['app/js/app'], function (App) { require(['flight/lib/debug'], function (debug) {
debug.enable(true);
DEBUG.events.logAll();
require(['app/page/app'],function(App){
App.initialize(); App.initialize();
});
}); });
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
'use strict'; 'use strict';
define([ define([
'./data/todos', 'data/todos',
'./data/stats', 'data/stats',
'./ui/new_item', 'ui/new_item',
'./ui/todo_list', 'ui/todo_list',
'./ui/stats', 'ui/stats',
'./ui/main_selector', 'ui/main_selector',
'./ui/toggle_all' 'ui/toggle_all'
], function (TodosData, StatsData, NewItemUI, TodoListUI, StatsUI, MainSelectorUI, ToggleAllUI) { ], function (TodosData, StatsData, NewItemUI, TodoListUI, StatsUI, MainSelectorUI, ToggleAllUI) {
var initialize = function () { var initialize = function () {
StatsData.attachTo(document); StatsData.attachTo(document);
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
define([ define([
'flight/lib/component', 'flight/lib/component',
'./with_filters', './with_filters',
'text!app/templates/stats.html', 'text!templates/stats.html',
'../utils' 'app/utils'
], function (defineComponent, withFilters, statsTmpl, utils) { ], function (defineComponent, withFilters, statsTmpl, utils) {
function stats() { function stats() {
var template = utils.tmpl(statsTmpl); var template = utils.tmpl(statsTmpl);
this.defaultAttrs({ this.attributes({
clearCompletedSelector: '#clear-completed' clearCompletedSelector: '#clear-completed'
}); });
......
...@@ -3,14 +3,14 @@ ...@@ -3,14 +3,14 @@
define([ define([
'flight/lib/component', 'flight/lib/component',
'text!app/templates/todo.html', 'text!templates/todo.html',
'../utils' 'app/utils'
], function (defineComponent, todoTmpl, utils) { ], function (defineComponent, todoTmpl, utils) {
function todoList() { function todoList() {
var ENTER_KEY = 13; var ENTER_KEY = 13;
var template = utils.tmpl(todoTmpl); var template = utils.tmpl(todoTmpl);
this.defaultAttrs({ this.attributes({
destroySelector: 'button.destroy', destroySelector: 'button.destroy',
toggleSelector: 'input.toggle', toggleSelector: 'input.toggle',
labelSelector: 'label', labelSelector: 'label',
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
define(function () { define(function () {
return function withFilters() { return function withFilters() {
this.defaultAttrs({ this.attributes({
filterSelector: '#filters a' filterSelector: '#filters a'
}); });
......
...@@ -2,15 +2,15 @@ ...@@ -2,15 +2,15 @@
"name": "flight-todomvc", "name": "flight-todomvc",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"depot": "~0.1.4", "depot": "~0.1.6",
"flight": "~1.1.0", "flight": "~1.3.0",
"jquery": "1.8.3", "jquery": "2.1.0",
"requirejs": "~2.1.5", "requirejs": "~2.1.15",
"todomvc-common": "~0.3.0", "todomvc-common": "~0.3.0",
"requirejs-text": "~2.0.10" "requirejs-text": "~2.0.13"
}, },
"devDependencies": { "devDependencies": {
"jasmine-flight": "~2.1.0", "jasmine-flight": "~4.0.0",
"jasmine-jquery": "~1.5.8" "jasmine-jquery": "~2.0.5"
} }
} }
// ========================================== /* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define( define(
[ [
'./compose' './utils'
], ],
function(compose) { function(utils) {
'use strict'; 'use strict';
var advice = { var advice = {
...@@ -20,8 +16,9 @@ define( ...@@ -20,8 +16,9 @@ define(
// unpacking arguments by hand benchmarked faster // unpacking arguments by hand benchmarked faster
var i = 0, l = arguments.length, args = new Array(l + 1); var i = 0, l = arguments.length, args = new Array(l + 1);
args[0] = base.bind(this); args[0] = base.bind(this);
for (; i < l; i++) args[i + 1] = arguments[i]; for (; i < l; i++) {
args[i + 1] = arguments[i];
}
return wrapped.apply(this, args); return wrapped.apply(this, args);
}; };
}, },
...@@ -49,7 +46,7 @@ define( ...@@ -49,7 +46,7 @@ define(
['before', 'after', 'around'].forEach(function(m) { ['before', 'after', 'around'].forEach(function(m) {
this[m] = function(method, fn) { this[m] = function(method, fn) {
compose.unlockProperty(this, method, function() { utils.mutateProperty(this, method, function() {
if (typeof this[method] == 'function') { if (typeof this[method] == 'function') {
this[method] = advice[m](this[method], fn); this[method] = advice[m](this[method], fn);
} else { } else {
......
// ========================================== /* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define( define(
...@@ -19,7 +15,7 @@ define( ...@@ -19,7 +15,7 @@ define(
// callback context is bound to component // callback context is bound to component
var componentId = 0; var componentId = 0;
function teardownInstance(instanceInfo){ function teardownInstance(instanceInfo) {
instanceInfo.events.slice().forEach(function(event) { instanceInfo.events.slice().forEach(function(event) {
var args = [event.type]; var args = [event.type];
...@@ -33,7 +29,7 @@ define( ...@@ -33,7 +29,7 @@ define(
function checkSerializable(type, data) { function checkSerializable(type, data) {
try { try {
window.postMessage(data, '*'); window.postMessage(data, '*');
} catch(e) { } catch (e) {
console.log('unserializable data for event',type,':',data); console.log('unserializable data for event',type,':',data);
throw new Error( throw new Error(
['The event', type, 'on component', this.toString(), 'was triggered with non-serializable data'].join(' ') ['The event', type, 'on component', this.toString(), 'was triggered with non-serializable data'].join(' ')
...@@ -41,6 +37,64 @@ define( ...@@ -41,6 +37,64 @@ define(
} }
} }
function initAttributes(attrs) {
var definedKeys = [], incomingKeys;
this.attr = new this.attrDef;
if (debug.enabled && window.console) {
for (var key in this.attrDef.prototype) {
definedKeys.push(key);
}
incomingKeys = Object.keys(attrs);
for (var i = incomingKeys.length - 1; i >= 0; i--) {
if (definedKeys.indexOf(incomingKeys[i]) == -1) {
console.warn('Passed unused attributes including "' + incomingKeys[i] +
'" to component "' + this.toString() + '".');
break;
}
}
}
for (var key in this.attrDef.prototype) {
if (typeof attrs[key] == 'undefined') {
if (this.attr[key] === null) {
throw new Error('Required attribute "' + key +
'" not specified in attachTo for component "' + this.toString() + '".');
}
} else {
this.attr[key] = attrs[key];
}
if (typeof this.attr[key] == 'function') {
this.attr[key] = this.attr[key].call(this);
}
}
}
function initDeprecatedAttributes(attrs) {
// 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);
}
function proxyEventTo(targetEvent) { function proxyEventTo(targetEvent) {
return function(e, data) { return function(e, data) {
$(e.target).trigger(targetEvent, data); $(e.target).trigger(targetEvent, data);
...@@ -90,12 +144,13 @@ define( ...@@ -90,12 +144,13 @@ define(
$element.trigger((event || type), data); $element.trigger((event || type), data);
if (defaultFn && !event.isDefaultPrevented()) { if (defaultFn && !event.isDefaultPrevented()) {
(this[defaultFn] || defaultFn).call(this); (this[defaultFn] || defaultFn).call(this, event, data);
} }
return $element; return $element;
}; };
this.on = function() { this.on = function() {
var $element, type, callback, originalCb; var $element, type, callback, originalCb;
var lastIndex = arguments.length - 1, origin = arguments[lastIndex]; var lastIndex = arguments.length - 1, origin = arguments[lastIndex];
...@@ -120,7 +175,8 @@ define( ...@@ -120,7 +175,8 @@ define(
} }
if (typeof originalCb != 'function' && typeof originalCb != 'object') { 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'); throw new Error('Unable to bind to "' + type +
'" because the given callback is not a function or an object');
} }
callback = originalCb.bind(this); callback = originalCb.bind(this);
...@@ -164,9 +220,18 @@ define( ...@@ -164,9 +220,18 @@ define(
return true; return true;
} }
}, this); }, this);
$element.off(type, callback);
} else {
// Loop through the events of `this` instance
// and unbind using the callback
registry.findInstanceInfo(this).events.forEach(function (event) {
if (type == event.type) {
$element.off(type, event.callback);
}
});
} }
return $element.off(type, callback); return $element;
}; };
this.resolveDelegateRules = function(ruleInfo) { this.resolveDelegateRules = function(ruleInfo) {
...@@ -182,17 +247,35 @@ define( ...@@ -182,17 +247,35 @@ define(
return rules; return rules;
}; };
this.defaultAttrs = function(defaults) {
utils.push(this.defaults, defaults, true) || (this.defaults = defaults);
};
this.select = function(attributeKey) { this.select = function(attributeKey) {
return this.$node.find(this.attr[attributeKey]); return this.$node.find(this.attr[attributeKey]);
}; };
// New-style attributes
this.attributes = function(attrs) {
var Attributes = function() {};
if (this.attrDef) {
Attributes.prototype = new this.attrDef;
}
for (var name in attrs) {
Attributes.prototype[name] = attrs[name];
}
this.attrDef = Attributes;
};
// Deprecated attributes
this.defaultAttrs = function(defaults) {
utils.push(this.defaults, defaults, true) || (this.defaults = defaults);
};
this.initialize = function(node, attrs) { this.initialize = function(node, attrs) {
attrs || (attrs = {}); attrs = attrs || {};
//only assign identity if there isn't one (initialize can be called multiple times)
this.identity || (this.identity = componentId++); this.identity || (this.identity = componentId++);
if (!node) { if (!node) {
...@@ -207,22 +290,11 @@ define( ...@@ -207,22 +290,11 @@ define(
this.$node = $(node); this.$node = $(node);
} }
// merge defaults with supplied options if (this.attrDef) {
// put options in attr.__proto__ to avoid merge overhead initAttributes.call(this, attrs);
var attr = Object.create(attrs); } else {
for (var key in this.defaults) { initDeprecatedAttributes.call(this, attrs);
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; return this;
}; };
......
// ========================================== /* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define( define(
...@@ -35,22 +31,13 @@ define( ...@@ -35,22 +31,13 @@ define(
}); });
} }
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 */) { function attachTo(selector/*, options args */) {
// unpacking arguments by hand benchmarked faster // unpacking arguments by hand benchmarked faster
var l = arguments.length; var l = arguments.length;
var args = new Array(l - 1); var args = new Array(l - 1);
for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; for (var i = 1; i < l; i++) {
args[i - 1] = arguments[i];
}
if (!selector) { if (!selector) {
throw new Error('Component needs to be attachTo\'d a jQuery object, native node or selector string'); throw new Error('Component needs to be attachTo\'d a jQuery object, native node or selector string');
...@@ -91,7 +78,9 @@ define( ...@@ -91,7 +78,9 @@ define(
// unpacking arguments by hand benchmarked faster // unpacking arguments by hand benchmarked faster
var l = arguments.length; var l = arguments.length;
var mixins = new Array(l); var mixins = new Array(l);
for (var i = 0; i < l; i++) mixins[i] = arguments[i]; for (var i = 0; i < l; i++) {
mixins[i] = arguments[i];
}
var Component = function() {}; var Component = function() {};
...@@ -107,6 +96,8 @@ define( ...@@ -107,6 +96,8 @@ define(
var newComponent = define(); //TODO: fix pretty print var newComponent = define(); //TODO: fix pretty print
var newPrototype = Object.create(Component.prototype); var newPrototype = Object.create(Component.prototype);
newPrototype.mixedIn = [].concat(Component.prototype.mixedIn); newPrototype.mixedIn = [].concat(Component.prototype.mixedIn);
newPrototype.defaults = utils.merge(Component.prototype.defaults);
newPrototype.attrDef = Component.prototype.attrDef;
compose.mixin(newPrototype, arguments); compose.mixin(newPrototype, arguments);
newComponent.prototype = newPrototype; newComponent.prototype = newPrototype;
newComponent.prototype.constructor = newComponent; newComponent.prototype.constructor = newComponent;
......
// ========================================== /* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define( define(
[ [
'./utils', './utils'
'./debug'
], ],
function(utils, debug) { function(utils) {
'use strict'; 'use strict';
//enumerables are shims - getOwnPropertyDescriptor shim doesn't work var dontLock = ['mixedIn', 'attrDef'];
var canWriteProtect = debug.enabled && !utils.isEnumerable(Object, 'getOwnPropertyDescriptor');
//whitelist of unlockable property names
var dontLock = ['mixedIn'];
if (canWriteProtect) { function setWritability(obj, writable) {
//IE8 getOwnPropertyDescriptor is built-in but throws exeption on non DOM objects Object.keys(obj).forEach(function (key) {
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) { if (dontLock.indexOf(key) < 0) {
var desc = Object.getOwnPropertyDescriptor(obj, key); utils.propertyWritability(obj, key, writable);
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) { function mixin(base, mixins) {
base.mixedIn = base.hasOwnProperty('mixedIn') ? base.mixedIn : []; base.mixedIn = base.hasOwnProperty('mixedIn') ? base.mixedIn : [];
for (var i=0; i<mixins.length; i++) { for (var i = 0; i < mixins.length; i++) {
if (base.mixedIn.indexOf(mixins[i]) == -1) { if (base.mixedIn.indexOf(mixins[i]) == -1) {
setPropertyWritability(base, false); setWritability(base, false);
mixins[i].call(base); mixins[i].call(base);
base.mixedIn.push(mixins[i]); base.mixedIn.push(mixins[i]);
} }
} }
setPropertyWritability(base, true); setWritability(base, true);
} }
return { return {
mixin: mixin, mixin: mixin
unlockProperty: unlockProperty
}; };
} }
......
// ========================================== /* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define( define(
[], ['./registry'],
function() { function(registry) {
'use strict'; 'use strict';
// ========================================== // ==========================================
...@@ -18,10 +14,10 @@ define( ...@@ -18,10 +14,10 @@ define(
function traverse(util, searchTerm, options) { function traverse(util, searchTerm, options) {
options = options || {}; options = options || {};
var obj = options.obj || window; var obj = options.obj || window;
var path = options.path || ((obj==window) ? 'window' : ''); var path = options.path || ((obj == window) ? 'window' : '');
var props = Object.keys(obj); var props = Object.keys(obj);
props.forEach(function(prop) { props.forEach(function(prop) {
if ((tests[util] || util)(searchTerm, obj, prop)){ if ((tests[util] || util)(searchTerm, obj, prop)) {
console.log([path, '.', prop].join(''), '->', ['(', typeof obj[prop], ')'].join(''), 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) { if (Object.prototype.toString.call(obj[prop]) == '[object Object]' && (obj[prop] != obj) && path.split('.').indexOf(prop) == -1) {
...@@ -107,7 +103,7 @@ define( ...@@ -107,7 +103,7 @@ define(
try { try {
eventNames = (window.localStorage && localStorage.getItem('logFilter_eventNames')); eventNames = (window.localStorage && localStorage.getItem('logFilter_eventNames'));
actions = (window.localStorage && localStorage.getItem('logFilter_actions')); actions = (window.localStorage && localStorage.getItem('logFilter_actions'));
} catch(ignored) { } catch (ignored) {
return; return;
} }
eventNames && (logFilter.eventNames = eventNames); eventNames && (logFilter.eventNames = eventNames);
...@@ -137,6 +133,8 @@ define( ...@@ -137,6 +133,8 @@ define(
window.DEBUG = this; window.DEBUG = this;
}, },
registry: registry,
find: { find: {
byName: byName, byName: byName,
byNameContains: byNameContains, byNameContains: byNameContains,
......
// ==========================================
// 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
};
}
);
// ========================================== /* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define( define(
...@@ -27,10 +23,12 @@ define( ...@@ -27,10 +23,12 @@ define(
} }
function log(action, component, eventArgs) { function log(action, component, eventArgs) {
if (!window.DEBUG || !window.DEBUG.enabled) return; if (!window.DEBUG || !window.DEBUG.enabled) {
return;
}
var name, eventType, elem, fn, payload, logFilter, toRegExp, actionLoggable, nameLoggable, info; var name, eventType, elem, fn, payload, logFilter, toRegExp, actionLoggable, nameLoggable, info;
if (typeof eventArgs[eventArgs.length-1] == 'function') { if (typeof eventArgs[eventArgs.length - 1] == 'function') {
fn = eventArgs.pop(); fn = eventArgs.pop();
fn = fn.unbound || fn; // use unbound version if any (better info) fn = fn.unbound || fn; // use unbound version if any (better info)
} }
......
// ========================================== /* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define( define(
...@@ -120,8 +116,6 @@ define( ...@@ -120,8 +116,6 @@ define(
}; };
this.removeInstance = function(instance) { this.removeInstance = function(instance) {
var index, instInfo = this.findInstanceInfo(instance);
//remove from component info //remove from component info
var componentInfo = this.findComponentInfo(instance); var componentInfo = this.findComponentInfo(instance);
componentInfo && componentInfo.removeInstance(instance); componentInfo && componentInfo.removeInstance(instance);
...@@ -174,12 +168,14 @@ define( ...@@ -174,12 +168,14 @@ define(
// unpacking arguments by hand benchmarked faster // unpacking arguments by hand benchmarked faster
var l = arguments.length, i = 1; var l = arguments.length, i = 1;
var otherArgs = new Array(l - 1); var otherArgs = new Array(l - 1);
for (; i < l; i++) otherArgs[i - 1] = arguments[i]; for (; i < l; i++) {
otherArgs[i - 1] = arguments[i];
}
if (instance) { if (instance) {
boundCallback = componentOn.apply(null, otherArgs); boundCallback = componentOn.apply(null, otherArgs);
if (boundCallback) { if (boundCallback) {
otherArgs[otherArgs.length-1] = boundCallback; otherArgs[otherArgs.length - 1] = boundCallback;
} }
var event = parseEventArgs(this, otherArgs); var event = parseEventArgs(this, otherArgs);
instance.addBind(event); instance.addBind(event);
......
// ========================================== /* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define( define(
[], ['./debug'],
function() { function(debug) {
'use strict'; 'use strict';
var arry = [];
var DEFAULT_INTERVAL = 100; var DEFAULT_INTERVAL = 100;
function canWriteProtect() {
var writeProtectSupported = debug.enabled && !Object.propertyIsEnumerable('getOwnPropertyDescriptor');
if (writeProtectSupported) {
//IE8 getOwnPropertyDescriptor is built-in but throws exeption on non DOM objects
try {
Object.getOwnPropertyDescriptor(Object, 'keys');
} catch (e) {
return false;
}
}
return writeProtectSupported;
}
var utils = { var utils = {
isDomObj: function(obj) { isDomObj: function(obj) {
...@@ -21,7 +30,12 @@ define( ...@@ -21,7 +30,12 @@ define(
}, },
toArray: function(obj, from) { toArray: function(obj, from) {
return arry.slice.call(obj, from); from = from || 0;
var len = obj.length, arr = new Array(len - from);
for (var i = from; i < len; i++) {
arr[i - from] = obj[i];
}
return arr;
}, },
// returns new object representing multiple objects merged together // returns new object representing multiple objects merged together
...@@ -48,14 +62,16 @@ define( ...@@ -48,14 +62,16 @@ define(
merge: function(/*obj1, obj2,....deepCopy*/) { merge: function(/*obj1, obj2,....deepCopy*/) {
// unpacking arguments by hand benchmarked faster // unpacking arguments by hand benchmarked faster
var l = arguments.length, var l = arguments.length,
i = 0,
args = new Array(l + 1); args = new Array(l + 1);
for (; i < l; i++) args[i + 1] = arguments[i];
if (l === 0) { if (l === 0) {
return {}; return {};
} }
for (var i = 0; i < l; i++) {
args[i + 1] = arguments[i];
}
//start with empty object so a copy is created //start with empty object so a copy is created
args[0] = {}; args[0] = {};
...@@ -107,8 +123,10 @@ define( ...@@ -107,8 +123,10 @@ define(
return base; return base;
}, },
isEnumerable: function(obj, property) { // If obj.key points to an enumerable property, return its value
return Object.keys(obj).indexOf(property) > -1; // If obj.key points to a non-enumerable property, return undefined
getEnumerableProperty: function(obj, key) {
return obj.propertyIsEnumerable(key) ? obj[key] : undefined;
}, },
// build a function from other function(s) // build a function from other function(s)
...@@ -120,7 +138,7 @@ define( ...@@ -120,7 +138,7 @@ define(
return function() { return function() {
var args = arguments; var args = arguments;
for (var i = funcs.length-1; i >= 0; i--) { for (var i = funcs.length - 1; i >= 0; i--) {
args = [funcs[i].apply(this, args)]; args = [funcs[i].apply(this, args)];
} }
...@@ -161,7 +179,7 @@ define( ...@@ -161,7 +179,7 @@ define(
}; };
var callNow = immediate && !timeout; var callNow = immediate && !timeout;
clearTimeout(timeout); timeout && clearTimeout(timeout);
timeout = setTimeout(later, wait); timeout = setTimeout(later, wait);
if (callNow) { if (callNow) {
...@@ -178,7 +196,7 @@ define( ...@@ -178,7 +196,7 @@ define(
} }
var context, args, timeout, throttling, more, result; var context, args, timeout, throttling, more, result;
var whenDone = this.debounce(function(){ var whenDone = this.debounce(function() {
more = throttling = false; more = throttling = false;
}, wait); }, wait);
...@@ -254,6 +272,29 @@ define( ...@@ -254,6 +272,29 @@ define(
return result; return result;
}; };
},
propertyWritability: function(obj, prop, writable) {
if (canWriteProtect() && obj.hasOwnProperty(prop)) {
Object.defineProperty(obj, prop, { writable: writable });
}
},
// Property locking/unlocking
mutateProperty: function(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 });
} }
}; };
......
This diff is collapsed.
This diff is collapsed.
/** /**
* @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * @license RequireJS text 2.0.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/requirejs/text for details * see: http://github.com/requirejs/text for details
*/ */
...@@ -23,7 +23,7 @@ define(['module'], function (module) { ...@@ -23,7 +23,7 @@ define(['module'], function (module) {
masterConfig = (module.config && module.config()) || {}; masterConfig = (module.config && module.config()) || {};
text = { text = {
version: '2.0.12', version: '2.0.13',
strip: function (content) { strip: function (content) {
//Strips <?xml ...?> declarations so that external SVG and XML //Strips <?xml ...?> declarations so that external SVG and XML
...@@ -85,13 +85,13 @@ define(['module'], function (module) { ...@@ -85,13 +85,13 @@ define(['module'], function (module) {
parseName: function (name) { parseName: function (name) {
var modName, ext, temp, var modName, ext, temp,
strip = false, strip = false,
index = name.indexOf("."), index = name.lastIndexOf("."),
isRelative = name.indexOf('./') === 0 || isRelative = name.indexOf('./') === 0 ||
name.indexOf('../') === 0; name.indexOf('../') === 0;
if (index !== -1 && (!isRelative || index > 1)) { if (index !== -1 && (!isRelative || index > 1)) {
modName = name.substring(0, index); modName = name.substring(0, index);
ext = name.substring(index + 1, name.length); ext = name.substring(index + 1);
} else { } else {
modName = name; modName = name;
} }
...@@ -252,7 +252,7 @@ define(['module'], function (module) { ...@@ -252,7 +252,7 @@ define(['module'], function (module) {
try { try {
var file = fs.readFileSync(url, 'utf8'); var file = fs.readFileSync(url, 'utf8');
//Remove BOM (Byte Mark Order) from utf8 files if it is there. //Remove BOM (Byte Mark Order) from utf8 files if it is there.
if (file.indexOf('\uFEFF') === 0) { if (file[0] === '\uFEFF') {
file = file.substring(1); file = file.substring(1);
} }
callback(file); callback(file);
......
/** vim: et:ts=4:sw=4:sts=4 /** vim: et:ts=4:sw=4:sts=4
* @license RequireJS 2.1.11 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * @license RequireJS 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
...@@ -12,7 +12,7 @@ var requirejs, require, define; ...@@ -12,7 +12,7 @@ var requirejs, require, define;
(function (global) { (function (global) {
var req, s, head, baseElement, dataMain, src, var req, s, head, baseElement, dataMain, src,
interactiveScript, currentlyAddingScript, mainScript, subPath, interactiveScript, currentlyAddingScript, mainScript, subPath,
version = '2.1.11', version = '2.1.15',
commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
jsSuffixRegExp = /\.js$/, jsSuffixRegExp = /\.js$/,
...@@ -180,7 +180,7 @@ var requirejs, require, define; ...@@ -180,7 +180,7 @@ var requirejs, require, define;
if (typeof requirejs !== 'undefined') { if (typeof requirejs !== 'undefined') {
if (isFunction(requirejs)) { if (isFunction(requirejs)) {
//Do not overwrite and existing requirejs instance. //Do not overwrite an existing requirejs instance.
return; return;
} }
cfg = requirejs; cfg = requirejs;
...@@ -232,21 +232,20 @@ var requirejs, require, define; ...@@ -232,21 +232,20 @@ var requirejs, require, define;
* @param {Array} ary the array of path segments. * @param {Array} ary the array of path segments.
*/ */
function trimDots(ary) { function trimDots(ary) {
var i, part, length = ary.length; var i, part;
for (i = 0; i < length; i++) { for (i = 0; i < ary.length; i++) {
part = ary[i]; part = ary[i];
if (part === '.') { if (part === '.') {
ary.splice(i, 1); ary.splice(i, 1);
i -= 1; i -= 1;
} else if (part === '..') { } else if (part === '..') {
if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { // If at the start, or previous value is still ..,
//End of the line. Keep at least one non-dot // keep them so that when converted to a path it may
//path segment at the front so it can be mapped // still work when converted to a path, even though
//correctly to disk. Otherwise, there is likely // as an ID it is less than ideal. In larger point
//no path mapping for a path starting with '..'. // releases, may be better to just kick out an error.
//This can still fail, but catches the most reasonable if (i === 0 || (i == 1 && ary[2] === '..') || ary[i - 1] === '..') {
//uses of .. continue;
break;
} else if (i > 0) { } else if (i > 0) {
ary.splice(i - 1, 2); ary.splice(i - 1, 2);
i -= 2; i -= 2;
...@@ -267,24 +266,13 @@ var requirejs, require, define; ...@@ -267,24 +266,13 @@ var requirejs, require, define;
*/ */
function normalize(name, baseName, applyMap) { function normalize(name, baseName, applyMap) {
var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex, var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex,
foundMap, foundI, foundStarMap, starI, foundMap, foundI, foundStarMap, starI, normalizedBaseParts,
baseParts = baseName && baseName.split('/'), baseParts = (baseName && baseName.split('/')),
normalizedBaseParts = baseParts,
map = config.map, map = config.map,
starMap = map && map['*']; starMap = map && map['*'];
//Adjust any relative paths. //Adjust any relative paths.
if (name && name.charAt(0) === '.') { if (name) {
//If have a base name, try to normalize against it,
//otherwise, assume it is a top-level require that will
//be relative to baseUrl in the end.
if (baseName) {
//Convert baseName to array, and lop off the last part,
//so that . matches that 'directory' and not name of the baseName's
//module. For instance, baseName of 'one/two/three', maps to
//'one/two/three.js', but we want the directory, 'one/two' for
//this normalization.
normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
name = name.split('/'); name = name.split('/');
lastIndex = name.length - 1; lastIndex = name.length - 1;
...@@ -296,14 +284,19 @@ var requirejs, require, define; ...@@ -296,14 +284,19 @@ var requirejs, require, define;
name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
} }
// Starts with a '.' so need the baseName
if (name[0].charAt(0) === '.' && baseParts) {
//Convert baseName to array, and lop off the last part,
//so that . matches that 'directory' and not name of the baseName's
//module. For instance, baseName of 'one/two/three', maps to
//'one/two/three.js', but we want the directory, 'one/two' for
//this normalization.
normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
name = normalizedBaseParts.concat(name); name = normalizedBaseParts.concat(name);
}
trimDots(name); trimDots(name);
name = name.join('/'); name = name.join('/');
} else if (name.indexOf('./') === 0) {
// No baseName, so this is ID is resolved relative
// to baseUrl, pull off the leading dot.
name = name.substring(2);
}
} }
//Apply map config if available. //Apply map config if available.
...@@ -379,7 +372,13 @@ var requirejs, require, define; ...@@ -379,7 +372,13 @@ var requirejs, require, define;
//retry //retry
pathConfig.shift(); pathConfig.shift();
context.require.undef(id); context.require.undef(id);
context.require([id]);
//Custom require that does not do map translation, since
//ID is "absolute", already mapped/resolved.
context.makeRequire(null, {
skipMap: true
})([id]);
return true; return true;
} }
} }
...@@ -445,7 +444,16 @@ var requirejs, require, define; ...@@ -445,7 +444,16 @@ var requirejs, require, define;
return normalize(name, parentName, applyMap); return normalize(name, parentName, applyMap);
}); });
} else { } else {
normalizedName = normalize(name, parentName, applyMap); // If nested plugin references, then do not try to
// normalize, as it will not normalize correctly. This
// places a restriction on resourceIds, and the longer
// term solution is not to normalize until plugins are
// loaded and all normalizations to allow for async
// loading of a loader plugin. But for now, fixes the
// common uses. Details in #1131
normalizedName = name.indexOf('!') === -1 ?
normalize(name, parentName, applyMap) :
name;
} }
} else { } else {
//A regular module. //A regular module.
......
...@@ -17,12 +17,13 @@ module.exports = function (config) { ...@@ -17,12 +17,13 @@ module.exports = function (config) {
// loaded without require // loaded without require
'bower_components/es5-shim/es5-shim.js', 'bower_components/es5-shim/es5-shim.js',
'bower_components/es5-shim/es5-sham.js', 'bower_components/es5-shim/es5-sham.js',
'bower_components/jquery/jquery.js',
'bower_components/jasmine-flight/lib/jasmine-flight.js', 'bower_components/jquery/dist/jquery.js',
'bower_components/jasmine-jquery/lib/jasmine-jquery.js', 'bower_components/jasmine-jquery/lib/jasmine-jquery.js',
'bower_components/jasmine-flight/lib/jasmine-flight.js',
// hack to load RequireJS after the shim libs // hack to load RequireJS after the shim libs
'node_modules/karma-requirejs/lib/require.js', 'node_modules/requirejs/require.js',
'node_modules/karma-requirejs/lib/adapter.js', 'node_modules/karma-requirejs/lib/adapter.js',
// loaded with require // loaded with require
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
"name": "flight-todomvc", "name": "flight-todomvc",
"version": "0.0.0", "version": "0.0.0",
"devDependencies": { "devDependencies": {
"karma": "~0.10.1", "karma": "~0.12.6",
"karma-jasmine": "~0.1.0", "karma-jasmine": "~0.2.0",
"karma-requirejs": "~0.1.0", "karma-requirejs": "~0.2.2",
"karma-chrome-launcher": "~0.1.0", "karma-chrome-launcher": "~0.1.0",
"karma-ie-launcher": "~0.1.1", "karma-ie-launcher": "~0.1.1",
"karma-firefox-launcher": "~0.1.0", "karma-firefox-launcher": "~0.1.0",
......
...@@ -12,9 +12,9 @@ The [Flight website](http://flightjs.github.io) is a great resource for getting ...@@ -12,9 +12,9 @@ The [Flight website](http://flightjs.github.io) is a great resource for getting
Here are some links you may find helpful: Here are some links you may find helpful:
* [GitHub](https://github.com/flightjs/flight) * [GitHub](https://github.com/flightjs/flight)
* [Demo Application](http://twitter.github.io/flight/demo) * [Demo Application](http://flightjs.github.io/example-app/)
* [Installation](https://github.com/flightjs/flight/blob/master/README.md#installation) * [Installation](https://github.com/flightjs/flight/blob/master/README.md#installation)
* [Flight on Twitter](http://twitter.com/flight) * [Flight on Twitter](https://twitter.com/flightjs)
_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
......
describeComponent('app/js/data/stats', function () { describeComponent('data/stats', function () {
'use strict'; 'use strict';
describe('recount without datastore', function () { describe('recount without datastore', function () {
beforeEach(function () { beforeEach(function () {
setupComponent({ this.setupComponent({
dataStore: new mocks.DataStore([]) dataStore: new mocks.DataStore([])
}); });
}); });
...@@ -38,7 +38,7 @@ describeComponent('app/js/data/stats', function () { ...@@ -38,7 +38,7 @@ describeComponent('app/js/data/stats', function () {
describe('recount with datastore', function () { describe('recount with datastore', function () {
beforeEach(function () { beforeEach(function () {
setupComponent({ this.setupComponent({
dataStore: new mocks.DataStore() dataStore: new mocks.DataStore()
}); });
}); });
......
describeComponent('app/js/data/todos', function () { describeComponent('data/todos', function () {
'use strict'; 'use strict';
describe('without datastore', function () { describe('without datastore', function () {
beforeEach(function () { beforeEach(function () {
this.dataStore = new mocks.DataStore([]); this.dataStore = new mocks.DataStore([]);
setupComponent({ this.setupComponent({
dataStore: this.dataStore dataStore: this.dataStore
}); });
}); });
...@@ -26,7 +26,7 @@ describeComponent('app/js/data/todos', function () { ...@@ -26,7 +26,7 @@ describeComponent('app/js/data/todos', function () {
describe('with datastore', function () { describe('with datastore', function () {
beforeEach(function () { beforeEach(function () {
this.dataStore = new mocks.DataStore(); this.dataStore = new mocks.DataStore();
setupComponent({ this.setupComponent({
dataStore: this.dataStore dataStore: this.dataStore
}); });
}); });
......
describeComponent('app/js/ui/new_item', function () { describeComponent('ui/new_item', function () {
'use strict'; 'use strict';
var ENTER_KEY = 13; var ENTER_KEY = 13;
beforeEach(function () { beforeEach(function () {
setupComponent(readFixtures('new_todo.html')); this.setupComponent(readFixtures('new_todo.html'));
}); });
it('triggers uiAddRequested on enter', function () { it('triggers uiAddRequested on enter', function () {
......
describeComponent('app/js/ui/stats', function () { describeComponent('ui/stats', function () {
'use strict'; 'use strict';
beforeEach(function () { beforeEach(function () {
setupComponent(readFixtures('footer.html')); this.setupComponent(readFixtures('footer.html'));
}); });
it('renders when stats change', function () { it('renders when stats change', function () {
......
describeComponent('app/js/ui/toggle_all', function () { describeComponent('ui/toggle_all', function () {
'use strict'; 'use strict';
beforeEach(function () { beforeEach(function () {
setupComponent(readFixtures('toggle_all.html')); this.setupComponent(readFixtures('toggle_all.html'));
}); });
it('check the checkbox w/o remaining', function () { it('check the checkbox w/o remaining', function () {
......
...@@ -15,7 +15,11 @@ requirejs.config({ ...@@ -15,7 +15,11 @@ requirejs.config({
paths: { paths: {
flight: 'bower_components/flight', flight: 'bower_components/flight',
depot: 'bower_components/depot/depot', depot: 'bower_components/depot/depot',
text: 'bower_components/requirejs-text/text' text: 'bower_components/requirejs-text/text',
ui: 'app/js/ui',
data: 'app/js/data',
app: 'app/js',
templates: 'app/templates'
}, },
// ask Require.js to load these files (all our tests) // ask Require.js to load these files (all our tests)
......
...@@ -1099,13 +1099,64 @@ ...@@ -1099,13 +1099,64 @@
"url": "https://github.com/flightjs/flight" "url": "https://github.com/flightjs/flight"
}, { }, {
"name": "Demo Application", "name": "Demo Application",
"url": "http://twitter.github.io/flight/demo/" "url": "http://flightjs.github.io/example-app/"
}, { }, {
"name": "Installation", "name": "Installation",
"url": "https://github.com/flightjs/flight/blob/master/README.md#installation" "url": "https://github.com/flightjs/flight/blob/master/README.md#installation"
}, {
"name": "Collection of Flight components",
"url": "http://flight-components.jit.su/"
}, { }, {
"name": "Flight on Twitter", "name": "Flight on Twitter",
"url": "http://twitter.com/flight" "url": "https://twitter.com/flightjs"
}]
}, {
"heading": "Articles and Guides",
"links": [{
"name": "Introducing Flight: a web application framework",
"url": "https://blog.twitter.com/2013/introducing-flight-a-web-application-framework"
}, {
"name": "Building Web Applications with Flight",
"url": "http://simplebutgood.net/building-web-applications-with-flight-part-1/"
}, {
"name": "Building a chat app with @flight",
"url": "http://blog.stefanritter.com/post/81767869139/building-a-chat-app-with-flight-part-1"
}, {
"name": "Redesigning Search at Airbnb",
"url": "http://nerds.airbnb.com/redesigning-search/"
}, {
"name": "Flight Mixins",
"url": "http://kenneth.kufluk.com/blog/2014/01/flight-mixins/"
}, {
"name": "Flight at TweetDeck",
"url": "https://blog.twitter.com/2013/flight-at-tweetdeck"
}, {
"name": "How Flight Plays Well With non-Flight JS",
"url": "http://www.retailmenot.com/corp/eng/posts/2014/08/28/how-flight-plays-well-with-non-flight-js/"
}, {
"name": "Learning to Fly — Twitter Flight and Mixins",
"url": "https://speakerdeck.com/anguscroll/learning-to-fly-twitter-flight-and-mixins-1"
}]
}, {
"heading":"Videos",
"links":[{
"name": "Dan Webb: Flight.js [JSConfUS 2013]",
"url": "https://www.youtube.com/watch?v=4WRmFp8jZjc"
}, {
"name": "MountainWest JavaScript 2014",
"url": "https://www.youtube.com/watch?v=PrcvUZGuUa8"
}]
}, {
"heading": "Community",
"links": [{
"name": "Stack Overflow",
"url": "http://stackoverflow.com/questions/tagged/twitter-flight"
}, {
"name": "Flight's Google Group",
"url": "https://groups.google.com/forum/?fromgroups#!forum/twitter-flight"
}, {
"name": "Flight on Freenode IRC (#flightjs)",
"url": "http://webchat.freenode.net/?channels=flightjs"
}] }]
}] }]
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment