rearrange things so that we can destroy/create the app for test isolation

This commit is contained in:
Sven Fuchs 2012-06-26 03:11:38 +02:00
parent cc49b87a97
commit daed80916b
22 changed files with 469 additions and 429 deletions

View File

@ -1,16 +1,22 @@
@Travis = Em.Application.create() @Travis = Em.Namespace.create
App: Em.Application.extend
initialize: ->
$.extend(this, Travis.Controllers)
$.extend(this, Travis.Views)
@store = Travis.Store.create()
@_super(Travis.Router.create())
run: ->
@app = Travis.App.create()
@app.initialize()
require 'ext/jquery' require 'ext/jquery'
require 'locales' require 'controllers'
require 'travis/data_store/rest_adapter'
require 'helpers' require 'helpers'
require 'models' require 'models'
require 'views' require 'router'
require 'store'
require 'templates' require 'templates'
require 'controllers' require 'views'
require 'routes' require 'locales'
Travis.store = DS.Store.extend(
revision: 4
adapter: Travis.RestAdapter.create()
).create()

View File

@ -1,9 +1,12 @@
Travis.ApplicationController = Em.Controller.extend() require 'helpers'
Travis.RepositoriesController = Em.ArrayController.extend()
Travis.RepositoryController = Em.ObjectController.extend(Travis.Urls.Repository) Travis.Controllers =
Travis.TabsController = Em.Controller.extend() ApplicationController: Em.Controller.extend()
Travis.HistoryController = Em.ArrayController.extend() RepositoriesController: Em.ArrayController.extend()
Travis.BuildController = Em.ObjectController.extend(Travis.Urls.Commit) RepositoryController: Em.ObjectController.extend(Travis.Urls.Repository)
Travis.JobController = Em.ObjectController.extend(Travis.Urls.Commit) TabsController: Em.Controller.extend()
HistoryController: Em.ArrayController.extend()
BuildController: Em.ObjectController.extend(Travis.Urls.Commit)
JobController: Em.ObjectController.extend(Travis.Urls.Commit)

View File

@ -49,7 +49,7 @@ require 'travis/model'
@Travis.Job.reopenClass @Travis.Job.reopenClass
queued: (queue) -> queued: (queue) ->
@all() @all()
Travis.store.filter this, (job) -> job.get('queue') == 'builds.' + queue Travis.app.store.filter this, (job) -> job.get('queue') == 'builds.' + queue
findMany: (ids) -> findMany: (ids) ->
Travis.store.findMany this, ids Travis.app.store.findMany this, ids

View File

@ -1,7 +1,7 @@
require 'hax0rs' require 'hax0rs'
@Travis.Router = Em.Router.extend @Travis.Router = Em.Router.extend
enableLogging: true # enableLogging: true
location: 'hash' location: 'hash'
root: Em.Route.extend root: Em.Route.extend
@ -108,7 +108,7 @@ require 'hax0rs'
serializeRepository: (object) -> serializeRepository: (object) ->
if object instanceof DS.Model if object instanceof Travis.Repository
slug = object.get('slug') || object._id # wat. slug = object.get('slug') || object._id # wat.
{ owner: slug.split('/')[0], name: slug.split('/')[1] } { owner: slug.split('/')[0], name: slug.split('/')[1] }
else else

View File

@ -0,0 +1,5 @@
require 'store/rest_adapter'
Travis.Store = DS.Store.extend
revision: 4
adapter: Travis.RestAdapter.create()

View File

@ -1,3 +1,5 @@
require 'models'
@Travis.RestAdapter = DS.RESTAdapter.extend @Travis.RestAdapter = DS.RESTAdapter.extend
init: -> init: ->
@_super() @_super()

View File

