diff --git a/labs/architecture-examples/cujo/README.md b/labs/architecture-examples/cujo/README.md index 9ac6038f0b..70251c450b 100644 --- a/labs/architecture-examples/cujo/README.md +++ b/labs/architecture-examples/cujo/README.md @@ -1,12 +1,12 @@ -# Cujojs TodoMVC +# cujoJS TodoMVC -[Cujojs](http://cujojs.com) is an *architectural framework* for building highly modular, scalable, maintainable applications in Javascript. It provides architectural plumbing, such as modules (AMD and CommonJS), declarative application composition, declarative connections, and aspect oriented programming. +[cujoJS](http://cujojs.com) is an *architectural framework* for building highly modular, scalable, maintainable applications in Javascript. It provides architectural plumbing, such as modules (AMD and CommonJS), declarative application composition, declarative connections, and aspect oriented programming. It is not a typical MV\* framework, although it does provide MV\* building blocks, such as templating and data binding. ## Highlights: -Some things we feel are interesting about cujojs's TodoMVC as compared to other implementations: +Some things we feel are interesting about cujoJS's TodoMVC as compared to other implementations: * Application composition is separate from application logic * Code is *highly* modular and organized into components, each consisting of diff --git a/labs/architecture-examples/cujo/TODO.md b/labs/architecture-examples/cujo/TODO.md index 740c146e73..924f679081 100644 --- a/labs/architecture-examples/cujo/TODO.md +++ b/labs/architecture-examples/cujo/TODO.md @@ -3,5 +3,3 @@ TODO before release * implement filters (using routing or another method) * build javascript using cram.js -* use curl's preloads feature rather than .next() in run.js -* use a theme.css file diff --git a/labs/architecture-examples/cujo/app/controller.js b/labs/architecture-examples/cujo/app/controller.js index cbfef69bb8..65ef9d44c5 100644 --- a/labs/architecture-examples/cujo/app/controller.js +++ b/labs/architecture-examples/cujo/app/controller.js @@ -2,25 +2,25 @@ define(function () { 'use strict'; - var textProp; + var textProp, updateRemainingCount; /** * Self-optimizing function to set the text of a node */ - var updateRemainingCount = function () { + updateRemainingCount = function (nodes, value) { // sniff for proper textContent property textProp = 'textContent' in document.documentElement ? 'textContent' : 'innerText'; // resume normally updateRemainingCount = setTextProp; - updateRemainingCount(arguments); + updateRemainingCount(nodes, value); }; - var setTextProp = function (nodes, value) { + function setTextProp(nodes, value) { for (var i = 0; i < nodes.length; i++) { nodes[i][textProp] = '' + value; } - }; + } return { /** @@ -84,8 +84,10 @@ define(function () { * Check/uncheck all todos */ toggleAll: function () { - var todos = this.todos; - var complete = this.masterCheckbox.checked; + var todos, complete; + + todos = this.todos; + complete = this.masterCheckbox.checked; todos.forEach(function (todo) { todo.complete = complete; @@ -99,8 +101,10 @@ define(function () { * checked or unchecked. */ updateCount: function () { - var total = 0; - var checked = 0; + var total, checked; + + total = 0; + checked = 0; this.todos.forEach(function (todo) { total++; @@ -128,4 +132,5 @@ define(function () { updateRemainingCount(this.remainingNodes, remaining); } }; + }); diff --git a/labs/architecture-examples/cujo/app/footer/template.html b/labs/architecture-examples/cujo/app/footer/template.html index 0f565fed6e..2338c145fa 100644 --- a/labs/architecture-examples/cujo/app/footer/template.html +++ b/labs/architecture-examples/cujo/app/footer/template.html @@ -1,6 +1,5 @@ diff --git a/labs/architecture-examples/cujo/app/list/template.html b/labs/architecture-examples/cujo/app/list/template.html index f396a889d1..a4b9cbf4b3 100644 --- a/labs/architecture-examples/cujo/app/list/template.html +++ b/labs/architecture-examples/cujo/app/list/template.html @@ -10,7 +10,7 @@ - +
diff --git a/labs/architecture-examples/cujo/app/main.js b/labs/architecture-examples/cujo/app/main.js index 985297b7b0..c256ee2b39 100644 --- a/labs/architecture-examples/cujo/app/main.js +++ b/labs/architecture-examples/cujo/app/main.js @@ -10,8 +10,8 @@ define({ // Render and insert the create view createView: { render: { - template: { module: 'text!create/template.html' }, - replace: { module: 'i18n!create/strings' } + template: { module: 'text!app/create/template.html' }, + replace: { module: 'i18n!app/create/strings' } }, insert: { first: 'root' } }, @@ -26,9 +26,9 @@ define({ // data and mapping data fields to the DOM listView: { render: { - template: { module: 'text!list/template.html' }, - replace: { module: 'i18n!list/strings' }, - css: { module: 'css!list/structure.css' } + template: { module: 'text!app/list/template.html' }, + replace: { module: 'i18n!app/list/strings' }, + css: { module: 'css!app/list/structure.css' } }, insert: { after: 'createView' }, bind: { @@ -38,7 +38,7 @@ define({ text: 'label, .edit', complete: [ '.toggle', - { attr: 'classList', handler: { module: 'list/setCompletedClass' } } + { attr: 'classList', handler: { module: 'app/list/setCompletedClass' } } ] } } @@ -48,9 +48,9 @@ define({ // filters, and clear completed button. controlsView: { render: { - template: { module: 'text!controls/template.html' }, - replace: { module: 'i18n!controls/strings' }, - css: { module: 'css!controls/structure.css' } + template: { module: 'text!app/controls/template.html' }, + replace: { module: 'i18n!app/controls/strings' }, + css: { module: 'css!app/controls/structure.css' } }, insert: { after: 'listView' } }, @@ -59,8 +59,8 @@ define({ // is still fully internationalized. footerView: { render: { - template: { module: 'text!footer/template.html' }, - replace: { module: 'i18n!footer/strings' } + template: { module: 'text!app/footer/template.html' }, + replace: { module: 'i18n!app/footer/strings' } }, insert: { after: 'root' } }, @@ -81,10 +81,10 @@ define({ todos: { create: { - module: 'cola/Hub', + module: 'cola/Collection', args: { strategyOptions: { - validator: { module: 'create/validateTodo' } + validator: { module: 'app/create/validateTodo' } } } }, @@ -100,11 +100,11 @@ define({ // view controllers. Since this is a relatively simple application, // a single controller fits well. todoController: { - prototype: { create: 'controller' }, + create: 'app/controller', properties: { todos: { $ref: 'todos' }, - createTodo: { compose: 'parseForm | todos.add' }, + createTodo: { compose: 'form.getValues | todos.add' }, removeTodo: { compose: 'todos.remove' }, updateTodo: { compose: 'todos.update' }, @@ -123,7 +123,8 @@ define({ 'change:.toggle': 'updateTodo', 'click:#toggle-all': 'toggleAll', 'dblclick:label': 'todos.edit', - 'change,focusout:.edit': 'todos.submit' // also need way to submit on [enter] + 'change,focusout:.edit': 'todos.submit', + 'submit:form': 'todos.submit' }, controlsView: { 'click:#clear-completed': 'removeCompleted' @@ -139,9 +140,9 @@ define({ } }, - parseForm: { module: 'cola/dom/formToObject' }, - cleanTodo: { module: 'create/cleanTodo' }, - generateMetadata: { module: 'create/generateMetadata' }, + form: { module: 'cola/dom/form' }, + cleanTodo: { module: 'app/create/cleanTodo' }, + generateMetadata: { module: 'app/create/generateMetadata' }, toggleEditingState: { create: { diff --git a/labs/architecture-examples/cujo/app/run.js b/labs/architecture-examples/cujo/app/run.js index 64514c132e..2317cddfd1 100644 --- a/labs/architecture-examples/cujo/app/run.js +++ b/labs/architecture-examples/cujo/app/run.js @@ -2,21 +2,20 @@ (function (curl) { 'use strict'; - var config = { - baseUrl: 'app', - paths: { - theme: '../theme', - curl: '../lib/curl/src/curl' - }, - pluginPath: 'curl/plugin', + curl({ + main: 'wire!app/main', packages: [ - { name: 'wire', location: '../lib/wire', main: 'wire' }, - { name: 'when', location: '../lib/when', main: 'when' }, - { name: 'aop', location: '../lib/aop', main: 'aop' }, - { name: 'cola', location: '../lib/cola', main: 'cola' }, - { name: 'poly', location: '../lib/poly', main: 'poly' } - ] - }; + { name: 'curl', location: 'bower_components/curl/src/curl' }, + { name: 'wire', location: 'bower_components/wire', main: 'wire' }, + { name: 'when', location: 'bower_components/when', main: 'when' }, + { name: 'meld', location: 'bower_components/meld', main: 'meld' }, + { name: 'cola', location: 'bower_components/cola', main: 'cola' }, + { name: 'poly', location: 'bower_components/poly', main: 'poly' } + ], + preloads: ['poly/string', 'poly/array'], + // Turn off i18n locale sniffing. Change or remove this line if you want to + // test specific locales or try automatic locale-sniffing. + locale: false + }); - curl(config, ['poly/string', 'poly/array']).next(['wire!main']); })(curl); diff --git a/labs/architecture-examples/cujo/bower.json b/labs/architecture-examples/cujo/bower.json index 70bee78fef..8e79668d6f 100644 --- a/labs/architecture-examples/cujo/bower.json +++ b/labs/architecture-examples/cujo/bower.json @@ -1,12 +1,12 @@ { - "name": "todomvc-cujo", + "name": "todomvc-cujoJS", "version": "0.0.0", "dependencies": { "todomvc-common": "~0.1.4", "curl": "~0.7.3", "cola": "latest", "poly": "~0.5.1", - "when": "~2.0.1", + "when": "~2.1.0", "wire": "~0.9.4", "meld": "~1.3.0" } diff --git a/labs/architecture-examples/cujo/bower_components/cola/.gitignore b/labs/architecture-examples/cujo/bower_components/cola/.gitignore new file mode 100644 index 0000000000..3a8b5bf354 --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/.gitignore @@ -0,0 +1,4 @@ +.idea/ +node_modules +/test/curl +test/util diff --git a/labs/architecture-examples/cujo/bower_components/cola/.gitmodules b/labs/architecture-examples/cujo/bower_components/cola/.gitmodules new file mode 100644 index 0000000000..827cdfeec7 --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/.gitmodules @@ -0,0 +1,9 @@ +[submodule "test/curl"] + path = test/curl + url = https://unscriptable@github.com/cujojs/curl.git +[submodule "test/util"] + path = test/util + url = https://unscriptable@github.com/cujojs/util.git +[submodule "support/when"] + path = support/when + url = https://github.com/cujojs/when.git diff --git a/labs/architecture-examples/cujo/bower_components/cola/Collection.js b/labs/architecture-examples/cujo/bower_components/cola/Collection.js new file mode 100644 index 0000000000..3b3272fe45 --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/Collection.js @@ -0,0 +1,110 @@ +/** + * Collection + */ +(function(define) { +define(function(require) { + + var Base, resolver, eventTypes, simpleStrategy; + + Base = require('./hub/Base'); + resolver = require('./collectionAdapterResolver'); + simpleStrategy = require('./network/strategy/default'); + + eventTypes = extend(Base.prototype.eventTypes, { + // collection item events. most of these come with data. devs can + // decide to use these events for their own purposes or send + // different data than described here, the following list outlines + // the intended behavior. + add: 1, // data == item added + remove: 1, // data == item removed + target: 1, // data == item targeted TODO: rename this to "point"? + // multi-item events + select: 1, // select an item (data == item) + unselect: 1, // deselect an item (data == item) + // batch events + collect: 1, // start of batch mode (until abort or submit) (data = batch purpose) + deliver: 1 // collected items (data = batch purpose with collected items array as property) + }); + + function Collection(options) { + Base.call(this, options); + + if(!options) { + options = {}; + } + + this.strategy = options.strategy; + if (!this.strategy) this.strategy = simpleStrategy(options.strategyOptions); + + } + + Collection.prototype = Object.create(Base.prototype, { + + eventTypes: { value: eventTypes }, + + resolver: { value: resolver }, + + forEach: { + value: function forEach(lambda) { + var provider = this.getProvider(); + return provider && provider.forEach(lambda); + } + }, + + findItem: { + value: function (anything) { + var info = this._findItemFor(anything); + return info && info.item; + } + }, + + findNode: { + value: function (anything) { + var info = this._findNodeFor(anything); + return info && info.node; + } + }, + + getProvider: { + value: function () { + var a, i = this.adapters.length; + while(a = this.adapters[--i]) { + if(a.provide) return a; + } + } + }, + + _findNodeFor: { + value: function (anything) { + var node, i, adapters, adapter; + + adapters = this.adapters; + + // loop through adapters that have the findNode() method + // to try to find out which adapter and which node + i = 0; + while (!node && (adapter = adapters[i++])) { + if (adapter.findNode) { + node = adapter.findNode(anything); + } + } + + return node && { node: node }; + } + } + + }); + + return Collection; + + function extend(base, mixin) { + var extended = Object.create(base); + for(var p in mixin) { + extended[p] = mixin[p]; + } + + return extended; + } + +}); +}(typeof define === 'function' ? define : function(factory) { module.exports = factory(require); })); diff --git a/labs/architecture-examples/cujo/bower_components/cola/Model.js b/labs/architecture-examples/cujo/bower_components/cola/Model.js new file mode 100644 index 0000000000..674c9a3438 --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/Model.js @@ -0,0 +1,34 @@ +/** + * Model + * @author: brian + */ +(function(define) { +define(function(require) { + + var Base, resolver, defaultModelStrategy; + + Base = require('./hub/Base'); + resolver = require('./objectAdapterResolver'); + defaultModelStrategy = require('./network/strategy/defaultModel'); + + function Model(options) { + Base.call(this, options); + + if(!options) { + options = {}; + } + + this.strategy = options.strategy; + if (!this.strategy) this.strategy = defaultModelStrategy(options.strategyOptions); + } + + Model.prototype = Object.create(Base.prototype, { + + resolver: { value: resolver } + + }); + + return Model; + +}); +}(typeof define === 'function' ? define : function(factory) { module.exports = factory(require); })); diff --git a/labs/architecture-examples/cujo/lib/cola/SortedMap.js b/labs/architecture-examples/cujo/bower_components/cola/SortedMap.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/SortedMap.js rename to labs/architecture-examples/cujo/bower_components/cola/SortedMap.js diff --git a/labs/architecture-examples/cujo/lib/cola/adapter/Array.js b/labs/architecture-examples/cujo/bower_components/cola/adapter/Array.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/adapter/Array.js rename to labs/architecture-examples/cujo/bower_components/cola/adapter/Array.js diff --git a/labs/architecture-examples/cujo/lib/cola/adapter/LocalStorage.js b/labs/architecture-examples/cujo/bower_components/cola/adapter/LocalStorage.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/adapter/LocalStorage.js rename to labs/architecture-examples/cujo/bower_components/cola/adapter/LocalStorage.js diff --git a/labs/architecture-examples/cujo/lib/cola/adapter/Object.js b/labs/architecture-examples/cujo/bower_components/cola/adapter/Object.js similarity index 81% rename from labs/architecture-examples/cujo/lib/cola/adapter/Object.js rename to labs/architecture-examples/cujo/bower_components/cola/adapter/Object.js index 046db52c9a..3273da3ea0 100644 --- a/labs/architecture-examples/cujo/lib/cola/adapter/Object.js +++ b/labs/architecture-examples/cujo/bower_components/cola/adapter/Object.js @@ -14,13 +14,23 @@ define(function (require) { */ function ObjectAdapter(obj, options) { + if(!options) { + options = {}; + } + this._obj = obj; this._options = options; + if('provide' in options) { + this.provide = options.provide; + } + } ObjectAdapter.prototype = { + provide: true, + update: function (item) { var self = this; @@ -39,6 +49,18 @@ define(function (require) { }, + properties: function(lambda) { + var self = this; + return when(this._obj, function(obj) { + function properties(l) { + l(obj); + } + self.properties = properties; + + return properties(lambda); + }); + }, + getOptions: function () { return this._options; } @@ -67,4 +89,4 @@ define(function (require) { typeof define == 'function' ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/adapter/ObjectToArray.js b/labs/architecture-examples/cujo/bower_components/cola/adapter/ObjectToArray.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/adapter/ObjectToArray.js rename to labs/architecture-examples/cujo/bower_components/cola/adapter/ObjectToArray.js diff --git a/labs/architecture-examples/cujo/lib/cola/adapter/Query.js b/labs/architecture-examples/cujo/bower_components/cola/adapter/Query.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/adapter/Query.js rename to labs/architecture-examples/cujo/bower_components/cola/adapter/Query.js diff --git a/labs/architecture-examples/cujo/lib/cola/adapter/makeJoined.js b/labs/architecture-examples/cujo/bower_components/cola/adapter/makeJoined.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/adapter/makeJoined.js rename to labs/architecture-examples/cujo/bower_components/cola/adapter/makeJoined.js diff --git a/labs/architecture-examples/cujo/lib/cola/adapter/makeTransformed.js b/labs/architecture-examples/cujo/bower_components/cola/adapter/makeTransformed.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/adapter/makeTransformed.js rename to labs/architecture-examples/cujo/bower_components/cola/adapter/makeTransformed.js index 0a6d6eab76..9e1a34fe95 100644 --- a/labs/architecture-examples/cujo/lib/cola/adapter/makeTransformed.js +++ b/labs/architecture-examples/cujo/bower_components/cola/adapter/makeTransformed.js @@ -98,4 +98,4 @@ define(function (require) { typeof define == 'function' ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/adapter/makeTransformedProperties.js b/labs/architecture-examples/cujo/bower_components/cola/adapter/makeTransformedProperties.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/adapter/makeTransformedProperties.js rename to labs/architecture-examples/cujo/bower_components/cola/adapter/makeTransformedProperties.js diff --git a/labs/architecture-examples/cujo/bower_components/cola/adapterResolver.js b/labs/architecture-examples/cujo/bower_components/cola/adapterResolver.js new file mode 100644 index 0000000000..9ebfc1312c --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/adapterResolver.js @@ -0,0 +1,43 @@ +(function (define) { +define(function () { +"use strict"; + + return { + /** + * Finds an adapter for the given object and the role. + * This is overly simplistic for now. We can replace this + * resolver later. + * @param object {Object} + * @description Loops through all Adapters registered with + * AdapterResolver.register, calling each Adapter's canHandle + * method. Adapters added later are found first. + */ + resolve: function(object) { + var adapters, i, Adapter; + + adapters = this.adapters; + + if (adapters) { + i = adapters.length; + while ((Adapter = adapters[--i])) { + if (Adapter.canHandle(object)) { + return Adapter; + } + } + } + }, + + register: function(Adapter) { + var adapters = this.adapters; + if(adapters.indexOf(Adapter) === -1) { + adapters.push(Adapter); + } + } + }; + +}); +}( + typeof define == 'function' + ? define + : function (factory) { module.exports = factory(); } +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/bower_components/cola/bower.json b/labs/architecture-examples/cujo/bower_components/cola/bower.json new file mode 100644 index 0000000000..4454dcadcd --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/bower.json @@ -0,0 +1,9 @@ +{ + "name": "cola", + "version": "0.0.0", + "commit": "27b8c7e8fe88feef62a746d29d30af945dcb244d", + "repository": { + "type": "git", + "url": "git://github.com/cujojs/cola" + } +} \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/cola.js b/labs/architecture-examples/cujo/bower_components/cola/cola.js similarity index 83% rename from labs/architecture-examples/cujo/lib/cola/cola.js rename to labs/architecture-examples/cujo/bower_components/cola/cola.js index 388457adc2..bad1abc235 100644 --- a/labs/architecture-examples/cujo/lib/cola/cola.js +++ b/labs/architecture-examples/cujo/bower_components/cola/cola.js @@ -21,9 +21,12 @@ function(when, propertiesKey, byProperty) { defaultQuerySelectorAll = { $ref: 'dom.all!' }; defaultOn = { $ref: 'on!' }; - function initBindOptions(incomingOptions, pluginOptions) { + function initBindOptions(incomingOptions, pluginOptions, resolver) { var options, identifier, comparator; + if(resolver.isRef(incomingOptions)) { + incomingOptions = { to: incomingOptions }; + } options = copyOwnProps(incomingOptions, pluginOptions); if(!options.querySelector) { @@ -56,7 +59,7 @@ function(when, propertiesKey, byProperty) { function doBind(facet, options, wire) { var target = facet.target; - return when(wire(initBindOptions(facet.options, options)), + return when(wire(initBindOptions(facet.options, options, wire.resolver)), function(options) { var to = options.to; if (!to) throw new Error('wire/cola: "to" must be specified'); @@ -78,18 +81,24 @@ function(when, propertiesKey, byProperty) { }; return { - wire$plugin: function(ready, destroyed, pluginOptions) { + wire$plugin: function(pluginOptions) { + + var options, p; - var options = {}; + options = {}; - for(var p in pluginOptions) { - if(!(p in excludeOptions)) { - options[p] = pluginOptions[p]; + if(arguments.length) { + pluginOptions = arguments[arguments.length-1]; + + for(p in pluginOptions) { + if(!(p in excludeOptions)) { + options[p] = pluginOptions[p]; + } } } function bindFacet(resolver, facet, wire) { - when.chain(doBind(facet, options, wire), resolver); + resolver.resolve(doBind(facet, options, wire)); } return { diff --git a/labs/architecture-examples/cujo/bower_components/cola/collectionAdapterResolver.js b/labs/architecture-examples/cujo/bower_components/cola/collectionAdapterResolver.js new file mode 100644 index 0000000000..d94a46735f --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/collectionAdapterResolver.js @@ -0,0 +1,19 @@ +/** + * collectionAdapterResolver + * @author: brian + */ +(function(define) { +define(function(require) { + + var adapterResolver = require('./adapterResolver'); + + return Object.create(adapterResolver, { + adapters: { value: [ + require('./adapter/Array'), + require('./dom/adapter/NodeList'), + require('./adapter/Query') + ]} + }); + +}); +}(typeof define === 'function' ? define : function(factory) { module.exports = factory(require); })); diff --git a/labs/architecture-examples/cujo/lib/cola/comparator/byProperty.js b/labs/architecture-examples/cujo/bower_components/cola/comparator/byProperty.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/comparator/byProperty.js rename to labs/architecture-examples/cujo/bower_components/cola/comparator/byProperty.js index 6de3bcafea..1484ca65f0 100644 --- a/labs/architecture-examples/cujo/lib/cola/comparator/byProperty.js +++ b/labs/architecture-examples/cujo/bower_components/cola/comparator/byProperty.js @@ -19,4 +19,4 @@ define(function (require) { typeof define == 'function' ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/comparator/compose.js b/labs/architecture-examples/cujo/bower_components/cola/comparator/compose.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/comparator/compose.js rename to labs/architecture-examples/cujo/bower_components/cola/comparator/compose.js diff --git a/labs/architecture-examples/cujo/lib/cola/comparator/naturalOrder.js b/labs/architecture-examples/cujo/bower_components/cola/comparator/naturalOrder.js similarity index 98% rename from labs/architecture-examples/cujo/lib/cola/comparator/naturalOrder.js rename to labs/architecture-examples/cujo/bower_components/cola/comparator/naturalOrder.js index f77b96b503..4f2fdff5b2 100644 --- a/labs/architecture-examples/cujo/lib/cola/comparator/naturalOrder.js +++ b/labs/architecture-examples/cujo/bower_components/cola/comparator/naturalOrder.js @@ -15,4 +15,4 @@ define(function () { typeof define == 'function' ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/comparator/reverse.js b/labs/architecture-examples/cujo/bower_components/cola/comparator/reverse.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/comparator/reverse.js rename to labs/architecture-examples/cujo/bower_components/cola/comparator/reverse.js diff --git a/labs/architecture-examples/cujo/lib/cola/dom/adapter/Node.js b/labs/architecture-examples/cujo/bower_components/cola/dom/adapter/Node.js similarity index 66% rename from labs/architecture-examples/cujo/lib/cola/dom/adapter/Node.js rename to labs/architecture-examples/cujo/bower_components/cola/dom/adapter/Node.js index db4e67bdce..7caefeabde 100644 --- a/labs/architecture-examples/cujo/lib/cola/dom/adapter/Node.js +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/adapter/Node.js @@ -5,9 +5,10 @@ define(function (require) { "use strict"; - var bindingHandler; + var bindingHandler, guess; bindingHandler = require('../bindingHandler'); + guess = require('../guess'); /** * Creates a cola adapter for interacting with dom nodes. Be sure to @@ -21,12 +22,12 @@ define(function (require) { this._rootNode = rootNode; // set options - if (!options.bindings) options.bindings = {}; + options.bindings = guessBindingsFromDom(this._rootNode, options); + this._options = options; this._handlers = {}; - this._createItemToDomHandlers(); - + this._createItemToDomHandlers(options.bindings); } NodeAdapter.prototype = { @@ -51,6 +52,10 @@ define(function (require) { }); }, + properties: function(lambda) { + lambda(this._item); + }, + _itemToDom: function (item, hash) { var p, handler; for (p in hash) { @@ -59,10 +64,9 @@ define(function (require) { } }, - _createItemToDomHandlers: function () { - var bindings, creator; + _createItemToDomHandlers: function (bindings) { + var creator; - bindings = this._options.bindings; creator = bindingHandler(this._rootNode, this._options); Object.keys(bindings).forEach(function (b) { @@ -85,9 +89,32 @@ define(function (require) { return NodeAdapter; + function guessBindingsFromDom(rootNode, options) { + var nodeFinder, nodes, bindings; + + bindings = options.bindings || {}; + nodeFinder = options.nodeFinder || options.querySelectorAll || options.querySelector; + + nodes = nodeFinder('[name],[data-cola-binding]', rootNode); + + if(nodes) { + Array.prototype.forEach.call(nodes, function(n) { + var name, attr; + + attr = n.name ? 'name' : 'data-cola-binding'; + name = guess.getNodePropOrAttr(n, attr); + if(name && !(name in bindings)) { + bindings[name] = '[' + attr + '="' + name + '"]'; + } + }); + } + + return bindings; + } + }); }( typeof define == 'function' ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/dom/adapter/NodeList.js b/labs/architecture-examples/cujo/bower_components/cola/dom/adapter/NodeList.js similarity index 92% rename from labs/architecture-examples/cujo/lib/cola/dom/adapter/NodeList.js rename to labs/architecture-examples/cujo/bower_components/cola/dom/adapter/NodeList.js index 49094473ca..c9809c15d0 100644 --- a/labs/architecture-examples/cujo/lib/cola/dom/adapter/NodeList.js +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/adapter/NodeList.js @@ -4,7 +4,7 @@ define(function(require) { var SortedMap, classList, NodeAdapter, defaultIdAttribute, defaultTemplateSelector, listElementsSelector, - colaListBindingStates, undef; + colaListBindingStates, allBindingStates, undef; SortedMap = require('../../SortedMap'); classList = require('../classList'); @@ -20,12 +20,17 @@ define(function(require) { unbound: 'cola-list-unbound' }; + allBindingStates = Object.keys(colaListBindingStates).map(function(key) { + return colaListBindingStates[key]; + }).join(' '); + /** * Manages a collection of dom trees that are synced with a data * collection. * @constructor * @param rootNode {Node} node to serve as a template for items * in the collection / list. + * @param {object} options * @param options.comparator {Function} comparator function to use for * ordering nodes * @param [options.containerNode] {Node} optional parent to all itemNodes. If @@ -295,14 +300,24 @@ define(function(require) { }, _checkBoundState: function () { - var state, isBound, isEmpty; - state = {}; + var states, isBound, isEmpty; + states = []; isBound = this._itemCount != null; isEmpty = this._itemCount == 0; - state[colaListBindingStates.unbound] = !isBound; - state[colaListBindingStates.empty] = isEmpty; - state[colaListBindingStates.bound] = isBound && !isEmpty; - classList.setClassSet(this._rootNode, state); + + if(!isBound) { + states.push(colaListBindingStates.unbound); + } + + if(isEmpty) { + states.push(colaListBindingStates.empty); + } + + if(isBound && !isEmpty) { + states.push(colaListBindingStates.bound); + } + + setBindingStates(states.join(' '), this._rootNode); } }; @@ -312,6 +327,10 @@ define(function(require) { return obj && obj.tagName && obj.insertBefore && obj.removeChild; }; + function setBindingStates(states, node) { + node.className = classList.addClass(states, classList.removeClass(allBindingStates, node.className)); + } + function findTemplateNode (root, options) { var useBestGuess, node; @@ -343,4 +362,4 @@ define(function(require) { typeof define == 'function' ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/dom/bindingHandler.js b/labs/architecture-examples/cujo/bower_components/cola/dom/bindingHandler.js similarity index 87% rename from labs/architecture-examples/cujo/lib/cola/dom/bindingHandler.js rename to labs/architecture-examples/cujo/bower_components/cola/dom/bindingHandler.js index b7b27140b6..686df2d436 100644 --- a/labs/architecture-examples/cujo/lib/cola/dom/bindingHandler.js +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/bindingHandler.js @@ -2,10 +2,11 @@ define(function (require) { "use strict"; - var slice, guess; + var slice, guess, form; slice = Array.prototype.slice; guess = require('./guess'); + form = require('./form'); defaultNodeHandler.inverse = defaultInverseNodeHandler; @@ -169,20 +170,33 @@ define(function (require) { function defaultNodeHandler (node, data, info) { var attr, value, current; - attr = info.attr || guess.propForNode(node); - value = data[info.prop]; - // always compare first to try to prevent unnecessary IE reflow/repaint - current = guess.getNodePropOrAttr(node, attr); - if (current !== value) { - guess.setNodePropOrAttr(node, attr, value); + if(node.form) { + form.setValues(node.form, data, function(_, name) { + return name === info.prop; + }); + } else { + attr = info.attr || guess.propForNode(node); + value = data[info.prop]; + // always compare first to try to prevent unnecessary IE reflow/repaint + current = guess.getNodePropOrAttr(node, attr); + if (current !== value) { + guess.setNodePropOrAttr(node, attr, value); + } } } function defaultInverseNodeHandler (node, data, info) { var attr, value; - attr = info.attr || guess.propForNode(node); - value = guess.getNodePropOrAttr(node, attr); - data[info.prop] = value; + + if(node.form) { + value = form.getValues(node.form, function(el) { + return el === node || el.name === node.name; + }); + data[info.prop] = value[info.prop]; + } else { + attr = info.attr || guess.propForNode(node); + data[info.prop] = guess.getNodePropOrAttr(node, attr); + } } function createInverseHandler (binding, propToDom) { @@ -215,4 +229,4 @@ define(function (require) { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/dom/classList.js b/labs/architecture-examples/cujo/bower_components/cola/dom/classList.js similarity index 79% rename from labs/architecture-examples/cujo/lib/cola/dom/classList.js rename to labs/architecture-examples/cujo/bower_components/cola/dom/classList.js index 478c0e7988..4780461339 100644 --- a/labs/architecture-examples/cujo/lib/cola/dom/classList.js +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/classList.js @@ -5,6 +5,10 @@ define(function (require, exports) { var splitClassNameRx = /\s+/; + var classRx = '(\\s+|^)(classNames)(\\b(?![\\-_])|$)'; + var trimLeadingRx = /^\s+/; + var splitClassNamesRx = /(\b\s+\b)|(\s+)/g; + /** * Returns the list of class names on a node as an array. * @param node {HTMLElement} @@ -135,7 +139,41 @@ define(function (require, exports) { return str.replace(outerSpacesRx, ''); } + + function addClass (className, str) { + var newClass = removeClass(className, str); + if(newClass && className) { + newClass += ' '; + } + + return newClass + className; + } + + function removeClass (removes, tokens) { + var rx; + + if (!removes) { + return tokens; + } + + // convert space-delimited tokens with bar-delimited (regexp `or`) + removes = removes.replace(splitClassNamesRx, function (m, inner, edge) { + // only replace inner spaces with | + return edge ? '' : '|'; + }); + + // create one-pass regexp + rx = new RegExp(classRx.replace('classNames', removes), 'g'); + + // remove all tokens in one pass (wish we could trim leading + // spaces in the same pass! at least the trim is not a full + // scan of the string) + return tokens.replace(rx, '').replace(trimLeadingRx, ''); + } + return { + addClass: addClass, + removeClass: removeClass, getClassList: getClassList, setClassList: setClassList, getClassSet: getClassSet, diff --git a/labs/architecture-examples/cujo/lib/cola/dom/events.js b/labs/architecture-examples/cujo/bower_components/cola/dom/events.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/dom/events.js rename to labs/architecture-examples/cujo/bower_components/cola/dom/events.js index 8c54053853..5b44213437 100644 --- a/labs/architecture-examples/cujo/lib/cola/dom/events.js +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/events.js @@ -91,4 +91,4 @@ define(function (require) { : function (factory) { module.exports = factory(require); }, this, this.document -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/bower_components/cola/dom/form.js b/labs/architecture-examples/cujo/bower_components/cola/dom/form.js new file mode 100644 index 0000000000..d3b6b071e0 --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/form.js @@ -0,0 +1,200 @@ +/** @license MIT License (c) copyright B Cavalier & J Hann */ + +(function (define) { +define(function () { + + var forEach, slice; + + forEach = Array.prototype.forEach; + slice = Array.prototype.slice; + + return { + getValues: formToObject, + getMultiSelectValue: getMultiSelectValue, + setValues: objectToForm, + setElementValue: setElementValue, + setGroupValue: setGroupValue, + setMultiSelectValue: setMultiSelectValue, + isCheckable: isCheckable + }; + + function objectToForm(form, object, filter) { + var els; + + els = form.elements; + if(typeof filter !== 'function') { + filter = alwaysInclude; + } + + Object.keys(object).forEach(function(name) { + + var el, value; + + value = object[name]; + el = els[name]; + + if(!filter(el, name, value)) return; + + if(el.length) { + setGroupValue(el, value); + } else { + setElementValue(el, value); + } + + }); + + return form; + } + + function setGroupValue(group, value) { + var getBooleanValue; + + getBooleanValue = Array.isArray(value) + ? function(array, el) { return array.indexOf(el.value) >= 0; } + : function(value, el) { return el.value == value; }; + + forEach.call(group, function(el, i) { + if(isCheckable(el)) { + el.checked = getBooleanValue(value, el); + } else { + el.value = textValue(value[i]); + } + }); + } + + function setElementValue(el, value) { + + if(isCheckable(el)) { + + el.checked = !!value; + + } else if(el.multiple && el.options) { + + if(!Array.isArray(value)) { + el.value = textValue(value); + } else { + setMultiSelectValue(el, value); + } + + } else { + el.value = textValue(value); + } + } + + function setMultiSelectValue(select, values) { + var i, option, options; + options = select.options; + i = 0; + while ((option = options[i++])) { + if(values.indexOf(option.value) >= 0) { + option.selected = true; + } + } + } + + function textValue(value) { + return value == null ? '' : value; + } + + function isCheckable(el) { + return el.type == 'radio' || el.type == 'checkbox'; + } + + /** + * Simple routine to pull input values out of a form. + * @param form {HTMLFormElement} + * @return {Object} populated object + */ + function formToObject (formOrEvent, filter) { + var obj, form, els, seen, i, el, name, value; + + form = formOrEvent.selectorTarget || formOrEvent.target || formOrEvent; + + if(typeof filter !== 'function') { + filter = alwaysInclude; + } + + obj = {}; + + els = form.elements; + seen = {}; // finds checkbox groups + i = 0; + + while ((el = els[i++])) { + name = el.name; + // skip over non-named elements and fieldsets (that have no value) + if (!name || !('value' in el) || !filter(el)) continue; + + value = el.value; + + if (el.type == 'radio') { + // only grab one radio value (to ensure that the property + // is always set, we set false if none are checked) + if (el.checked) obj[name] = value; + else if (!(name in seen)) obj[name] = false; + } + else if (el.type == 'checkbox') { + if (!(name in seen)) { + // we're going against normal form convention by ensuring + // the object always has a property of the given name. + // forms would normally not submit a checkbox if it isn't + // checked. + // Note: IE6&7 don't support el.hasAttribute() so we're using el.attributes[] + obj[name] = el.attributes['value'] ? !!el.checked && value : !!el.checked; + } + else if (el.checked) { + // collect checkbox groups into an array. + // if we found a false value, none have been checked so far + obj[name] = (name in obj && obj[name] !== false) + ? [].concat(obj[name], value) + : [value]; + } + } + else if (el.type == 'file') { + if (!(name in seen)) { + obj[name] = getFileInputValue(el); + } + } + else if (el.multiple && el.options) { + // grab all selected options + obj[name] = getMultiSelectValue(el); + } + else { + obj[name] = value; + } + + seen[name] = name; + } + + return obj; + } + + function getFileInputValue (fileInput) { + if ('files' in fileInput) { + return fileInput.multiple ? slice.call(fileInput.files) : fileInput.files[0]; + } else { + return fileInput.value; + } + } + + function getMultiSelectValue (select) { + var values, options, i, option; + values = []; + options = select.options; + i = 0; + while ((option = options[i++])) { + if (option.selected) values.push(option.value); + } + return values; + } + + function alwaysInclude() { + return true; + } + +}); +}( + typeof define == 'function' && define.amd + ? define + : function (factory) { module.exports = factory(); } +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/dom/formElementFinder.js b/labs/architecture-examples/cujo/bower_components/cola/dom/formElementFinder.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/dom/formElementFinder.js rename to labs/architecture-examples/cujo/bower_components/cola/dom/formElementFinder.js index ac3c43f224..f5e4a656a0 100644 --- a/labs/architecture-examples/cujo/lib/cola/dom/formElementFinder.js +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/formElementFinder.js @@ -22,4 +22,4 @@ define(function () { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/dom/guess.js b/labs/architecture-examples/cujo/bower_components/cola/dom/guess.js similarity index 97% rename from labs/architecture-examples/cujo/lib/cola/dom/guess.js rename to labs/architecture-examples/cujo/bower_components/cola/dom/guess.js index 277f67be60..040b8f877d 100644 --- a/labs/architecture-examples/cujo/lib/cola/dom/guess.js +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/guess.js @@ -54,9 +54,9 @@ define(function (require) { if (Array.isArray(node)) { // get unique list of events return node.reduce(function (events, node) { - return guessEventsFor(node).filter(function (event) { + return events.concat(guessEventsFor(node).filter(function (event) { return event && events.indexOf(event) < 0; - }) + })); },[]); } else if (isFormValueNode(node)) { @@ -148,4 +148,4 @@ define(function (require) { typeof define == 'function' ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/dom/has.js b/labs/architecture-examples/cujo/bower_components/cola/dom/has.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/dom/has.js rename to labs/architecture-examples/cujo/bower_components/cola/dom/has.js index 2562b06e36..99ddb4bd51 100644 --- a/labs/architecture-examples/cujo/lib/cola/dom/has.js +++ b/labs/architecture-examples/cujo/bower_components/cola/dom/has.js @@ -29,4 +29,4 @@ define(function () { : function (factory) { module.exports = factory(); }, this, this.document -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/enqueue.js b/labs/architecture-examples/cujo/bower_components/cola/enqueue.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/enqueue.js rename to labs/architecture-examples/cujo/bower_components/cola/enqueue.js diff --git a/labs/architecture-examples/cujo/bower_components/cola/hub/Base.js b/labs/architecture-examples/cujo/bower_components/cola/hub/Base.js new file mode 100644 index 0000000000..1d6ef811da --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/hub/Base.js @@ -0,0 +1,334 @@ +/** + * base + * @author: brian + */ +(function(define) { +define(function(require) { + + var when, baseEvents, eventProcessor, simpleStrategy, defaultIdentifier, + beforePhase, propagatingPhase, afterPhase, canceledPhase, + undef; + + when = require('when'); + eventProcessor = require('./eventProcessor'); + simpleStrategy = require('../network/strategy/default'); + defaultIdentifier = require('../identifier/default'); + + // TODO: make these configurable/extensible + baseEvents = { + // basic item events. most of these come with data. devs can + // decide to use these events for their own purposes or send + // different data than described here, the following list outlines + // the intended behavior. + update: 1, // data == item updated + change: 1, // data == event type that caused the change + validate: 1, // data == validation result object with at least a boolean valid prop + // mode events + abort: 1, // abort the current mode (no data) + submit: 1, // finalize the current mode (no data) + // edit event + edit: 1, // enter edit mode (data == item to edit) + // network-level events (not to be used by adapters) + join: 1, // an adapter has joined (data == adapter) + sync: 1, // adapters need to sync (data == boolean. true == provider) + leave: 1 // an adapter has left (data == adapter) + }; + + /** + * Signal that event has not yet been pushed onto the network. + * Return false to prevent the event from being pushed. + */ + beforePhase = {}; + + /** + * Signal that event is currently being propagated to adapters. + */ + propagatingPhase = {}; + + /** + * Signal that an event has already been pushed onto the network. + * Return value is ignored since the event has already propagated. + */ + afterPhase = {}; + + /** + * Signal that an event was canceled and not pushed onto the network. + * Return value is ignored since the event has already propagated. + */ + canceledPhase = {}; + + function BaseHub(options) { + var eventTypes, t; + + this.adapters = []; + + if (!options) options = {}; + + this.identifier = options.identifier || defaultIdentifier; + + this.eventProcessor = Object.create(eventProcessor, { + queue: { value: [] }, + eventProcessor: { value: this.processEvent.bind(this) } + }); + + eventTypes = this.eventTypes; + for(t in eventTypes) { + this.addApi(t); + } + } + + BaseHub.prototype = { + + eventTypes: baseEvents, + + dispatchEvent: function (name, data) { + try { + return this[name](data); + } + catch (ex) { + // TODO: do something with this exception + return false; + } + }, + + createAdapter: function (source, options) { + var Adapter = this.resolver.resolve(source); + return Adapter ? new Adapter(source, options) : source; + }, + + addSource: function (source, options) { + var adapter, proxy; + + if (!options) options = {}; + + if (!options.identifier) options.identifier = this.identifier; + + // create an adapter for this source + adapter = this.createAdapter(source, options); + proxy = this._createAdapterProxy(adapter, options); + proxy.origSource = source; + + // save the proxied adapter + this.adapters.push(proxy); + + this.eventProcessor.processEvent(proxy, null, 'join'); + + return adapter; + }, + + /* + 1. call events.beforeXXX(data) + 2. call strategy on each source/dest pair w/ event XXX and data + - cancel iteration if any strategy returns false for any pair + 3. if not canceled, call events.XXX(data) + */ + processEvent: function (source, data, type) { + var context, strategyApi, self, strategy, adapters; + + context = {}; + self = this; + strategy = this.strategy; + adapters = this.adapters; + + return when( + self.dispatchEvent(eventProcessor.makeBeforeEventName(type), data) + ).then( + function (result) { + context.canceled = result === false; + if (context.canceled) return when.reject(context); + + context.phase = beforePhase; + strategyApi = createStrategyApi(context, self.eventProcessor); + + return strategy(source, undef, data, type, strategyApi); + } + ).then( + function () { + context.phase = propagatingPhase; + return when.map(adapters, function (adapter) { + if (source != adapter) { + return strategy(source, adapter, data, type, strategyApi); + } + }); + } + ).then( + function () { + context.phase = context.canceled + ? canceledPhase + : afterPhase; + return strategy(source, undef, data, type, strategyApi); + } + ).then( + function (result) { + context.canceled = result === false; + if (context.canceled) return when.reject(context); + + return self.dispatchEvent(eventProcessor.makeEventName(type), data); + } + ).then( + function () { + return context; + } + ); + }, + + destroy: function () { + var adapters, adapter; + + adapters = this.adapters; + + while ((adapter = adapters.pop())) { + if (typeof adapter.destroy == 'function') { + adapter.destroy(); + } + } + }, + + addApi: function (name) { + this._addApiMethod(name); + this._addApiEvent(name); + }, + + _createAdapterProxy: function (adapter, options) { + var eventFinder, name, method, proxy; + + proxy = Object.create(adapter); + + // keep copy of original source so we can match it up later + if('provide' in options) { + proxy.provide = options.provide; + } + + // sniff for event hooks + eventFinder = this.configureEventFinder(options.eventNames); + + // override methods that require event hooks + for (name in adapter) { + method = adapter[name]; + if (typeof method == 'function' && eventFinder(name)) { + // store original method on proxy (to stop recursion) + proxy[name] = callOriginalMethod(adapter, method); + // change public api of adapter to call back into hub + observeMethod(this.eventProcessor, adapter, name, method); + // ensure hub has a public method of the same name + this.addApi(name); + } + } + + return proxy; + }, + + configureEventFinder: function (option) { + var eventTypes = this.eventTypes; + return typeof option == 'function' + ? option + : function (name) { return name in eventTypes; }; + }, + + _addApiMethod: function (name) { + var adapters, self, eventProcessor; + + adapters = this.adapters; + eventProcessor = this.eventProcessor; + self = this; + + if (!this[name]) { + this[name] = function (anything) { + var sourceInfo; + + sourceInfo = self._findItemFor(anything); + + if(!sourceInfo) { + sourceInfo = { + item: anything, + source: findAdapterForSource(arguments[1], adapters) + }; + } + + return eventProcessor.queueEvent(sourceInfo.source, sourceInfo.item, name); + }; + } + }, + + _addApiEvent: function (name) { + var eventName = this.eventProcessor.makeEventName(name); + // add function stub to api + if (!this[eventName]) { + this[eventName] = function (data) {}; + } + // add beforeXXX stub, too + eventName = this.eventProcessor.makeBeforeEventName(name); + if (!this[eventName]) { + this[eventName] = function (data) {}; + } + }, + + _findItemFor: function (anything) { + var item, i, adapters, adapter; + + adapters = this.adapters; + + // loop through adapters that have the getItemForEvent() method + // to try to find out which adapter and which data item + i = 0; + while (!item && (adapter = adapters[i++])) { + if (adapter.findItem) { + item = adapter.findItem(anything); + } + } + + return item && { item: item }; + } + }; + + return BaseHub; + + function createStrategyApi (context, eventProcessor) { + return { + queueEvent: function(source, data, type) { + return eventProcessor.queueEvent(source, data, type); + }, + cancel: function () { context.canceled = true; }, + isCanceled: function () { return !!context.canceled; }, + handle: function () { context.handled = true; }, + isHandled: function () { return !!context.handled; }, + isBefore: function () { return isPhase(beforePhase); }, + isAfter: function () { return isPhase(afterPhase); }, + isAfterCanceled: function () { return isPhase(canceledPhase); }, + isPropagating: function () { return isPhase(propagatingPhase); } + }; + + function isPhase (phase) { + return context.phase == phase; + } + } + + function callOriginalMethod (adapter, orig) { + return function () { + return orig.apply(adapter, arguments); + }; + } + + function observeMethod (queue, adapter, type, origMethod) { + return adapter[type] = function (data) { + queue.queueEvent(adapter, data, type); + return origMethod.call(adapter, data); + }; + } + + function findAdapterForSource (source, adapters) { + var i, adapter, found; + + // loop through adapters and find which one was created for this source + i = 0; + while (!found && (adapter = adapters[i++])) { + if (adapter.origSource == source) { + found = adapter; + } + } + + return found; + } + +}); +}(typeof define === 'function' ? define : function(factory) { module.exports = factory(require); })); diff --git a/labs/architecture-examples/cujo/bower_components/cola/hub/eventProcessor.js b/labs/architecture-examples/cujo/bower_components/cola/hub/eventProcessor.js new file mode 100644 index 0000000000..3c46bc55d5 --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/hub/eventProcessor.js @@ -0,0 +1,90 @@ +/** + * eventQueue + * @author: brian + */ +(function(define) { +define(function(require) { + + var when, enqueue; + + when = require('when'); + enqueue = require('../enqueue'); + + return { + + makeBeforeEventName: function (name) { + return makeEventName('before', name); + }, + + makeEventName: function(name) { + return makeEventName('on', name); + }, + + /** + * Queue an event for processing later + * @param source + * @param data + * @param type + */ + queueEvent: function (source, data, type) { + // if queue length is zero, we need to start processing it again + var queueNeedsRestart = this.queue.length == 0; + + // enqueue event + this.queue.push({ source: source, data: data, type: type }); + + // start processing, if necessary + return queueNeedsRestart && this._dispatchNextEvent(); + }, + + /** + * Process an event immediately + * @param source + * @param data + * @param type + */ + processEvent: function(source, data, type) { + var self = this; + + this.inflight = when(this.inflight).always(function() { + return self.eventProcessor(source, data, type); + }); + + return this.inflight; + }, + + _dispatchNextEvent: function () { + var event, remaining, deferred, self; + + self = this; + + // get the next event, if any + event = this.queue.shift(); + remaining = this.queue.length; + + // Ensure resolution is next turn, even if no event + // is actually dispatched. + deferred = when.defer(); + enqueue(function () { + var inflight = event && self.processEvent(event.source, event.data, event.type); + deferred.resolve(inflight); + }); + + // Only continue processing the queue if it's not empty + if(remaining) { + deferred.promise.always(function() { + self._dispatchNextEvent(); + }); + } + + return deferred.promise; + + } + }; + + function makeEventName (prefix, name) { + return prefix + name.charAt(0).toUpperCase() + name.substr(1); + } + +}); +}(typeof define === 'function' ? define : function(factory) { module.exports = factory(require); })); diff --git a/labs/architecture-examples/cujo/lib/cola/identifier/default.js b/labs/architecture-examples/cujo/bower_components/cola/identifier/default.js similarity index 98% rename from labs/architecture-examples/cujo/lib/cola/identifier/default.js rename to labs/architecture-examples/cujo/bower_components/cola/identifier/default.js index 7c7f3c4177..3abe6a286f 100644 --- a/labs/architecture-examples/cujo/lib/cola/identifier/default.js +++ b/labs/architecture-examples/cujo/bower_components/cola/identifier/default.js @@ -13,4 +13,4 @@ define(function (require) { typeof define == 'function' ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/identifier/property.js b/labs/architecture-examples/cujo/bower_components/cola/identifier/property.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/identifier/property.js rename to labs/architecture-examples/cujo/bower_components/cola/identifier/property.js index 85fa892224..3ecf66cb0e 100644 --- a/labs/architecture-examples/cujo/lib/cola/identifier/property.js +++ b/labs/architecture-examples/cujo/bower_components/cola/identifier/property.js @@ -21,4 +21,4 @@ define(function () { typeof define == 'function' ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/base.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/base.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/base.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/base.js index c5c9e774d2..a647124c8b 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/base.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/base.js @@ -26,4 +26,4 @@ define(function () { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/changeEvent.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/changeEvent.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/changeEvent.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/changeEvent.js index 0550838d17..78ee2c3108 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/changeEvent.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/changeEvent.js @@ -33,4 +33,4 @@ define(function () { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/collectThenDeliver.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/collectThenDeliver.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/collectThenDeliver.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/collectThenDeliver.js index 076ba824c7..4645e6c125 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/collectThenDeliver.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/collectThenDeliver.js @@ -139,4 +139,4 @@ define(function () { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/compose.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/compose.js similarity index 87% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/compose.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/compose.js index d1ea67089f..734d857f97 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/compose.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/compose.js @@ -16,7 +16,7 @@ define(function (require) { return function composeStrategies (strategies) { return function (source, dest, data, type, api) { - when.reduce(strategies, + return when.reduce(strategies, function(result, strategy) { var strategyResult = strategy(source, dest, data, type, api); return api.isCanceled() @@ -24,15 +24,19 @@ define(function (require) { : strategyResult; }, data - ).always(function(result) { return result }); + ).then(propagateSuccess, propagateSuccess); } }; + function propagateSuccess(x) { + return x; + } + }); }( typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/default.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/default.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/default.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/default.js index cdf1aa8b6c..46538482ae 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/default.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/default.js @@ -47,4 +47,4 @@ define(function (require) { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/bower_components/cola/network/strategy/defaultModel.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/defaultModel.js new file mode 100644 index 0000000000..43d376e4dc --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/defaultModel.js @@ -0,0 +1,52 @@ +(function (define) { +define(function (require) { + "use strict"; + + // Note: browser loaders and builders require that we don't "meta-program" + // the require() calls: + var compose, base, syncAfterJoin, syncModel, validate, changeEvent; + + compose = require('./compose'); + base = require('./base'); + syncAfterJoin = require('./syncAfterJoin'); + syncModel = require('./syncModel'); + validate = require('./validate'); + changeEvent = require('./changeEvent'); + + /** + * This is a composition of the strategies that Brian and I think + * make sense. :) + * + * @param options {Object} a conglomeration of all of the options for the + * strategies used. + * @param options.targetFirstItem {Boolean} if truthy, the strategy + * will automatically target the first item that is added to the network. + * If falsey, it will not automatically target. + * @param options.validator {Function} if provided, will be used + * to validate data items on add and update events + * + * @return {Function} a composite network strategy function + */ + return function (options) { + + // compose them + return compose([ + // Validate should be early so it can cancel other events + // when validation fails + validate(options), + // Change event support should be earlier than sync events + // so that it can translate them + changeEvent(options), + syncAfterJoin(options), + syncModel(options), + base(options) + ]); + + }; + +}); +}( + typeof define == 'function' && define.amd + ? define + : function (factory) { module.exports = factory(require); } +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/minimal.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/minimal.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/minimal.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/minimal.js index d6ea703c62..f1c2cfb739 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/minimal.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/minimal.js @@ -47,4 +47,4 @@ define(function (require) { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/syncAfterJoin.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncAfterJoin.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/syncAfterJoin.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncAfterJoin.js index 8fda0ba7d3..d186c236e4 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/syncAfterJoin.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncAfterJoin.js @@ -49,4 +49,4 @@ define(function () { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/syncDataDirectly.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncDataDirectly.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/syncDataDirectly.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncDataDirectly.js index 6408a4b7e8..096add85ac 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/syncDataDirectly.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncDataDirectly.js @@ -112,4 +112,4 @@ define(function () { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncModel.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncModel.js new file mode 100644 index 0000000000..c5d4ab7dad --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncModel.js @@ -0,0 +1,115 @@ +(function (define) { + define(function () { + "use strict"; + + /** + * Creates a strategy to push all data from a source into the consumers + * in the network directly (rather than as a sequence of 'add' events + * in the network) when a sync event happens. + * + * @description This strategy helps eliminate loops and complexities + * when data providers and consumers are added at unpredictable times. + * During a sync, all 'add' events are squelched while providers push + * all items to all consumers. + * + * @param [options.providersAreConsumers] {Boolean} if truthy, providers + * are also treated as consumers and receive items from other providers. + * @return {Function} a network strategy function + */ + return function (options) { + var synced, providers, consumers, undef; + + if (!options) options = {}; + + // TODO: consider putting these on the api object so they can be shared across strategies + // a list of all known providers and consumers + // these lists tend to be very small + providers = []; + consumers = []; + // the adapter currently being synced + synced = undef; + + return function syncDataDirectly (source, dest, provide, type, api) { + // this strategy stops sync events before going on the network + if ('sync' == type && api.isBefore()) { + synced = source; + try { + if (provide) { + // provide data onto consumers in network + if (typeof source.properties != 'function') { + throw new Error('syncModel: provider doesn\'t have `properties()`.'); + } + // keep track of providers + add(providers, synced); + // also add to consumers list, if specified + if (options.providersAreConsumers) { + add(consumers, synced); + } + // push data to all consumers + forEach(consumers, function (consumer) { + source.properties(function (item) { + consumer.update(item); + }); + }); + } + else { + // keep track of consumers + add(consumers, synced); + // provide data onto consumers in network + if (typeof source.update == 'function') { + // consume data from all providers + forEach(providers, function (provider) { + provider.properties(function (item) { + synced.update(item); + }); + }); + } + } + // the sync event never gets onto the network: + api.cancel(); + } + finally { + synced = undef; + } + } + // stop 'add' events between adapters while sync'ing, but allow + // strategies interested in the event to see it before + else if ('add' == type && synced && !api.isBefore()) { + api.cancel(); + } + // keep track of adapters that leave + else if ('leave' == type && api.isAfter()) { + // these just end up being noops if the source isn't in the list + remove(providers, source); + remove(consumers, source); + } + }; + + function add (list, adapter) { + list.push(adapter); + } + + function remove (list, adapter) { + forEach(list, function (provider, i , providers) { + if (provider == adapter) { + providers.splice(i, 1); + } + }); + } + + function forEach (list, lambda) { + var i, obj; + i = list.length; + while ((obj = list[--i])) { + lambda(obj, i, list); + } + } + + }; + + }); +}( + typeof define == 'function' && define.amd + ? define + : function (factory) { module.exports = factory(); } + )); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/targetFirstItem.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/targetFirstItem.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/targetFirstItem.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/targetFirstItem.js index 59d6c10e23..f6988a303a 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/targetFirstItem.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/targetFirstItem.js @@ -31,4 +31,4 @@ define(function () { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/network/strategy/validate.js b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/validate.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/network/strategy/validate.js rename to labs/architecture-examples/cujo/bower_components/cola/network/strategy/validate.js index 0f949f75ee..07ea2c7945 100644 --- a/labs/architecture-examples/cujo/lib/cola/network/strategy/validate.js +++ b/labs/architecture-examples/cujo/bower_components/cola/network/strategy/validate.js @@ -37,4 +37,4 @@ define(function () { typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/bower_components/cola/objectAdapterResolver.js b/labs/architecture-examples/cujo/bower_components/cola/objectAdapterResolver.js new file mode 100644 index 0000000000..8445240b7c --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/cola/objectAdapterResolver.js @@ -0,0 +1,18 @@ +/** + * objectAdapterResolver + * @author: brian + */ +(function(define) { +define(function(require) { + + var adapterResolver = require('./adapterResolver'); + + return Object.create(adapterResolver, { + adapters: { value: [ + require('./dom/adapter/Node'), + require('./adapter/Object') + ]} + }); + +}); +}(typeof define === 'function' ? define : function(factory) { module.exports = factory(require); })); diff --git a/labs/architecture-examples/cujo/lib/cola/projection/assign.js b/labs/architecture-examples/cujo/bower_components/cola/projection/assign.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/projection/assign.js rename to labs/architecture-examples/cujo/bower_components/cola/projection/assign.js index 90ac3cc50d..ab42eb3fd5 100644 --- a/labs/architecture-examples/cujo/lib/cola/projection/assign.js +++ b/labs/architecture-examples/cujo/bower_components/cola/projection/assign.js @@ -29,4 +29,4 @@ define(function () { typeof define == 'function' ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/projection/inherit.js b/labs/architecture-examples/cujo/bower_components/cola/projection/inherit.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/projection/inherit.js rename to labs/architecture-examples/cujo/bower_components/cola/projection/inherit.js index 49c78f5c52..ffdf624668 100644 --- a/labs/architecture-examples/cujo/lib/cola/projection/inherit.js +++ b/labs/architecture-examples/cujo/bower_components/cola/projection/inherit.js @@ -33,4 +33,4 @@ define(function () { typeof define == 'function' ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/relational/hashJoin.js b/labs/architecture-examples/cujo/bower_components/cola/relational/hashJoin.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/relational/hashJoin.js rename to labs/architecture-examples/cujo/bower_components/cola/relational/hashJoin.js diff --git a/labs/architecture-examples/cujo/lib/cola/relational/propertiesKey.js b/labs/architecture-examples/cujo/bower_components/cola/relational/propertiesKey.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/relational/propertiesKey.js rename to labs/architecture-examples/cujo/bower_components/cola/relational/propertiesKey.js index 36287deec5..0c58760c82 100644 --- a/labs/architecture-examples/cujo/lib/cola/relational/propertiesKey.js +++ b/labs/architecture-examples/cujo/bower_components/cola/relational/propertiesKey.js @@ -47,4 +47,4 @@ define(function () { typeof define == 'function' ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/relational/strategy/leftOuterJoin.js b/labs/architecture-examples/cujo/bower_components/cola/relational/strategy/leftOuterJoin.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/relational/strategy/leftOuterJoin.js rename to labs/architecture-examples/cujo/bower_components/cola/relational/strategy/leftOuterJoin.js diff --git a/labs/architecture-examples/cujo/lib/cola/transform/compose.js b/labs/architecture-examples/cujo/bower_components/cola/transform/compose.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/transform/compose.js rename to labs/architecture-examples/cujo/bower_components/cola/transform/compose.js diff --git a/labs/architecture-examples/cujo/lib/cola/transform/configure.js b/labs/architecture-examples/cujo/bower_components/cola/transform/configure.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/transform/configure.js rename to labs/architecture-examples/cujo/bower_components/cola/transform/configure.js index 36ddb244da..d8fd7615a7 100644 --- a/labs/architecture-examples/cujo/lib/cola/transform/configure.js +++ b/labs/architecture-examples/cujo/bower_components/cola/transform/configure.js @@ -33,4 +33,4 @@ define(function () { typeof define == 'function' ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/transform/createEnum.js b/labs/architecture-examples/cujo/bower_components/cola/transform/createEnum.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/transform/createEnum.js rename to labs/architecture-examples/cujo/bower_components/cola/transform/createEnum.js index 8f9326f6c4..557c35182a 100644 --- a/labs/architecture-examples/cujo/lib/cola/transform/createEnum.js +++ b/labs/architecture-examples/cujo/bower_components/cola/transform/createEnum.js @@ -142,4 +142,4 @@ define(function () { typeof define == 'function' ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/transform/expression.js b/labs/architecture-examples/cujo/bower_components/cola/transform/expression.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/transform/expression.js rename to labs/architecture-examples/cujo/bower_components/cola/transform/expression.js index a5c90d8035..0530c1101f 100644 --- a/labs/architecture-examples/cujo/lib/cola/transform/expression.js +++ b/labs/architecture-examples/cujo/bower_components/cola/transform/expression.js @@ -33,4 +33,4 @@ define(function () { // string because of "oddities" between `eval` and `this`. return eval('' + this); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/validation/composeValidators.js b/labs/architecture-examples/cujo/bower_components/cola/validation/composeValidators.js similarity index 99% rename from labs/architecture-examples/cujo/lib/cola/validation/composeValidators.js rename to labs/architecture-examples/cujo/bower_components/cola/validation/composeValidators.js index ff981857f4..63d86ed7f7 100644 --- a/labs/architecture-examples/cujo/lib/cola/validation/composeValidators.js +++ b/labs/architecture-examples/cujo/bower_components/cola/validation/composeValidators.js @@ -49,4 +49,4 @@ define(function () { typeof define == 'function' ? define : function (factory) { module.exports = factory(); } -)); +)); \ No newline at end of file diff --git a/labs/architecture-examples/cujo/lib/cola/validation/form/formValidationHandler.js b/labs/architecture-examples/cujo/bower_components/cola/validation/form/formValidationHandler.js similarity index 100% rename from labs/architecture-examples/cujo/lib/cola/validation/form/formValidationHandler.js rename to labs/architecture-examples/cujo/bower_components/cola/validation/form/formValidationHandler.js diff --git a/labs/architecture-examples/cujo/lib/curl/.gitmodules b/labs/architecture-examples/cujo/bower_components/curl/.gitmodules similarity index 100% rename from labs/architecture-examples/cujo/lib/curl/.gitmodules rename to labs/architecture-examples/cujo/bower_components/curl/.gitmodules diff --git a/labs/architecture-examples/cujo/bower_components/curl/bower.json b/labs/architecture-examples/cujo/bower_components/curl/bower.json new file mode 100644 index 0000000000..0a8f45c43d --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/curl/bower.json @@ -0,0 +1,8 @@ +{ + "name": "curl", + "version": "0.7.3", + "repository": { + "type": "git", + "url": "git://github.com/cujojs/curl" + } +} \ No newline at end of file diff --git a/labs/architecture-examples/cujo/bower_components/curl/package.json b/labs/architecture-examples/cujo/bower_components/curl/package.json new file mode 100644 index 0000000000..3498e8fc2a --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/curl/package.json @@ -0,0 +1,39 @@ +{ + "name": "curl", + "version": "0.7.3", + "description": "A small, fast module and resource loader with dependency management. (AMD, CommonJS Modules/1.1, CSS, HTML, etc.)", + "keywords": ["curl", "cujo", "amd", "loader", "module"], + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/mit-license.php" + } + ], + "repositories": [ + { + "type": "git", + "url": "https://github.com/cujojs/curl" + } + ], + "bugs": "https://github.com/cujojs/curl/issues", + "maintainers": [ + { + "name": "John Hann", + "web": "http://unscriptable.com" + } + ], + "contributors": [ + { + "name": "John Hann", + "web": "http://unscriptable.com" + }, + { + "name": "Brian Cavalier", + "web": "http://hovercraftstudios.com" + } + ], + "main": "./src/curl", + "directories": { + "test": "test" + } +} diff --git a/labs/architecture-examples/cujo/lib/curl/src/curl.js b/labs/architecture-examples/cujo/bower_components/curl/src/curl.js similarity index 63% rename from labs/architecture-examples/cujo/lib/curl/src/curl.js rename to labs/architecture-examples/cujo/bower_components/curl/src/curl.js index a5ca3a55d1..d19ced37e2 100644 --- a/labs/architecture-examples/cujo/lib/curl/src/curl.js +++ b/labs/architecture-examples/cujo/bower_components/curl/src/curl.js @@ -9,42 +9,46 @@ * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * - * @version 0.6.6 */ (function (global) { //"use strict"; don't restore this until the config routine is refactored var - version = '0.6.6', + version = '0.7.3', curlName = 'curl', - userCfg = global[curlName], + defineName = 'define', + userCfg, prevCurl, prevDefine, doc = global.document, head = doc && (doc['head'] || doc.getElementsByTagName('head')[0]), + // to keep IE from crying, we need to put scripts before any + // elements, but after any . this should do it: + insertBeforeEl = head && head.getElementsByTagName('base')[0] || null, // constants / flags msgUsingExports = {}, msgFactoryExecuted = {}, - interactive = {}, // this is the list of scripts that IE is loading. one of these will // be the "interactive" script. too bad IE doesn't send a readystatechange // event to tell us exactly which one. activeScripts = {}, + // readyStates for IE6-9 + readyStates = 'addEventListener' in global ? {} : { 'loaded': 1, 'complete': 1 }, // these are always handy :) cleanPrototype = {}, toString = cleanPrototype.toString, undef, - // script ready states that signify it's loaded - readyStates = { 'loaded': 1, 'interactive': interactive, 'complete': 1 }, // local cache of resource definitions (lightweight promises) cache = {}, + // local url cache + urlCache = {}, // preload are files that must be loaded before any others preload = false, // net to catch anonymous define calls' arguments (non-IE browsers) argsNet, - // RegExp's used later, "cached" here - dontAddExtRx = /\?/, + // RegExp's used later, pre-compiled here + dontAddExtRx = /\?|\.js\b/, absUrlRx = /^\/|^[^:]+:\/\//, - findLeadingDotsRx = /(\.)(\.?)(?:$|\/([^\.\/]+.*)?)/g, // /(?:^|\/)(\.)(\.?)\/?/g, + findDotsRx = /(\.)(\.?)(?:$|\/([^\.\/]+.*)?)/g, removeCommentsRx = /\/\*[\s\S]*?\*\/|(?:[^\\])\/\/.*?[\n\r]/g, findRValueRequiresRx = /require\s*\(\s*["']([^"']+)["']\s*\)|(?:[^\\]?)(["'])/g, cjsGetters, @@ -60,16 +64,24 @@ var main; descriptor.path = removeEndSlash(descriptor['path'] || descriptor['location'] || ''); - main = removeEndSlash(descriptor['main']) || 'main'; - if (main.charAt(0) != '.') main = './' + main; + main = descriptor['main'] || './main'; + if (!isRelUrl(main)) main = './' + main; // trailing slashes trick reduceLeadingDots to see them as base ids descriptor.main = reduceLeadingDots(main, descriptor.name + '/'); - descriptor.mainPath = reduceLeadingDots(main, descriptor.path + '/'); + //if (isRelUrl(descriptor.main)) throw new Error('invalid main (' + main + ') in ' + descriptor.name); descriptor.config = descriptor['config']; return descriptor; } + function isRelUrl (it) { + return it.charAt(0) == '.'; + } + + function isAbsUrl (it) { + return absUrlRx.test(it); + } + function joinPath (path, file) { return removeEndSlash(path) + '/' + file; } @@ -83,22 +95,35 @@ // module ids of "." and ".." as meaning "grab the module whose name is // the same as my folder or parent folder". These special module ids // are not included in the AMD spec but seem to work in node.js, too. - var levels, removeLevels, isRelative; + var removeLevels, normId, levels, isRelative, diff; + removeLevels = 1; - childId = childId.replace(findLeadingDotsRx, function (m, dot, doubleDot, remainder) { - if (doubleDot) removeLevels++; + normId = childId; + + // remove leading dots and count levels + if (isRelUrl(normId)) { isRelative = true; - return remainder || ''; - }); - // TODO: throw if removeLevels > baseId levels in debug module + normId = normId.replace(findDotsRx, function (m, dot, doubleDot, remainder) { + if (doubleDot) removeLevels++; + return remainder || ''; + }); + } + if (isRelative) { levels = baseId.split('/'); - levels.splice(levels.length - removeLevels, removeLevels); - // childId || [] is a trick to not concat if no childId - return levels.concat(childId || []).join('/'); + diff = levels.length - removeLevels; + if (diff < 0) { + // this is an attempt to navigate above parent module. + // maybe dev wants a url or something. punt and return url; + return childId; + } + levels.splice(diff, removeLevels); + // normId || [] prevents concat from adding extra "/" when + // normId is reduced to a blank string + return levels.concat(normId || []).join('/'); } else { - return childId; + return normId; } } @@ -217,30 +242,77 @@ core = { + /** + * * reduceLeadingDots of id against parentId + * - if there are too many dots (path goes beyond parent), it's a url + * - return reduceLeadingDots of id against baseUrl + parentId; + * * if id is a url (starts with dots or slash or protocol) + * - pathInfo = { config: userCfg, url: url } + * * if not a url, id-to-id transform here. + * - main module expansion + * - plugin prefix expansion + * - coordinate main module expansion with plugin expansion + * - main module expansion happens first + * - future: other transforms? + * @param id + * @param parentId + * @param cfg + * @return {*} + */ + toAbsId: function (id, parentId, cfg) { + var absId, pluginId, parts; + + absId = reduceLeadingDots(id, parentId); + + // if this is still a relative path, it must be a url + // so just punt, otherwise... + if (isRelUrl(absId)) return absId; + + // plugin id split + parts = pluginParts(absId); + pluginId = parts.pluginId; + absId = pluginId || parts.resourceId; + + // main id expansion + if (absId in cfg.pathMap) { + absId = cfg.pathMap[absId].main || absId; + } + + // plugin id expansion + if (pluginId) { + if (pluginId.indexOf('/') < 0 && !(pluginId in cfg.pathMap)) { + absId = joinPath(cfg.pluginPath, pluginId); + } + absId = absId + '!' + parts.resourceId; + } + + return absId; + }, + createContext: function (cfg, baseId, depNames, isPreload) { var def; def = new Promise(); - def.ctxId = def.id = baseId || ''; // '' == global + def.id = baseId || ''; // '' == global def.isPreload = isPreload; def.depNames = depNames; + def.config = cfg; // functions that dependencies will use: function toAbsId (childId) { - return reduceLeadingDots(childId, def.ctxId); + return core.toAbsId(childId, def.id, cfg); } function toUrl (n) { - // even though internally, we don't seem to need to do - // toAbsId, the AMD spec says we need to do this for plugins. - // also, the spec states that we should not append an extension - // in this function. + // the AMD spec states that we should not append an extension + // in this function since it could already be appended. + // we need to use toAbsId in case this is a module id. return core.resolvePathInfo(toAbsId(n), cfg).url; } - function localRequire (ids, callback) { + function localRequire (ids, callback, errback) { var cb, rvid, childDef, earlyExport; // this is public, so send pure function @@ -249,24 +321,23 @@ // RValue require (CommonJS) if (isType(ids, 'String')) { + if (cb) { + throw new Error('require(id, callback) not allowed'); + } // return resource rvid = toAbsId(ids); childDef = cache[rvid]; - earlyExport = isPromise(childDef) && childDef.exports; if (!(rvid in cache)) { // this should only happen when devs attempt their own // manual wrapping of cjs modules or get confused with // the callback syntax: throw new Error('Module not resolved: ' + rvid); } - if (cb) { - throw new Error('require(id, callback) not allowed'); - } + earlyExport = isPromise(childDef) && childDef.exports; return earlyExport || childDef; } else { - // use same id so that relative modules are normalized correctly - when(core.getDeps(core.createContext(cfg, def.ctxId, ids, isPreload)), cb); + when(core.getDeps(core.createContext(cfg, def.id, ids, isPreload)), cb, errback); } } @@ -277,11 +348,10 @@ return def; }, - createResourceDef: function (cfg, id, isPreload, optCtxId) { + createResourceDef: function (cfg, id, isPreload) { var def, origResolve, execute; def = core.createContext(cfg, id, undef, isPreload); - def.ctxId = optCtxId == undef ? id : optCtxId; origResolve = def.resolve; // using countdown to only execute definition function once @@ -299,7 +369,7 @@ // before resolving def.resolve = function resolve (deps) { when(isPreload || preload, function () { - origResolve((cache[def.id] = execute(deps))); + origResolve((cache[def.id] = urlCache[def.url] = execute(deps))); }); }; @@ -319,11 +389,11 @@ return def; }, - createPluginDef: function (cfg, id, isPreload, ctxId) { + createPluginDef: function (cfg, id, resId, isPreload) { var def; - def = core.createContext(cfg, id, undef, isPreload); - def.ctxId = ctxId; + // use resource id for local require and toAbsId + def = core.createContext(cfg, resId, undef, isPreload); return def; }, @@ -342,7 +412,8 @@ module = def.module = { 'id': def.id, 'uri': core.getDefUrl(def), - 'exports': core.getCjsExports(def) + 'exports': core.getCjsExports(def), + 'config': function () { return def.config; } }; module.exports = module['exports']; // oh closure compiler! } @@ -350,71 +421,119 @@ }, getDefUrl: function (def) { - // note: don't look up an anon module's id from it's own toUrl cuz - // the parent's config was used to find this module - // the toUrl fallback is for named modules in built files - // which must have absolute ids. - return def.url || (def.url = core.checkToAddJsExt(def.require['toUrl'](def.id))); + // note: this is used by cjs module.uri + return def.url || (def.url = core.checkToAddJsExt(def.require['toUrl'](def.id), def.config)); }, - config: function (cfg) { - var hasCfg, defineName, - apiName, apiObj, defName, defObj, define; - - hasCfg = cfg; - - defineName = 'define'; - - if (!cfg) cfg = {}; + /** + * Sets the curl() and define() APIs. + * @param [cfg] {Object|Null} set of config params. If missing or null, + * this function will set the default API! + */ + setApi: function (cfg) { + /* + scenarios: + 1. global config sets apiName: "require" + - first call to config sets api + - second and later calls are ignored + - prevCurl cannot exist + 2. no global config, first call to config() sets api + - first call to config has no api info + - second call to config sets api + - third and later calls must be ignored + 3. global config that doesn't set api, first call does though + - same as #2 + 4. api info is never set + - how to know when to stop ignoring? + + objectives: + 1. fail before mistakenly overwriting global[curlName] + 2. allow rename/relocate of curl() and define() + 3. restore curl() if we overwrote it + */ + + var apiName, defName, apiObj, defObj, + failMsg, okToOverwrite; + + apiName = curlName; + defName = defineName; + apiObj = defObj = global; + failMsg = ' already exists'; + + // if we're not setting defaults + if (cfg) { + // is it ok to overwrite existing api functions? + okToOverwrite = cfg['overwriteApi'] || cfg.overwriteApi; + // allow dev to rename/relocate curl() to another object + apiName = cfg['apiName'] || cfg.apiName || apiName; + apiObj = cfg['apiContext'] || cfg.apiContext || apiObj; + // define() too + defName = cfg['defineName'] || cfg.defineName || defName; + defObj = cfg['defineContext'] || cfg.defineContext || defObj; + + // curl() already existed, restore it if this is not a + // setDefaults pass. dev must be a good citizen and set + // apiName/apiContext (see below). + if (prevCurl && isType(prevCurl, 'Function')) { + // restore previous curl() + global[curlName] = prevCurl; + } + prevCurl = null; // don't check ever again + // ditto for define() + if (prevDefine && isType(prevDefine, 'Function')) { + // restore previous curl() + global[defineName] = prevDefine; + } + prevDefine = null; // don't check ever again + + // check if we're mistakenly overwriting either api + // if we're configuring, and there's a curl(), and it's not + // ours -- and we're not explicitly overwriting -- throw! + // Note: if we're setting defaults, we *must* overwrite curl + // so that dev can configure it. This is no different than + // noConflict()-type methods. + if (!okToOverwrite) { + if (apiObj[apiName] && apiObj[apiName] != _curl) { + throw new Error(apiName + failMsg); + } + // check if we're overwriting amd api + if (defObj[defName] && defObj[defName] != define) { + throw new Error(defName + failMsg); + } + } - // allow dev to rename/relocate curl() to another object - apiName = cfg['apiName'] || curlName; - apiObj = cfg['apiContext'] || global; - // if the dev is overwriting an existing curl() - if (apiObj != global || apiName != curlName ? apiObj[apiName] : prevCurl && hasCfg) { - throw new Error(apiName + ' already exists'); - } - apiObj[apiName] = _curl; - // restore previous curl - if (prevCurl && hasCfg) global[curlName] = prevCurl; - - // allow dev to rename/relocate define() to another object - defName = cfg['defineName'] || defineName; - defObj = cfg['defineContext'] || global; - if (defObj != global || defName != defineName ? defObj[defName] : prevDefine && hasCfg) { - throw new Error(defName + ' already exists'); } - defObj[defName] = define = function () { - // wrap inner _define so it can be replaced without losing define.amd - var args = core.fixArgs(arguments); - _define(args); - }; - // restore previous define - if (prevDefine && hasCfg) global[defineName] = prevDefine; - // indicate our capabilities: - define['amd'] = { 'plugins': true, 'jQuery': true, curlName: version }; + // set curl api + apiObj[apiName] = _curl; - // switch to re-runnable config - if (hasCfg) core.config = core.moreConfig; + // set AMD public api: define() + defObj[defName] = define; - return core.moreConfig(cfg); }, - moreConfig: function (cfg, prevCfg) { - var newCfg, pluginCfgs; + config: function (cfg) { + var prevCfg, newCfg, pluginCfgs, p; + + // convert from closure-safe names + if ('baseUrl' in cfg) cfg.baseUrl = cfg['baseUrl']; + if ('main' in cfg) cfg.main = cfg['main']; + if ('preloads' in cfg) cfg.preloads = cfg['preloads']; + if ('pluginPath' in cfg) cfg.pluginPath = cfg['pluginPath']; + if ('dontAddFileExt' in cfg || cfg.dontAddFileExt) { + cfg.dontAddFileExt = new RegExp(cfg['dontAddFileExt'] || cfg.dontAddFileExt); + } - if (!prevCfg) prevCfg = {}; + prevCfg = userCfg; newCfg = beget(prevCfg, cfg); - // set defaults and convert from closure-safe names - newCfg.baseUrl = newCfg['baseUrl'] || ''; - newCfg.pluginPath = newCfg['pluginPath'] || 'curl/plugin'; - // create object to hold path map. // each plugin and package will have its own pathMap, too. newCfg.pathMap = beget(prevCfg.pathMap); - pluginCfgs = newCfg.plugins = beget(prevCfg.plugins, cfg['plugins']); + pluginCfgs = cfg['plugins'] || {}; + newCfg.plugins = beget(prevCfg.plugins); + newCfg.paths = beget(prevCfg.paths, cfg.paths); + newCfg.packages = beget(prevCfg.packages, cfg.packages); // temporary arrays of paths. this will be converted to // a regexp for fast path parsing. @@ -427,12 +546,15 @@ var id, pluginId, data, parts, currCfg, info; for (var name in coll) { data = coll[name]; + if (isType(data, 'String')) data = { + path: coll[name] + }; // grab the package id, if specified. default to - // property name. - data.name = data['id'] || data['name'] || name; + // property name, if missing. + data.name = data.name || name; currCfg = newCfg; - // don't remove `|| name` since data may be a string, not an object - parts = pluginParts(removeEndSlash(data.name || name)); + // check if this is a plugin-specific path + parts = pluginParts(removeEndSlash(data.name)); id = parts.resourceId; pluginId = parts.pluginId; if (pluginId) { @@ -448,9 +570,10 @@ } if (isPkg) { info = normalizePkgDescriptor(data); + if (info.config) info.config = beget(newCfg, info.config); } else { - info = { path: removeEndSlash(data) }; + info = { path: removeEndSlash(data.path) }; } info.specificity = id.split('/').length; if (id) { @@ -461,7 +584,7 @@ // naked plugin name signifies baseUrl for plugin // resources. baseUrl could be relative to global // baseUrl. - currCfg.baseUrl = core.resolveUrl(data, newCfg); + currCfg.baseUrl = core.resolveUrl(data.path, newCfg); } } } @@ -470,7 +593,7 @@ function convertPathMatcher (cfg) { var pathMap = cfg.pathMap; cfg.pathRx = new RegExp('^(' + - cfg.pathList.sort(function (a, b) { return pathMap[a].specificity < pathMap[b].specificity; } ) + cfg.pathList.sort(function (a, b) { return pathMap[b].specificity - pathMap[a].specificity; } ) .join('|') .replace(/\/|\./g, '\\$&') + ')(?=\\/|$)' @@ -478,18 +601,36 @@ delete cfg.pathList; } - // fix all new paths and packages - fixAndPushPaths(cfg['paths'], false); + // fix all new packages, then paths (in case there are + // plugin-specific paths for a main module, such as wire!) fixAndPushPaths(cfg['packages'], true); + fixAndPushPaths(cfg['paths'], false); + + // process plugins after packages in case we already perform an + // id transform on a plugin (i.e. it's a package.main) + for (p in pluginCfgs) { + var absId = core.toAbsId(p + '!', '', newCfg); + newCfg.plugins[absId.substr(0, absId.length - 1)] = pluginCfgs[p]; + } + pluginCfgs = newCfg.plugins; // create search regex for each path map - for (var p in pluginCfgs) { + for (p in pluginCfgs) { + // inherit full config + pluginCfgs[p] = beget(newCfg, pluginCfgs[p]); var pathList = pluginCfgs[p].pathList; if (pathList) { pluginCfgs[p].pathList = pathList.concat(newCfg.pathList); convertPathMatcher(pluginCfgs[p]); } } + + // ugh, this is ugly, but necessary until we refactor this function + // copy previous pathMap items onto pathList + for (p in prevCfg.pathMap) { + if (!newCfg.pathMap.hasOwnProperty(p)) newCfg.pathList.push(p); + } + convertPathMatcher(newCfg); return newCfg; @@ -508,36 +649,18 @@ }, - resolvePathInfo: function (absId, cfg, forPlugin) { + resolvePathInfo: function (absId, cfg) { // searches through the configured path mappings and packages - var pathMap, pathInfo, ctxId, path, pkgCfg, found; + var pathMap, pathInfo, path, pkgCfg; pathMap = cfg.pathMap; - if (forPlugin && cfg.pluginPath && absId.indexOf('/') < 0 && !(absId in pathMap)) { - // prepend plugin folder path, if it's missing and path isn't in pathMap - // Note: this munges the concepts of ids and paths for plugins, - // but is generally safe since it's only for non-namespaced - // plugins (plugins without path or package info). - ctxId = absId = joinPath(cfg.pluginPath, absId); - } - if (!absUrlRx.test(absId)) { + if (!isAbsUrl(absId)) { path = absId.replace(cfg.pathRx, function (match) { - + // TODO: remove fallbacks here since they should never need to happen pathInfo = pathMap[match] || {}; - found = true; pkgCfg = pathInfo.config; - - // if pathInfo.main and match == absId, this is a main module - if (pathInfo.main && match == absId) { - ctxId = pathInfo.main; - return pathInfo.mainPath; - } - // if pathInfo.path return pathInfo.path - else { - return pathInfo.path || ''; - } - + return pathInfo.path || ''; }); } else { @@ -545,7 +668,6 @@ } return { - ctxId: ctxId || absId, config: pkgCfg || userCfg, url: core.resolveUrl(path, cfg) }; @@ -553,13 +675,13 @@ resolveUrl: function (path, cfg) { var baseUrl = cfg.baseUrl; - return baseUrl && !absUrlRx.test(path) ? joinPath(baseUrl, path) : path; + return baseUrl && !isAbsUrl(path) ? joinPath(baseUrl, path) : path; }, - checkToAddJsExt: function (url) { + checkToAddJsExt: function (url, cfg) { // don't add extension if a ? is found in the url (query params) // i'd like to move this feature to a moduleLoader - return url + (dontAddExtRx.test(url) ? '' : '.js'); + return url + ((cfg || userCfg).dontAddFileExt.test(url) ? '' : '.js'); }, loadScript: function (def, success, failure) { @@ -572,6 +694,9 @@ function process (ev) { ev = ev || global.event; // detect when it's done loading + // ev.type == 'load' is for all browsers except IE6-9 + // IE6-9 need to use onreadystatechange and look for + // el.readyState in {loaded, complete} (yes, we need both) if (ev.type == 'load' || readyStates[el.readyState]) { delete activeScripts[def.id]; // release event listeners @@ -604,8 +729,8 @@ // IE will load the script sync if it's in the cache, so // indicate the current resource definition if this happens. activeScripts[def.id] = el; - // use insertBefore to keep IE from throwing Operation Aborted (thx Bryan Forbes!) - head.insertBefore(el, head.firstChild); + + head.insertBefore(el, insertBeforeEl); // the js! plugin uses this return el; @@ -628,7 +753,7 @@ else if (!currQuote) { ids.push(id); } - return m; // uses least RAM/CPU + return ''; // uses least RAM/CPU }); return ids; }, @@ -739,7 +864,7 @@ // signal any waiters/parents that we can export // early (see progress callback in getDep below). // note: this may fire for `require` as well, if it - // is listed after `module` or `exports` in teh deps list, + // is listed after `module` or `exports` in the deps list, // but that is okay since all waiters will only record // it once. if (parentDef.exports) { @@ -846,60 +971,68 @@ }, fetchDep: function (depName, parentDef) { - var toAbsId, isPreload, parts, mainId, loaderId, pluginId, + var toAbsId, isPreload, cfg, parts, mainId, loaderId, pluginId, resId, pathInfo, def, tempDef, resCfg; toAbsId = parentDef.toAbsId; isPreload = parentDef.isPreload; + cfg = parentDef.config || userCfg; // is this fallback necessary? // check for plugin loaderId - parts = pluginParts(depName); - // resId is not normalized since the plugin may need to do it + // TODO: this runs pluginParts() twice. how to run it just once? + parts = pluginParts(toAbsId(depName)); resId = parts.resourceId; - // get id of first resource to load (which could be a plugin) - mainId = toAbsId(parts.pluginId || resId); - pathInfo = core.resolvePathInfo(mainId, userCfg, !!parts.pluginId); + mainId = parts.pluginId || resId; + pathInfo = core.resolvePathInfo(mainId, cfg); // get custom module loader from package config if not a plugin - // TODO: figure out how to make module loaders work with plugins if (parts.pluginId) { loaderId = mainId; } else { - loaderId = pathInfo.config['moduleLoader']; + // TODO: move config.moduleLoader to config.transform + loaderId = pathInfo.config['moduleLoader'] || pathInfo.config.moduleLoader; if (loaderId) { - // since we're not using toAbsId, transformers must be absolute + // TODO: allow transforms to have relative module ids? + // (we could do this by returning package location from + // resolvePathInfo. why not return all package info?) resId = mainId; mainId = loaderId; - pathInfo = core.resolvePathInfo(loaderId, userCfg); + pathInfo = core.resolvePathInfo(loaderId, cfg); } } - // find resource definition. ALWAYS check via (id in cache) b/c - // falsey values could be in there. - def = cache[mainId]; - if (!(mainId in cache)) { - def = cache[mainId] = core.createResourceDef(pathInfo.config, mainId, isPreload, pathInfo.ctxId); - def.url = core.checkToAddJsExt(pathInfo.url); + if (mainId in cache) { + def = cache[mainId]; + } + else if (pathInfo.url in urlCache) { + def = cache[mainId] = urlCache[pathInfo.url]; + } + else { + def = core.createResourceDef(pathInfo.config, mainId, isPreload); + // TODO: can this go inside createResourceDef? + // TODO: can we pass pathInfo.url to createResourceDef instead? + def.url = core.checkToAddJsExt(pathInfo.url, pathInfo.config); + cache[mainId] = urlCache[pathInfo.url] = def; core.fetchResDef(def); } // plugin or transformer if (mainId == loaderId) { - // we need to use depName until plugin tells us normalized id. - // if the plugin changes the id, we need to consolidate - // def promises below. Note: exports objects will be different - // between pre-normalized and post-normalized defs! does this matter? + // we need to use an anonymous promise until plugin tells + // us normalized id. then, we need to consolidate the promises + // below. Note: exports objects will be different between + // pre-normalized and post-normalized defs! does this matter? // don't put this resource def in the cache because if the // resId doesn't change, the check if this is a new // normalizedDef (below) will think it's already being loaded. - tempDef = /*cache[depName] =*/ new Promise(); + tempDef = new Promise(); // note: this means moduleLoaders can store config info in the // plugins config, too. - resCfg = userCfg.plugins[loaderId] || userCfg; + resCfg = cfg.plugins[loaderId] || cfg; // wait for plugin resource def when(def, function(plugin) { @@ -908,8 +1041,8 @@ dynamic = plugin['dynamic']; // check if plugin supports the normalize method if ('normalize' in plugin) { - // dojo/has may return falsey values (0, actually) - resId = plugin['normalize'](resId, toAbsId, resCfg) || ''; + // note: dojo/has may return falsey values (0, actually) + resId = plugin['normalize'](resId, toAbsId, def.config) || ''; } else { resId = toAbsId(resId); @@ -926,9 +1059,9 @@ // because we're using resId, plugins, such as wire!, // can use paths relative to the resource - normalizedDef = core.createPluginDef(resCfg, fullId, isPreload, resId); + normalizedDef = core.createPluginDef(resCfg, fullId, resId, isPreload); - // don't cache non-determinate "dynamic" resources (or non-existent resources) + // don't cache non-determinate "dynamic" resources if (!dynamic) { cache[fullId] = normalizedDef; } @@ -941,7 +1074,7 @@ if (!dynamic) cache[fullId] = res; }; loaded['resolve'] = loaded; - loaded['reject'] = normalizedDef.reject; + loaded['reject'] = loaded['error'] = normalizedDef.reject; // load the resource! plugin.load(resId, normalizedDef.require, loaded, resCfg); @@ -962,7 +1095,7 @@ }, getCurrentDefName: function () { - // IE marks the currently executing thread as "interactive" + // IE6-9 mark the currently executing thread as "interactive" // Note: Opera lies about which scripts are "interactive", so we // just have to test for it. Opera provides a true browser test, not // a UA sniff, thankfully. @@ -970,7 +1103,7 @@ var def; if (!isType(global.opera, 'Opera')) { for (var d in activeScripts) { - if (readyStates[activeScripts[d].readyState] == interactive) { + if (activeScripts[d].readyState == 'interactive') { def = d; break; } @@ -991,48 +1124,69 @@ // extract config, if it's specified if (isType(args[0], 'Object')) { cfg = args.shift(); - userCfg = core.config(cfg, userCfg); - core.checkPreloads(cfg); + _config(cfg); } - // thanks to Joop Ringelberg for helping troubleshoot the API - function CurlApi (ids, callback, waitFor) { - var then, ctx; - ctx = core.createContext(userCfg, undef, [].concat(ids)); - this['then'] = then = function (resolved, rejected) { - when(ctx, - // return the dependencies as arguments, not an array - function (deps) { - if (resolved) resolved.apply(undef, deps); - }, - // just throw if the dev didn't specify an error handler - function (ex) { - if (rejected) rejected(ex); else throw ex; - } - ); - return this; - }; - this['next'] = function (ids, cb) { - // chain api - return new CurlApi(ids, cb, ctx); - }; - if (callback) then(callback); - when(waitFor, function () { core.getDeps(ctx); }); - } + return new CurlApi(args[0], args[1], args[2]); + + } - return new CurlApi(args[0], args[1]); + function _config (cfg) { + if (cfg) { + core.setApi(cfg); + userCfg = core.config(cfg); + // check for preloads + core.checkPreloads(cfg); + // check for main module(s) + if ('main' in cfg) { + // start in next turn to wait for other modules in current file + setTimeout(function () { + var ctx; + ctx = core.createContext(userCfg, undef, [].concat(cfg['main'])); + core.getDeps(ctx); + }, 0); + } + } + } + // thanks to Joop Ringelberg for helping troubleshoot the API + function CurlApi (ids, callback, errback, waitFor) { + var then, ctx; + ctx = core.createContext(userCfg, undef, [].concat(ids)); + this['then'] = then = function (resolved, rejected) { + when(ctx, + // return the dependencies as arguments, not an array + function (deps) { + if (resolved) resolved.apply(undef, deps); + }, + // just throw if the dev didn't specify an error handler + function (ex) { + if (rejected) rejected(ex); else throw ex; + } + ); + return this; + }; + this['next'] = function (ids, cb, eb) { + // chain api + return new CurlApi(ids, cb, eb, ctx); + }; + this['config'] = _config; + if (callback || errback) then(callback, errback); + when(waitFor, function () { core.getDeps(ctx); }); } _curl['version'] = version; + _curl['config'] = _config; function _define (args) { - var id = args.id; + var id, def, pathInfo; + + id = args.id; if (id == undef) { if (argsNet !== undef) { - argsNet = {ex: 'Multiple anonymous defines in url'}; + argsNet = { ex: 'Multiple anonymous defines in url' }; } else if (!(id = core.getCurrentDefName())/* intentional assignment */) { // anonymous define(), defer processing until after script loads @@ -1042,13 +1196,12 @@ if (id != undef) { // named define(), it is in the cache if we are loading a dependency // (could also be a secondary define() appearing in a built file, etc.) - var def = cache[id]; + def = cache[id]; if (!(id in cache)) { // id is an absolute id in this case, so we can get the config. - // there's no way to allow a named define to fetch dependencies - // in the preload phase since we can't cascade the parent def. - var cfg = core.resolvePathInfo(id, userCfg).config; - def = cache[id] = core.createResourceDef(cfg, id); + pathInfo = core.resolvePathInfo(id, userCfg); + def = core.createResourceDef(pathInfo.config, id); + cache[id] = def; } if (!isPromise(def)) throw new Error('duplicate define: ' + id); // check if this resource has already been resolved @@ -1058,16 +1211,40 @@ } - // look for pre-existing globals - if (typeof define == 'function') prevDefine = define; - if (typeof userCfg == 'function') { - prevCurl = userCfg; - userCfg = false; + function define () { + // wrap inner _define so it can be replaced without losing define.amd + var args = core.fixArgs(arguments); + _define(args); } - // configure first time - userCfg = core.config(userCfg); - core.checkPreloads(userCfg); + // indicate our capabilities: + define['amd'] = { 'plugins': true, 'jQuery': true, 'curl': version }; + + // default configs + userCfg = { + baseUrl: '', + pluginPath: 'curl/plugin', + dontAddFileExt: dontAddExtRx, + paths: {}, + packages: {}, + plugins: {}, + pathMap: {}, + pathRx: /$^/ + }; + + // handle pre-existing global + prevCurl = global[curlName]; + prevDefine = global[defineName]; + if (!prevCurl || isType(prevCurl, 'Function')) { + // set default api + core.setApi(); + } + else { + // remove global curl object + global[curlName] = undef; // can't use delete in IE 6-8 + // configure curl + _config(prevCurl); + } // allow curl to be a dependency cache[curlName] = _curl; @@ -1080,10 +1257,10 @@ cache['curl/_privileged'] = { 'core': core, 'cache': cache, - 'cfg': userCfg, + 'config': function () { return userCfg; }, '_define': _define, '_curl': _curl, 'Promise': Promise }; -}(this.window || global)); +}(this.window || (typeof global != 'undefined' && global) || this)); diff --git a/labs/architecture-examples/cujo/lib/curl/src/curl/debug.js b/labs/architecture-examples/cujo/bower_components/curl/src/curl/debug.js similarity index 82% rename from labs/architecture-examples/cujo/lib/curl/src/curl/debug.js rename to labs/architecture-examples/cujo/bower_components/curl/src/curl/debug.js index 155e41c80e..2279359999 100644 --- a/labs/architecture-examples/cujo/lib/curl/src/curl/debug.js +++ b/labs/architecture-examples/cujo/bower_components/curl/src/curl/debug.js @@ -10,11 +10,14 @@ /** * usage: - * curl({ debug: true }, ['curl/debug']).next(['other/modules'], function (otherModules) { + * curl({ preloads: ['curl/debug'] }, ['my/app'], function (myApp) { * // do stuff while logging debug messages * }); * - * The debug module must be used in conjunction with the debug: true config param! + * TODO: warn when main module still has leading dots (normalizePackageDescriptor) + * TODO: warn when a module id still has leading dots (toAbsId) + * TODO: use curl/tdd/undefine module instead of quick-and-dirty method below + * TODO: only add logging to some of the useful core functions * */ define(['require', 'curl/_privileged'], function (require, priv) { diff --git a/labs/architecture-examples/cujo/lib/curl/src/curl/domReady.js b/labs/architecture-examples/cujo/bower_components/curl/src/curl/domReady.js similarity index 100% rename from labs/architecture-examples/cujo/lib/curl/src/curl/domReady.js rename to labs/architecture-examples/cujo/bower_components/curl/src/curl/domReady.js diff --git a/labs/architecture-examples/cujo/lib/curl/src/curl/loader/cjsm11.js b/labs/architecture-examples/cujo/bower_components/curl/src/curl/loader/cjsm11.js similarity index 84% rename from labs/architecture-examples/cujo/lib/curl/src/curl/loader/cjsm11.js rename to labs/architecture-examples/cujo/bower_components/curl/src/curl/loader/cjsm11.js index f6bcb17fd4..6177cfa68d 100644 --- a/labs/architecture-examples/cujo/lib/curl/src/curl/loader/cjsm11.js +++ b/labs/architecture-examples/cujo/bower_components/curl/src/curl/loader/cjsm11.js @@ -14,7 +14,7 @@ define(/*=='curl/loader/cjsm11',==*/ function () { - var head /*, findRequiresRx, myId*/; + var head, insertBeforeEl /*, findRequiresRx, myId*/; // findRequiresRx = /require\s*\(\s*['"](\w+)['"]\s*\)/, @@ -56,6 +56,9 @@ define(/*=='curl/loader/cjsm11',==*/ function () { // } head = document && (document['head'] || document.getElementsByTagName('head')[0]); + // to keep IE from crying, we need to put scripts before any + // elements, but after any . this should do it: + insertBeforeEl = head && head.getElementsByTagName('base')[0] || null; function wrapSource (source, resourceId, fullUrl) { var sourceUrl = fullUrl ? '////@ sourceURL=' + fullUrl.replace(/\s/g, '%20') + '.js' : ''; @@ -76,13 +79,12 @@ define(/*=='curl/loader/cjsm11',==*/ function () { var el = document.createElement('script'); injectSource(el, source); el.charset = 'utf-8'; - // use insertBefore to keep IE from throwing Operation Aborted (thx Bryan Forbes!) - head.insertBefore(el, head.firstChild); + head.insertBefore(el, insertBeforeEl); } return { - 'load': function (resourceId, require, loaded, config) { - // TODO: extract xhr from text! plugin and use that instead? + 'load': function (resourceId, require, callback, config) { + // TODO: extract xhr from text! plugin and use that instead (after we upgrade to cram.js) require(['text!' + resourceId + '.js', 'curl/_privileged'], function (source, priv) { var moduleMap; @@ -104,10 +106,10 @@ define(/*=='curl/loader/cjsm11',==*/ function () { globalEval(source); } - // call loaded now that the module is defined - loaded(require(resourceId)); + // call callback now that the module is defined + callback(require(resourceId)); - }); + }, callback['error'] || function (ex) { throw ex; }); }); } diff --git a/labs/architecture-examples/cujo/lib/curl/src/curl/plugin/README.md b/labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/README.md similarity index 100% rename from labs/architecture-examples/cujo/lib/curl/src/curl/plugin/README.md rename to labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/README.md diff --git a/labs/architecture-examples/cujo/lib/curl/src/curl/plugin/async.js b/labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/async.js similarity index 75% rename from labs/architecture-examples/cujo/lib/curl/src/curl/plugin/async.js rename to labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/async.js index 12feacaebf..a6db064d7f 100644 --- a/labs/architecture-examples/cujo/lib/curl/src/curl/plugin/async.js +++ b/labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/async.js @@ -37,31 +37,19 @@ }); */ -define(/*=='async',==*/ function () { +define(/*=='curl/plugin/async',==*/ function () { return { 'load': function (resourceId, require, callback, config) { - function resolved (resource) { - // return the resource to the callback - if (typeof callback.resolve == 'function') { - // promise-like callback - callback.resolve(resource); - } - else { - // just a function - callback(resource); - } - } - function rejected (error) { // report that an error happened - if (typeof callback.reject == 'function') { + if (typeof callback.error == 'function') { // promise-like callback - callback.reject(error); + callback.error(error); } - // no way to report errors if the callback is not a promise + // no way to report errors if the callback doesn't have error() } // go get the module in the standard way @@ -72,16 +60,16 @@ define(/*=='async',==*/ function () { module.then( function (resource) { if (arguments.length == 0) resource = module; - resolved(resource); + callback(resource); }, rejected ); } else { - // just a callback - resolved(module); + // just a normal module + callback(module); } - }); + }, callback['error'] || function (ex) { throw ex; }); }, // for cram's analyze phase diff --git a/labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/builder/css.js b/labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/builder/css.js new file mode 100644 index 0000000000..5b8e2a4767 --- /dev/null +++ b/labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/builder/css.js @@ -0,0 +1,178 @@ +/** MIT License (c) copyright B Cavalier & J Hann */ + +/** + * curl css! plugin build-time module + * + * Licensed under the MIT License at: + * http://www.opensource.org/licenses/mit-license.php + */ +define(function () { +"use strict"; + + // collection of modules that have been written to the built file + var built = {}; + + function nameWithExt (name, defaultExt) { + return name.lastIndexOf('.') <= name.lastIndexOf('/') ? + name + '.' + defaultExt : name; + } + + function jsEncode (text) { + // TODO: hoist the map and regex to the enclosing scope for better performance + var map = { 34: '\\"', 13: '\\r', 12: '\\f', 10: '\\n', 9: '\\t', 8: '\\b' }; + return text.replace(/(["\n\f\t\r\b])/g, function (c) { + return map[c.charCodeAt(0)]; + }); + } + + function parseSuffixes (name) { + // creates a dual-structure: both an array and a hashmap + // suffixes[0] is the actual name + var parts = name.split('!'), + suf, i = 1, pair; + while ((suf = parts[i++])) { // double-parens to avoid jslint griping + pair = suf.split('=', 2); + parts[pair[0]] = pair.length == 2 ? pair[1] : true; + } + return parts; + } + + var + // this actually tests for absolute urls and root-relative urls + // they're both non-relative + nonRelUrlRe = /^\/|^[^:]*:\/\//, + // Note: this will fail if there are parentheses in the url + findUrlRx = /url\s*\(['"]?([^'"\)]*)['"]?\)/g; + + function translateUrls (cssText, baseUrl) { + return cssText.replace(findUrlRx, function (all, url) { + return 'url("' + translateUrl(url, baseUrl) + '")'; + }); + } + + function translateUrl (url, parentPath) { + // if this is a relative url + if (!nonRelUrlRe.test(url)) { + // append path onto it + url = parentPath + url; + } + return url; + } + + function createSheetProxy (sheet) { + return { + cssRules: function () { + return sheet.cssRules || sheet.rules; + }, + insertRule: sheet.insertRule || function (text, index) { + var parts = text.split(/\{|\}/g); + sheet.addRule(parts[0], parts[1], index); + return index; + }, + deleteRule: sheet.deleteRule || function (index) { + sheet.removeRule(index); + return index; + }, + sheet: function () { + return sheet; + } + }; + } + + /***** style element functions *****/ + + var currentStyle; + + function createStyle (cssText) { + clearTimeout(createStyle.debouncer); + if (createStyle.accum) { + createStyle.accum.push(cssText); + } + else { + createStyle.accum = [cssText]; + currentStyle = doc.createStyleSheet ? doc.createStyleSheet() : + head.appendChild(doc.createElement('style')); + } + + createStyle.debouncer = setTimeout(function () { + // Note: IE 6-8 won't accept the W3C method for inserting css text + var style, allCssText; + + style = currentStyle; + currentStyle = undef; + + allCssText = createStyle.accum.join('\n'); + createStyle.accum = undef; + + // for safari which chokes on @charset "UTF-8"; + allCssText = allCssText.replace(/.+charset[^;]+;/g, ''); + + // TODO: hoist all @imports to the top of the file to follow w3c spec + + 'cssText' in style ? style.cssText = allCssText : + style.appendChild(doc.createTextNode(allCssText)); + + }, 0); + + return currentStyle; + } + +/* + // return the run-time API + callback({ + 'translateUrls': function (cssText, baseId) { + var baseUrl; + baseUrl = require['toUrl'](baseId); + baseUrl = baseUrl.substr(0, baseUrl.lastIndexOf('/') + 1); + return translateUrls(cssText, baseUrl); + }, + 'injectStyle': function (cssText) { + return createStyle(cssText); + }, + + 'proxySheet': function (sheet) { + // for W3C, `sheet` is a reference to a - - - -
-
- Form header -
-
-
- - - -
-
- -
- - - diff --git a/labs/architecture-examples/cujo/lib/cola/doc/ICollectionAdapter.js b/labs/architecture-examples/cujo/lib/cola/doc/ICollectionAdapter.js deleted file mode 100644 index 167e98a1d6..0000000000 --- a/labs/architecture-examples/cujo/lib/cola/doc/ICollectionAdapter.js +++ /dev/null @@ -1,116 +0,0 @@ -/** MIT License (c) copyright B Cavalier & J Hann */ - -/** - * Stores a watchable interface of collection. This is the interface - * that all collection/list adapters must implement. - * - * @constructor - * - * @param collection {Object} - */ -function ICollectionAdapter (collection) { - -} - -ICollectionAdapter.prototype = { - - /** - * Compares two data items. Works just like the comparator function - * for Array.prototype.sort. - * @memberOf ICollectionAdapter - * - * @param a {Object} - * @param b {Object} - * - * @returns {Number} -1, 0, 1 - * - * @description This comparator is used for two purposes: - * 1. to sort the items in the list (sequence) - * 2. to find an item in the list (identity) - * This property is undefined by default and should be injected. - * If not supplied, the mediator will supply one from another source. - * If the comparator tests for identity, it must indicate this via - * a truthy "identity" property on the function. Example: - * function compareWidgets (w1, w2) { - * if (w1.id == w2.id) return 0; - * else return w1.id - w2.id; - * } - * compareWidgets.identity = true; - * myWidgetCollectionAdapter.comparator = compareWidgets; - */ - comparator: undefined, - - /** - * Uniquely names a data item. This isn't a key generator, - * it extracts a unique string representation from an object. - * @memberOf ICollectionAdapter - * - * @param object {Object} - * - * @returns {String} - */ - identifier: undefined, - - /** - * Indicates that a new item should be added to the collection. - * @memberOf ICollectionAdapter - * - * @param item {Object} - * - * @description This function will only work if the collection has a - * identity function. - */ - add: function (item) {}, - - /** - * Indicates that an item in the collection should be removed. - * @memberOf ICollectionAdapter - * - * @param item {Object} - * - * @description This function will only work if the collection has a - * identity function. - */ - remove: function (item) {}, - - /** - * Indicates that an item in the collection should be updated. If the - * item doesn't already exist in the collection, it should be added. - * @memberOf ICollectionAdapter - * - * @param item {Object} - * - * @description This function will only work if the collection has a - * identity function. - */ - update: function (item) {}, - - /** - * Iterates over all of the items in the collection and runs the - * lambda functionfor each one. - * @param lambda {Function} function (item) { } - */ - forEach: function (lambda) {}, - - /** - * Optional method to get the options information that - * were provided to the adapter - * @returns {Object} - */ - getOptions: function () { - - } - -}; - -/** - * Tests an object to determine if it has an interface sufficient - * for use with this adapter. - * @memberOf ICollectionAdapter - * @static - * - * @param object {Object} - * - * @returns {Boolean} - */ -ICollectionAdapter.canHandle = function (object) {}; diff --git a/labs/architecture-examples/cujo/lib/cola/doc/IObjectAdapter.js b/labs/architecture-examples/cujo/lib/cola/doc/IObjectAdapter.js deleted file mode 100644 index b942be1b33..0000000000 --- a/labs/architecture-examples/cujo/lib/cola/doc/IObjectAdapter.js +++ /dev/null @@ -1,35 +0,0 @@ -/** MIT License (c) copyright B Cavalier & J Hann */ - -/** - * Creates a cola adapter for interacting with a single object. - * @constructor - * @param object {Object} - */ -function IObjectAdapter (object) {} - -IObjectAdapter.prototype = { - - /** - * Gets the options information that - * were provided to the adapter. - * @returns {Object} - */ - getOptions: function () { - - }, - - /** - * Signals that one or more of the properties has changed. - * @param item {Object} the newly updated item - */ - update: function (item) {} - -}; - -/** - * Tests whether the given object is a candidate to be handled by - * this adapter. - * @param obj - * @returns {Boolean} - */ -IObjectAdapter.canHandle = function (obj) {}; diff --git a/labs/architecture-examples/cujo/lib/cola/dom/formToObject.js b/labs/architecture-examples/cujo/lib/cola/dom/formToObject.js deleted file mode 100644 index 2810a99644..0000000000 --- a/labs/architecture-examples/cujo/lib/cola/dom/formToObject.js +++ /dev/null @@ -1,82 +0,0 @@ -/** @license MIT License (c) copyright B Cavalier & J Hann */ - -(function (define) { -define(function () { - - /** - * Simple routine to pull input values out of a form. - * @param form {HTMLFormElement} - * @return {Object} populated object - */ - return function formToObject (formOrEvent) { - var obj, form, els, seen, i, el, name, value; - - form = formOrEvent.selectorTarget || formOrEvent.target || formOrEvent; - - obj = {}; - - els = form.elements; - seen = {}; // finds checkbox groups - i = 0; - - while ((el = els[i++])) { - name = el.name; - value = el.value; - - // skip over non-named elements and fieldsets (that have no value) - if (!name || !('value' in el)) continue; - - if (el.type == 'radio') { - // only grab one radio value (to ensure that the property - // is always set, we set false if none are checked) - if (el.checked) obj[name] = value; - else if (!(name in seen)) obj[name] = false; - } - else if (el.type == 'checkbox') { - if (!(name in seen)) { - // we're going against normal form convention by ensuring - // the object always has a property of the given name. - // forms would normally not submit a checkbox if it isn't - // checked. - // Note: IE6&7 don't support el.hasAttribute() so we're using el.attributes[] - obj[name] = el.attributes['value'] ? !!el.checked && value : !!el.checked; - } - else if (el.checked) { - // collect checkbox groups into an array. - // if we found a false value, none have been checked so far - obj[name] = (name in obj && obj[name] !== false) - ? [].concat(obj[name], value) - : [value]; - } - } - else if (el.multiple && el.options) { - // grab all selected options - obj[name] = multiSelectToValue(el); - } - else { - obj[name] = value; - } - - seen[name] = name; - } - - return obj; - }; - - function multiSelectToValue (select) { - var values, options, i, option; - values = []; - options = select.options; - i = 0; - while ((option = options[i++])) { - if (option.selected) values.push(option.value); - } - return values; - } - -}); -}( - typeof define == 'function' && define.amd - ? define - : function (factory) { module.exports = factory(); } -)); diff --git a/labs/architecture-examples/cujo/lib/cola/package.json b/labs/architecture-examples/cujo/lib/cola/package.json deleted file mode 100644 index 10e614ca6b..0000000000 --- a/labs/architecture-examples/cujo/lib/cola/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "cola", - "version": "0.1.0", - "description": "cujo object linking architecture", - "keywords": ["data binding", "data linking", "rest", "data"], - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/mit-license.php" - } - ], - "repositories": [ - { - "type": "git", - "url": "https://github.com/cujojs/cola" - } - ], - "bugs": "https://github.com/cujojs/cola/issues", - "maintainers": [ - { - "name": "John Hann", - "web": "http://unscriptable.com" - } - ], - "contributors": [ - { - "name": "Brian Cavalier", - "web": "http://hovercraftstudios.com" - }, - { - "name": "John Hann", - "web": "http://unscriptable.com" - } - ], - "dependencies": { - "when": "~1" - }, - "devDependencies": { - "buster": "~0.5" - }, - "main": "./cola", - "directories": { - "test": "test" - }, - "scripts": { - "test": "buster test -e node" - } -} diff --git a/labs/architecture-examples/cujo/lib/curl/LICENSE.txt b/labs/architecture-examples/cujo/lib/curl/LICENSE.txt deleted file mode 100644 index 3012729dac..0000000000 --- a/labs/architecture-examples/cujo/lib/curl/LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -Open Source Initiative OSI - The MIT License - -http://www.opensource.org/licenses/mit-license.php - -Copyright (c) 2012 Brian Cavalier and John Hann - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/labs/architecture-examples/cujo/lib/curl/README.md b/labs/architecture-examples/cujo/lib/curl/README.md deleted file mode 100644 index 77ae8193ef..0000000000 --- a/labs/architecture-examples/cujo/lib/curl/README.md +++ /dev/null @@ -1,802 +0,0 @@ -curl (cujo resource loader) -===================== - -Check out the newly updated [wiki](https://github.com/cujojs/curl/wiki)! - -See the [wiki](https://github.com/cujojs/curl/wiki) for information about using -curl.js with jQuery, dojo, or underscore. - -Please Note: this project has moved from unscriptable/curl to cujojs/curl. -Any existing forks have been automatically moved to cujojs/curl. However, -you will need to update your clone and submodule remotes manually. - -Update the url in your .git/config, and also .gitmodules for submodules: - git://github.com/cujojs/curl.git - https://cujojs@github.com/cujojs/curl.git - -Helpful link for updating submodules: -[Git Submodules: Adding, Using, Removing, Updating](http://chrisjean.com/2009/04/20/git-submodules-adding-using-removing-and-updating/) - -What's New? -======= - -* 0.6.6 - * Fix for Safari 6's strict treatment of string properties in un-compiled - files (paths were broken -- thanks Tiago!) -* 0.6.5 - * better support when unning under RingoJS and node.js (still experimental) - * fixed bugs with apiContext/apiName or defineContext/defineName - * added package.json - * configuration can be overridden by successive calls: `curl({})` -* 0.6.4 - * curl now restores any previous curl() or define() if the dev reassigns - either using apiContext/apiName or defineContext/defineName -* 0.6.3 - * fix !exports option of js! plugin when file is compressed - * now resolves arbitrarily deep double-dot module ids (dojo and node compatibility) - * more non-standard dojo-isms added to shim/dojo16 (dojo 1.6.x and 1.7.x) - * correctly locates relative dependencies from main modules - * scoped `define` (e.g. `mylib.define()`) - * new tdd/runner and tdd/undefine modules - * new experimental shim/ssjs (to be released by v0.7) - * minor improvements to interpretation of unwrapped CJS modules -* 0.6.2 - * curl no longer repeatedly downloads modules that don't return any value - (bug introduced in 0.6 refactor) fixes issue #63 -* 0.6.1 - * better CommonJS modules compatibility and circular dependency checking - * fixes an issue in which curl.js could attempt to download the same module - file twice if the module is required using relative paths from - different locations -* 0.6 - * works with underscore fork at [amdjs](https://github.com/amdjs/underscore) - * tested and works with dojo 1.7.1 (using curl/shim/dojo16 as a preload) - * allows normal, non-AMD js files to return values to AMD modules (!exports - option) - * unwrapped CommonJS Modules/1.1 compatibility (experimental) - * non-AMD module loading via moduleLoader config property - * updated to latest AMD plugin specifications - * preloads config array to ensure shims (or other modules) are loaded - first - * package-specific configurations - * avoids circular dependencies when using cjsm modules - * folder reorganization. shims were moved into their own folder - * many bugs fixed, including #21, #22, #28, #34, #36, #39, #40 -* 0.5.4 - * jQuery 1.7 support!!! - * curl.js indicates to jQuery that it is a jQuery-aware AMD loader (#31) - * AMD/CJSM Hybrid format (see Manual Conversion section of this - page: http://requirejs.org/docs/commonjs.html) - * Now supports node's module.exports = x; export model - * bug fixes: - * multiple .next() calls now pass variables correctly - * curl.js now ignores blank or falsy module ids for better compatibility - wth yepnope and has! (#32) -* 0.5.3 - * fix to js! plugin (now works without !order option) -* 0.5.2 - * better CDN support! - * protocol-relative urls fixed - * plugin-specific paths (for segmenting by file type) - * robust 404 detection for non-module js resources - * better AMD plugin compliance - * new `dynamic: true` to prevent resource caching - * `normalize()` API for non-module-like resource names - * faster domReady detection in non-IE browsers - * link! plugin for ultra-simple css loading (no waiting, no embedding) - * new apiContext config param to keep curl API off global object - * `curl()` allows a single dependency to be specified without an array - * removed broken !noexec option for js! plugin since it no longer worked - in the current browsers -* 0.5.1: - * fixes to domReady! in the compiled dist/ versions and - * fixes for commonjs compatibility caused by google-closure in dist/ - versions - * support for parent module ids (../sibling-of-parent) -* 0.5: - * dojo 1.6 support has been moved to separate module (curl/dojo16Compat) - * curl/domReady now returns a callback function (not a promise) - * new async! plugin to allow a module to defer definition - * new css! plugin that inlines css into javascript when used with cram - * cram (AMD builder) support (css! and async! plugins) - * `require` is no longer an alias for `curl` unless you set the - `apiName` config param to "require" - * configuration parameters for plugins are now defined in a sub-object - of the main config object: { css: { cssOption: true } } - -TODO: - -* finish i18n plugin! -* document plugin configuration options and how to use each plugin -* notes about using JSONP (it works for objects, arrays, functions, numbers - and strings! use ?callback=define) - ----------------------------------------- - -What is curl.js? -================ - -curl.js is a small and very fast AMD-compliant asynchronous loader. -Size: 5KB (2.5KB gzipped) using Google's Closure Compiler. - -If you'd like to use curl.js for non-AMD modules (ordinary javascript files), -you'll want to use a version with the js! plugin built in. You may also -want to build-in the domReady module. The combined curl+js+domReady loader -is still only 6.5KB (3KB gzipped). - -What the heck is "cujo"? cujo.js is a web app development platform. -See the bottom of this file for more info. - -What is "cram"? cram (cujo resource assembler) is the build tool companion to -curl.js. You use cram to compile all of your modules into a small number of -javascript files which are loaded much faster into the browsers. - ----------------------------------------- - -Features at a glance: -===================== - -* Loads CommonJS AMD-formatted javascript modules in parallel (fast!) -* Loads CommonJS Modules (v1.1 when wrapped in a `define()`) (fast!) -* Loads CommonJS Packages (v1.1 modules wrapped in a `define()`) (fast!) -* Loads non-AMD javascript files in parallel, too (fast! via js! plugin) -* Loads CSS files and text files in parallel (fast! via plugins) -* Waits for dependencies (js, css, text, etc) before executing javascript -* Waits for domReady, if/when desired -* Allows for virtually limitless combinations of files and dependencies -* Tested with Chrome, FF3+, Safari 3.2+, IE6-8, Opera 9.5+ - -Oh, did we mention? It's fast! It's even faster than the leading non-AMD -script loaders. - ----------------------------------------- - -How to get support -=============== - -1. Go to the issues section of the curl repo (https://github.com/cujojs/curl/issues) - and search for an answer to your question or problem. -2. If no answer exists, file a new ticket! Somebody will typically respond within a - few hours. - -It's that easy. - ----------------------------------------- - -API at a glance -=============== - -For a complete description, check out the [wiki](https://github.com/cujojs/curl/wiki). - -```javascript -curl(['dep1', 'dep2', 'dep3' /* etc */], callback); -``` - -Loads dependencies and the executes callback. - -* ['dep1', 'dep2', 'dep3']: Module names or plugin-prefixed resource files -* callback: Function to receive modules or resources. This is where you'd - typically start up your app. - ---------- - -```javascript -curl(['dep1', 'dep2', 'dep3' /* etc */]) - .then(callback, errorback); -``` - -Promises-based API for executing callbacks. - -* ['dep1', 'dep2', 'dep3']: Module names or plugin-prefixed resource files -* callback: Function to receive modules or resources -* errorback: Function to call if an exception occurred while loading -* For full CommonJS Promises/A compliance, use [when.js](https://github.com/cujojs/when) - * `when(curl(['dep1'])).then(callback);` - ---------- - -```javascript -curl(config, ['dep1', 'dep2', 'dep3' /* etc */], callback); -``` -Specify configuration options, load dependencies, and execute callback. - -* config: Object containing curl configuration options (paths, etc.) -* ['dep1', 'dep2', 'dep3']: Module names or plugin-prefixed resource files -* callback: Function to receive modules or resources - ---------- - -```javascript -curl(['domReady!', 'dep2', 'dep3' /* etc */]) - .then( - callback, - errorback - ); -curl(['dep1', 'dep2', 'domReady!' /* etc */], function (dep1, dep2) { - // do something here -}); -``` - -Executes the callback when the dom is ready for manipulation AND -all dependencies have loaded. - -* callback: No parameters except the domReady object -* errorback: Function to call if an exception occurred while loading - ---------- - -```javascript -curl(['domReady!', 'js!nonAMD.js!order', 'js!another.js!order']), function () { - /* do something cool here */ -}); -``` - -Executes the function when the non-AMD javascript files are loaded and -the dom is ready. The another.js file will wait for the nonAMD.js file -before executing. - ---------- - -```javascript -curl(['js!nonAMD.js']) - .next(['dep1', 'dep2', 'dep3'], function (dep1, dep2, dep3) { - // do something before the dom is ready - }) - .next(['domReady!']) - .then( - function () { - // do something after the dom is ready - }, - function (ex) { - // show an error to the user - } - ); -``` - -Executes callbacks in stages using `.next(deps, callback)`. - ---------- - -```javascript -curl = { - baseUrl: '/path/to/my/js', - pluginPath: 'for/some/reason/plugins/r/here', - paths: { - curl: 'curl/src/curl', - cssx: 'cssx/src/cssx', - my: '../../my-lib/' - }, - apiName: 'someOtherName' -}; -``` - -If called before the ` - - -``` - -The file structure for this example would look as follows: - - js/ - curl/ - plugin/ - i18n.js - text.js - domReady.js - cssx/ - src/ - cssx/ - css.js - my/ - stuff/ - nls/ - strings.js - base.css - template.html - three.js - curl.js - ----------------------------------------- - -What is an asynchronous loader? -=============================== - -Web apps, especially large ones, require many modules and resources. Most of -these modules and resources need to be loaded at page load, but some may be -loaded later, either in the background or "just in time". They also need to be -loaded as quickly as possible. - -The traditional way to load javascript modules is via a `` -1. `when` will be available as `window.when` - -### Node - -1. `npm install when` -1. `var when = require('when');` - -### RingoJS - -1. `ringo-admin install cujojs/when` -1. `var when = require('when');` - -Docs & Examples -=============== - -See the API section below, and the [wiki for more detailed docs](https://github.com/cujojs/when/wiki) and [examples](https://github.com/cujojs/when/wiki/Examples) - -API -=== - -when() ------- - -Register a handler for a promise or immediate value: - -```javascript -when(promiseOrValue, callback, errback, progressback) - -// Always returns a promise, so can be chained: - -when(promiseOrValue, callback, errback, progressback).then(anotherCallback, anotherErrback, anotherProgressback) -``` - -**Getting an already-resolved Promise** - -You can also use `when()` to get an already-resolved promise for a value, similarly to using `when.reject()` to get a rejected promise (see below): - -```javascript -var resolved = when(anything); -``` - -when.defer() ------------- - -Create a new Deferred containing separate `promise` and `resolver` parts: - -```javascript -var deferred = when.defer(); - -var promise = deferred.promise; -var resolver = deferred.resolver; -``` - -**Promise API** - -```javascript -// var promise = deferred.promise; - -// then() -// Main promise API -// Register callback, errback, and/or progressback -promise.then(callback, errback, progressback); -``` - -**Extended Promise API** - -Convenience methods that are not part of the Promises/A proposal. - -```js -// always() -// Register an alwaysback that will be called when the promise resolves or rejects -promise.always(alwaysback [, progressback]); - -// otherwise() -// Convenience method to register only an errback -promise.otherwise(errback); -``` - -**Resolver API** - -```javascript -// var resolver = deferred.resolver; -resolver.resolve(value); -resolver.reject(err); -resolver.progress(update); -``` - -The deferred has the full `promise` + `resolver` API: - -```javascript -deferred.then(callback, errback, progressback); -deferred.resolve(value); -deferred.reject(reason); -deferred.progress(update); -``` - -when.reject() -------------- - -```javascript -var rejected = when.reject(anything); -``` - -Return a rejected promise for the supplied promiseOrValue. If promiseOrValue is a value, it will be the rejection value of the returned promise. If promiseOrValue is a promise, its completion value will be the rejected value of the returned promise. - -This can be useful in situations where you need to reject a promise *without* throwing an exception. For example, it allows you to propagate a rejection with the value of another promise. - -```javascript -when(doSomething(), - handleSuccess, - function(error) { - // doSomething failed, but we want to do some processing on the error - // to return something more useful to the caller. - // This allows processError to return either a value or a promise. - return when.reject(processError(e)); - } -); -``` - -when.isPromise() ----------------- - -```javascript -var is = when.isPromise(anything); -``` - -Return true if `anything` is truthy and implements the then() promise API. Note that this will return true for both a deferred (i.e. `when.defer()`), and a `deferred.promise` since both implement the promise API. - -when.some() ------------ - -```javascript -when.some(promisesOrValues, howMany, callback, errback, progressback) -``` - -Return a promise that will resolve when `howMany` of the supplied `promisesOrValues` have resolved. The resolution value of the returned promise will be an array of length `howMany` containing the resolutions values of the triggering `promisesOrValues`. - -when.all() ----------- - -```javascript -when.all(promisesOrValues, callback, errback, progressback) -``` - -Return a promise that will resolve only once *all* the supplied `promisesOrValues` have resolved. The resolution value of the returned promise will be an array containing the resolution values of each of the `promisesOrValues`. - -when.any() ----------- - -```javascript -when.any(promisesOrValues, callback, errback, progressback) -``` - -Return a promise that will resolve when any one of the supplied `promisesOrValues` has resolved. The resolution value of the returned promise will be the resolution value of the triggering `promiseOrValue`. - -when.chain() ------------- - -```javascript -when.chain(promiseOrValue, resolver, optionalValue) -``` - -Ensure that resolution of `promiseOrValue` will complete `resolver` with the completion value of `promiseOrValue`, or instead with `optionalValue` if it is provided. - -Returns a new promise that will complete when `promiseOrValue` is completed, with the completion value of `promiseOrValue`, or instead with `optionalValue` if it is provided. - -**Note:** If `promiseOrValue` is not an immediate value, it can be anything that supports the promise API (i.e. `then()`), so you can pass a `deferred` as well. Similarly, `resolver` can be anything that supports the resolver API (i.e. `resolve()`, `reject()`), so a `deferred` will work there, too. - -when.map() ----------- - -```javascript -when.map(promisesOrValues, mapFunc) -``` - -Traditional map function, similar to `Array.prototype.map()`, but allows input to contain promises and/or values, and mapFunc may return either a value or a promise. - -The map function should have the signature: - -```javascript -mapFunc(item) -``` - -Where: - -* `item` is a fully resolved value of a promise or value in `promisesOrValues` - -when.reduce() -------------- - -```javascript -when.reduce(promisesOrValues, reduceFunc, initialValue) -``` - -Traditional reduce function, similar to `Array.prototype.reduce()`, but input may contain promises and/or values, and reduceFunc may return either a value or a promise, *and* initialValue may be a promise for the starting value. - -The reduce function should have the signature: - -```javascript -reduceFunc(currentValue, nextItem, index, total) -``` - -Where: - -* `currentValue` is the current accumulated reduce value -* `nextItem` is the fully resolved value of the promise or value at `index` in `promisesOrValues` -* `index` the *basis* of `nextItem` ... practically speaking, this is the array index of the promiseOrValue corresponding to `nextItem` -* `total` is the total number of items in `promisesOrValues` - -when/apply ----------- - -```javascript -function functionThatAcceptsMultipleArgs(array) { - // ... -} - -var functionThatAcceptsAnArray = apply(functionThatAcceptsMultipleArgs); -``` - -Helper that allows using callbacks that take multiple args, instead of an array, with `when.all/some/map`: - -```javascript -when.all(arrayOfPromisesOrValues, apply(functionThatAcceptsMultipleArgs)); -``` - -[See the wiki](https://github.com/cujojs/when/wiki/when-apply) for more info and examples. - -Running the Unit Tests -====================== - -Install [buster.js](http://busterjs.org/) - -`npm install -g buster` - -Run unit tests in Node: - -1. `buster test -e node` - -Run unit tests in Browsers (and Node): - -1. `buster server` - this will print a url -2. Point browsers at /capture, e.g. `localhost:1111/capture` -3. `buster test` or `buster test -e browser` - -References ----------- - -Much of this code was inspired by @[unscriptable](https://github.com/unscriptable)'s [tiny promises](https://github.com/unscriptable/promises), the async innards of [wire.js](https://github.com/cujojs/wire), and some gists [here](https://gist.github.com/870729), [here](https://gist.github.com/892345), [here](https://gist.github.com/894356), and [here](https://gist.github.com/894360) - -Some of the code has been influenced by the great work in [Q](https://github.com/kriskowal/q), [Dojo's Deferred](https://github.com/dojo/dojo), and [uber.js](https://github.com/phiggins42/uber.js). diff --git a/labs/architecture-examples/cujo/lib/when/debug.js b/labs/architecture-examples/cujo/lib/when/debug.js deleted file mode 100644 index 7ce4080974..0000000000 --- a/labs/architecture-examples/cujo/lib/when/debug.js +++ /dev/null @@ -1,261 +0,0 @@ -/** @license MIT License (c) copyright B Cavalier & J Hann */ - -/** - * This is a drop-in replacement for the when module that sets up automatic - * debug output for promises created or consumed by when.js. Use this - * instead of when to help with debugging. - * - * WARNING: This module **should never** be use this in a production environment. - * It exposes details of the promise - * - * In an AMD environment, you can simply change your path or package mappings: - * - * paths: { - * // 'when': 'path/to/when/when' - * 'when': 'path/to/when/debug' - * } - * - * or - * - * packages: [ - * // { name: 'when', location: 'path/to/when', main: 'when' } - * { name: 'when', location: 'path/to/when', main: 'debug' } - * ] - * - * In a CommonJS environment, you can directly require this module where - * you would normally require 'when': - * - * // var when = require('when'); - * var when = require('when/debug'); - * - * Or you can temporarily modify the package.js to point main at debug. - * For example, when/package.json: - * - * ... - * "main": "./debug" - * ... - * - * @author brian@hovercraftstudios.com - */ -(function(define) { -define(['./when'], function(when) { - - var promiseId, freeze, pending, exceptionsToRethrow, undef; - - promiseId = 0; - freeze = Object.freeze || function(o) { return o; }; - pending = {}; - - exceptionsToRethrow = { - RangeError: 1, - ReferenceError: 1, - SyntaxError: 1, - TypeError: 1 - }; - - /** - * Setup debug output handlers for the supplied promise. - * @param p {Promise} A trusted (when.js) promise - * @return p - */ - function debugPromise(p) { - // TODO: Need to find a way for promises returned by .then() - // to also be debug promises. - p.then( - undef, - function(err) { - if(p.id) { - console.error(p.toString()); - } else { - console.error('[object Promise] REJECTED:', err); - } - } - ); - - return p; - } - - function wrapCallback(cb) { - if(typeof cb != 'function') return cb; - - return function(v) { - try { - return cb(v); - } catch(err) { - if(err) { - if (err.name in exceptionsToRethrow) { - setTimeout(function() { - throw err; - }, 0); - } else if (err.stack) { - console.error(err.stack); - } - } - - throw err; - } - } - } - - /** - * Helper to form debug string for promises depending on their - * current state - * @param name - * @param id - * @param status - * @param value - */ - function toString(name, id, status, value) { - var s = '[object ' + name + ' ' + id + '] ' + status; - if(value !== pending) s += ': ' + value; - return s; - } - - function F() {} - function beget(o) { - F.prototype = o; - o = new F(); - F.prototype = undef; - - return o; - } - - /** - * Replacement for when() that sets up debug logging on the - * returned promise. - */ - function whenDebug() { - return debugPromise(when.apply(null, arguments)); - } - - /** - * Replacement for when.defer() that sets up debug logging - * on the created Deferred, its resolver, and its promise. - * @param [id] anything optional identifier for this Deferred that will show - * up in debug output - * @return {Deferred} a Deferred with debug logging - */ - function deferDebug() { - var d, status, value, origResolve, origReject, origThen, id; - - // Delegate to create a Deferred; - d = when.defer(); - - status = 'pending'; - value = pending; - - // if no id provided, generate one. Not sure if this is - // useful or not. - id = arguments[arguments.length - 1]; - if(id === undef) id = ++promiseId; - - // Promise and resolver are frozen, so have to delegate - // in order to setup toString() on promise, resolver, - // and deferred - d.promise = beget(d.promise); - d.promise.toString = function() { - return toString('Promise', id, status, value); - }; - - d.resolver = beget(d.resolver); - d.resolver.toString = function() { - return toString('Resolver', id, status, value); - }; - - origResolve = d.resolver.resolve; - d.resolve = d.resolver.resolve = function(val) { - value = val; - status = 'resolving'; -// console.log(d.resolver.toString()); - return origResolve.apply(undef, arguments); - }; - - origReject = d.resolver.reject; - d.reject = d.resolver.reject = function(err) { - value = err; - status = 'REJECTING'; -// console.error(d.resolver.toString()); - return origReject.apply(undef, arguments); - }; - - d.toString = function() { - return toString('Deferred', id, status, value); - }; - - // Setup final state change handlers - d.then( - function(v) { status = 'resolved'; return v; }, - function(e) { status = 'REJECTED'; throw e; } - ); - - // Experimenting with setting up ways to also debug promises returned - // by .then(). Also need to find a way to extend the id in a way that - // makes it obvious the returned promise is NOT the original, but is - // related to it--it's downstream in the promise chain. - origThen = d.promise.then; - d.then = d.promise.then = function(cb, eb, pb) { - var args, p, id; - - id = d.id + '+'; - - args = []; - - if(arguments.length > 0) args[0] = wrapCallback(cb, id); - if(arguments.length > 1) args[1] = wrapCallback(eb, id); - if(arguments.length > 2) args[2] = wrapCallback(pb, id); - - var p = origThen.apply(null, args); - - p.id = id; - p = beget(p); - p.toString = function() { - return toString('Promise', p.id, status, value); - }; - - // See below. Not sure if debug promises should be frozen - return freeze(p); - }; - - // Add an id to all directly created promises. It'd be great - // to find a way to propagate this id to promise created by .then() - d.id = d.promise.id = d.resolver.id = id; - - // Attach debug handlers after the substitute promise - // has been setup, so the id can be logged. - debugPromise(d.promise); - - // TODO: Should we still freeze these? - // Seems safer for now to err on the side of caution and freeze them, - // but it could be useful to all them to be modified during debugging. - freeze(d.promise); - freeze(d.resolver); - - return d; - } - - whenDebug.defer = deferDebug; - whenDebug.isPromise = when.isPromise; - - // For each method we haven't already replaced, replace it with - // one that sets up debug logging on the returned promise - for(var p in when) { - if(when.hasOwnProperty(p) && !(p in whenDebug)) { - (function(p, orig) { - whenDebug[p] = function() { - return debugPromise(orig.apply(when, arguments)); - }; - })(p, when[p]); - } - } - - return whenDebug; - -}); -})(typeof define == 'function' - ? define - : function (deps, factory) { typeof module != 'undefined' - ? (module.exports = factory(require('./when'))) - : (this.when = factory(this.when)); - } - // Boilerplate for AMD, Node, and browser global -); diff --git a/labs/architecture-examples/cujo/lib/when/delay.js b/labs/architecture-examples/cujo/lib/when/delay.js deleted file mode 100644 index 6e7f8c6dd9..0000000000 --- a/labs/architecture-examples/cujo/lib/when/delay.js +++ /dev/null @@ -1,59 +0,0 @@ -/** @license MIT License (c) copyright B Cavalier & J Hann */ - -/** - * delay.js - * - * Helper that returns a promise that resolves after a delay. - * - * @author brian@hovercraftstudios.com - */ - -(function(define) { -define(['./when'], function(when) { - - var undef; - - /** - * Creates a new promise that will resolve after a msec delay. If promise - * is supplied, the delay will start *after* the supplied promise is resolved. - * - * Usage: - * // Do something after 1 second, similar to using setTimeout - * delay(1000).then(doSomething); - * // or - * when(delay(1000), doSomething); - * - * // Do something 1 second after triggeringPromise resolves - * delay(triggeringPromise, 1000).then(doSomething, handleRejection); - * // or - * when(delay(triggeringPromise, 1000), doSomething, handleRejection); - * - * @param [promise] anything - any promise or value after which the delay will start - * @param msec {Number} delay in milliseconds - */ - return function delay(promise, msec) { - if(arguments.length < 2) { - msec = promise >>> 0; - promise = undef; - } - - return when(promise, function(val) { - var deferred = when.defer(); - setTimeout(function() { - deferred.resolve(val); - }, msec); - return deferred.promise; - }); - }; - -}); -})(typeof define == 'function' - ? define - : function (deps, factory) { typeof module != 'undefined' - ? (module.exports = factory(require('./when'))) - : (this.when_delay = factory(this.when)); - } - // Boilerplate for AMD, Node, and browser global -); - - diff --git a/labs/architecture-examples/cujo/lib/when/package.json b/labs/architecture-examples/cujo/lib/when/package.json deleted file mode 100644 index f7eeb480d7..0000000000 --- a/labs/architecture-examples/cujo/lib/when/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "when", - "version": "1.3.1", - "description": "A lightweight Promise and when() implementation, plus other async goodies.", - "keywords": ["promises", "when", "async"], - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/mit-license.php" - } - ], - "repositories": [ - { - "type": "git", - "url": "https://github.com/cujojs/when" - } - ], - "bugs": "https://github.com/cujojs/when/issues", - "maintainers": [ - { - "name": "Brian Cavalier", - "web": "http://hovercraftstudios.com" - }, - { - "name": "John Hann", - "web": "http://unscriptable.com" - } - ], - "devDependencies": { - "buster": "~0.6" - }, - "main": "when", - "directories": { - "test": "test" - }, - "scripts": { - "test": "./node_modules/buster/bin/buster-test -e node" - } -} diff --git a/labs/architecture-examples/cujo/lib/when/timeout.js b/labs/architecture-examples/cujo/lib/when/timeout.js deleted file mode 100644 index 27c89e4233..0000000000 --- a/labs/architecture-examples/cujo/lib/when/timeout.js +++ /dev/null @@ -1,73 +0,0 @@ -/** @license MIT License (c) copyright B Cavalier & J Hann */ - -/** - * timeout.js - * - * Helper that returns a promise that rejects after a specified timeout, - * if not explicitly resolved or rejected before that. - * - * @author brian@hovercraftstudios.com - */ - -(function(define) { -define(['./when'], function(when) { - - var undef; - - /** - * Returns a new promise that will automatically reject after msec if - * the supplied promise doesn't resolve or reject before that. - * - * Usage: - * - * var d = when.defer(); - * // Setup d however you need - * - * // return a new promise that will timeout if we don't resolve/reject first - * return timeout(d, 1000); - * - * @param promise anything - any promise or value that should trigger - * the returned promise to resolve or reject before the msec timeout - * @param msec {Number} timeout in milliseconds - * - * @returns {Promise} - */ - return function timeout(promise, msec) { - var deferred, timeout; - - deferred = when.defer(); - - timeout = setTimeout(function onTimeout() { - timeout && deferred.reject(new Error('timed out')); - }, msec); - - function cancelTimeout() { - clearTimeout(timeout); - timeout = undef; - } - - when(promise, deferred.resolve, deferred.reject); - - return deferred.then( - function(value) { - cancelTimeout(); - return value; - }, - function(reason) { - cancelTimeout(); - throw reason; - } - ); - }; - -}); -})(typeof define == 'function' - ? define - : function (deps, factory) { typeof module != 'undefined' - ? (module.exports = factory(require('./when'))) - : (this.when_timeout = factory(this.when)); - } - // Boilerplate for AMD, Node, and browser global -); - - diff --git a/labs/architecture-examples/cujo/lib/when/when.js b/labs/architecture-examples/cujo/lib/when/when.js deleted file mode 100644 index 17348987fa..0000000000 --- a/labs/architecture-examples/cujo/lib/when/when.js +++ /dev/null @@ -1,771 +0,0 @@ -/** @license MIT License (c) copyright B Cavalier & J Hann */ - -/** - * when - * A lightweight CommonJS Promises/A and when() implementation - * - * when is part of the cujo.js family of libraries (http://cujojs.com/) - * - * Licensed under the MIT License at: - * http://www.opensource.org/licenses/mit-license.php - * - * @version 1.3.0 - */ - -(function(define) { -define(function() { - var freeze, reduceArray, slice, undef; - - // - // Public API - // - - when.defer = defer; - when.reject = reject; - when.isPromise = isPromise; - - when.all = all; - when.some = some; - when.any = any; - - when.map = map; - when.reduce = reduce; - - when.chain = chain; - - /** Object.freeze */ - freeze = Object.freeze || function(o) { return o; }; - - /** - * Trusted Promise constructor. A Promise created from this constructor is - * a trusted when.js promise. Any other duck-typed promise is considered - * untrusted. - * - * @constructor - */ - function Promise() {} - - Promise.prototype = freeze({ - always: function(alwaysback, progback) { - return this.then(alwaysback, alwaysback, progback); - }, - - otherwise: function(errback) { - return this.then(undef, errback); - } - }); - - /** - * Create an already-resolved promise for the supplied value - * @private - * - * @param value anything - * @return {Promise} - */ - function resolved(value) { - - var p = new Promise(); - - p.then = function(callback) { - try { - return promise(callback ? callback(value) : value); - } catch(e) { - return rejected(e); - } - }; - - return freeze(p); - } - - /** - * Create an already-rejected {@link Promise} with the supplied - * rejection reason. - * @private - * - * @param reason rejection reason - * @return {Promise} - */ - function rejected(reason) { - - var p = new Promise(); - - p.then = function(callback, errback) { - try { - return errback ? promise(errback(reason)) : rejected(reason); - } catch(e) { - return rejected(e); - } - }; - - return freeze(p); - } - - /** - * Returns a rejected promise for the supplied promiseOrValue. If - * promiseOrValue is a value, it will be the rejection value of the - * returned promise. If promiseOrValue is a promise, its - * completion value will be the rejected value of the returned promise - * - * @param promiseOrValue {*} the rejected value of the returned {@link Promise} - * - * @return {Promise} rejected {@link Promise} - */ - function reject(promiseOrValue) { - return when(promiseOrValue, function(value) { - return rejected(value); - }); - } - - /** - * Creates a new, CommonJS compliant, Deferred with fully isolated - * resolver and promise parts, either or both of which may be given out - * safely to consumers. - * The Deferred itself has the full API: resolve, reject, progress, and - * then. The resolver has resolve, reject, and progress. The promise - * only has then. - * - * @memberOf when - * @function - * - * @returns {Deferred} - */ - function defer() { - var deferred, promise, listeners, progressHandlers, _then, _progress, complete; - - listeners = []; - progressHandlers = []; - - /** - * Pre-resolution then() that adds the supplied callback, errback, and progback - * functions to the registered listeners - * - * @private - * - * @param [callback] {Function} resolution handler - * @param [errback] {Function} rejection handler - * @param [progback] {Function} progress handler - * - * @throws {Error} if any argument is not null, undefined, or a Function - */ - _then = function unresolvedThen(callback, errback, progback) { - var deferred = defer(); - - listeners.push(function(promise) { - promise.then(callback, errback) - .then(deferred.resolve, deferred.reject, deferred.progress); - }); - - progback && progressHandlers.push(progback); - - return deferred.promise; - }; - - /** - * Registers a handler for this {@link Deferred}'s {@link Promise}. Even though all arguments - * are optional, each argument that *is* supplied must be null, undefined, or a Function. - * Any other value will cause an Error to be thrown. - * - * @memberOf Promise - * - * @param [callback] {Function} resolution handler - * @param [errback] {Function} rejection handler - * @param [progback] {Function} progress handler - * - * @throws {Error} if any argument is not null, undefined, or a Function - */ - function then(callback, errback, progback) { - return _then(callback, errback, progback); - } - - /** - * Resolves this {@link Deferred}'s {@link Promise} with val as the - * resolution value. - * - * @memberOf Resolver - * - * @param val anything - */ - function resolve(val) { - complete(resolved(val)); - } - - /** - * Rejects this {@link Deferred}'s {@link Promise} with err as the - * reason. - * - * @memberOf Resolver - * - * @param err anything - */ - function reject(err) { - complete(rejected(err)); - } - - /** - * @private - * @param update - */ - _progress = function(update) { - var progress, i = 0; - while (progress = progressHandlers[i++]) progress(update); - }; - - /** - * Emits a progress update to all progress observers registered with - * this {@link Deferred}'s {@link Promise} - * - * @memberOf Resolver - * - * @param update anything - */ - function progress(update) { - _progress(update); - } - - /** - * Transition from pre-resolution state to post-resolution state, notifying - * all listeners of the resolution or rejection - * - * @private - * - * @param completed {Promise} the completed value of this deferred - */ - complete = function(completed) { - var listener, i = 0; - - // Replace _then with one that directly notifies with the result. - _then = completed.then; - - // Replace complete so that this Deferred can only be completed - // once. Also Replace _progress, so that subsequent attempts to issue - // progress throw. - complete = _progress = function alreadyCompleted() { - // TODO: Consider silently returning here so that parties who - // have a reference to the resolver cannot tell that the promise - // has been resolved using try/catch - throw new Error("already completed"); - }; - - // Free progressHandlers array since we'll never issue progress events - // for this promise again now that it's completed - progressHandlers = undef; - - // Notify listeners - // Traverse all listeners registered directly with this Deferred - - while (listener = listeners[i++]) { - listener(completed); - } - - listeners = []; - }; - - /** - * The full Deferred object, with both {@link Promise} and {@link Resolver} - * parts - * @class Deferred - * @name Deferred - */ - deferred = {}; - - // Promise and Resolver parts - // Freeze Promise and Resolver APIs - - promise = new Promise(); - promise.then = deferred.then = then; - - /** - * The {@link Promise} for this {@link Deferred} - * @memberOf Deferred - * @name promise - * @type {Promise} - */ - deferred.promise = freeze(promise); - - /** - * The {@link Resolver} for this {@link Deferred} - * @memberOf Deferred - * @name resolver - * @class Resolver - */ - deferred.resolver = freeze({ - resolve: (deferred.resolve = resolve), - reject: (deferred.reject = reject), - progress: (deferred.progress = progress) - }); - - return deferred; - } - - /** - * Determines if promiseOrValue is a promise or not. Uses the feature - * test from http://wiki.commonjs.org/wiki/Promises/A to determine if - * promiseOrValue is a promise. - * - * @param promiseOrValue anything - * - * @returns {Boolean} true if promiseOrValue is a {@link Promise} - */ - function isPromise(promiseOrValue) { - return promiseOrValue && typeof promiseOrValue.then === 'function'; - } - - /** - * Register an observer for a promise or immediate value. - * - * @function - * @name when - * @namespace - * - * @param promiseOrValue anything - * @param {Function} [callback] callback to be called when promiseOrValue is - * successfully resolved. If promiseOrValue is an immediate value, callback - * will be invoked immediately. - * @param {Function} [errback] callback to be called when promiseOrValue is - * rejected. - * @param {Function} [progressHandler] callback to be called when progress updates - * are issued for promiseOrValue. - * - * @returns {Promise} a new {@link Promise} that will complete with the return - * value of callback or errback or the completion value of promiseOrValue if - * callback and/or errback is not supplied. - */ - function when(promiseOrValue, callback, errback, progressHandler) { - // Get a promise for the input promiseOrValue - // See promise() - var trustedPromise = promise(promiseOrValue); - - // Register promise handlers - return trustedPromise.then(callback, errback, progressHandler); - } - - /** - * Returns promiseOrValue if promiseOrValue is a {@link Promise}, a new Promise if - * promiseOrValue is a foreign promise, or a new, already-resolved {@link Promise} - * whose resolution value is promiseOrValue if promiseOrValue is an immediate value. - * - * Note that this function is not safe to export since it will return its - * input when promiseOrValue is a {@link Promise} - * - * @private - * - * @param promiseOrValue anything - * - * @returns Guaranteed to return a trusted Promise. If promiseOrValue is a when.js {@link Promise} - * returns promiseOrValue, otherwise, returns a new, already-resolved, when.js {@link Promise} - * whose resolution value is: - * * the resolution value of promiseOrValue if it's a foreign promise, or - * * promiseOrValue if it's a value - */ - function promise(promiseOrValue) { - var promise, deferred; - - if(promiseOrValue instanceof Promise) { - // It's a when.js promise, so we trust it - promise = promiseOrValue; - - } else { - // It's not a when.js promise. Check to see if it's a foreign promise - // or a value. - - deferred = defer(); - if(isPromise(promiseOrValue)) { - // It's a compliant promise, but we don't know where it came from, - // so we don't trust its implementation entirely. Introduce a trusted - // middleman when.js promise - - // IMPORTANT: This is the only place when.js should ever call .then() on - // an untrusted promise. - promiseOrValue.then(deferred.resolve, deferred.reject, deferred.progress); - promise = deferred.promise; - - } else { - // It's a value, not a promise. Create an already-resolved promise - // for it. - deferred.resolve(promiseOrValue); - promise = deferred.promise; - } - } - - return promise; - } - - /** - * Return a promise that will resolve when howMany of the supplied promisesOrValues - * have resolved. The resolution value of the returned promise will be an array of - * length howMany containing the resolutions values of the triggering promisesOrValues. - * - * @memberOf when - * - * @param promisesOrValues {Array} array of anything, may contain a mix - * of {@link Promise}s and values - * @param howMany - * @param [callback] - * @param [errback] - * @param [progressHandler] - * - * @returns {Promise} - */ - function some(promisesOrValues, howMany, callback, errback, progressHandler) { - - checkCallbacks(2, arguments); - - return when(promisesOrValues, function(promisesOrValues) { - - var toResolve, results, ret, deferred, resolver, rejecter, handleProgress, len, i; - - len = promisesOrValues.length >>> 0; - - toResolve = Math.max(0, Math.min(howMany, len)); - results = []; - deferred = defer(); - ret = when(deferred, callback, errback, progressHandler); - - // Wrapper so that resolver can be replaced - function resolve(val) { - resolver(val); - } - - // Wrapper so that rejecter can be replaced - function reject(err) { - rejecter(err); - } - - // Wrapper so that progress can be replaced - function progress(update) { - handleProgress(update); - } - - function complete() { - resolver = rejecter = handleProgress = noop; - } - - // No items in the input, resolve immediately - if (!toResolve) { - deferred.resolve(results); - - } else { - // Resolver for promises. Captures the value and resolves - // the returned promise when toResolve reaches zero. - // Overwrites resolver var with a noop once promise has - // be resolved to cover case where n < promises.length - resolver = function(val) { - // This orders the values based on promise resolution order - // Another strategy would be to use the original position of - // the corresponding promise. - results.push(val); - - if (!--toResolve) { - complete(); - deferred.resolve(results); - } - }; - - // Rejecter for promises. Rejects returned promise - // immediately, and overwrites rejecter var with a noop - // once promise to cover case where n < promises.length. - // TODO: Consider rejecting only when N (or promises.length - N?) - // promises have been rejected instead of only one? - rejecter = function(err) { - complete(); - deferred.reject(err); - }; - - handleProgress = deferred.progress; - - // TODO: Replace while with forEach - for(i = 0; i < len; ++i) { - if(i in promisesOrValues) { - when(promisesOrValues[i], resolve, reject, progress); - } - } - } - - return ret; - }); - } - - /** - * Return a promise that will resolve only once all the supplied promisesOrValues - * have resolved. The resolution value of the returned promise will be an array - * containing the resolution values of each of the promisesOrValues. - * - * @memberOf when - * - * @param promisesOrValues {Array|Promise} array of anything, may contain a mix - * of {@link Promise}s and values - * @param [callback] {Function} - * @param [errback] {Function} - * @param [progressHandler] {Function} - * - * @returns {Promise} - */ - function all(promisesOrValues, callback, errback, progressHandler) { - - checkCallbacks(1, arguments); - - return when(promisesOrValues, function(promisesOrValues) { - return _reduce(promisesOrValues, reduceIntoArray, []); - }).then(callback, errback, progressHandler); - } - - function reduceIntoArray(current, val, i) { - current[i] = val; - return current; - } - - /** - * Return a promise that will resolve when any one of the supplied promisesOrValues - * has resolved. The resolution value of the returned promise will be the resolution - * value of the triggering promiseOrValue. - * - * @memberOf when - * - * @param promisesOrValues {Array|Promise} array of anything, may contain a mix - * of {@link Promise}s and values - * @param [callback] {Function} - * @param [errback] {Function} - * @param [progressHandler] {Function} - * - * @returns {Promise} - */ - function any(promisesOrValues, callback, errback, progressHandler) { - - function unwrapSingleResult(val) { - return callback ? callback(val[0]) : val[0]; - } - - return some(promisesOrValues, 1, unwrapSingleResult, errback, progressHandler); - } - - /** - * Traditional map function, similar to `Array.prototype.map()`, but allows - * input to contain {@link Promise}s and/or values, and mapFunc may return - * either a value or a {@link Promise} - * - * @memberOf when - * - * @param promise {Array|Promise} array of anything, may contain a mix - * of {@link Promise}s and values - * @param mapFunc {Function} mapping function mapFunc(value) which may return - * either a {@link Promise} or value - * - * @returns {Promise} a {@link Promise} that will resolve to an array containing - * the mapped output values. - */ - function map(promise, mapFunc) { - return when(promise, function(array) { - return _map(array, mapFunc); - }); - } - - /** - * Private map helper to map an array of promises - * @private - * - * @param promisesOrValues {Array} - * @param mapFunc {Function} - * @return {Promise} - */ - function _map(promisesOrValues, mapFunc) { - - var results, len, i; - - // Since we know the resulting length, we can preallocate the results - // array to avoid array expansions. - len = promisesOrValues.length >>> 0; - results = new Array(len); - - // Since mapFunc may be async, get all invocations of it into flight - // asap, and then use reduce() to collect all the results - for(i = 0; i < len; i++) { - if(i in promisesOrValues) - results[i] = when(promisesOrValues[i], mapFunc); - } - - // Could use all() here, but that would result in another array - // being allocated, i.e. map() would end up allocating 2 arrays - // of size len instead of just 1. Since all() uses reduce() - // anyway, avoid the additional allocation by calling reduce - // directly. - return _reduce(results, reduceIntoArray, results); - } - - /** - * Traditional reduce function, similar to `Array.prototype.reduce()`, but - * input may contain {@link Promise}s and/or values, and reduceFunc - * may return either a value or a {@link Promise}, *and* initialValue may - * be a {@link Promise} for the starting value. - * - * @memberOf when - * - * @param promise {Array|Promise} array of anything, may contain a mix - * of {@link Promise}s and values. May also be a {@link Promise} for - * an array. - * @param reduceFunc {Function} reduce function reduce(currentValue, nextValue, index, total), - * where total is the total number of items being reduced, and will be the same - * in each call to reduceFunc. - * @param initialValue starting value, or a {@link Promise} for the starting value - * - * @returns {Promise} that will resolve to the final reduced value - */ - function reduce(promise, reduceFunc, initialValue) { - var args = slice.call(arguments, 1); - return when(promise, function(array) { - return _reduce.apply(undef, [array].concat(args)); - }); - } - - /** - * Private reduce to reduce an array of promises - * @private - * - * @param promisesOrValues {Array} - * @param reduceFunc {Function} - * @param initialValue {*} - * @return {Promise} - */ - function _reduce(promisesOrValues, reduceFunc, initialValue) { - - var total, args; - - total = promisesOrValues.length; - - // Skip promisesOrValues, since it will be used as 'this' in the call - // to the actual reduce engine below. - - // Wrap the supplied reduceFunc with one that handles promises and then - // delegates to the supplied. - - args = [ - function (current, val, i) { - return when(current, function (c) { - return when(val, function (value) { - return reduceFunc(c, value, i, total); - }); - }); - } - ]; - - if (arguments.length > 2) args.push(initialValue); - - return reduceArray.apply(promisesOrValues, args); - } - - /** - * Ensure that resolution of promiseOrValue will complete resolver with the completion - * value of promiseOrValue, or instead with resolveValue if it is provided. - * - * @memberOf when - * - * @param promiseOrValue - * @param resolver {Resolver} - * @param [resolveValue] anything - * - * @returns {Promise} - */ - function chain(promiseOrValue, resolver, resolveValue) { - var useResolveValue = arguments.length > 2; - - return when(promiseOrValue, - function(val) { - if(useResolveValue) val = resolveValue; - resolver.resolve(val); - return val; - }, - function(e) { - resolver.reject(e); - return rejected(e); - }, - resolver.progress - ); - } - - // - // Utility functions - // - - /** - * Helper that checks arrayOfCallbacks to ensure that each element is either - * a function, or null or undefined. - * - * @private - * - * @param arrayOfCallbacks {Array} array to check - * @throws {Error} if any element of arrayOfCallbacks is something other than - * a Functions, null, or undefined. - */ - function checkCallbacks(start, arrayOfCallbacks) { - var arg, i = arrayOfCallbacks.length; - while(i > start) { - arg = arrayOfCallbacks[--i]; - if (arg != null && typeof arg != 'function') throw new Error('callback is not a function'); - } - } - - /** - * No-Op function used in method replacement - * @private - */ - function noop() {} - - slice = [].slice; - - // ES5 reduce implementation if native not available - // See: http://es5.github.com/#x15.4.4.21 as there are many - // specifics and edge cases. - reduceArray = [].reduce || - function(reduceFunc /*, initialValue */) { - // ES5 dictates that reduce.length === 1 - - // This implementation deviates from ES5 spec in the following ways: - // 1. It does not check if reduceFunc is a Callable - - var arr, args, reduced, len, i; - - i = 0; - arr = Object(this); - len = arr.length >>> 0; - args = arguments; - - // If no initialValue, use first item of array (we know length !== 0 here) - // and adjust i to start at second item - if(args.length <= 1) { - // Skip to the first real element in the array - for(;;) { - if(i in arr) { - reduced = arr[i++]; - break; - } - - // If we reached the end of the array without finding any real - // elements, it's a TypeError - if(++i >= len) { - throw new TypeError(); - } - } - } else { - // If initialValue provided, use it - reduced = args[1]; - } - - // Do the actual reduce - for(;i < len; ++i) { - // Skip holes - if(i in arr) - reduced = reduceFunc(reduced, arr[i], i, arr); - } - - return reduced; - }; - - return when; -}); -})(typeof define == 'function' - ? define - : function (factory) { typeof module != 'undefined' - ? (module.exports = factory()) - : (this.when = factory()); - } - // Boilerplate for AMD, Node, and browser global -); diff --git a/labs/architecture-examples/cujo/lib/wire/LICENSE.txt b/labs/architecture-examples/cujo/lib/wire/LICENSE.txt deleted file mode 100644 index 2727d4f556..0000000000 --- a/labs/architecture-examples/cujo/lib/wire/LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -Open Source Initiative OSI - The MIT License - -http://www.opensource.org/licenses/mit-license.php - -Copyright (c) 2011 Brian Cavalier - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/labs/architecture-examples/cujo/lib/wire/README.md b/labs/architecture-examples/cujo/lib/wire/README.md deleted file mode 100644 index 7dff44ba6c..0000000000 --- a/labs/architecture-examples/cujo/lib/wire/README.md +++ /dev/null @@ -1,176 +0,0 @@ -Please Note: this project has moved from briancavalier/wire to cujojs/wire. -Any existing forks have been automatically moved to cujojs/wire. However, -you'll need to update your clone and submodule remotes manually. - -Update the url in your .git/config, and also .gitmodules for submodules: - -``` -git://github.com/cujojs/wire.git -https://cujojs@github.com/cujojs/wire.git -``` - -Helpful link for updating submodules: -[Git Submodules: Adding, Using, Removing, Updating](http://chrisjean.com/2009/04/20/git-submodules-adding-using-removing-and-updating/) - ----- - -# wire.js - -Wire.js is an [Inversion of Control Container](http://martinfowler.com/articles/injection.html "Inversion of Control Containers and the Dependency Injection pattern") for Javascript apps. - -With wire.js, you can focus on coding the business logic of your components and let wire.js handle the bootstrapping and the glue that connects them together. You write a simple [wiring spec](https://github.com/cujojs/wire/wiki/Wire-specs) in JSON (or Javascript) that describes how your components should be wired together, and wire will load, configure, and connect those components to create your application, and will clean them up later. - -### Specifically, wire.js provides: - -* Component lifecycle management -* Dependency Inversion via constructor and setter Dependency Injection -* Automatic dependency ordering -* Connectors -* Service locator pattern and reference resolution - -### Plugins - -Wire.js also has a plugin architecture that allows plugins to provide new capabilities to wire.js *and syntax* to wiring specs. Here are some of the capabilities provided by the bundled plugins: - -* Dependency Injection for DOM nodes. For example, you can reference DOM nodes by id *or dom query*, and inject them into your views. -* Event and PubSub connectors. Write your components without any glue code, and connect them together in the wiring spec using events or pubsub. The event connector works for DOM nodes, too! -* Aspect Oriented Programming (AOP). Wire.js comes with an AOP plugin that allows you to declaratively apply decorators, before/after/around advice, and to introduce mixins on the fly. - -### Framework integration - -Plugins also allow you to use capabilities of your existing modules/libraries/frameworks. For example, wire.js has a set of plugins for Dojo that allow it to integrate with Dijit's widget system, to use dojo.connect as the event connector, and dojo.publish/subscribe as the pubsub connector. If you are already using those aspects of Dojo, you can use wire.js's Dojo plugins to integrate easily with all your existing components. - -# Ok, What Now? - -1. [Read about](https://github.com/briancavalier/hello-wire.js) and [try out](http://briancavalier.com/code/hello-wire) the Hello Wire introduction. -1. Check out the [wire.js presentation from JSConf 2011](http://bit.ly/mkWy1L "wire.js - Javascript IOC Container w/Dependency Injection"). -1. Get the code for the [Piratescript or N00bscript](https://github.com/briancavalier/piratescript) game from the presentation. *Docs coming soon!* -1. See the [wiki for more documentation](https://github.com/cujojs/wire/wiki). -1. Fork it and try it out! - -# What's new - -### 0.8.1 - -* Compatible with [when.js](https://github.com/cujojs/when) v1.0.x - v1.3.0 - -### 0.8.0 - -* See the [full release notes](https://github.com/cujojs/wire/wiki/release-notes-080) for more detail, documentation, and examples of all the new features. -* Node and RingoJS -* New wire/dom/render plugin -* Plenty of other new DOM features -* Easier `wire/aop` single advices -* Improved debugging with `wire/debug` - -### 0.7.6 - -* New `waitParent` option for the [wire factory](https://github.com/cujojs/wire/wiki/Factories). When set to `true`, it guarantees a child context will not even start wiring until the encompassing parent has completed. -* Update to [when.js](https://github.com/cujojs/when) v1.0.2 - -### 0.7.5 - -* Minor fix for using wire in a non-AMD browser environment -* Update to [when.js](https://github.com/cujojs/when) v0.10.4 -* Update to [aop.js](https://github.com/cujojs/aop) v0.5.2 - -### 0.7.4 - -* `wire/debug` plugin now supports runtime app tracing. Check out the [new options](https://github.com/cujojs/wire/wiki/wire-debug). -* Fix for all known instances where wire would not notice errors that happen during wiring. -* Baby steps toward Node compatibility for the wire.js core. *We're currently targetting v0.8.0 as the first Node-compatible version*. -* Update to [when.js](https://github.com/cujojs/when) v0.10.3 -* Update to [aop.js](https://github.com/cujojs/aop) v0.5.0 - -### 0.7.3 - -* Updated `wire/domReady` helper to work with latest [RequireJS](https://github.com/jrburke/requirejs) `domReady!` plugin, while maintaining backward compatibility with older versions of RequireJS that use `require.ready` -* Updates for compatibility with [curl](https://github.com/unscriptable/curl) v0.5.4 and curl `domReady!` plugin -* `wire/debug` plugin - Simplified solution for broken/missing console in IE < 8 - -### 0.7.2 - -* Updated build/optimizer support for [cram](https://github.com/unscriptable/cram) v0.2+ - -### 0.7.1 - -* Improved logging in `wire/debug`, now with stack traces, and guards against missing `console` in IE. -* Guard against null when scanning plugins -* Update to [when.js](https://github.com/cujojs/when) v0.9.4 - -### 0.7.0 - -* New [wire factory](https://github.com/cujojs/wire/wiki/Factories) (aka wire inception!) that allows wiring chains of other specs, or injecting functions for deferred wiring. [See the docs](https://github.com/cujojs/wire/wiki/Factories) -* [wire/dojo/dijit](https://github.com/cujojs/wire/wiki/wire-dojo-dijit) plugin: - * `placeAt` feature that allows easier placement of Dijit widgets. - * supports easy dijit theming via its `theme` option -* New [wire/dojo/data](https://github.com/cujojs/wire/wiki/wire-dojo-data) plugin that supports legacy `dojo/data` datastores -* [wire/dom](https://github.com/cujojs/wire/wiki/wire-dom) plugin now supports options for adding/removing classes to `` during wiring. -* Now using [when.js](https://github.com/cujojs/when) v0.9.3 for promises and async handling. See also the Deprecated Functionality below. -* The wire.js core is now **only 2.5k** with Google Closure + gzip! -* **Limited support** for using wire in a non-AMD setup. This is intended to aid in transitioning to AMD and CommonJS modules, and *it's unlikely that wire's full functionality will ever be extended to cover non-AMD/CommonJS environments.* - * wire.js can now create components using raw constructors in addition to AMD module ids. This allows wire.js to create components instances from libraries that haven't yet fully committed to AMD or CommonJS. -* **Deprecated functionality** - to be removed in v0.8.0 - * Injecting a reference to the [full current context](https://github.com/cujojs/wire/wiki/Contexts) via `{ $ref: 'wire!context' }` - * The components in the current context will always be in an incomplete state, and relying on this is potentially dangerous. - * I may consider allowing injecting a *promise* for the current context, which would resolve after the current context has finished wiring. - * If you were using the `wire()` method of a context injected via `{ $ref: 'wire!context' }`, you can use `{ $ref: 'wire!' }` instead, which provides a direct reference to the `wire()` method itself--i.e. it injects a *function* that works just like `context.wire()`. - * Many plugin methods received a `wire` parameter that had several promise helper methods, such as `wire.when`, `wire.whenAll`, etc. These are deprecated in favor of simply using [when.js](https://github.com/cujojs/when) instead, which is provided as a submodule in the support dir. - -### 0.6.0 - -* [wire/aop](https://github.com/cujojs/wire/wiki/wire-aop) plugin: AOP weaving with pointcuts, and before, after, afterReturning, afterThrowing, after (aka "afterFinally") advice using [aop.js](https://github.com/cujojs/aop) -* Experimental optimizer/build tool support for [cram](https://github.com/unscriptable/cram). Point cram at your wire spec and let it optimize your entire app! *Docs coming soon* -* [wire/debug](https://github.com/cujojs/wire/wiki/wire-debug) plugin: tracks components and tells you which ones couldn't be wired and why -* Improved memory management, especially when destroying contexts. -* **Breaking Changes** - * The plugin format has changed to support new, more powerful async plugins. See the [Plugin format wiki](https://github.com/cujojs/wire/wiki/Plugin-format) for more information - * [wire/aop](https://github.com/cujojs/wire/wiki/wire-aop) decorator and introduction options have changed. See the [wire/aop wiki](https://github.com/cujojs/wire/wiki/wire-aop) for more information - -### 0.5.2 - -* Fix for [wire/sizzle](https://github.com/cujojs/wire/wiki/wire-aop) plugin -* Updated to work with [curl v0.5](https://github.com/unscriptable/curl) domReady. -* **NOTE** wire.js v0.5.2 now requires curl.js 0.5 or later. It will also work with any recent version of RequireJS, and with dojo 1.6 or later. - -### 0.5.1 - -* `create` factory now supports the `isConstructor` option, when `true`, forces an object instance to be created using `new`. -* Improved debug output when using [wire/debug](https://github.com/cujojs/wire/wiki/wire-debug) plugin, -* Slimmed down [wire/aop](https://github.com/cujojs/wire/wiki/wire-aop) plugin in preparation for a new version in an upcoming release, -* Automated unit tests using [Dojo DOH](http://dojotoolkit.org/reference-guide/util/doh.html), -* Semantic versioning - -### 0.5 - -* Re-engineered core: smaller, faster, and more loader-independent, -* Can be used as either an AMD module or an AMD plugin, -* Tested with [curl.js](https://github.com/unscriptable/curl), and [RequireJS](http://requirejs.org/). Should also work with the upcoming [dojo 1.7 loader](http://dojotoolkit.org/) (but hasn't been tested yet), -* Improved plugin system, -* AOP plugin, [wire/aop](https://github.com/cujojs/wire/wiki/wire-aop): Decorators and Introductions. *Coming Soon*: before, after, afterReturning, afterThrowing, and around advice, -* Prototype factory plugin allows using the JS prototype chain to create new objects directly from other objects in your wire spec. -* Sizzle plugin, `wire/sizzle`, courtesy of [@unscriptable](https://twitter.com/unscriptable) -* Not entirely new to 0.5, but worth mentioning Dojo integration, including: - * pubsub connector, subscribe *and publish* non-invasively using `dojo.publish/subscribe` - * event connector that uses dojo.connect - * easy JsonRest datastores via `resource!` reference resolver - * `dom.query!` reference resolver that uses `dojo.query` - -# Roadmap - -### v0.8.0 - -* Plugin namespacing -* CommonJS compatibility -* Node.js compatibility - -## Future - -* Library/Framework agnostic event and pubsub connectors -* AOP weaving support for decorators and introductions -* Support for more AMD loaders -* Integration with more libs and frameworks. - -# License - -wire.js is licensed under [The MIT License](http://www.opensource.org/licenses/mit-license.php). diff --git a/labs/architecture-examples/cujo/lib/wire/debug.js b/labs/architecture-examples/cujo/lib/wire/debug.js deleted file mode 100644 index 67506a6c82..0000000000 --- a/labs/architecture-examples/cujo/lib/wire/debug.js +++ /dev/null @@ -1,517 +0,0 @@ -/** @license MIT License (c) copyright B Cavalier & J Hann */ - -/** - * debug - * wire plugin that logs timing and debug information about wiring context and object - * lifecycle events (e.g. creation, properties set, initialized, etc.). - * - * wire is part of the cujo.js family of libraries (http://cujojs.com/) - * - * Licensed under the MIT License at: - * http://www.opensource.org/licenses/mit-license.php - * - * Usage: - * { - * module: 'wire/debug', - * - * // verbose (Optional) - * // If set to true, even more (a LOT) info will be output. - * // Default is false if not specified. - * verbose: false, - * - * // timeout (Optional) - * // Milliseconds to wait for wiring to finish before reporting - * // failed components. There may be failures caused by 3rd party - * // wire plugins and components that wire.js cannot detect. This - * // provides a last ditch way to try to report those failures. - * // Default is 5000ms (5 seconds) - * timeout: 5000, - * - * // filter (Optional) - * // String or RegExp to match against a component's name. Only - * // components whose path matches will be reported in the debug - * // diagnostic output. - * // All components will still be tracked for failures. - * // This can be useful in reducing the amount of diagnostic output and - * // focusing it on specific components. - * // Defaults to matching all components - * // Examples: - * // filter: ".*View" - * // filter: /.*View/ - * // filter: "[fF]oo[bB]ar" - * filter: ".*" - * - * // trace (Optional) - * // Enables application component tracing that will log information about component - * // method calls while your application runs. This provides a powerful way to watch - * // and debug your application as it runs. - * // To enable full tracing, which is a LOT of information: - * trace: true - * // Or, specify options to enable more focused tracing: - * trace: { - * // filter (Optional) - * // Similar to above, can be string pattern or RegExp - * // If not specified, the general debug filter is used (see above) - * filter: ".*View", - * - * // pointcut (Optional) - * // Matches *method names*. Can be used with or without specifying filter - * // When filter is not specified, this will match methods across all components. - * // For example, if all your components name their event emitters "on", e.g. "onClick" - * // you could trace all your event emitters: - * // Default: "^[^_]" (all methods not starting with '_') - * pointcut: "on.*", - * - * // step (Optional) - * // At what step in the wiring process should tracing start. This can be helpful - * // if you need to trace a component during wiring. - * // Values: 'create', 'configure', 'initialize', 'ready', 'destroy' - * // NOTE: This defines when tracing *begins*. For example, if this is set to - * // 'configure' (the default), anything that happens to components during and - * // after the configure step, until that component is destroyed, will be traced. - * // Default: 'configure' - * step: 'configure' - * } - * } - */ -(function(global, define) { -define(['aop'], function(aop) { - var timer, defaultTimeout, logger, createTracer; - - function noop() {} - - // Setup console for node, sane browsers, or IE - logger = typeof console != 'undefined' - ? console - : global['console'] || { log:noop, error:noop }; - - // TODO: Consider using stacktrace.js - // https://github.com/eriwen/javascript-stacktrace - // For now, quick and dirty, based on how stacktrace.js chooses the appropriate field - // and log using console.error - function logStack(e) { - var stack = e.stack || e.stacktrace; - if(!stack) { - // If e.sourceURL and e.line are available, this is probably Safari, so - // we can build a clickable source:line - // Fallback to message if available - // If all else fails, just use e itself - stack = e.sourceURL && e.line - ? e.sourceURL + ':' + e.line - : e.message || e; - } - - logger.error(stack); - } - - timer = createTimer(); - - // If we don't see any wiring progress in this amount of time - // since the last time we saw something happen, then we'll log - // an error. - defaultTimeout = 5000; - - /** - * Builds a string with timing info and a message for debug output - * - * @param text {String} message - * @param contextTimer per-context timer information - * - * @returns A formatted string for output - */ - function time(text, contextTimer) { - var all, timing; - - all = timer(); - timing = "(total: " + - (contextTimer - ? all.total + "ms, context: " + contextTimer() - : all) - + "): "; - - return "DEBUG " + timing + text; - } - - /** - * Creates a timer function that, when called, returns an object containing - * the total elapsed time since the timer was created, and the split time - * since the last time the timer was called. All times in milliseconds - * - * @returns timer - */ - function createTimer() { - var start, split; - - start = new Date().getTime(); - split = start; - - /** - * Returns the total elapsed time since this timer was created, and the - * split time since this getTime was last called. - * - * @returns Object containing total and split times in milliseconds, plus a - * toString() function that is useful in logging the time. - */ - return function getTime() { - var now, total, splitTime; - - now = new Date().getTime(); - total = now - start; - splitTime = now - split; - split = now; - - return { - total:total, - split:splitTime, - toString:function () { - return '' + splitTime + 'ms / ' + total + 'ms'; - } - }; - }; - } - - function defaultFilter(path) { - return !!path; - } - - function createPathFilter(filter) { - if (!filter) return defaultFilter; - - var rx = filter.test ? filter : new RegExp(filter); - - return function (path) { - return rx.test(path); - } - - } - - /** - * Returns true if it is a Node - * Adapted from: http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object - * @param it anything - * @return true iff it is a Node - */ - function isNode(it) { - return typeof Node === "object" ? it instanceof Node : - it && typeof it === "object" && typeof it.nodeType === "number" && typeof it.nodeName==="string"; - } - - /** - * Function that applies tracing AOP to components being wired - * @function - * @param options {Object} tracing options - * @param plugin {Object} debug plugin instance to which to add tracing functionality - */ - createTracer = (function() { - var depth, padding, defaultStep, defaultPointcut; - - /** Current trace depth */ - depth = 0; - - /** Padding character for indenting traces */ - padding = '.'; - - /** 2^8 padding = 128 */ - for(var i=0; i<8; i++) { - padding += padding; - } - - /** Default lifecycle step at which to begin tracing */ - defaultStep = 'configure'; - - /** Default pointcut query to match methods that will be traced */ - defaultPointcut = /^[^_]/; - - function logAfter(context, tag, start, val) { - console.log(context + tag + (new Date().getTime() - start.getTime()) + 'ms): ', val); - } - - /** - * Creates an aspect to be applied to components that are being traced - * @param path {String} component path - */ - function createTraceAspect(path) { - return { - around:function (joinpoint) { - var val, context, start, indent; - - // Setup current indent level - indent = padding.substr(0, depth); - // Form full path to invoked method - context = indent + 'DEBUG: ' + path + '.' + joinpoint.method; - - // Increase the depth before proceeding so that nested traces will be indented - ++depth; - - logger.log(context, joinpoint.args); - - try { - start = new Date(); - val = joinpoint.proceed(); - - logAfter(context, ' RETURN (', start, val); - - // return result - return val; - - } catch (e) { - - // rethrow - logAfter(context, ' THROW (', start, e ? e.toString() : e); - - throw e; - - } finally { - // And now decrease the depth after - --depth; - } - } - }; - } - - /** - * Implementation of createTracer - */ - return function(options, plugin, filter) { - var trace, untrace, traceStep, traceFilter, tracePointcut, traceAspects; - - traceFilter = options.trace.filter ? createPathFilter(options.trace.filter) : filter; - tracePointcut = options.trace.pointcut || defaultPointcut; - traceStep = options.trace.step || defaultStep; - - function isTraceable(target, prop) { - return typeof target[prop] === 'function' - && prop !== 'wire$plugin' - && tracePointcut.test(prop); - } - - /** - * Trace pointcut query function that filters out wire plugins - * @param target {Object} target object to query for methods to advise - */ - function pointcut(target) { - var matches = []; - - if(isNode(target)) return matches; - - for (var p in target) { - // Only match functions, exclude wire plugins, and then apply - // the supplied tracePointcut regexp - if (isTraceable(target, p)) { - matches.push(p); - } - } - - return matches; - } - - traceAspects = []; - trace = function (path, target) { - if (traceFilter(path)) { - // Create the aspect, if the path matched - traceAspects.push(aop.add(target, pointcut, createTraceAspect(path))); - } - // trace intentionally does not resolve the promise - // trace relies on the existing plugin method to resolve it - }; - - untrace = function () { - for (var i = traceAspects.length-1; i >= 0; --i) { - traceAspects[i].remove(); - } - }; - - // Defend against changes to the plugin in future revs - var orig = plugin[traceStep] || function (promise) { promise.resolve(); }; - - // Replace the plugin listener method with one that will call trace() - // and add traceAspect - plugin[traceStep] = function (promise, proxy, wire) { - trace(proxy.path, proxy.target); - orig(promise, proxy, wire); - }; - - return { trace: trace, untrace: untrace }; - } - - })(); - - function logSeparator() { - logger.log('---------------------------------------------------'); - } - - return { - wire$plugin:function debugPlugin(ready, destroyed, options) { - - var contextTimer, timeout, paths, count, tag, logCreated, logDestroyed, checkPathsTimeout, - verbose, filter, plugin, tracer; - - verbose = options.verbose; - contextTimer = createTimer(); - - count = 0; - tag = "WIRING"; - - tracer = { trace: noop, untrace: noop }; - - filter = createPathFilter(options.filter); - - function contextTime(msg) { - return time(msg, contextTimer); - } - - logger.log(contextTime("Context init")); - - ready.then( - function onContextReady(context) { - cancelPathsTimeout(); - logger.log(contextTime("Context ready"), context); - }, - function onContextError(err) { - cancelPathsTimeout(); - console.error(contextTime("Context ERROR: ") + err, err); - logStack(err); - } - ); - - destroyed.then( - function onContextDestroyed() { - tracer.untrace(); - logger.log(contextTime("Context destroyed")); - }, - function onContextDestroyError(err) { - tracer.untrace(); - logger.error(contextTime("Context destroy ERROR") + err, err); - logStack(err); - } - ); - - function makeListener(step, verbose) { - return function (promise, proxy /*, wire */) { - cancelPathsTimeout(); - - var path = proxy.path; - - if (paths[path]) { - paths[path].status = step; - } - - if (verbose && filter(path)) { - var message = time(step + ' ' + (path || proxy.id || ''), contextTimer); - if (proxy.target) { - logger.log(message, proxy.target, proxy.spec); - } else { - logger.log(message, proxy); - } - } - - if(count) { - checkPathsTimeout = setTimeout(checkPaths, timeout); - } - - promise.resolve(); - } - } - - paths = {}; - timeout = options.timeout || defaultTimeout; - logCreated = makeListener('created', verbose); - logDestroyed = makeListener('destroyed', true); - - function cancelPathsTimeout() { - clearTimeout(checkPathsTimeout); - checkPathsTimeout = null; - } - - function checkPaths() { - if (!checkPathsTimeout) return; - - var p, component, msg, ready, notReady; - - logSeparator(); - if(count) { - ready = []; - notReady = []; - logger.error(tag + ': No progress in ' + timeout + 'ms, status:'); - - for (p in paths) { - component = paths[p]; - msg = p + ': ' + component.status; - - (component.status == 'ready' ? ready : notReady).push( - { msg: msg, spec: component.spec } - ); - } - - if(notReady.length > 0) { - logSeparator(); - logger.log('Components that DID NOT finish wiring'); - for(p = notReady.length-1; p >= 0; --p) { - component = notReady[p]; - logger.error(component.msg, component.spec); - } - } - - if(ready.length > 0) { - logSeparator(); - logger.log('Components that finished wiring'); - for(p = ready.length-1; p >= 0; --p) { - component = ready[p]; - logger.log(component.msg, component.spec); - } - } - } else { - logger.error(tag + ': No components created after ' + timeout + 'ms'); - } - - logSeparator(); - } - - plugin = { - create:function (promise, proxy) { - var path = proxy.path; - - count++; - paths[path || ('(unnamed-' + count + ')')] = { - spec:proxy.spec - }; - - logCreated(promise, proxy); - }, - configure: makeListener('configured', verbose), - initialize: makeListener('initialized', verbose), - ready: makeListener('ready', true), - destroy: function(promise, proxy) { - // stop tracking destroyed components, since we don't - // care anymore - delete paths[proxy.path]; - count--; - tag = "DESTROY"; - - logDestroyed(promise, proxy); - } - }; - - if (options.trace) { - tracer = createTracer(options, plugin, filter); - } - - checkPathsTimeout = setTimeout(checkPaths, timeout); - - return plugin; - } - }; - -}); -})(this, typeof define == 'function' - // use define for AMD if available - ? define - : typeof module != 'undefined' - ? function(deps, factory) { - module.exports = factory.apply(this, deps.map(function(x) { - return require(x); - })); - } - // If no define or module, attach to current context. - : function(deps, factory) { this.wire_debug = factory(this.aop); } -); diff --git a/labs/architecture-examples/cujo/lib/wire/dom/transform/mapTokenList.js b/labs/architecture-examples/cujo/lib/wire/dom/transform/mapTokenList.js deleted file mode 100644 index 54eb018348..0000000000 --- a/labs/architecture-examples/cujo/lib/wire/dom/transform/mapTokenList.js +++ /dev/null @@ -1,32 +0,0 @@ -(function (define) { -define(function () { -"use strict"; - - var parser = /(^|\s+)([^\s]+)/g; - - return function (map, options) { - var fallbackToken; - - if (!options) options = {}; - - fallbackToken = options.otherwise || ''; - - return function translateTokenLists (tokenList) { - tokenList = '' + tokenList; - return tokenList.replace(parser, function (m, s, token) { - var trans = map[token]; - // if there's a delimiter already (spaces, typically), - // replace it. if a translated value exists, use it. - // otherwise, use original token. - return (s ? ' ' : s) + (trans ? trans : fallbackToken); - }); - } - - }; - -}); -}( - typeof define == 'function' && define.amd - ? define - : function (factory) { module.exports = factory(); } -)); diff --git a/labs/architecture-examples/cujo/lib/wire/package.json b/labs/architecture-examples/cujo/lib/wire/package.json deleted file mode 100644 index 0f15c30b27..0000000000 --- a/labs/architecture-examples/cujo/lib/wire/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "wire", - "version": "0.9.0-dev", - "description": "A light, fast, flexible Javascript IOC container.", - "keywords": [ - "ioc", - "aop", - "dependency injection", - "dependency inversion", - "application composition" - ], - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/mit-license.php" - } - ], - "repositories": [ - { - "type": "git", - "url": "https://github.com/cujojs/wire" - } - ], - "bugs": "https://github.com/cujojs/wire/issues", - "maintainers": [ - { - "name": "Brian Cavalier", - "web": "http://hovercraftstudios.com" - } - ], - "contributors": [ - { - "name": "Brian Cavalier", - "web": "http://hovercraftstudios.com" - }, - { - "name": "John Hann", - "web": "http://unscriptable.com" - } - ], - "dependencies": { - "aop": "git://github.com/cujojs/aop#0.5.3", - "when": "~1" - }, - "main": "./wire", - "directories": { - "test": "test" - }, - "scripts": { - "test": "buster test -e node" - } -} diff --git a/readme.md b/readme.md index 8901cc937f..053b77cc4a 100644 --- a/readme.md +++ b/readme.md @@ -48,7 +48,7 @@ We also have a number of in-progress applications in Labs: - [Kendo UI](http://kendoui.com) - [Flight by Twitter](https://github.com/twitter/flight) - [Maria.js](https://github.com/petermichaux/maria) -- [cujo.js](http://cujojs.github.com) +- [cujoJS](http://cujojs.com) - [MarionetteJS](http://marionettejs.com/) - [SocketStream](http://www.socketstream.org) + [jQuery](http://jquery.com) - [Ext.js](http://www.sencha.com/products/extjs)