@ -11,7 +11,7 @@
<tbody> <tbody>
{{#each build in content}} {{#each build in content}}
{{#view Travis.BuildsItemView contextBinding="build"}} {{#view Travis.Views.BuildsItemView contextBinding="build"}}
<tr> <tr>
<td class="number"><a {{action viewBuild href=true}}>{{number}}</a></td> <td class="number"><a {{action viewBuild href=true}}>{{number}}</a></td>
<td class="commit"><a {{bindAttr href="view.urlGithubCommit"}}>{{formatCommit commit}}</a></td> <td class="commit"><a {{bindAttr href="view.urlGithubCommit"}}>{{formatCommit commit}}</a></td>

View File

@ -37,10 +37,10 @@
{{#if isLoaded}} {{#if isLoaded}}
{{#if view.isMatrix}} {{#if view.isMatrix}}
{{view Travis.JobsView jobsBinding="view.requiredJobs" required="true"}} {{view Travis.Views.JobsView jobsBinding="view.requiredJobs" required="true"}}
{{view Travis.JobsView jobsBinding="view.allowedFailureJobs"}} {{view Travis.Views.JobsView jobsBinding="view.allowedFailureJobs"}}
{{else}} {{else}}
{{view Travis.LogView contextBinding="jobs.firstObject"}} {{view Travis.Views.LogView contextBinding="jobs.firstObject"}}
{{/if}} {{/if}}
{{/if}} {{/if}}
</div> </div>

View File

@ -32,6 +32,6 @@
<dd class="config">{{formatConfig config}}</dd> <dd class="config">{{formatConfig config}}</dd>
</dl> </dl>
{{view Travis.LogView}} {{view Travis.Views.LogView}}
</div> </div>

View File

@ -1,7 +1,7 @@
{{#if content.lastObject.isLoaded}} {{#if content.lastObject.isLoaded}}
<ul id="repositories"> <ul id="repositories">
{{#each repository in content}} {{#each repository in content}}
{{#view Travis.RepositoriesItemView tagName="li" classBinding="classes" contextBinding="repository"}} {{#view Travis.Views.RepositoriesItemView tagName="li" classBinding="classes" contextBinding="repository"}}
<div class="wrapper"> <div class="wrapper">
<a {{action viewCurrent href=true}} class="slug">{{slug}}</a> <a {{action viewCurrent href=true}} class="slug">{{slug}}</a>
<a {{action viewBuild href=true context="lastBuild"}} class="build">#{{lastBuildNumber}}</a> <a {{action viewBuild href=true context="lastBuild"}} class="build">#{{lastBuildNumber}}</a>

View File

@ -1,66 +1,67 @@
Travis.ApplicationView = Em.View.extend Travis.Views =
templateName: 'application' ApplicationView: Em.View.extend
templateName: 'application'
Travis.RepositoriesView = Em.View.extend RepositoriesView: Em.View.extend
templateName: 'repositories/list' templateName: 'repositories/list'
Travis.RepositoriesItemView = Em.View.extend RepositoriesItemView: Em.View.extend
classes: (-> classes: (->
color = Travis.Helpers.colorForResult(@getPath('repository.lastBuildResult')) color = Travis.Helpers.colorForResult(@getPath('repository.lastBuildResult'))
classes = ['repository', color] classes = ['repository', color]
classes.push 'selected' if @getPath('repository.selected') classes.push 'selected' if @getPath('repository.selected')
classes.join(' ') classes.join(' ')
).property('repository.lastBuildResult', 'repository.selected') ).property('repository.lastBuildResult', 'repository.selected')
lastBuild: (-> lastBuild: (->
owner: @getPath('repository.owner') owner: @getPath('repository.owner')
name: @getPath('repository.name') name: @getPath('repository.name')
id: @getPath('repository.lastBuildId') id: @getPath('repository.lastBuildId')
).property('repository.owner', 'repository.name', 'repository.lastBuildId') ).property('repository.owner', 'repository.name', 'repository.lastBuildId')
Travis.RepositoryView = Em.View.extend RepositoryView: Em.View.extend
templateName: 'repositories/show' templateName: 'repositories/show'
Travis.TabsView = Em.View.extend TabsView: Em.View.extend
templateName: 'repositories/tabs' templateName: 'repositories/tabs'
Travis.HistoryView = Em.View.extend HistoryView: Em.View.extend
templateName: 'builds/list' templateName: 'builds/list'
Travis.BuildsItemView = Em.View.extend BuildsItemView: Em.View.extend
classes: (-> classes: (->
Travis.Helpers.colorForResult(@getPath('content.result')) Travis.Helpers.colorForResult(@getPath('content.result'))
).property('content.result') ).property('content.result')
Travis.BuildView = Em.View.extend BuildView: Em.View.extend
templateName: 'builds/show' templateName: 'builds/show'
classes: (-> classes: (->
Travis.Helpers.colorForResult(@get('result')) Helpers.colorForResult(@get('result'))
).property('result') ).property('result')
isMatrix: (-> isMatrix: (->
@getPath('context.data.job_ids.length') > 1 @getPath('context.data.job_ids.length') > 1
).property() # TODO if i bind this to 'context.data.job_ids.length', that breaks the entire view (as if context was always undefined) ).property() # TODO if i bind this to 'context.data.job_ids.length', that breaks the entire view (as if context was always undefined)
requiredJobs: (-> requiredJobs: (->
@getPath('context.jobs').filter((job) -> job.get('allow_failure') != true) @getPath('context.jobs').filter((job) -> job.get('allow_failure') != true)
).property() # TODO same here with binding to 'context.data.job_ids' ).property() # TODO same here with binding to 'context.data.job_ids'
allowedFailureJobs: (-> allowedFailureJobs: (->
@getPath('context.jobs').filter((job) -> job.get('allow_failure')) @getPath('context.jobs').filter((job) -> job.get('allow_failure'))
).property() ).property()
Travis.JobsView = Em.View.extend JobsView: Em.View.extend
templateName: 'jobs/list' templateName: 'jobs/list'
Travis.JobView = Em.View.extend JobView: Em.View.extend
templateName: 'jobs/show' templateName: 'jobs/show'
classes: (-> classes: (->
Travis.Helpers.colorForResult(@get('result')) Travis.Helpers.colorForResult(@get('result'))
).property('result') ).property('result')
Travis.LogView = Em.View.extend LogView: Em.View.extend
templateName: 'jobs/log' templateName: 'jobs/log'

View File

@ -4,7 +4,7 @@
refresh: -> refresh: ->
id = @get('id') id = @get('id')
Travis.store.adapter.find(Travis.store, @constructor, id) if id Travis.app.store.adapter.find(Travis.app.store, @constructor, id) if id
update: (attrs) -> update: (attrs) ->
$.each attrs, (key, value) => $.each attrs, (key, value) =>
@ -13,7 +13,7 @@
@Travis.Model.reopenClass @Travis.Model.reopenClass
load: (attrs) -> load: (attrs) ->
Travis.store.load(this, attrs) Travis.app.store.load(this, attrs)
buildURL: (suffix) -> buildURL: (suffix) ->
base = @url || @pluralName() base = @url || @pluralName()
@ -29,5 +29,5 @@
name.replace(/([A-Z])/g, '_$1').toLowerCase().slice(1) name.replace(/([A-Z])/g, '_$1').toLowerCase().slice(1)
pluralName: -> pluralName: ->
Travis.store.adapter.pluralize(@singularName()) Travis.app.store.adapter.pluralize(@singularName())

View File

@ -1,14 +1,10 @@
describe 'Foo', -> describe 'Foo', ->
it 'bar', -> it 'bar', ->
console.log('before spec')
link = $($('#repositories a.slug')[0]) link = $($('#repositories a.slug')[0])
console.log $('body').html().toString() console.log $('body').html()
# link.attr('href').should.equal '#/travis-ci/travis-core' # link.attr('href').should.equal '#/travis-ci/travis-core'
console.log('after spec')
it 'bar', -> it 'bar', ->
console.log('before spec')
link = $($('#repositories a.slug')[0]) link = $($('#repositories a.slug')[0])
# link.attr('href').should.equal '#/travis-ci/travis-core' # link.attr('href').should.equal '#/travis-ci/travis-core'
console.log('after spec')

View File

@ -1,11 +1,12 @@
minispade.require 'app' minispade.require 'app'
$('body').append($('<div id="spec_content"></div>')) beforeEach ->
Travis.rootElement = '#spec_content' $('body #content').empty()
Em.run ->
Travis.app = Travis.App.create()
Travis.app.set('rootElement', '#content')
Travis.app.initialize()
# beforeEach -> afterEach ->
# $('body #spec_content').empty() Travis.app.destroy()
# Travis.initialize()
# afterEach ->
#

View File

@ -1,5 +1,5 @@
// Version: v0.9.8.1-423-g84e9626 // Version: v0.9.8.1-437-g68d406e
// Last commit: 84e9626 (2012-06-22 15:45:46 -0700) // Last commit: 68d406e (2012-06-25 14:59:55 -0700)
(function() { (function() {
@ -16,22 +16,12 @@ if ('undefined' === typeof Ember) {
/** /**
Define an assertion that will throw an exception if the condition is not Define an assertion that will throw an exception if the condition is not
met. Ember build tools will remove any calls to Ember.assert() when met. Ember build tools will remove any calls to Ember.assert() when
doing a production build. doing a production build. Example:
## Examples // Test for truthiness
Ember.assert('Must pass a valid object', obj);
#js: // Fail unconditionally
Ember.assert('This code path should never be run')
// pass a simple Boolean value
Ember.assert('must pass a valid object', !!obj);
// pass a function. If the function returns false the assertion fails
// any other return value (including void) will pass.
Ember.assert('a passed record must have a firstName', function() {
if (obj instanceof Ember.Record) {
return !Ember.empty(obj.firstName);
}
});
@static @static
@function @function
@ -40,12 +30,10 @@ if ('undefined' === typeof Ember) {
thrown if the assertion fails. thrown if the assertion fails.
@param {Boolean} test @param {Boolean} test
Must return true for the assertion to pass. If you pass a function it Must be truthy for the assertion to pass. If falsy, an exception will be
will be executed. If the function returns false an exception will be
thrown. thrown.
*/ */
Ember.assert = function(desc, test) { Ember.assert = function(desc, test) {
if ('function' === typeof test) test = test()!==false;
if (!test) throw new Error("assertion failed: "+desc); if (!test) throw new Error("assertion failed: "+desc);
}; };
@ -60,12 +48,9 @@ Ember.assert = function(desc, test) {
A warning to display. A warning to display.
@param {Boolean} test @param {Boolean} test
An optional boolean or function. If the test returns false, the warning An optional boolean. If falsy, the warning will be displayed.
will be displayed.
*/ */
Ember.warn = function(message, test) { Ember.warn = function(message, test) {
if (arguments.length === 1) { test = false; }
if ('function' === typeof test) test = test()!==false;
if (!test) { if (!test) {
Ember.Logger.warn("WARNING: "+message); Ember.Logger.warn("WARNING: "+message);
if ('trace' in Ember.Logger) Ember.Logger.trace(); if ('trace' in Ember.Logger) Ember.Logger.trace();
@ -83,14 +68,12 @@ Ember.warn = function(message, test) {
A description of the deprecation. A description of the deprecation.
@param {Boolean} test @param {Boolean} test
An optional boolean or function. If the test returns false, the deprecation An optional boolean. If falsy, the deprecation will be displayed.
will be displayed.
*/ */
Ember.deprecate = function(message, test) { Ember.deprecate = function(message, test) {
if (Ember && Ember.TESTING_DEPRECATION) { return; } if (Ember && Ember.TESTING_DEPRECATION) { return; }
if (arguments.length === 1) { test = false; } if (arguments.length === 1) { test = false; }
if ('function' === typeof test) { test = test()!==false; }
if (test) { return; } if (test) { return; }
if (Ember && Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); } if (Ember && Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); }
@ -153,8 +136,8 @@ window.ember_deprecateFunc = Ember.deprecateFunc("ember_deprecateFunc is deprec
})(); })();
// Version: v0.9.8.1-424-g260b1b4 // Version: v0.9.8.1-437-g68d406e
// Last commit: 260b1b4 (2012-06-23 11:41:18 -0700) // Last commit: 68d406e (2012-06-25 14:59:55 -0700)
(function() { (function() {
@ -1003,6 +986,26 @@ Ember.makeArray = function(obj) {
var guidFor = Ember.guidFor, var guidFor = Ember.guidFor,
indexOf = Ember.ArrayPolyfills.indexOf; indexOf = Ember.ArrayPolyfills.indexOf;
var copy = function(obj) {
var output = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) { output[prop] = obj[prop]; }
}
return output;
};
var copyMap = function(original, newObject) {
var keys = original.keys.copy(),
values = copy(original.values);
newObject.keys = keys;
newObject.values = values;
return newObject;
};
// This class is used internally by Ember.js and Ember Data. // This class is used internally by Ember.js and Ember Data.
// Please do not use it at this time. We plan to clean it up // Please do not use it at this time. We plan to clean it up
// and add many tests soon. // and add many tests soon.
@ -1059,6 +1062,15 @@ OrderedSet.prototype = {
toArray: function() { toArray: function() {
return this.list.slice(); return this.list.slice();
},
copy: function() {
var set = new OrderedSet();
set.presenceSet = copy(this.presenceSet);
set.list = this.list.slice();
return set;
} }
}; };
@ -1174,6 +1186,10 @@ Map.prototype = {
var guid = guidFor(key); var guid = guidFor(key);
callback.call(self, key, values[guid]); callback.call(self, key, values[guid]);
}); });
},
copy: function() {
return copyMap(this, new Map());
} }
}; };
@ -1204,6 +1220,12 @@ MapWithDefault.prototype.get = function(key) {
} }
}; };
MapWithDefault.prototype.copy = function() {
return copyMap(this, new MapWithDefault({
defaultValue: this.defaultValue
}));
};
})(); })();
@ -10138,6 +10160,8 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
// Copyright: ©2011 Strobe Inc. and contributors. // Copyright: ©2011 Strobe Inc. and contributors.
// License: Licensed under MIT license (see license.js) // License: Licensed under MIT license (see license.js)
// ========================================================================== // ==========================================================================
var get = Ember.get, set = Ember.set;
/** /**
@class @class
@ -10177,8 +10201,6 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
@extends Ember.ArrayProxy @extends Ember.ArrayProxy
*/ */
var get = Ember.get, set = Ember.set;
Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin, Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
Ember.SortableMixin); Ember.SortableMixin);
@ -14713,7 +14735,8 @@ Ember.State = Ember.Object.extend(Ember.Evented,
} }
} }
set(this, 'routes', {}); set(this, 'pathsCache', {});
set(this, 'pathsCacheNoContext', {});
}, },
/** @private */ /** @private */
@ -15346,9 +15369,9 @@ Ember.StateManager = Ember.State.extend(
return possible; return possible;
}, },
findStatesByRoute: function(state, route) { findStatesByPath: function(state, path) {
if (!route || route === "") { return undefined; } if (!path || path === "") { return undefined; }
var r = route.split('.'), var r = path.split('.'),
ret = []; ret = [];
for (var i=0, len = r.length; i < len; i++) { for (var i=0, len = r.length; i < len; i++) {
@ -15370,122 +15393,118 @@ Ember.StateManager = Ember.State.extend(
return this.transitionTo.apply(this, arguments); return this.transitionTo.apply(this, arguments);
}, },
pathForSegments: function(array) { transitionTo: function(path, context) {
return Ember.ArrayPolyfills.map.call(array, function(tuple) {
Ember.assert("A segment passed to transitionTo must be an Array", Ember.typeOf(tuple) === "array");
return tuple[0];
}).join(".");
},
transitionTo: function(name, context) {
// 1. Normalize arguments // 1. Normalize arguments
// 2. Ensure that we are in the correct state // 2. Ensure that we are in the correct state
// 3. Map provided path to context objects and send // 3. Map provided path to context objects and send
// appropriate transitionEvent events // appropriate transitionEvent events
if (Ember.empty(name)) { return; } if (Ember.empty(path)) { return; }
var segments, explicitSegments; var contexts = context ? Array.prototype.slice.call(arguments, 1) : [],
if (Ember.typeOf(name) === "array") {
segments = [].slice.call(arguments);
explicitSegments = true;
} else {
segments = [[name, context]];
explicitSegments = false;
}
var path = this.pathForSegments(segments),
currentState = get(this, 'currentState') || this, currentState = get(this, 'currentState') || this,
state = currentState, resolveState = currentState,
newState,
exitStates = [], exitStates = [],
matchedContexts = [],
cachedPath,
enterStates, enterStates,
resolveState, state,
setupContexts = []; initialState,
stateIdx,
useContext;
if (state.routes[path]) { if (!context && (cachedPath = currentState.pathsCacheNoContext[path])) {
// cache hit // fast path
var route = state.routes[path]; exitStates = cachedPath.exitStates;
exitStates = route.exitStates; enterStates = cachedPath.enterStates;
enterStates = route.enterStates; resolveState = cachedPath.resolveState;
state = route.futureState;
resolveState = route.resolveState;
} else { } else {
// cache miss // normal path
newState = this.findStatesByRoute(currentState, path); if ((cachedPath = currentState.pathsCache[path])) {
// cache hit
while (state && !newState) { exitStates = cachedPath.exitStates;
exitStates.unshift(state); enterStates = cachedPath.enterStates;
resolveState = cachedPath.resolveState;
} else {
// cache miss
state = get(state, 'parentState'); enterStates = this.findStatesByPath(currentState, path);
if (!state) {
newState = this.findStatesByRoute(this, path); while (resolveState && !enterStates) {
if (!newState) { return; } exitStates.unshift(resolveState);
resolveState = get(resolveState, 'parentState');
if (!resolveState) {
enterStates = this.findStatesByPath(this, path);
if (!enterStates) { return; }
}
enterStates = this.findStatesByPath(resolveState, path);
} }
newState = this.findStatesByRoute(state, path);
while (enterStates.length > 0 && enterStates[0] === exitStates[0]) {
resolveState = enterStates.shift();
exitStates.shift();
}
currentState.pathsCache[name] = {
exitStates: exitStates,
enterStates: enterStates,
resolveState: resolveState
};
} }
resolveState = state; stateIdx = enterStates.length-1;
while (contexts.length > 0) {
if (stateIdx >= 0) {
state = enterStates[stateIdx--];
} else {
state = enterStates[0] ? get(enterStates[0], 'parentState') : resolveState;
if (!state) { throw "Cannot match all contexts to states"; }
enterStates.unshift(state);
exitStates.unshift(state);
}
enterStates = newState.slice(0); useContext = context && (!get(state, 'isRoutable') || get(state, 'isDynamic'));
exitStates = exitStates.slice(0); matchedContexts.unshift(useContext ? contexts.pop() : null);
}
if (enterStates.length > 0) { if (enterStates.length > 0) {
state = enterStates[enterStates.length - 1]; state = enterStates[enterStates.length - 1];
var initialState; while(true) {
while(initialState = get(state, 'initialState')) { initialState = get(state, 'initialState') || 'start';
state = getPath(state, 'states.'+initialState); state = getPath(state, 'states.'+initialState);
if (!state) { break; }
enterStates.push(state); enterStates.push(state);
} }
while (enterStates.length > 0) { while (enterStates.length > 0) {
if (enterStates[0] !== exitStates[0]) { break; } if (enterStates[0] !== exitStates[0]) { break; }
var newContext; if (enterStates.length === matchedContexts.length) {
if (explicitSegments) { if (this.getStateMeta(enterStates[0], 'context') !== matchedContexts[0]) { break; }
var segmentIndex = segments.length - enterStates.length; matchedContexts.shift();
newContext = segments[segmentIndex][1];
} else if (enterStates.length === 1) {
newContext = context;
} }
if (newContext) { resolveState = enterStates.shift();
if (newContext !== this.getStateMeta(enterStates[0], 'context')) { break; }
}
enterStates.shift();
exitStates.shift(); exitStates.shift();
} }
if (enterStates.length > 0) {
setupContexts = Ember.EnumerableUtils.map(enterStates, function(state, index) {
return [state, explicitSegments ? segments[index][1] : context];
});
}
} }
currentState.routes[path] = {
exitStates: exitStates,
enterStates: enterStates,
futureState: state,
resolveState: resolveState
};
} }
this.enterState(exitStates, enterStates, state); this.enterState(exitStates, enterStates, enterStates[enterStates.length-1] || resolveState);
this.triggerSetupContext(setupContexts); this.triggerSetupContext(enterStates, matchedContexts);
}, },
triggerSetupContext: function(segments) { triggerSetupContext: function(enterStates, contexts) {
arrayForEach.call(segments, function(tuple) { var offset = enterStates.length - contexts.length;
var state = tuple[0], Ember.assert("More contexts provided than states", offset >= 0);
context = tuple[1];
state.trigger(get(this, 'transitionEvent'), this, context); arrayForEach.call(enterStates, function(state, idx) {
state.trigger(get(this, 'transitionEvent'), this, contexts[idx-offset]);
}, this); }, this);
}, },
@ -15514,28 +15533,7 @@ Ember.StateManager = Ember.State.extend(
state.trigger('enter', stateManager); state.trigger('enter', stateManager);
}); });
var startState = state, set(this, 'currentState', state);
enteredState,
initialState = get(startState, 'initialState');
if (!initialState) {
initialState = 'start';
}
while (startState = get(get(startState, 'states'), initialState)) {
enteredState = startState;
if (log) { Ember.Logger.log("STATEMANAGER: Entering " + get(startState, 'path')); }
startState.trigger('enter', stateManager);
initialState = get(startState, 'initialState');
if (!initialState) {
initialState = 'start';
}
}
set(this, 'currentState', enteredState || state);
} }
}); });
@ -15614,6 +15612,7 @@ Ember.Routable = Ember.Mixin.create({
*/ */
stashContext: function(manager, context) { stashContext: function(manager, context) {
var serialized = this.serialize(manager, context); var serialized = this.serialize(manager, context);
Ember.assert('serialize must return a hash', !serialized || typeof serialized === 'object');
manager.setStateMeta(this, 'context', context); manager.setStateMeta(this, 'context', context);
manager.setStateMeta(this, 'serialized', serialized); manager.setStateMeta(this, 'serialized', serialized);
@ -15691,8 +15690,21 @@ Ember.Routable = Ember.Mixin.create({
string property. string property.
*/ */
routeMatcher: Ember.computed(function() { routeMatcher: Ember.computed(function() {
if (get(this, 'route')) { var route = get(this, 'route');
return Ember._RouteMatcher.create({ route: get(this, 'route') }); if (route) {
return Ember._RouteMatcher.create({ route: route });
}
}).cacheable(),
/**
@private
Check whether the route has dynamic segments
*/
isDynamic: Ember.computed(function() {
var routeMatcher = get(this, 'routeMatcher');
if (routeMatcher) {
return routeMatcher.identifiers.length > 0;
} }
}).cacheable(), }).cacheable(),
@ -15843,7 +15855,7 @@ Ember.Routable = Ember.Mixin.create({
Ember.assert("Could not find state for path " + path, !!state); Ember.assert("Could not find state for path " + path, !!state);
var object = state.deserialize(manager, match.hash) || {}; var object = state.deserialize(manager, match.hash);
manager.transitionTo(get(state, 'path'), object); manager.transitionTo(get(state, 'path'), object);
manager.send('routePath', match.remaining); manager.send('routePath', match.remaining);
}, },
@ -15958,7 +15970,7 @@ Ember._RouteMatcher = Ember.Object.extend({
return { return {
remaining: path.substr(match[0].length), remaining: path.substr(match[0].length),
hash: hash hash: identifiers.length > 0 ? hash : null
}; };
} }
}, },
@ -16071,10 +16083,10 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
root: Ember.Route.extend({ root: Ember.Route.extend({
aRoute: Ember.Route.extend({ aRoute: Ember.Route.extend({
route: '/', route: '/',
connectOutlets: function(router){ enter: function(router) {
console.log("entering root.aRoute from", router.getPath('currentState.name')); console.log("entering root.aRoute from", router.getPath('currentState.name'));
}, },
connectOutlets: function(router){ connectOutlets: function(router) {
console.log("entered root.aRoute, fully transitioned to", router.getPath('currentState.path')); console.log("entered root.aRoute, fully transitioned to", router.getPath('currentState.path'));
} }
}) })
@ -16088,7 +16100,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
'entering root.aRoute from root' 'entering root.aRoute from root'
'entered root.aRoute, fully transitioned to root.aRoute ' 'entered root.aRoute, fully transitioned to root.aRoute '
Ember.Route has two additional callbacks for handling URL serializization and deserialization. See Ember.Route has two additional callbacks for handling URL serialization and deserialization. See
'Serializing/Deserializing URLs' 'Serializing/Deserializing URLs'
## Routes With Dynamic Segments ## Routes With Dynamic Segments
@ -16097,8 +16109,8 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
`deserialize` method of the matching Route (see 'Serializing/Deserializing URLs'). `deserialize` method of the matching Route (see 'Serializing/Deserializing URLs').
## Serializing/Deserializing URLs ## Serializing/Deserializing URLs
Ember.Route has two callbacks for assocating a particilar object context with a URL: `serialize` Ember.Route has two callbacks for associating a particular object context with a URL: `serialize`
for converting an object into a paramaters hash to fill dynamic segments of a URL and `deserialize` for converting an object into a parameters hash to fill dynamic segments of a URL and `deserialize`
for converting a hash of dynamic segments from the URL into the appropriate object. for converting a hash of dynamic segments from the URL into the appropriate object.
### Deserializing A URL's Dynamic Segments ### Deserializing A URL's Dynamic Segments
@ -16114,7 +16126,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
root: Ember.Route.extend({ root: Ember.Route.extend({
aRoute: Ember.Route.extend({ aRoute: Ember.Route.extend({
route: '/fixed/:dynamicSectionA/anotherFixed/:dynamicSectionB', route: '/fixed/:dynamicSectionA/anotherFixed/:dynamicSectionB',
deserialize: function(router, urlParts){} deserialize: function(router, params) {}
}) })
}) })
}) })
@ -16131,7 +16143,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
Within `deserialize` you should use this information to retrieve or create an appropriate context Within `deserialize` you should use this information to retrieve or create an appropriate context
object for the given url (e.g. by loading from a remote API or accessing the browser's object for the given url (e.g. by loading from a remote API or accessing the browser's
`localStorage`). This object must be the the `return` value for `deserialize` and will be `localStorage`). This object must be the `return` value for `deserialize` and will be
passed to the Route's `connectOutlets` and `serialize` methods. passed to the Route's `connectOutlets` and `serialize` methods.
When an application's state is changed from within the application itself, the context provided for When an application's state is changed from within the application itself, the context provided for
@ -16152,8 +16164,8 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
route: '/' route: '/'
}), }),
bRoute: Ember.Route.extend({ bRoute: Ember.Route.extend({
route: '/staticSection/:someDynamicSegment route: '/staticSection/:someDynamicSegment',
serialize: function(router, context){ serialize: function(router, context) {
return { return {
someDynamicSegment: context.get('name') someDynamicSegment: context.get('name')
} }
@ -16166,11 +16178,11 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
Transitioning to "root.bRoute" with a context of `Object.create({name: 'Yehuda'})` will call Transitioning to "root.bRoute" with a context of `Object.create({name: 'Yehuda'})` will call
the Route's `serialize` method with the context as it second argument and update the URL to the Route's `serialize` method with the context as its second argument and update the URL to
'#/staticSection/Yehuda' '#/staticSection/Yehuda'.
## Transitions Between States ## Transitions Between States
Once a routed application has initialized its state based on the entry URL subsequent transitions to other Once a routed application has initialized its state based on the entry URL, subsequent transitions to other
states will update the URL if the entered Route has a `route` property. Given the following route structure states will update the URL if the entered Route has a `route` property. Given the following route structure
loaded at the URL '#/': loaded at the URL '#/':
@ -16208,8 +16220,8 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
moveElsewhere: Ember.Route.transitionTo('bRoute') moveElsewhere: Ember.Route.transitionTo('bRoute')
}), }),
bRoute: Ember.Route.extend({ bRoute: Ember.Route.extend({
route: '/a/route/:dynamicSection/:anotherDynamicSection' route: '/a/route/:dynamicSection/:anotherDynamicSection',
connectOutlets: function(router, context){}, connectOutlets: function(router, context) {},
}) })
}) })
}) })
@ -16226,7 +16238,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
Will transition the application's state to 'root.bRoute' and trigger an update of the URL to Will transition the application's state to 'root.bRoute' and trigger an update of the URL to
'#/a/route/42/Life'. '#/a/route/42/Life'.
The context argument will also be passed as the second argument to the `deserialize` method call. The context argument will also be passed as the second argument to the `serialize` method call.
## Injection of Controller Singletons ## Injection of Controller Singletons
During application initialization Ember will detect properties of the application ending in 'Controller', During application initialization Ember will detect properties of the application ending in 'Controller',
@ -16258,13 +16270,13 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
root: Ember.Route.extend({ root: Ember.Route.extend({
aRoute: Ember.Route.extend({ aRoute: Ember.Route.extend({
route: '/', route: '/',
anActionOnTheRouter: function(router, context){ anActionOnTheRouter: function(router, context) {
router.transitionTo('anotherState', context); router.transitionTo('anotherState', context);
} }
}) })
anotherState: Ember.Route.extend({ anotherState: Ember.Route.extend({
route: '/differentUrl', route: '/differentUrl',
connectOutlets: function(router, context){ connectOutlets: function(router, context) {
} }
}) })
@ -16311,7 +16323,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
root: Ember.Route.extend({ root: Ember.Route.extend({
aRoute: Ember.Route.extend({ aRoute: Ember.Route.extend({
route: '/', route: '/',
connectOutlets: function(router, context){ connectOutlets: function(router, context) {
router.get('oneController').connectOutlet('another'); router.get('oneController').connectOutlet('another');
}, },
}) })
@ -16325,10 +16337,10 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
fill it with a rendered instance of `App.AnotherView` whose `context` will be the single instance of fill it with a rendered instance of `App.AnotherView` whose `context` will be the single instance of
`App.AnotherController` stored on the router in the `anotherController` property. `App.AnotherController` stored on the router in the `anotherController` property.
For more information about Outlets see Ember.Handlebars.helpers.outlet. For additional inforamtion on For more information about Outlets, see `Ember.Handlebars.helpers.outlet`. For additional information on
the `connectOutlet` method Controllers, see `Ember.Controller.connectOutlet`, For more information on the `connectOutlet` method, see `Ember.Controller.connectOutlet`. For more information on
controller injections see Ember.Application#initialize(). For additional information about view context controller injections, see `Ember.Application#initialize()`. For additional information about view context,
see Ember.View. see `Ember.View`.
@extends Ember.StateManager @extends Ember.StateManager
*/ */
@ -19975,8 +19987,8 @@ Ember.$(document).ready(
})(); })();
// Version: v0.9.8.1-424-g260b1b4 // Version: v0.9.8.1-437-g68d406e
// Last commit: 260b1b4 (2012-06-23 11:41:18 -0700) // Last commit: 68d406e (2012-06-25 14:59:55 -0700)
(function() { (function() {

View File

@ -9,7 +9,7 @@
<script src="javascripts/application.js"></script> <script src="javascripts/application.js"></script>
<script> <script>
minispade.require('app') minispade.require('app')
Travis.initialize() Travis.run()
</script> </script>
</head> </head>
<body> <body>

File diff suppressed because one or more lines are too long

View File

@ -3,16 +3,12 @@
describe('Foo', function() { describe('Foo', function() {
it('bar', function() { it('bar', function() {
var link; var link;
console.log('before spec');
link = $($('#repositories a.slug')[0]); link = $($('#repositories a.slug')[0]);
console.log($('body').html().toString()); return console.log($('body').html());
return console.log('after spec');
}); });
return it('bar', function() { return it('bar', function() {
var link; var link;
console.log('before spec'); return link = $($('#repositories a.slug')[0]);
link = $($('#repositories a.slug')[0]);
return console.log('after spec');
}); });
}); });
@ -21,8 +17,17 @@
minispade.require('app'); minispade.require('app');
$('body').append($('<div id="spec_content"></div>')); beforeEach(function() {
$('body #content').empty();
return Em.run(function() {
Travis.app = Travis.App.create();
Travis.app.set('rootElement', '#content');
return Travis.app.initialize();
});
});
Travis.rootElement = '#spec_content'; afterEach(function() {
return Travis.app.destroy();
});
}).call(this); }).call(this);

View File

@ -1952,8 +1952,8 @@ Handlebars.VM = {
Handlebars.template = Handlebars.VM.template; Handlebars.template = Handlebars.VM.template;
; ;
// Version: v0.9.8.1-423-g84e9626 // Version: v0.9.8.1-437-g68d406e
// Last commit: 84e9626 (2012-06-22 15:45:46 -0700) // Last commit: 68d406e (2012-06-25 14:59:55 -0700)
(function() { (function() {
@ -1970,22 +1970,12 @@ if ('undefined' === typeof Ember) {
/** /**
Define an assertion that will throw an exception if the condition is not Define an assertion that will throw an exception if the condition is not
met. Ember build tools will remove any calls to Ember.assert() when met. Ember build tools will remove any calls to Ember.assert() when
doing a production build. doing a production build. Example:
## Examples // Test for truthiness
Ember.assert('Must pass a valid object', obj);
#js: // Fail unconditionally
Ember.assert('This code path should never be run')
// pass a simple Boolean value
Ember.assert('must pass a valid object', !!obj);
// pass a function. If the function returns false the assertion fails
// any other return value (including void) will pass.
Ember.assert('a passed record must have a firstName', function() {
if (obj instanceof Ember.Record) {
return !Ember.empty(obj.firstName);
}
});
@static @static
@function @function
@ -1994,12 +1984,10 @@ if ('undefined' === typeof Ember) {
thrown if the assertion fails. thrown if the assertion fails.
@param {Boolean} test @param {Boolean} test
Must return true for the assertion to pass. If you pass a function it Must be truthy for the assertion to pass. If falsy, an exception will be
will be executed. If the function returns false an exception will be
thrown. thrown.
*/ */
Ember.assert = function(desc, test) { Ember.assert = function(desc, test) {
if ('function' === typeof test) test = test()!==false;
if (!test) throw new Error("assertion failed: "+desc); if (!test) throw new Error("assertion failed: "+desc);
}; };
@ -2014,12 +2002,9 @@ Ember.assert = function(desc, test) {
A warning to display. A warning to display.
@param {Boolean} test @param {Boolean} test
An optional boolean or function. If the test returns false, the warning An optional boolean. If falsy, the warning will be displayed.
will be displayed.
*/ */
Ember.warn = function(message, test) { Ember.warn = function(message, test) {
if (arguments.length === 1) { test = false; }
if ('function' === typeof test) test = test()!==false;
if (!test) { if (!test) {
Ember.Logger.warn("WARNING: "+message); Ember.Logger.warn("WARNING: "+message);
if ('trace' in Ember.Logger) Ember.Logger.trace(); if ('trace' in Ember.Logger) Ember.Logger.trace();
@ -2037,14 +2022,12 @@ Ember.warn = function(message, test) {
A description of the deprecation. A description of the deprecation.
@param {Boolean} test @param {Boolean} test
An optional boolean or function. If the test returns false, the deprecation An optional boolean. If falsy, the deprecation will be displayed.
will be displayed.
*/ */
Ember.deprecate = function(message, test) { Ember.deprecate = function(message, test) {
if (Ember && Ember.TESTING_DEPRECATION) { return; } if (Ember && Ember.TESTING_DEPRECATION) { return; }
if (arguments.length === 1) { test = false; } if (arguments.length === 1) { test = false; }
if ('function' === typeof test) { test = test()!==false; }
if (test) { return; } if (test) { return; }
if (Ember && Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); } if (Ember && Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); }
@ -2107,8 +2090,8 @@ window.ember_deprecateFunc = Ember.deprecateFunc("ember_deprecateFunc is deprec
})(); })();
// Version: v0.9.8.1-424-g260b1b4 // Version: v0.9.8.1-437-g68d406e
// Last commit: 260b1b4 (2012-06-23 11:41:18 -0700) // Last commit: 68d406e (2012-06-25 14:59:55 -0700)
(function() { (function() {
@ -2957,6 +2940,26 @@ Ember.makeArray = function(obj) {
var guidFor = Ember.guidFor, var guidFor = Ember.guidFor,
indexOf = Ember.ArrayPolyfills.indexOf; indexOf = Ember.ArrayPolyfills.indexOf;
var copy = function(obj) {
var output = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) { output[prop] = obj[prop]; }
}
return output;
};
var copyMap = function(original, newObject) {
var keys = original.keys.copy(),
values = copy(original.values);
newObject.keys = keys;
newObject.values = values;
return newObject;
};
// This class is used internally by Ember.js and Ember Data. // This class is used internally by Ember.js and Ember Data.
// Please do not use it at this time. We plan to clean it up // Please do not use it at this time. We plan to clean it up
// and add many tests soon. // and add many tests soon.
@ -3013,6 +3016,15 @@ OrderedSet.prototype = {
toArray: function() { toArray: function() {
return this.list.slice(); return this.list.slice();
},
copy: function() {
var set = new OrderedSet();
set.presenceSet = copy(this.presenceSet);
set.list = this.list.slice();
return set;
} }
}; };
@ -3128,6 +3140,10 @@ Map.prototype = {
var guid = guidFor(key); var guid = guidFor(key);
callback.call(self, key, values[guid]); callback.call(self, key, values[guid]);
}); });
},
copy: function() {
return copyMap(this, new Map());
} }
}; };
@ -3158,6 +3174,12 @@ MapWithDefault.prototype.get = function(key) {
} }
}; };
MapWithDefault.prototype.copy = function() {
return copyMap(this, new MapWithDefault({
defaultValue: this.defaultValue
}));
};
})(); })();
@ -12092,6 +12114,8 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
// Copyright: ©2011 Strobe Inc. and contributors. // Copyright: ©2011 Strobe Inc. and contributors.
// License: Licensed under MIT license (see license.js) // License: Licensed under MIT license (see license.js)
// ========================================================================== // ==========================================================================
var get = Ember.get, set = Ember.set;
/** /**
@class @class
@ -12131,8 +12155,6 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
@extends Ember.ArrayProxy @extends Ember.ArrayProxy
*/ */
var get = Ember.get, set = Ember.set;
Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin, Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
Ember.SortableMixin); Ember.SortableMixin);
@ -16667,7 +16689,8 @@ Ember.State = Ember.Object.extend(Ember.Evented,
} }
} }
set(this, 'routes', {}); set(this, 'pathsCache', {});
set(this, 'pathsCacheNoContext', {});
}, },
/** @private */ /** @private */
@ -17300,9 +17323,9 @@ Ember.StateManager = Ember.State.extend(
return possible; return possible;
}, },
findStatesByRoute: function(state, route) { findStatesByPath: function(state, path) {
if (!route || route === "") { return undefined; } if (!path || path === "") { return undefined; }
var r = route.split('.'), var r = path.split('.'),
ret = []; ret = [];
for (var i=0, len = r.length; i < len; i++) { for (var i=0, len = r.length; i < len; i++) {
@ -17324,122 +17347,118 @@ Ember.StateManager = Ember.State.extend(
return this.transitionTo.apply(this, arguments); return this.transitionTo.apply(this, arguments);
}, },
pathForSegments: function(array) { transitionTo: function(path, context) {
return Ember.ArrayPolyfills.map.call(array, function(tuple) {
Ember.assert("A segment passed to transitionTo must be an Array", Ember.typeOf(tuple) === "array");
return tuple[0];
}).join(".");
},
transitionTo: function(name, context) {
// 1. Normalize arguments // 1. Normalize arguments
// 2. Ensure that we are in the correct state // 2. Ensure that we are in the correct state
// 3. Map provided path to context objects and send // 3. Map provided path to context objects and send
// appropriate transitionEvent events // appropriate transitionEvent events
if (Ember.empty(name)) { return; } if (Ember.empty(path)) { return; }
var segments, explicitSegments; var contexts = context ? Array.prototype.slice.call(arguments, 1) : [],
if (Ember.typeOf(name) === "array") {
segments = [].slice.call(arguments);
explicitSegments = true;
} else {
segments = [[name, context]];
explicitSegments = false;
}
var path = this.pathForSegments(segments),
currentState = get(this, 'currentState') || this, currentState = get(this, 'currentState') || this,
state = currentState, resolveState = currentState,
newState,
exitStates = [], exitStates = [],
matchedContexts = [],
cachedPath,
enterStates, enterStates,
resolveState, state,
setupContexts = []; initialState,
stateIdx,
useContext;
if (state.routes[path]) { if (!context && (cachedPath = currentState.pathsCacheNoContext[path])) {
// cache hit // fast path
var route = state.routes[path]; exitStates = cachedPath.exitStates;
exitStates = route.exitStates; enterStates = cachedPath.enterStates;
enterStates = route.enterStates; resolveState = cachedPath.resolveState;
state = route.futureState;
resolveState = route.resolveState;
} else { } else {
// cache miss // normal path
newState = this.findStatesByRoute(currentState, path); if ((cachedPath = currentState.pathsCache[path])) {
// cache hit
while (state && !newState) { exitStates = cachedPath.exitStates;
exitStates.unshift(state); enterStates = cachedPath.enterStates;
resolveState = cachedPath.resolveState;
} else {
// cache miss
state = get(state, 'parentState'); enterStates = this.findStatesByPath(currentState, path);
if (!state) {
newState = this.findStatesByRoute(this, path); while (resolveState && !enterStates) {
if (!newState) { return; } exitStates.unshift(resolveState);
resolveState = get(resolveState, 'parentState');
if (!resolveState) {
enterStates = this.findStatesByPath(this, path);
if (!enterStates) { return; }
}
enterStates = this.findStatesByPath(resolveState, path);
} }
newState = this.findStatesByRoute(state, path);
while (enterStates.length > 0 && enterStates[0] === exitStates[0]) {
resolveState = enterStates.shift();
exitStates.shift();
}
currentState.pathsCache[name] = {
exitStates: exitStates,
enterStates: enterStates,
resolveState: resolveState
};
} }
resolveState = state; stateIdx = enterStates.length-1;
while (contexts.length > 0) {
if (stateIdx >= 0) {
state = enterStates[stateIdx--];
} else {
state = enterStates[0] ? get(enterStates[0], 'parentState') : resolveState;
if (!state) { throw "Cannot match all contexts to states"; }
enterStates.unshift(state);
exitStates.unshift(state);
}
enterStates = newState.slice(0); useContext = context && (!get(state, 'isRoutable') || get(state, 'isDynamic'));
exitStates = exitStates.slice(0); matchedContexts.unshift(useContext ? contexts.pop() : null);
}
if (enterStates.length > 0) { if (enterStates.length > 0) {
state = enterStates[enterStates.length - 1]; state = enterStates[enterStates.length - 1];
var initialState; while(true) {
while(initialState = get(state, 'initialState')) { initialState = get(state, 'initialState') || 'start';
state = getPath(state, 'states.'+initialState); state = getPath(state, 'states.'+initialState);
if (!state) { break; }
enterStates.push(state); enterStates.push(state);
} }
while (enterStates.length > 0) { while (enterStates.length > 0) {
if (enterStates[0] !== exitStates[0]) { break; } if (enterStates[0] !== exitStates[0]) { break; }
var newContext; if (enterStates.length === matchedContexts.length) {
if (explicitSegments) { if (this.getStateMeta(enterStates[0], 'context') !== matchedContexts[0]) { break; }
var segmentIndex = segments.length - enterStates.length; matchedContexts.shift();
newContext = segments[segmentIndex][1];
} else if (enterStates.length === 1) {
newContext = context;
} }
if (newContext) { resolveState = enterStates.shift();
if (newContext !== this.getStateMeta(enterStates[0], 'context')) { break; }
}
enterStates.shift();
exitStates.shift(); exitStates.shift();
} }
if (enterStates.length > 0) {
setupContexts = Ember.EnumerableUtils.map(enterStates, function(state, index) {
return [state, explicitSegments ? segments[index][1] : context];
});
}
} }
currentState.routes[path] = {
exitStates: exitStates,
enterStates: enterStates,
futureState: state,
resolveState: resolveState
};
} }
this.enterState(exitStates, enterStates, state); this.enterState(exitStates, enterStates, enterStates[enterStates.length-1] || resolveState);
this.triggerSetupContext(setupContexts); this.triggerSetupContext(enterStates, matchedContexts);
}, },
triggerSetupContext: function(segments) { triggerSetupContext: function(enterStates, contexts) {
arrayForEach.call(segments, function(tuple) { var offset = enterStates.length - contexts.length;
var state = tuple[0], Ember.assert("More contexts provided than states", offset >= 0);
context = tuple[1];
state.trigger(get(this, 'transitionEvent'), this, context); arrayForEach.call(enterStates, function(state, idx) {
state.trigger(get(this, 'transitionEvent'), this, contexts[idx-offset]);
}, this); }, this);
}, },
@ -17468,28 +17487,7 @@ Ember.StateManager = Ember.State.extend(
state.trigger('enter', stateManager); state.trigger('enter', stateManager);
}); });
var startState = state, set(this, 'currentState', state);
enteredState,
initialState = get(startState, 'initialState');
if (!initialState) {
initialState = 'start';
}
while (startState = get(get(startState, 'states'), initialState)) {
enteredState = startState;
if (log) { Ember.Logger.log("STATEMANAGER: Entering " + get(startState, 'path')); }
startState.trigger('enter', stateManager);
initialState = get(startState, 'initialState');
if (!initialState) {
initialState = 'start';
}
}
set(this, 'currentState', enteredState || state);
} }
}); });
@ -17568,6 +17566,7 @@ Ember.Routable = Ember.Mixin.create({
*/ */
stashContext: function(manager, context) { stashContext: function(manager, context) {
var serialized = this.serialize(manager, context); var serialized = this.serialize(manager, context);
Ember.assert('serialize must return a hash', !serialized || typeof serialized === 'object');
manager.setStateMeta(this, 'context', context); manager.setStateMeta(this, 'context', context);
manager.setStateMeta(this, 'serialized', serialized); manager.setStateMeta(this, 'serialized', serialized);
@ -17645,8 +17644,21 @@ Ember.Routable = Ember.Mixin.create({
string property. string property.
*/ */
routeMatcher: Ember.computed(function() { routeMatcher: Ember.computed(function() {
if (get(this, 'route')) { var route = get(this, 'route');
return Ember._RouteMatcher.create({ route: get(this, 'route') }); if (route) {
return Ember._RouteMatcher.create({ route: route });
}
}).cacheable(),
/**
@private
Check whether the route has dynamic segments
*/
isDynamic: Ember.computed(function() {
var routeMatcher = get(this, 'routeMatcher');
if (routeMatcher) {
return routeMatcher.identifiers.length > 0;
} }
}).cacheable(), }).cacheable(),
@ -17797,7 +17809,7 @@ Ember.Routable = Ember.Mixin.create({
Ember.assert("Could not find state for path " + path, !!state); Ember.assert("Could not find state for path " + path, !!state);
var object = state.deserialize(manager, match.hash) || {}; var object = state.deserialize(manager, match.hash);
manager.transitionTo(get(state, 'path'), object); manager.transitionTo(get(state, 'path'), object);
manager.send('routePath', match.remaining); manager.send('routePath', match.remaining);
}, },
@ -17912,7 +17924,7 @@ Ember._RouteMatcher = Ember.Object.extend({
return { return {
remaining: path.substr(match[0].length), remaining: path.substr(match[0].length),
hash: hash hash: identifiers.length > 0 ? hash : null
}; };
} }
}, },
@ -18025,10 +18037,10 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
root: Ember.Route.extend({ root: Ember.Route.extend({
aRoute: Ember.Route.extend({ aRoute: Ember.Route.extend({
route: '/', route: '/',
connectOutlets: function(router){ enter: function(router) {
console.log("entering root.aRoute from", router.getPath('currentState.name')); console.log("entering root.aRoute from", router.getPath('currentState.name'));
}, },
connectOutlets: function(router){ connectOutlets: function(router) {
console.log("entered root.aRoute, fully transitioned to", router.getPath('currentState.path')); console.log("entered root.aRoute, fully transitioned to", router.getPath('currentState.path'));
} }
}) })
@ -18042,7 +18054,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
'entering root.aRoute from root' 'entering root.aRoute from root'
'entered root.aRoute, fully transitioned to root.aRoute ' 'entered root.aRoute, fully transitioned to root.aRoute '
Ember.Route has two additional callbacks for handling URL serializization and deserialization. See Ember.Route has two additional callbacks for handling URL serialization and deserialization. See
'Serializing/Deserializing URLs' 'Serializing/Deserializing URLs'
## Routes With Dynamic Segments ## Routes With Dynamic Segments
@ -18051,8 +18063,8 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
`deserialize` method of the matching Route (see 'Serializing/Deserializing URLs'). `deserialize` method of the matching Route (see 'Serializing/Deserializing URLs').
## Serializing/Deserializing URLs ## Serializing/Deserializing URLs
Ember.Route has two callbacks for assocating a particilar object context with a URL: `serialize` Ember.Route has two callbacks for associating a particular object context with a URL: `serialize`
for converting an object into a paramaters hash to fill dynamic segments of a URL and `deserialize` for converting an object into a parameters hash to fill dynamic segments of a URL and `deserialize`
for converting a hash of dynamic segments from the URL into the appropriate object. for converting a hash of dynamic segments from the URL into the appropriate object.
### Deserializing A URL's Dynamic Segments ### Deserializing A URL's Dynamic Segments
@ -18068,7 +18080,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
root: Ember.Route.extend({ root: Ember.Route.extend({
aRoute: Ember.Route.extend({ aRoute: Ember.Route.extend({
route: '/fixed/:dynamicSectionA/anotherFixed/:dynamicSectionB', route: '/fixed/:dynamicSectionA/anotherFixed/:dynamicSectionB',
deserialize: function(router, urlParts){} deserialize: function(router, params) {}
}) })
}) })
}) })
@ -18085,7 +18097,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
Within `deserialize` you should use this information to retrieve or create an appropriate context Within `deserialize` you should use this information to retrieve or create an appropriate context
object for the given url (e.g. by loading from a remote API or accessing the browser's object for the given url (e.g. by loading from a remote API or accessing the browser's
`localStorage`). This object must be the the `return` value for `deserialize` and will be `localStorage`). This object must be the `return` value for `deserialize` and will be
passed to the Route's `connectOutlets` and `serialize` methods. passed to the Route's `connectOutlets` and `serialize` methods.
When an application's state is changed from within the application itself, the context provided for When an application's state is changed from within the application itself, the context provided for
@ -18106,8 +18118,8 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
route: '/' route: '/'
}), }),
bRoute: Ember.Route.extend({ bRoute: Ember.Route.extend({
route: '/staticSection/:someDynamicSegment route: '/staticSection/:someDynamicSegment',
serialize: function(router, context){ serialize: function(router, context) {
return { return {
someDynamicSegment: context.get('name') someDynamicSegment: context.get('name')
} }
@ -18120,11 +18132,11 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
Transitioning to "root.bRoute" with a context of `Object.create({name: 'Yehuda'})` will call Transitioning to "root.bRoute" with a context of `Object.create({name: 'Yehuda'})` will call
the Route's `serialize` method with the context as it second argument and update the URL to the Route's `serialize` method with the context as its second argument and update the URL to
'#/staticSection/Yehuda' '#/staticSection/Yehuda'.
## Transitions Between States ## Transitions Between States
Once a routed application has initialized its state based on the entry URL subsequent transitions to other Once a routed application has initialized its state based on the entry URL, subsequent transitions to other
states will update the URL if the entered Route has a `route` property. Given the following route structure states will update the URL if the entered Route has a `route` property. Given the following route structure
loaded at the URL '#/': loaded at the URL '#/':
@ -18162,8 +18174,8 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
moveElsewhere: Ember.Route.transitionTo('bRoute') moveElsewhere: Ember.Route.transitionTo('bRoute')
}), }),
bRoute: Ember.Route.extend({ bRoute: Ember.Route.extend({
route: '/a/route/:dynamicSection/:anotherDynamicSection' route: '/a/route/:dynamicSection/:anotherDynamicSection',
connectOutlets: function(router, context){}, connectOutlets: function(router, context) {},
}) })
}) })
}) })
@ -18180,7 +18192,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
Will transition the application's state to 'root.bRoute' and trigger an update of the URL to Will transition the application's state to 'root.bRoute' and trigger an update of the URL to
'#/a/route/42/Life'. '#/a/route/42/Life'.
The context argument will also be passed as the second argument to the `deserialize` method call. The context argument will also be passed as the second argument to the `serialize` method call.
## Injection of Controller Singletons ## Injection of Controller Singletons
During application initialization Ember will detect properties of the application ending in 'Controller', During application initialization Ember will detect properties of the application ending in 'Controller',
@ -18212,13 +18224,13 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
root: Ember.Route.extend({ root: Ember.Route.extend({
aRoute: Ember.Route.extend({ aRoute: Ember.Route.extend({
route: '/', route: '/',
anActionOnTheRouter: function(router, context){ anActionOnTheRouter: function(router, context) {
router.transitionTo('anotherState', context); router.transitionTo('anotherState', context);
} }
}) })
anotherState: Ember.Route.extend({ anotherState: Ember.Route.extend({
route: '/differentUrl', route: '/differentUrl',
connectOutlets: function(router, context){ connectOutlets: function(router, context) {
} }
}) })
@ -18265,7 +18277,7 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
root: Ember.Route.extend({ root: Ember.Route.extend({
aRoute: Ember.Route.extend({ aRoute: Ember.Route.extend({
route: '/', route: '/',
connectOutlets: function(router, context){ connectOutlets: function(router, context) {
router.get('oneController').connectOutlet('another'); router.get('oneController').connectOutlet('another');
}, },
}) })
@ -18279,10 +18291,10 @@ var get = Ember.get, getPath = Ember.getPath, set = Ember.set;
fill it with a rendered instance of `App.AnotherView` whose `context` will be the single instance of fill it with a rendered instance of `App.AnotherView` whose `context` will be the single instance of
`App.AnotherController` stored on the router in the `anotherController` property. `App.AnotherController` stored on the router in the `anotherController` property.
For more information about Outlets see Ember.Handlebars.helpers.outlet. For additional inforamtion on For more information about Outlets, see `Ember.Handlebars.helpers.outlet`. For additional information on
the `connectOutlet` method Controllers, see `Ember.Controller.connectOutlet`, For more information on the `connectOutlet` method, see `Ember.Controller.connectOutlet`. For more information on
controller injections see Ember.Application#initialize(). For additional information about view context controller injections, see `Ember.Application#initialize()`. For additional information about view context,
see Ember.View. see `Ember.View`.
@extends Ember.StateManager @extends Ember.StateManager
*/ */
@ -21929,8 +21941,8 @@ Ember.$(document).ready(
})(); })();
// Version: v0.9.8.1-424-g260b1b4 // Version: v0.9.8.1-437-g68d406e
// Last commit: 260b1b4 (2012-06-23 11:41:18 -0700) // Last commit: 68d406e (2012-06-25 14:59:55 -0700)
(function() { (function() {

View File

@ -5,9 +5,7 @@
<title>Travis CI - Distributed Continuous Integration Platform for the Open Source Community</title> <title>Travis CI - Distributed Continuous Integration Platform for the Open Source Community</title>
<link rel="stylesheet" href="stylesheets/application.css"> <link rel="stylesheet" href="stylesheets/application.css">
<link rel="stylesheet" href="stylesheets/jasmine.css"> <link rel="stylesheet" href="stylesheets/jasmine.css">
<script>
var ENV = 'test'
</script>
<script src="javascripts/vendor.js"></script> <script src="javascripts/vendor.js"></script>
<script src="javascripts/mocks.js"></script> <script src="javascripts/mocks.js"></script>
<script src="javascripts/application.js"></script> <script src="javascripts/application.js"></script>
@ -15,10 +13,10 @@
<script src="javascripts/specs/specs.js"></script> <script src="javascripts/specs/specs.js"></script>
</head> </head>
<body> <body>
<div id="content"></div>
<script> <script>
for(key in minispade.modules) for(key in minispade.modules)
if(key.match(/_spec$/)) if(key.match(/_spec$/))
console.log(key)
minispade.require(key); minispade.require(key);
var console_reporter = new jasmine.ConsoleReporter() var console_reporter = new jasmine.ConsoleReporter()

View File

@ -25,7 +25,6 @@ body {
#left, #main { #left, #main {
float: left; float: left;
height: 500px;
} }
#left { #left {