diff --git a/Gemfile b/Gemfile
index e11cac00..69bb11d3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
ruby '1.9.3' rescue nil
-source :rubygems
+source 'https://rubygems.org'
gem 'puma'
gem 'rack-ssl', '~> 1.3'
diff --git a/Gemfile.lock b/Gemfile.lock
index fcdcc460..91af9a57 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -16,7 +16,7 @@ GIT
rake-pipeline (~> 0.6)
GEM
- remote: http://rubygems.org/
+ remote: https://rubygems.org/
specs:
POpen4 (0.1.4)
Platform (>= 0.4.0)
diff --git a/assets/scripts/app/controllers/flash.coffee b/assets/scripts/app/controllers/flash.coffee
index 006af592..67ad6ae5 100644
--- a/assets/scripts/app/controllers/flash.coffee
+++ b/assets/scripts/app/controllers/flash.coffee
@@ -5,8 +5,8 @@ Travis.FlashController = Ember.ArrayController.extend
broadcastBinding: 'currentUser.broadcasts'
init: ->
- @set('flashes', Ember.A())
@_super.apply this, arguments
+ @set('flashes', Ember.A())
content: (->
@get('unseenBroadcasts').concat(@get('flashes'))
diff --git a/assets/scripts/app/controllers/job.coffee b/assets/scripts/app/controllers/job.coffee
index 274a7555..9d5734fe 100644
--- a/assets/scripts/app/controllers/job.coffee
+++ b/assets/scripts/app/controllers/job.coffee
@@ -4,3 +4,15 @@ Travis.JobController = Em.Controller.extend
jobBinding: 'controllers.repo.job'
repoBinding: 'controllers.repo.repo'
commitBinding: 'job.commit'
+
+ urlGithubCommit: (->
+ Travis.Urls.githubCommit(@get('repo.slug'), @get('commit.sha'))
+ ).property('repo.slug', 'commit.sha')
+
+ urlAuthor: (->
+ Travis.Urls.email(@get('commit.authorEmail'))
+ ).property('commit.authorEmail')
+
+ urlCommitter: (->
+ Travis.Urls.email(@get('commit.committerEmail'))
+ ).property('commit.committerEmail')
diff --git a/assets/scripts/app/controllers/profile.coffee b/assets/scripts/app/controllers/profile.coffee
index ae0dc24f..84b7fd4f 100644
--- a/assets/scripts/app/controllers/profile.coffee
+++ b/assets/scripts/app/controllers/profile.coffee
@@ -6,6 +6,8 @@ Travis.ProfileController = Travis.Controller.extend
accountsBinding: 'controllers.accounts'
init: ->
+ @_super.apply this, arguments
+
self = this
Travis.on("user:synced", (->
self.reloadHooks()
diff --git a/assets/scripts/app/controllers/repo.coffee b/assets/scripts/app/controllers/repo.coffee
index 556dd5dc..256ba110 100644
--- a/assets/scripts/app/controllers/repo.coffee
+++ b/assets/scripts/app/controllers/repo.coffee
@@ -6,17 +6,6 @@ Travis.RepoController = Travis.Controller.extend
init: ->
@_super.apply this, arguments
Ember.run.later(@updateTimes.bind(this), Travis.INTERVALS.updateTimes)
- @set 'builds', Em.ArrayProxy.create(Em.SortableMixin,
- isLoadedBinding: 'content.isLoaded'
- sortProperties: ['number']
- sortAscending: false
- content: []
- isLoadingBinding: 'content.isLoading'
- load: (records) ->
- content = @get('content')
- if content && content.load
- content.load(records)
- )
updateTimes: ->
if builds = @get('builds')
@@ -45,15 +34,15 @@ Travis.RepoController = Travis.Controller.extend
viewBuilds: ->
@connectTab('builds')
- @_bind('builds.content', 'repo.builds')
+ @_bind('builds', 'repo.builds')
viewPullRequests: ->
@connectTab('pull_requests')
- @_bind('builds.content', 'repo.pullRequests')
+ @_bind('builds', 'repo.pullRequests')
viewBranches: ->
@connectTab('branches')
- @_bind('builds.content', 'repo.branches')
+ @_bind('builds', 'repo.branches')
viewEvents: ->
@connectTab('events')
diff --git a/assets/scripts/app/controllers/repos.coffee b/assets/scripts/app/controllers/repos.coffee
index d3c64ab8..c26ee34e 100644
--- a/assets/scripts/app/controllers/repos.coffee
+++ b/assets/scripts/app/controllers/repos.coffee
@@ -13,8 +13,8 @@ Travis.ReposController = Ember.ArrayController.extend
).property('controllers.repo.repo', 'controllers.repo.repo.content')
init: ->
- Ember.run.later(@updateTimes.bind(this), Travis.INTERVALS.updateTimes)
@_super.apply this, arguments
+ Ember.run.later(@updateTimes.bind(this), Travis.INTERVALS.updateTimes)
recentRepos: (->
Travis.LimitedArray.create
diff --git a/assets/scripts/app/controllers/running_jobs.coffee b/assets/scripts/app/controllers/running_jobs.coffee
index 71778532..08eab756 100644
--- a/assets/scripts/app/controllers/running_jobs.coffee
+++ b/assets/scripts/app/controllers/running_jobs.coffee
@@ -3,6 +3,7 @@ Travis.RunningJobsController = Em.ArrayProxy.extend
repo: (-> @get('jobs.firstObject.repo') ).property('jobs.firstObject.repo')
init: ->
+ @_super.apply this, arguments
@set 'jobs', []
@set 'sortedJobs', Em.ArrayProxy.extend(Em.SortableMixin,
diff --git a/assets/scripts/app/controllers/sidebar.coffee b/assets/scripts/app/controllers/sidebar.coffee
index 390ffdad..42bfd638 100644
--- a/assets/scripts/app/controllers/sidebar.coffee
+++ b/assets/scripts/app/controllers/sidebar.coffee
@@ -1,6 +1,7 @@
Travis.reopen
SidebarController: Em.ArrayController.extend
init: ->
+ @_super.apply this, arguments
@tickables = []
Travis.Ticker.create(target: this, interval: Travis.INTERVALS.sponsors)
diff --git a/assets/scripts/app/controllers/stats.coffee b/assets/scripts/app/controllers/stats.coffee
index b0b31704..3d6da596 100644
--- a/assets/scripts/app/controllers/stats.coffee
+++ b/assets/scripts/app/controllers/stats.coffee
@@ -2,7 +2,7 @@ Travis.StatsController = Travis.Controller.extend
name: 'stats'
init: ->
- @_super('top')
+ @_super.apply this, arguments
#@connectOutlet(outletName: 'main', controller: this, viewClass: Travis.StatsView)
activate: (action, params) ->
diff --git a/assets/scripts/app/helpers/helpers.coffee b/assets/scripts/app/helpers/helpers.coffee
index 2c4ed12e..f3decb63 100644
--- a/assets/scripts/app/helpers/helpers.coffee
+++ b/assets/scripts/app/helpers/helpers.coffee
@@ -39,16 +39,6 @@ require 'config/emoij'
message = message.split(/\n/)[0] if options.short
@_emojize(@_escape(message)).replace /\n/g, '
'
- formatLog: (log, repo, item) ->
- event = if item.constructor == Travis.Build
- 'showBuild'
- else
- 'showJob'
-
- url = Travis.app.get('router').urlForEvent(event, repo, item)
-
- Travis.Log.filter(log, url)
-
pathFrom: (url) ->
(url || '').split('/').pop()
diff --git a/assets/scripts/app/models/repo.coffee b/assets/scripts/app/models/repo.coffee
index 332063b1..a4ee3cbf 100644
--- a/assets/scripts/app/models/repo.coffee
+++ b/assets/scripts/app/models/repo.coffee
@@ -28,6 +28,7 @@ require 'travis/model'
builds: (->
id = @get('id')
builds = Travis.Build.byRepoId id, event_type: 'push'
+
# TODO: move to controller
array = Travis.ExpandableRecordArray.create
type: Travis.Build
diff --git a/assets/scripts/app/store.coffee b/assets/scripts/app/store.coffee
index cf8f8d5c..b0a1717d 100644
--- a/assets/scripts/app/store.coffee
+++ b/assets/scripts/app/store.coffee
@@ -141,6 +141,7 @@ Travis.Store = DS.Store.extend
result = @merge(type, hash, true)
if result && result.clientId
@addLoadedData(type, result.clientId, hash)
+ #@_updateRelationships(type, hash)
result
@@ -158,3 +159,18 @@ Travis.Store = DS.Store.extend
root = type.pluralName()
@adapter.sideload(store, type, json, root)
@loadMany(type, json[root])
+
+ _updateRelationships: (type, data) ->
+ Em.get(type, 'relationshipsByName').forEach (key, meta) =>
+ if meta.kind == 'belongsTo'
+ id = data["#{key}_id"]
+ if clientId = @typeMapFor(meta.type).idToCid[id]
+ if parent = this.findByClientId(meta.type, clientId, id)
+ dataProxy = parent.get('data')
+ if ids = dataProxy['hasMany'][type.pluralName()]
+ unless data.id in ids
+ state = parent.get('stateManager.currentState.path')
+ unless state == "rootState.loaded.materializing"
+ parent.send('materializingData')
+ ids.pushObject(data.id)
+ parent.notifyPropertyChange('data')
diff --git a/assets/scripts/app/templates/jobs/show.hbs b/assets/scripts/app/templates/jobs/show.hbs
index f24454ba..1d7a9989 100644
--- a/assets/scripts/app/templates/jobs/show.hbs
+++ b/assets/scripts/app/templates/jobs/show.hbs
@@ -19,22 +19,24 @@
{{formatDuration job.duration}}
-
+ {{#if commit}}
+
+ {{/if}}
{{t jobs.message}}
{{formatMessage commit.message}}
diff --git a/assets/scripts/app/views/repo/show.coffee b/assets/scripts/app/views/repo/show.coffee
index b44d91cb..0664abd8 100644
--- a/assets/scripts/app/views/repo/show.coffee
+++ b/assets/scripts/app/views/repo/show.coffee
@@ -123,7 +123,7 @@ Travis.reopen
success: =>
@popup('regeneration-success')
error: ->
- Travis.app.router.flashController.loadFlashes([{ error: 'Travis encountered an error while trying to regenerate the key, please try again.'}])
+ Travis.lookup('controller:flash').loadFlashes([{ error: 'Travis encountered an error while trying to regenerate the key, please try again.'}])
displayRequeueBuild: (->
@get('isBuildTab') && @get('build.isFinished')
diff --git a/assets/scripts/lib/travis/ajax.coffee b/assets/scripts/lib/travis/ajax.coffee
index a9e4175b..40939951 100644
--- a/assets/scripts/lib/travis/ajax.coffee
+++ b/assets/scripts/lib/travis/ajax.coffee
@@ -33,13 +33,13 @@ Travis.ajax = Em.Object.create
success = options.success || (->)
options.success = (data) =>
- Travis.app.router.flashController.loadFlashes(data.flash) if Travis.app?.router && data.flash
+ Travis.lookup('controller:flash').loadFlashes(data.flash) if data.flash
delete data.flash if data?
success.apply(this, arguments)
error = options.error || (->)
options.error = (data) =>
- Travis.app.router.flashController.pushObject(data.flash) if data.flash
+ Travis.lookup('controller:flash').pushObject(data.flash) if data.flash
delete data.flash if data?
error.apply(this, arguments)
diff --git a/assets/scripts/lib/travis/model.coffee b/assets/scripts/lib/travis/model.coffee
index 9084dd02..4587033e 100644
--- a/assets/scripts/lib/travis/model.coffee
+++ b/assets/scripts/lib/travis/model.coffee
@@ -42,14 +42,14 @@
# undefined key
return if !key || key == 'undefined'
- message = "Load missing fields for #{@constructor.toString()} because of missing key '#{key}', cid: #{@get('clientId')}"
+ message = "Load missing fields for #{@constructor.toString()} because of missing key '#{key}', cid: #{@get('clientId')}, id: #{@get('id')}"
if @constructor.isAttribute('state') && key != 'state'
message += ", in state: #{@get('state')}"
console.log message
return if @get('isCompleting')
@set 'isCompleting', true
- if @get('stateManager.currentState.path') != 'rootState.loaded.materializing'
+ unless @get('stateManager.currentState.path').match /^rootState.loaded.materializing/
@reload()
@set 'incomplete', false
diff --git a/assets/scripts/lib/travis/ticker.coffee b/assets/scripts/lib/travis/ticker.coffee
index b85506d0..81f14517 100644
--- a/assets/scripts/lib/travis/ticker.coffee
+++ b/assets/scripts/lib/travis/ticker.coffee
@@ -11,6 +11,4 @@
@schedule()
schedule: ->
- Ember.run.later((=> @tick()), @get('interval') || Travis.app.TICK_INTERVAL)
-
-
+ Ember.run.later((=> @tick()), @get('interval') || Travis.TICK_INTERVAL)
diff --git a/assets/scripts/spec/event_spec.coffee b/assets/scripts/spec/event_spec.coffee
index 1f2f6f48..8ea55595 100644
--- a/assets/scripts/spec/event_spec.coffee
+++ b/assets/scripts/spec/event_spec.coffee
@@ -21,7 +21,7 @@ describe 'events', ->
responseText: payload
Em.run ->
- Travis.app.receive 'build:started',
+ Travis.receive 'build:started',
build:
id: 10
repository:
@@ -54,13 +54,12 @@ describe 'events', ->
started_at: '2012-07-02T00:02:00Z'
finished_at: '2012-07-02T00:02:55Z'
event_type: 'push'
- result: 1
message: 'commit message 3'
commit: '1234567'
- state: 'started'
+ state: 'failed'
Em.run ->
- Travis.app.receive 'build:started', payload
+ Travis.receive 'build:started', payload
waits(100)
runs ->
@@ -75,40 +74,6 @@ describe 'events', ->
runs ->
waitFor queuesRendered
- it 'adds a job to the jobs matrix', ->
- payload =
- job:
- id: 15
- repository_id: 1
- build_id: 1
- commit_id: 1
- log_id: 1
- number: '1.4'
- duration: 55
- started_at: '2012-07-02T00:02:00Z'
- finished_at: '2012-07-02T00:02:55Z'
- config: { rvm: 'jruby' }
-
- $.mockjax
- url: '/jobs/15'
- responseTime: 0
- responseText: payload
-
- Em.run ->
- Travis.app.receive 'job:started',
- job:
- id: 15
- repository_id: 1
- build_id: 1
- commit_id: 1
-
- waits(100)
- runs ->
- listsJob
- table: $('#jobs')
- row: 3
- item: { id: 15, number: '1.4', repo: 'travis-ci/travis-core', finishedAt: 'less than a minute ago', duration: '55 sec', rvm: 'jruby' }
-
it 'adds a job to the jobs queue', ->
payload =
job:
@@ -123,7 +88,7 @@ describe 'events', ->
responseText: payload
Em.run ->
- Travis.app.receive 'job:started',
+ Travis.receive 'job:started',
job:
id: 12
repository_id: 1
@@ -140,7 +105,7 @@ describe 'events', ->
it 'updates only keys that are available', ->
Em.run ->
- Travis.app.receive 'job:started',
+ Travis.receive 'job:started',
job:
id: 1
build_id: 1
@@ -171,7 +136,7 @@ describe 'events', ->
responseText: payload
Em.run ->
- Travis.app.receive 'worker:created',
+ Travis.receive 'worker:created',
worker:
id: 10
name: 'ruby-3'
@@ -191,7 +156,7 @@ describe 'events', ->
app '/travis-ci/travis-core'
waitFor workersRendered
- it 'does not update repository if it\'s already in store', ->
+ it 'does not update repository if it\'s already in the store', ->
payload =
worker:
id: 1
@@ -205,7 +170,7 @@ describe 'events', ->
last_build_number: '999'
Em.run ->
- Travis.app.receive 'worker:updated', payload
+ Travis.receive 'worker:updated', payload
waits(100)
runs ->
diff --git a/assets/scripts/spec/job_spec.coffee b/assets/scripts/spec/job_spec.coffee
index 73e63337..4b4c5f88 100644
--- a/assets/scripts/spec/job_spec.coffee
+++ b/assets/scripts/spec/job_spec.coffee
@@ -1,5 +1,11 @@
describe 'on the "job" state', ->
beforeEach ->
+ $.mockjax
+ url: '/jobs/1/log?cors_hax=true'
+ responseTime: 0
+ responseText: 'log 1'
+
+
app 'travis-ci/travis-core/jobs/1'
waitFor jobRendered
runs ->
@@ -32,6 +38,8 @@ describe 'on the "job" state', ->
build: { href: '/travis-ci/travis-core/builds/1' }
job: { href: '/travis-ci/travis-core/jobs/1', active: true }
- displaysLog [
- 'log 1'
- ]
+ waits 10
+ runs ->
+ displaysLog [
+ 'log 1'
+ ]
diff --git a/assets/scripts/spec/support/expectations.coffee b/assets/scripts/spec/support/expectations.coffee
index 6365fdc7..edf80ddc 100644
--- a/assets/scripts/spec/support/expectations.coffee
+++ b/assets/scripts/spec/support/expectations.coffee
@@ -41,9 +41,8 @@
expect(element.text()).toEqual data.message
@displaysLog = (lines) ->
- ix = 0
- log = $.map(lines, (line) -> ix += 1; "#{ix}#{line}").join("\n")
- expect($('#log p').text().trim()).toEqual log
+ log = lines.join()
+ expect($('#log').text().trim()).toEqual log
@listsRepos = (items) ->
listsItems('repo', items)
diff --git a/assets/scripts/spec/support/mocks.coffee b/assets/scripts/spec/support/mocks.coffee
index e7b153ab..6d31b625 100644
--- a/assets/scripts/spec/support/mocks.coffee
+++ b/assets/scripts/spec/support/mocks.coffee
@@ -1,45 +1,45 @@
responseTime = 0
repos = [
- { id: 1, owner: 'travis-ci', name: 'travis-core', slug: 'travis-ci/travis-core', build_ids: [1, 2], last_build_id: 1, last_build_number: 1, last_build_result: 0, last_build_duration: 30, last_build_started_at: '2012-07-02T00:00:00Z', last_build_finished_at: '2012-07-02T00:00:30Z', description: 'Description of travis-core' },
- { id: 2, owner: 'travis-ci', name: 'travis-assets', slug: 'travis-ci/travis-assets', build_ids: [3], last_build_id: 3, last_build_number: 3, last_build_result: 1, last_build_duration: 30, last_build_started_at: '2012-07-02T00:01:00Z', last_build_finished_at: '2012-07-01T00:01:30Z', description: 'Description of travis-assets'},
- { id: 3, owner: 'travis-ci', name: 'travis-hub', slug: 'travis-ci/travis-hub', build_ids: [4], last_build_id: 4, last_build_number: 4, last_build_result: undefined, last_build_duration: undefined, last_build_started_at: '2012-07-02T00:02:00Z', last_build_finished_at: undefined, description: 'Description of travis-hub'},
+ { id: '1', owner: 'travis-ci', name: 'travis-core', slug: 'travis-ci/travis-core', build_ids: [1, 2], last_build_id: 1, last_build_number: 1, last_build_result: 0, last_build_duration: 30, last_build_started_at: '2012-07-02T00:00:00Z', last_build_finished_at: '2012-07-02T00:00:30Z', description: 'Description of travis-core' },
+ { id: '2', owner: 'travis-ci', name: 'travis-assets', slug: 'travis-ci/travis-assets', build_ids: [3], last_build_id: 3, last_build_number: 3, last_build_result: 1, last_build_duration: 30, last_build_started_at: '2012-07-02T00:01:00Z', last_build_finished_at: '2012-07-01T00:01:30Z', description: 'Description of travis-assets'},
+ { id: '3', owner: 'travis-ci', name: 'travis-hub', slug: 'travis-ci/travis-hub', build_ids: [4], last_build_id: 4, last_build_number: 4, last_build_result: undefined, last_build_duration: undefined, last_build_started_at: '2012-07-02T00:02:00Z', last_build_finished_at: undefined, description: 'Description of travis-hub'},
]
builds = [
- { id: 1, repository_id: '1', commit_id: 1, job_ids: [1, 2, 3], number: 1, pull_request: false, config: { rvm: ['rbx', '1.9.3', 'jruby'] }, duration: 30, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:30Z', state: 'passed' },
- { id: 2, repository_id: '1', commit_id: 2, job_ids: [4], number: 2, pull_request: false, config: { rvm: ['rbx'] } },
- { id: 3, repository_id: '2', commit_id: 3, job_ids: [5], number: 3, pull_request: false, config: { rvm: ['rbx'] }, duration: 30, started_at: '2012-07-02T00:01:00Z', finished_at: '2012-07-01T00:01:30Z', state: 'failed' },
- { id: 4, repository_id: '3', commit_id: 4, job_ids: [6], number: 4, pull_request: false, config: { rvm: ['rbx'] }, started_at: '2012-07-02T00:02:00Z' },
+ { id: '1', repository_id: '1', commit_id: 1, job_ids: [1, 2, 3], number: 1, pull_request: false, config: { rvm: ['rbx', '1.9.3', 'jruby'] }, duration: 30, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:30Z', state: 'passed' },
+ { id: '2', repository_id: '1', commit_id: 2, job_ids: [4], number: 2, pull_request: false, config: { rvm: ['rbx'] } },
+ { id: '3', repository_id: '2', commit_id: 3, job_ids: [5], number: 3, pull_request: false, config: { rvm: ['rbx'] }, duration: 30, started_at: '2012-07-02T00:01:00Z', finished_at: '2012-07-01T00:01:30Z', state: 'failed' },
+ { id: '4', repository_id: '3', commit_id: 4, job_ids: [6], number: 4, pull_request: false, config: { rvm: ['rbx'] }, started_at: '2012-07-02T00:02:00Z' },
]
commits = [
- { id: 1, sha: '1234567', branch: 'master', message: 'commit message 1', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'http://github.com/compare/0123456..1234567' },
- { id: 2, sha: '2345678', branch: 'feature', message: 'commit message 2', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'http://github.com/compare/0123456..2345678' },
- { id: 3, sha: '3456789', branch: 'master', message: 'commit message 3', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'http://github.com/compare/0123456..3456789' },
- { id: 4, sha: '4567890', branch: 'master', message: 'commit message 4', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'http://github.com/compare/0123456..4567890' },
+ { id: '1', sha: '1234567', branch: 'master', message: 'commit message 1', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'http://github.com/compare/0123456..1234567' },
+ { id: '2', sha: '2345678', branch: 'feature', message: 'commit message 2', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'http://github.com/compare/0123456..2345678' },
+ { id: '3', sha: '3456789', branch: 'master', message: 'commit message 3', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'http://github.com/compare/0123456..3456789' },
+ { id: '4', sha: '4567890', branch: 'master', message: 'commit message 4', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'http://github.com/compare/0123456..4567890' },
]
jobs = [
- { id: 1, repository_id: 1, build_id: 1, commit_id: 1, log_id: 1, number: '1.1', config: { rvm: 'rbx' }, duration: 30, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:30Z', state: 'passed' }
- { id: 2, repository_id: 1, build_id: 1, commit_id: 1, log_id: 2, number: '1.2', config: { rvm: '1.9.3' }, duration: 40, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:40Z', state: 'failed' }
- { id: 3, repository_id: 1, build_id: 1, commit_id: 1, log_id: 3, number: '1.3', config: { rvm: 'jruby' }, allow_failure: true }
- { id: 4, repository_id: 1, build_id: 2, commit_id: 2, log_id: 4, number: '2.1', config: { rvm: 'rbx' } }
- { id: 5, repository_id: 2, build_id: 3, commit_id: 3, log_id: 5, number: '3.1', config: { rvm: 'rbx' }, duration: 30, started_at: '2012-07-02T00:01:00Z', finished_at: '2012-07-02T00:01:30Z', state: 'failed' }
- { id: 6, repository_id: 3, build_id: 4, commit_id: 4, log_id: 6, number: '4.1', config: { rvm: 'rbx' }, started_at: '2012-07-02T00:02:00Z' }
- { id: 7, repository_id: 1, build_id: 5, commit_id: 5, log_id: 7, number: '5.1', config: { rvm: 'rbx' }, state: 'created', queue: 'builds.common' }
- { id: 8, repository_id: 1, build_id: 5, commit_id: 5, log_id: 8, number: '5.2', config: { rvm: 'rbx' }, state: 'created', queue: 'builds.common' }
+ { id: '1', repository_id: 1, build_id: 1, commit_id: 1, log_id: 1, number: '1.1', config: { rvm: 'rbx' }, duration: 30, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:30Z', state: 'passed' }
+ { id: '2', repository_id: 1, build_id: 1, commit_id: 1, log_id: 2, number: '1.2', config: { rvm: '1.9.3' }, duration: 40, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:40Z', state: 'failed' }
+ { id: '3', repository_id: 1, build_id: 1, commit_id: 1, log_id: 3, number: '1.3', config: { rvm: 'jruby' }, allow_failure: true }
+ { id: '4', repository_id: 1, build_id: 2, commit_id: 2, log_id: 4, number: '2.1', config: { rvm: 'rbx' } }
+ { id: '5', repository_id: 2, build_id: 3, commit_id: 3, log_id: 5, number: '3.1', config: { rvm: 'rbx' }, duration: 30, started_at: '2012-07-02T00:01:00Z', finished_at: '2012-07-02T00:01:30Z', state: 'failed' }
+ { id: '6', repository_id: 3, build_id: 4, commit_id: 4, log_id: 6, number: '4.1', config: { rvm: 'rbx' }, started_at: '2012-07-02T00:02:00Z' }
+ { id: '7', repository_id: 1, build_id: 5, commit_id: 5, log_id: 7, number: '5.1', config: { rvm: 'rbx' }, state: 'created', queue: 'builds.common' }
+ { id: '8', repository_id: 1, build_id: 5, commit_id: 5, log_id: 8, number: '5.2', config: { rvm: 'rbx' }, state: 'created', queue: 'builds.common' }
]
artifacts = [
- { id: 1, body: 'log 1' }
- { id: 2, body: 'log 2' }
- { id: 3, body: 'log 3' }
- { id: 4, body: 'log 4' }
- { id: 5, body: 'log 5' }
- { id: 6, body: 'log 6' }
- { id: 7, body: 'log 7' }
- { id: 8, body: 'log 8' }
+ { id: '1', body: 'log 1' }
+ { id: '2', body: 'log 2' }
+ { id: '3', body: 'log 3' }
+ { id: '4', body: 'log 4' }
+ { id: '5', body: 'log 5' }
+ { id: '6', body: 'log 6' }
+ { id: '7', body: 'log 7' }
+ { id: '8', body: 'log 8' }
]
branches = [
@@ -49,8 +49,8 @@ branches = [
]
workers = [
- { id: 1, name: 'ruby-1', host: 'worker.travis-ci.org', state: 'ready' }
- { id: 2, name: 'ruby-2', host: 'worker.travis-ci.org', state: 'ready' }
+ { id: '1', name: 'ruby-1', host: 'worker.travis-ci.org', state: 'ready' }
+ { id: '2', name: 'ruby-2', host: 'worker.travis-ci.org', state: 'ready' }
]
hooks = [
diff --git a/assets/scripts/spec/unit/artifact_spec.coffee b/assets/scripts/spec/unit/artifact_spec.coffee
deleted file mode 100644
index 4458152e..00000000
--- a/assets/scripts/spec/unit/artifact_spec.coffee
+++ /dev/null
@@ -1,36 +0,0 @@
-store = null
-record = null
-
-describe 'Travis.Artifact', ->
- beforeEach ->
- store = Travis.Store.create()
-
- afterEach ->
- store.destroy()
-
- describe 'with part of the body loaded', ->
- beforeEach =>
- store.load Travis.Artifact, 1, { id: 1, body: 'first\nsecond\n' }
- record = store.find(Travis.Artifact, 1)
-
- it 'packs the existing part of the body to parts', ->
- expect( record.get('parts').toArray() ).toEqual( ['first\nsecond\n'] )
-
- it 'adds new chunks of log to parts', ->
- record.append('third\n')
- expect( record.get('parts').toArray() ).toEqual( ['first\nsecond\n', 'third\n'] )
-
- it 'properly handles array observers', ->
- called = 0
- observer = {
- arrayDidChange: -> called += 1
- arrayWillChange: -> called += 1
- }
-
- record.get('parts').addArrayObserver observer,
- willChange: 'arrayWillChange'
- didChange: 'arrayDidChange'
-
- record.append('something')
-
- expect(called).toEqual 2
diff --git a/assets/scripts/spec/unit/build_spec.coffee b/assets/scripts/spec/unit/build_spec.coffee
index 2a81e1d1..f7374224 100644
--- a/assets/scripts/spec/unit/build_spec.coffee
+++ b/assets/scripts/spec/unit/build_spec.coffee
@@ -10,7 +10,8 @@ describe 'Travis.Build', ->
describe 'incomplete attributes', ->
beforeEach ->
- record = store.loadIncomplete Travis.Build, { id: 1, state: 'started' }
+ store.loadIncomplete Travis.Build, { id: 1, state: 'started' }
+ record = store.find Travis.Build, 1
it 'does not load record on duration, finishedAt and result if job is not in finished state', ->
record.get('_duration')
@@ -19,12 +20,13 @@ describe 'Travis.Build', ->
waits 50
runs ->
- expect( record.get('complete') ).toBeFalsy()
+ expect( record.get('incomplete') ).toBeTruthy()
it 'loads the rest of the record if it\'s in finished state', ->
- record = store.loadIncomplete Travis.Build, { id: 1, state: 'finished' }
+ store.loadIncomplete Travis.Build, { id: 1, state: 'passed' }
+ record = store.find Travis.Build, 1
record.get('finishedAt')
waits 50
runs ->
- expect( record.get('complete') ).toBeTruthy()
+ expect( record.get('incomplete') ).toBeFalsy()
diff --git a/assets/scripts/spec/unit/incomplete_spec.coffee b/assets/scripts/spec/unit/incomplete_spec.coffee
index fdbcdfce..adf501c3 100644
--- a/assets/scripts/spec/unit/incomplete_spec.coffee
+++ b/assets/scripts/spec/unit/incomplete_spec.coffee
@@ -2,13 +2,13 @@ record = null
store = null
adapterClass = null
-$.mockjax
- url: '/foos/1'
- responseTime: 10
- responseText: { foo: { id: 1, name: 'foo', description: 'bar' } }
-
describe 'Travis.Model - incomplete', ->
beforeEach ->
+ $.mockjax
+ url: '/foos/1'
+ responseTime: 1
+ responseText: { foo: { id: 1, name: 'foo', description: 'bar' } }
+
Travis.Foo = Travis.Model.extend
name: DS.attr('string')
description: DS.attr('string')
@@ -18,10 +18,14 @@ describe 'Travis.Model - incomplete', ->
niceBar: DS.belongsTo('Travis.Bar')
veryNiceBar: DS.belongsTo('Travis.Bar')
+ Travis.Foo.toString = -> 'Travis.Foo'
+
Travis.Bar = Travis.Model.extend
name: DS.attr('string')
foos: DS.hasMany('Travis.Foo')
+ Travis.Bar.toString = -> 'Travis.Bar'
+
adapterClass = Travis.RestAdapter.extend()
adapterClass.map 'Travis.Foo',
veryNiceBar: { key: 'very_nice_bar_indeed_id' }
diff --git a/assets/scripts/spec/unit/job_spec.coffee b/assets/scripts/spec/unit/job_spec.coffee
index 2550058b..42efff80 100644
--- a/assets/scripts/spec/unit/job_spec.coffee
+++ b/assets/scripts/spec/unit/job_spec.coffee
@@ -10,7 +10,8 @@ describe 'Travis.Job', ->
describe 'incomplete attributes', ->
beforeEach ->
- record = store.loadIncomplete Travis.Job, { id: 1, state: 'started' }
+ store.loadIncomplete Travis.Job, { id: 1, state: 'started' }
+ record = store.find Travis.Job, 1
it 'does not load record on duration, finishedAt and result if job is not in finished state', ->
record.get('_duration')
@@ -19,15 +20,16 @@ describe 'Travis.Job', ->
waits 50
runs ->
- expect( record.get('complete') ).toBeFalsy()
+ expect( record.get('incomplete') ).toBeTruthy()
it 'loads the rest of the record if it\'s in finished state', ->
- record = store.loadIncomplete Travis.Job, { id: 1, state: 'finished' }
+ store.loadIncomplete Travis.Job, { id: 1, state: 'passed' }
+ record = store.find Travis.Job, 1
record.get('finishedAt')
waits 50
runs ->
- expect( record.get('complete') ).toBeTruthy()
+ expect( record.get('incomplete') ).toBeFalsy()
describe 'with different number of config keys in sibling jobs', ->
diff --git a/assets/scripts/spec/unit/log_spec.coffee b/assets/scripts/spec/unit/log_spec.coffee
deleted file mode 100644
index a8ff7d1d..00000000
--- a/assets/scripts/spec/unit/log_spec.coffee
+++ /dev/null
@@ -1,229 +0,0 @@
-log = null
-target = null
-
-describe 'Travis.Log', ->
- beforeEach ->
- target = Em.Object.create
- calls: []
- appendLog: (payloads) ->
- lines = payloads.map (p) ->
- line = p.content
- delete p.content
- line
-
- @get('calls').pushObject
- options: payloads
- lines: lines
-
- log = Travis.Log.create(target: target)
-
- it 'works with log passed as a string', ->
- log.append '1\n2'
-
- expect( target.get('calls.firstObject.lines') ).toEqual ['1', '2']
-
-
- it 'splits lines', ->
- log.append ['1\r\n2\n\n', '3']
-
- expect( target.get('calls.length') ).toEqual 1
- expect( target.get('calls.firstObject.lines') ).toEqual ['1', '2', '', '3']
-
- it 'escapes html characters', ->
- log.append '<>'
-
- expect( target.get('calls.firstObject.lines') ).toEqual ['<>']
-
- it 'normalizes ansi mess', ->
- log.append ['foo\r\r', 'bar']
-
- expect( target.get('calls.firstObject.lines') ).toEqual [ 'foo', 'bar' ]
-
- it 'calls target with folds separation', ->
- fold = Em.Object.create name: 'foo', startPattern: /^\$ foo/, endPattern: /^\$/
- log.addFold fold
-
- fold = Em.Object.create name: 'qux', startPattern: /^\$ qux/, endPattern: /^\$/
- log.addFold fold
-
- log.append [
- '1\n', '2\n'
- '$ foo --foo\n', '1\n'
- '$ bar\n'
- '$ baz\n'
- '$ qux\n', '1\n', '2\n'
- '$ end\n'
- ]
-
- # expect( target.get('calls.length') ).toEqual 5
- lines = target.get('calls').map (call) -> call.lines
- options = target.get('calls').map (call) -> call.options
-
- expect( lines[0] ).toEqual ['1', '2']
- expect( options[0]).toEqual [ { number: 1 }, { number: 2 } ]
-
- expect( lines[1] ).toEqual ['$ foo --foo', '1']
- expect( options[1]).toEqual [
- { number: 3, fold: 'foo' },
- { number: 4, fold: 'foo', foldContinuation: true, foldEnd: true }]
-
- expect( lines[2] ).toEqual ['$ bar', '$ baz']
- expect( options[2]).toEqual [{ number: 5 }, { number: 6 }]
-
- expect( lines[3] ).toEqual ['$ qux', '1', '2']
- expect( options[3]).toEqual [
- { number: 7, fold: 'qux' },
- { number: 8, fold: 'qux', foldContinuation: true },
- { number: 9, fold: 'qux', foldContinuation: true, foldEnd: true }]
-
- expect( lines[4] ).toEqual ['$ end']
- expect( options[4]).toEqual [{ number: 10 }]
-
- it 'works properly when log is started with fold', ->
- fold = Em.Object.create name: 'foo', startPattern: /^\$ foo/, endPattern: /^\$/
- log.addFold fold
-
- log.append [
- '$ foo --foo\n', '1\n'
- '$ bar\n'
- ]
-
- expect( target.get('calls.length') ).toEqual 2
- lines = target.get('calls').map (call) -> call.lines
- options = target.get('calls').map (call) -> call.options
-
- expect( lines[0] ).toEqual ['$ foo --foo', '1']
- expect( options[0]).toEqual [
- { number: 1, fold: 'foo' },
- { number: 2, fold: 'foo', foldContinuation: true, foldEnd: true }]
-
- expect( lines[1] ).toEqual ['$ bar']
- expect( options[1]).toEqual [{ number: 3 }]
-
- it 'works properly for 2 consecutive folds', ->
- fold = Em.Object.create name: 'foo', startPattern: /^\$ foo/, endPattern: /^\$/
- log.addFold fold
-
- log.append [
- '$ foo --foo\n', '1\n'
- '$ foo --bar\n', '2\n'
- '$ bar\n'
- ]
-
- expect( target.get('calls.length') ).toEqual 3
- lines = target.get('calls').map (call) -> call.lines
- options = target.get('calls').map (call) -> call.options
-
- expect( lines[0] ).toEqual ['$ foo --foo', '1']
- expect( options[0]).toEqual [
- { number: 1, fold: 'foo' },
- { number: 2, fold: 'foo', foldContinuation: true, foldEnd: true }]
-
- expect( lines[1] ).toEqual ['$ foo --bar', '2']
- expect( options[1]).toEqual [
- { number: 3, fold: 'foo' },
- { number: 4, fold: 'foo', foldContinuation: true, foldEnd: true }]
-
- expect( lines[2] ).toEqual ['$ bar']
- expect( options[2]).toEqual [{ number: 5 }]
-
- it 'works fine with not finalized fold', ->
- fold = Em.Object.create name: 'foo', startPattern: /^\$ foo/, endPattern: /^\$/
- log.addFold fold
-
- log.append [
- '$ foo --foo\n', '1\n'
- ]
-
- expect( target.get('calls.length') ).toEqual 1
- lines = target.get('calls').map (call) -> call.lines
- options = target.get('calls').map (call) -> call.options
-
- expect( lines[0] ).toEqual ['$ foo --foo', '1']
- expect( options[0]).toEqual [
- { fold: 'foo', number: 1 },
- { fold: 'foo', number: 2, foldContinuation: true }]
-
- it 'allows to continue fold', ->
- fold = Em.Object.create name: 'foo', startPattern: /^\$ foo/, endPattern: /^\$/
- log.addFold fold
-
- log.append [
- '$ foo --foo\n', '1\n'
- ]
-
- log.append '2\n'
-
- log.append [
- '3\n'
- '$ bar\n'
- ]
-
- expect( target.get('calls.length') ).toEqual 4
- lines = target.get('calls').map (call) -> call.lines
- options = target.get('calls').map (call) -> call.options
-
- expect( lines[0] ).toEqual ['$ foo --foo', '1']
- expect( options[0]).toEqual [
- { fold: 'foo', number: 1 },
- { fold: 'foo', number: 2, foldContinuation: true }]
-
- expect( lines[1] ).toEqual ['2']
- expect( options[1]).toEqual [
- { fold: 'foo', number: 3, foldContinuation: true }
- ]
-
- expect( lines[2] ).toEqual ['3']
- expect( options[2]).toEqual [
- { fold: 'foo', number: 4, foldContinuation: true, foldEnd: true }
- ]
-
- expect( lines[3] ).toEqual ['$ bar']
- expect( options[3]).toEqual [{ number: 5 }]
-
- it 'notifies that the line should be appended', ->
- log.append '$ foo\n.'
-
- log.append '...'
-
- log.append '..\n$ bar\n'
-
- expect( target.get('calls.length') ).toEqual 3
- lines = target.get('calls').map (call) -> call.lines
- options = target.get('calls').map (call) -> call.options
-
- expect( lines[0] ).toEqual ['$ foo', '.']
- expect( options[0]).toEqual [{ number: 1 }, { number: 2 }]
-
- expect( lines[1] ).toEqual ['...']
- expect( options[1]).toEqual [{ append: true, number: 2 }]
-
- expect( lines[2] ).toEqual ['..', '$ bar']
- expect( options[2]).toEqual [{ append: true, number: 2 }, { number: 3 }]
-
- it 'notifies that the line should be replaced', ->
- log.append '$ foo\n'
-
- log.append '\rDownloading 50%'
- log.append '\rDownloading 100%\r\n'
-
- log.append '$ bar\n'
-
- expect( target.get('calls.length') ).toEqual 4
- lines = target.get('calls').map (call) -> call.lines
- options = target.get('calls').map (call) -> call.options
-
- expect( lines[0] ).toEqual ['$ foo']
- expect( options[0]).toEqual [{ number: 1 }]
-
- expect( lines[1] ).toEqual ['', 'Downloading 50%']
- expect( options[1]).toEqual [{ number: 2 }, { number: 2, replace: true }]
-
- expect( lines[2] ).toEqual ['', 'Downloading 100%']
- expect( options[2]).toEqual [{ number: 2, append: true }, { number: 2, replace: true }]
-
- expect( lines[3] ).toEqual ['$ bar']
- expect( options[3]).toEqual [{ number: 3 }]
-
- it 'notifies that the line should be replaced even if carriage return is in the middle', ->
-
diff --git a/assets/scripts/spec/unit/merge_spec.coffee b/assets/scripts/spec/unit/merge_spec.coffee
index 7feda345..75007d1e 100644
--- a/assets/scripts/spec/unit/merge_spec.coffee
+++ b/assets/scripts/spec/unit/merge_spec.coffee
@@ -36,7 +36,7 @@ describe 'Travis.Model - merge', ->
record.removeObserver 'firstName', observer
- expect(changes).toEqual(1)
+ expect(changes > 0).toBeTruthy()
expect(record.get('firstName')).toEqual('Peter')
expect(record.get('login')).toEqual('drogus')
expect(record.get('email')).toEqual('drogus@example.org')
diff --git a/assets/scripts/spec/unit/pre_view_spec.coffee b/assets/scripts/spec/unit/pre_view_spec.coffee
deleted file mode 100644
index c1a95ce5..00000000
--- a/assets/scripts/spec/unit/pre_view_spec.coffee
+++ /dev/null
@@ -1,161 +0,0 @@
-view = null
-store = null
-record = null
-
-describe 'Travis.PreView', ->
- beforeEach ->
- store = Travis.Store.create()
-
- afterEach ->
- store.destroy()
- view.remove()
- view.destroy()
-
- it 'works fine with existing log, which is appended', ->
- store.load Travis.Artifact, 1, { id: 1, body: '$ start\n' }
- log = Travis.Artifact.find(1)
- log.set('version', 1)
-
- Ember.run ->
- view = Travis.PreView.create(log: null)
- view.append()
-
- expect( view.$('#log').length ).toEqual 1
-
- Ember.run ->
- view.set 'log', log
- log.set 'isLoaded', true
-
- waits 50
- runs ->
- expect( view.$('#log p').length ).toEqual 1
- expect( view.$('#log p').text().trim() ).toEqual '1$ start'
-
- Ember.run ->
- log.append('$ end')
-
- waits 50
- runs ->
- expect( view.$('#log p').length ).toEqual 2
- expect( view.$('#log p').text().trim() ).toEqual '1$ start2$ end'
-
- it 'works fine with log already attahed to view', ->
- store.load Travis.Artifact, 1, { id: 1, body: '$ start\n' }
- log = Travis.Artifact.find(1)
-
- Ember.run ->
- view = Travis.PreView.create()
- view.set('log', log)
- view.append()
-
- Ember.run ->
- log.append('end')
-
- waits 50
- runs ->
- expect( view.$('#log p').length ).toEqual 2
- expect( view.$('#log p').text().trim() ).toEqual '1$ start2end'
-
- it 'folds items', ->
- store.load Travis.Artifact, 1, { id: 1, body: '$ start\n' }
- log = Travis.Artifact.find(1)
-
- Ember.run ->
- view = Travis.PreView.create()
- view.set('log', log)
- view.append()
-
- Ember.run ->
- log.append '$ bundle install\n1\n2\n'
-
- Ember.run ->
- log.append '3\n4\n$ something'
-
- waits 50
- runs ->
- expect( view.$('#log > p').length ).toEqual 2
- expect( view.$('#log .fold.bundle').length ).toEqual 1
- expect( view.$('#log .fold.bundle > p').length ).toEqual 5
-
-
- it 'works properly with fragment document', ->
- store.load Travis.Artifact, 1, { id: 1, body: '' }
- log = Travis.Artifact.find(1)
-
- Ember.run ->
- view = Travis.PreView.create()
- view.set('log', log)
- view.append()
-
- waits 50
- runs ->
- payloads = [
- { number: 1, content: 'foo' }
- { number: 1, content: 'bar', append: true }
- ]
-
- # it should work even if we need to append to fragment in memory
- view.appendLog(payloads)
-
- expect( view.$('#L1').parent().text().trim() ).toEqual '1foobar'
-
- # now, let's append more to this line, it's in DOM already
- view.appendLog([ { number: 1, content: 'baz', append: true } ])
-
- expect( view.$('#L1').parent().text().trim() ).toEqual '1foobarbaz'
-
- payloads = [
- { number: 1, content: 'foo', replace: true }
- ]
- # replace should work in DOM
- view.appendLog(payloads)
- expect( view.$('#L1').parent().text().trim() ).toEqual '1foo'
-
- payloads = [
- { number: 2, content: 'foo' }
- { number: 2, content: 'bar', replace: true }
- ]
- # replace should work when element is in fragment
- view.appendLog(payloads)
- expect( view.$('#L2').parent().text().trim() ).toEqual '2bar'
-
- payloads = [
- { number: 3, content: '$ bundle install', fold: 'bundle' }
- { number: 4, content: 'Installing rails', fold: 'bundle', foldContinuation: true }
- ]
- # folds should work properly with fragment
- view.appendLog(payloads)
- expect( view.$('.bundle #L3').parent().text().trim() ).toEqual '3$ bundle install'
- expect( view.$('.bundle #L4').parent().text().trim() ).toEqual '4Installing rails'
- expect( view.$('.bundle > p').length ).toEqual 2
-
- payloads = [
- { number: 5, content: 'Installing travis', fold: 'bundle', foldContinuation: true }
- ]
- # folds should also work when already in DOM
- view.appendLog(payloads)
- expect( view.$('.bundle #L5').parent().text().trim() ).toEqual '5Installing travis'
- expect( view.$('.bundle > p').length ).toEqual 3
-
- # regular line append
- view.appendLog([ { number: 6, content: 'next'} ])
- expect( view.$('#L6').parent().text().trim() ).toEqual '6next'
-
- # openFold when in fragment
- payloads = [
- { number: 7, content: '$ install', fold: 'install' }
- { number: 8, content: 'Installing foo', fold: 'install', foldContinuation: true }
- { number: 9, content: 'error', openFold: true, fold: 'install', foldContinuation: true }
- ]
- # folds should work properly with fragment
- view.appendLog(payloads)
- expect( view.$('.install').hasClass('show-first-line') ).toEqual false
-
- # end fold when in fragment
- payloads = [
- { number: 10, content: '$ install', fold: 'install2' }
- { number: 11, content: 'Installing foo', fold: 'install2', foldEnd: true, foldContinuation: true }
- ]
- # folds should work properly with fragment
- view.appendLog(payloads)
- expect( view.$('.install2').hasClass('show-first-line') ).toEqual false
diff --git a/assets/scripts/travis.coffee b/assets/scripts/travis.coffee
index 2e52417d..21253131 100644
--- a/assets/scripts/travis.coffee
+++ b/assets/scripts/travis.coffee
@@ -38,6 +38,9 @@ window.Travis = Em.Application.extend(Ember.Evented,
@_super.apply(this, arguments);
+ lookup: ->
+ @__container__.lookup.apply this, arguments
+
storeAfterSignInPath: (path) ->
@get('auth').storeAfterSignInPath(path)
diff --git a/assets/scripts/vendor/ember.js b/assets/scripts/vendor/ember.js
index 35a9c6a5..524baafb 100644
--- a/assets/scripts/vendor/ember.js
+++ b/assets/scripts/vendor/ember.js
@@ -1,5 +1,5 @@
-// Version: v1.0.0-pre.4-209-g455440d
-// Last commit: 455440d (2013-02-13 12:03:37 -0800)
+// Version: v1.0.0-rc.1-109-g8cc5392
+// Last commit: 8cc5392 (2013-03-04 02:00:20 +0100)
(function() {
@@ -150,8 +150,8 @@ Ember.deprecateFunc = function(message, func) {
})();
-// Version: v1.0.0-pre.4-209-g455440d
-// Last commit: 455440d (2013-02-13 12:03:37 -0800)
+// Version: v1.0.0-rc.1-109-g8cc5392
+// Last commit: 8cc5392 (2013-03-04 02:00:20 +0100)
(function() {
@@ -211,7 +211,7 @@ var define, requireModule;
@class Ember
@static
- @version 1.0.0-pre.4
+ @version 1.0.0-rc.1
*/
if ('undefined' === typeof Ember) {
@@ -238,10 +238,10 @@ Ember.toString = function() { return "Ember"; };
/**
@property VERSION
@type String
- @default '1.0.0-pre.4'
+ @default '1.0.0-rc.1'
@final
*/
-Ember.VERSION = '1.0.0-pre.4';
+Ember.VERSION = '1.0.0-rc.1';
/**
Standard environmental variables. You can define these in a global `ENV`
@@ -297,6 +297,15 @@ Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !
*/
Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES;
+/**
+ Determines whether Ember logs info about version of used libraries
+
+ @property LOG_VERSION
+ @type Boolean
+ @default true
+*/
+Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true;
+
/**
Empty function. Useful for some operations.
@@ -651,7 +660,7 @@ Ember.generateGuid = function generateGuid(obj, prefix) {
@method guidFor
@for Ember
- @param obj {Object} any object, string, number, Element, or primitive
+ @param {Object} obj any object, string, number, Element, or primitive
@return {String} the unique guid for this instance.
*/
Ember.guidFor = function guidFor(obj) {
@@ -1001,8 +1010,8 @@ var needsFinallyFix = (function() {
@method tryFinally
@for Ember
- @param {Function} function The function to run the try callback
- @param {Function} function The function to run the finally callback
+ @param {Function} tryable The function to run the try callback
+ @param {Function} finalizer The function to run the finally callback
@param [binding]
@return {anything} The return value is the that of the finalizer,
unless that valueis undefined, in which case it is the return value
@@ -1051,9 +1060,9 @@ if (needsFinallyFix) {
@method tryCatchFinally
@for Ember
- @param {Function} function The function to run the try callback
- @param {Function} function The function to run the catchable callback
- @param {Function} function The function to run the finally callback
+ @param {Function} tryable The function to run the try callback
+ @param {Function} catchable The function to run the catchable callback
+ @param {Function} finalizer The function to run the finally callback
@param [binding]
@return {anything} The return value is the that of the finalizer,
unless that value is undefined, in which case it is the return value
@@ -1565,8 +1574,8 @@ OrderedSet.prototype = {
/**
@method forEach
- @param {Function} function
- @param target
+ @param {Function} fn
+ @param self
*/
forEach: function(fn, self) {
// allow mutation during iteration
@@ -2087,7 +2096,7 @@ Ember.setPath = Ember.deprecateFunc('setPath is deprecated since set now support
@method trySet
@for Ember
@param {Object} obj The object to modify.
- @param {String} keyName The property key to set
+ @param {String} path The property path to set
@param {Object} value The value to set
*/
Ember.trySet = function(root, path, value) {
@@ -2232,6 +2241,7 @@ Ember.defineProperty = function(obj, keyName, desc, data, meta) {
} else {
obj[keyName] = undefined; // make enumerable
}
+ desc.setup(obj, keyName);
} else {
descs[keyName] = undefined; // shadow descriptor in proto
if (desc == null) {
@@ -2950,12 +2960,15 @@ Ember.watch = function(obj, keyName) {
// can't watch length on Array - it is special...
if (keyName === 'length' && Ember.typeOf(obj) === 'array') { return this; }
- var m = metaFor(obj), watching = m.watching;
+ var m = metaFor(obj), watching = m.watching, desc;
// activate watching first time
if (!watching[keyName]) {
watching[keyName] = 1;
if (isKeyName(keyName)) {
+ desc = m.descs[keyName];
+ if (desc && desc.willWatch) { desc.willWatch(obj, keyName); }
+
if ('function' === typeof obj.willWatchProperty) {
obj.willWatchProperty(keyName);
}
@@ -2990,12 +3003,15 @@ Ember.unwatch = function(obj, keyName) {
// can't watch length on Array - it is special...
if (keyName === 'length' && Ember.typeOf(obj) === 'array') { return this; }
- var m = metaFor(obj), watching = m.watching;
+ var m = metaFor(obj), watching = m.watching, desc;
if (watching[keyName] === 1) {
watching[keyName] = 0;
if (isKeyName(keyName)) {
+ desc = m.descs[keyName];
+ if (desc && desc.didUnwatch) { desc.didUnwatch(obj, keyName); }
+
if ('function' === typeof obj.didUnwatchProperty) {
obj.didUnwatchProperty(keyName);
}
@@ -3404,6 +3420,25 @@ ComputedPropertyPrototype.meta = function(meta) {
}
};
+/* impl descriptor API */
+ComputedPropertyPrototype.willWatch = function(obj, keyName) {
+ // watch already creates meta for this instance
+ var meta = obj[META_KEY];
+ Ember.assert('watch should have setup meta to be writable', meta.source === obj);
+ if (!(keyName in meta.cache)) {
+ addDependentKeys(this, obj, keyName, meta);
+ }
+};
+
+ComputedPropertyPrototype.didUnwatch = function(obj, keyName) {
+ var meta = obj[META_KEY];
+ Ember.assert('unwatch should have setup meta to be writable', meta.source === obj);
+ if (!(keyName in meta.cache)) {
+ // unwatch already creates meta for this instance
+ removeDependentKeys(this, obj, keyName, meta);
+ }
+};
+
/* impl descriptor API */
ComputedPropertyPrototype.didChange = function(obj, keyName) {
// _suspended is set via a CP.set to ensure we don't clear
@@ -3412,7 +3447,9 @@ ComputedPropertyPrototype.didChange = function(obj, keyName) {
var meta = metaFor(obj);
if (keyName in meta.cache) {
delete meta.cache[keyName];
- removeDependentKeys(this, obj, keyName, meta);
+ if (!meta.watching[keyName]) {
+ removeDependentKeys(this, obj, keyName, meta);
+ }
}
}
};
@@ -3425,7 +3462,9 @@ ComputedPropertyPrototype.get = function(obj, keyName) {
cache = meta.cache;
if (keyName in cache) { return cache[keyName]; }
ret = cache[keyName] = this.func.call(obj, keyName);
- addDependentKeys(this, obj, keyName, meta);
+ if (!meta.watching[keyName]) {
+ addDependentKeys(this, obj, keyName, meta);
+ }
} else {
ret = this.func.call(obj, keyName);
}
@@ -3478,7 +3517,7 @@ ComputedPropertyPrototype.set = function(obj, keyName, value) {
}
if (cacheable) {
- if (!hadCachedValue) {
+ if (!watched && !hadCachedValue) {
addDependentKeys(this, obj, keyName, meta);
}
cache[keyName] = ret;
@@ -3491,11 +3530,19 @@ ComputedPropertyPrototype.set = function(obj, keyName, value) {
return ret;
};
+/* called when property is defined */
+ComputedPropertyPrototype.setup = function(obj, keyName) {
+ var meta = obj[META_KEY];
+ if (meta && meta.watching[keyName]) {
+ addDependentKeys(this, obj, keyName, metaFor(obj));
+ }
+};
+
/* called before property is overridden */
ComputedPropertyPrototype.teardown = function(obj, keyName) {
var meta = metaFor(obj);
- if (keyName in meta.cache) {
+ if (meta.watching[keyName] || keyName in meta.cache) {
removeDependentKeys(this, obj, keyName, meta);
}
@@ -3719,6 +3766,7 @@ function actionsDiff(obj, eventName, otherActions) {
@param {String} eventName
@param {Object|Function} targetOrMethod A target object or a function
@param {Function|String} method A function or the name of a function to be called on `target`
+ @param {Boolean} once A flag whether a function should only be called once
*/
function addListener(obj, eventName, target, method, once) {
Ember.assert("You must pass at least an object and event name to Ember.addListener", !!obj && !!eventName);
@@ -3904,6 +3952,7 @@ function watchedEvents(obj) {
@param obj
@param {String} eventName
@param {Array} params
+ @param {Array} actions
@return true
*/
function sendEvent(obj, eventName, params, actions) {
@@ -4515,6 +4564,21 @@ function scheduleOnce(queue, target, method, args) {
// doFoo will only be executed once at the end of the RunLoop
});
```
+
+ Also note that passing an anonymous function to `Ember.run.once` will
+ not prevent additional calls with an identical anonymous function from
+ scheduling the items multiple times, e.g.:
+
+ ```javascript
+ function scheduleIt() {
+ Ember.run.once(myContext, function() { console.log("Closure"); });
+ }
+ scheduleIt();
+ scheduleIt();
+ // "Closure" will print twice, even though we're using `Ember.run.once`,
+ // because the function we pass to it is anonymous and won't match the
+ // previously scheduled operation.
+ ```
@method once
@param {Object} [target] target of method to invoke
@@ -4691,7 +4755,7 @@ Binding.prototype = {
`get()` - see that method for more information.
@method from
- @param {String} propertyPath the property path to connect to
+ @param {String} path the property path to connect to
@return {Ember.Binding} `this`
*/
from: function(path) {
@@ -4709,7 +4773,7 @@ Binding.prototype = {
`get()` - see that method for more information.
@method to
- @param {String|Tuple} propertyPath A property path or tuple
+ @param {String|Tuple} path A property path or tuple
@return {Ember.Binding} `this`
*/
to: function(path) {
@@ -5450,6 +5514,38 @@ Mixin.finishPartial = finishPartial;
Ember.anyUnprocessedMixins = false;
/**
+ Creates an instance of a class. Accepts either no arguments, or an object
+ containing values to initialize the newly instantiated object with.
+
+ ```javascript
+ App.Person = Ember.Object.extend({
+ helloWorld: function() {
+ alert("Hi, my name is " + this.get('name'));
+ }
+ });
+
+ var tom = App.Person.create({
+ name: 'Tom Dale'
+ });
+
+ tom.helloWorld(); // alerts "Hi, my name is Tom Dale".
+ ```
+
+ `create` will call the `init` function if defined during
+ `Ember.AnyObject.extend`
+
+ If no arguments are passed to `create`, it will not set values to the new
+ instance during initialization:
+
+ ```javascript
+ var noName = App.Person.create();
+ noName.helloWorld(); // alerts undefined
+ ```
+
+ NOTE: For performance reasons, you cannot declare methods or computed
+ properties during `create`. You should instead declare methods and computed
+ properties when using `extend`.
+
@method create
@static
@param arguments*
@@ -5845,7 +5941,8 @@ define("rsvp",
callbacks, callbackTuple, callback, binding, event;
if (callbacks = allCallbacks[eventName]) {
- for (var i=0, l=callbacks.length; i 'InnerHTML'
- 'action_name'.capitalize() => 'Action_name'
- 'css-class-name'.capitalize() => 'Css-class-name'
- 'my favorite items'.capitalize() => 'My favorite items'
+ 'innerHTML'.capitalize() // 'InnerHTML'
+ 'action_name'.capitalize() // 'Action_name'
+ 'css-class-name'.capitalize() // 'Css-class-name'
+ 'my favorite items'.capitalize() // 'My favorite items'
@method capitalize
@param {String} str
@@ -7305,10 +7456,10 @@ Ember.Enumerable = Ember.Mixin.create(
```javascript
var arr = ["a", "b", "c"];
- arr.firstObject(); // "a"
+ arr.get('firstObject'); // "a"
var arr = [];
- arr.firstObject(); // undefined
+ arr.get('firstObject'); // undefined
```
@property firstObject
@@ -7331,10 +7482,10 @@ Ember.Enumerable = Ember.Mixin.create(
```javascript
var arr = ["a", "b", "c"];
- arr.lastObject(); // "c"
+ arr.get('lastObject'); // "c"
var arr = [];
- arr.lastObject(); // undefined
+ arr.get('lastObject'); // undefined
```
@property lastObject
@@ -7467,7 +7618,7 @@ Ember.Enumerable = Ember.Mixin.create(
@return {Array} The mapped array.
*/
map: function(callback, target) {
- var ret = [];
+ var ret = Ember.A([]);
this.forEach(function(x, idx, i) {
ret[idx] = callback.call(target, x, idx,i);
});
@@ -7517,7 +7668,7 @@ Ember.Enumerable = Ember.Mixin.create(
@return {Array} A filtered array.
*/
filter: function(callback, target) {
- var ret = [];
+ var ret = Ember.A([]);
this.forEach(function(x, idx, i) {
if (callback.call(target, x, idx, i)) ret.push(x);
});
@@ -7806,7 +7957,7 @@ Ember.Enumerable = Ember.Mixin.create(
@return {Array} return values from calling invoke.
*/
invoke: function(methodName) {
- var args, ret = [];
+ var args, ret = Ember.A([]);
if (arguments.length>1) args = a_slice.call(arguments, 1);
this.forEach(function(x, idx) {
@@ -7827,7 +7978,7 @@ Ember.Enumerable = Ember.Mixin.create(
@return {Array} the enumerable as an array.
*/
toArray: function() {
- var ret = [];
+ var ret = Ember.A([]);
this.forEach(function(o, idx) { ret[idx] = o; });
return ret ;
},
@@ -7861,7 +8012,7 @@ Ember.Enumerable = Ember.Mixin.create(
*/
without: function(value) {
if (!this.contains(value)) return this; // nothing to do
- var ret = [] ;
+ var ret = Ember.A([]);
this.forEach(function(k) {
if (k !== value) ret[ret.length] = k;
}) ;
@@ -7881,7 +8032,7 @@ Ember.Enumerable = Ember.Mixin.create(
@return {Ember.Enumerable}
*/
uniq: function() {
- var ret = [];
+ var ret = Ember.A([]);
this.forEach(function(k){
if (a_indexOf(ret, k)<0) ret.push(k);
});
@@ -7912,8 +8063,8 @@ Ember.Enumerable = Ember.Mixin.create(
mixin.
@method addEnumerableObserver
- @param target {Object}
- @param opts {Hash}
+ @param {Object} target
+ @param {Hash} [opts]
*/
addEnumerableObserver: function(target, opts) {
var willChange = (opts && opts.willChange) || 'enumerableWillChange',
@@ -7931,8 +8082,8 @@ Ember.Enumerable = Ember.Mixin.create(
Removes a registered enumerable observer.
@method removeEnumerableObserver
- @param target {Object}
- @param [opts] {Hash}
+ @param {Object} target
+ @param {Hash} [opts]
*/
removeEnumerableObserver: function(target, opts) {
var willChange = (opts && opts.willChange) || 'enumerableWillChange',
@@ -8049,7 +8200,7 @@ Ember.Enumerable = Ember.Mixin.create(
// HELPERS
//
-var get = Ember.get, set = Ember.set, meta = Ember.meta, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor;
+var get = Ember.get, set = Ember.set, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor;
function none(obj) { return obj===null || obj===undefined; }
@@ -8191,12 +8342,12 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
```
@method slice
- @param beginIndex {Integer} (Optional) index to begin slicing from.
- @param endIndex {Integer} (Optional) index to end the slice at.
+ @param {Integer} beginIndex (Optional) index to begin slicing from.
+ @param {Integer} endIndex (Optional) index to end the slice at.
@return {Array} New array with specified slice
*/
slice: function(beginIndex, endIndex) {
- var ret = [];
+ var ret = Ember.A([]);
var length = get(this, 'length') ;
if (none(beginIndex)) beginIndex = 0 ;
if (none(endIndex) || (endIndex > length)) endIndex = length ;
@@ -8297,7 +8448,7 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
@method addArrayObserver
@param {Object} target The observer object.
@param {Hash} opts Optional hash of configuration options including
- `willChange`, `didChange`, and a `context` option.
+ `willChange` and `didChange` option.
@return {Ember.Array} receiver
*/
addArrayObserver: function(target, opts) {
@@ -8319,6 +8470,8 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
@method removeArrayObserver
@param {Object} target The object observing the array.
+ @param {Hash} opts Optional hash of configuration options including
+ `willChange` and `didChange` option.
@return {Ember.Array} receiver
*/
removeArrayObserver: function(target, opts) {
@@ -8535,7 +8688,7 @@ Ember.Copyable = Ember.Mixin.create(
an exception.
@method copy
- @param deep {Boolean} if `true`, a deep copy of the object should be made
+ @param {Boolean} deep if `true`, a deep copy of the object should be made
@return {Object} copy of receiver
*/
copy: Ember.required(Function),
@@ -9096,7 +9249,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
@submodule ember-runtime
*/
-var get = Ember.get, set = Ember.set, defineProperty = Ember.defineProperty;
+var get = Ember.get, set = Ember.set;
/**
## Overview
@@ -9201,7 +9354,7 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
not defined upfront.
@method get
- @param {String} key The property to retrieve
+ @param {String} keyName The property to retrieve
@return {Object} The property value or undefined.
*/
get: function(keyName) {
@@ -9282,7 +9435,7 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
```
@method set
- @param {String} key The property to set
+ @param {String} keyName The property to set
@param {Object} value The value to set or `null`.
@return {Ember.Observable}
*/
@@ -9359,7 +9512,7 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
like.
@method propertyWillChange
- @param {String} key The property key that is about to change.
+ @param {String} keyName The property key that is about to change.
@return {Ember.Observable}
*/
propertyWillChange: function(keyName){
@@ -10042,6 +10195,37 @@ CoreObject.PrototypeMixin = Mixin.create({
isInstance: true,
+ /**
+ An overridable method called when objects are instantiated. By default,
+ does nothing unless it is overridden during class definition.
+
+ Example:
+
+ ```javascript
+ App.Person = Ember.Object.extend({
+ init: function() {
+ this._super();
+ alert('Name is ' + this.get('name'));
+ }
+ });
+
+ var steve = App.Person.create({
+ name: "Steve"
+ });
+
+ // alerts 'Name is Steve'.
+ ```
+
+ NOTE: If you do override `init` for a framework class like `Ember.View` or
+ `Ember.ArrayController`, be sure to call `this._super()` in your
+ `init` declaration! If you don't, Ember may not have an opportunity to
+ do important setup work, and you'll see strange behavior in your
+ application.
+
+ ```
+
+ @method init
+ */
init: function() {},
/**
@@ -10192,7 +10376,7 @@ CoreObject.PrototypeMixin = Mixin.create({
}
});
teacher = App.Teacher.create()
- teacher.toString(); // #=> ""
+ teacher.toString(); //=> ""
@method toString
@return {String} string representation
@@ -10900,16 +11084,28 @@ var Namespace = Ember.Namespace = Ember.Object.extend({
Namespace.reopenClass({
NAMESPACES: [Ember],
+ NAMESPACES_BY_ID: {},
PROCESSED: false,
- processAll: processAllNamespaces
+ processAll: processAllNamespaces,
+ byName: function(name) {
+ if (!Ember.BOOTED) {
+ processAllNamespaces();
+ }
+
+ return NAMESPACES_BY_ID[name];
+ }
});
+var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
+
var hasOwnProp = ({}).hasOwnProperty,
guidFor = Ember.guidFor;
function processNamespace(paths, root, seen) {
var idx = paths.length;
+ NAMESPACES_BY_ID[paths.join('.')] = root;
+
// Loop over all of the keys in the namespace, looking for classes
for(var key in root) {
if (!hasOwnProp.call(root, key)) { continue; }
@@ -11009,12 +11205,15 @@ function classToString() {
}
function processAllNamespaces() {
- if (!Namespace.PROCESSED) {
+ var unprocessedNamespaces = !Namespace.PROCESSED,
+ unprocessedMixins = Ember.anyUnprocessedMixins;
+
+ if (unprocessedNamespaces) {
findNamespaces();
Namespace.PROCESSED = true;
}
- if (Ember.anyUnprocessedMixins) {
+ if (unprocessedNamespaces || unprocessedMixins) {
var namespaces = Namespace.NAMESPACES, namespace;
for (var i=0, l=namespaces.length; i0) {
/**
The NativeArray mixin contains the properties needed to to make the native
Array support Ember.MutableArray and all of its dependent APIs. Unless you
- have `Ember.EXTEND_PROTOTYPES or `Ember.EXTEND_PROTOTYPES.Array` set to
+ have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` set to
false, this will be applied automatically. Otherwise you can apply the mixin
at anytime by calling `Ember.NativeArray.activate`.
@@ -12351,7 +12537,8 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
objectAtContent: function(idx) {
var length = get(this, 'length'),
- object = get(this,'arrangedContent').objectAt(idx);
+ arrangedContent = get(this,'arrangedContent'),
+ object = arrangedContent && arrangedContent.objectAt(idx);
if (idx >= 0 && idx < length) {
var controllerClass = this.lookupItemController(object);
@@ -12371,20 +12558,20 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
arrangedContentDidChange: function() {
this._super();
- this._resetSubContainers();
+ this._resetSubControllers();
},
arrayContentDidChange: function(idx, removedCnt, addedCnt) {
- var subContainers = get(this, 'subContainers'),
- subContainersToRemove = subContainers.slice(idx, idx+removedCnt);
+ var subControllers = get(this, '_subControllers'),
+ subControllersToRemove = subControllers.slice(idx, idx+removedCnt);
- forEach(subContainersToRemove, function(subContainer) {
- if (subContainer) { subContainer.destroy(); }
+ forEach(subControllersToRemove, function(subController) {
+ if (subController) { subController.destroy(); }
});
- replace(subContainers, idx, removedCnt, new Array(addedCnt));
+ replace(subControllers, idx, removedCnt, new Array(addedCnt));
- // The shadow array of subcontainers must be updated before we trigger
+ // The shadow array of subcontrollers must be updated before we trigger
// observers, otherwise observers will get the wrong subcontainer when
// calling `objectAt`
this._super(idx, removedCnt, addedCnt);
@@ -12392,42 +12579,40 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
init: function() {
this._super();
- this._resetSubContainers();
+ if (!this.get('content')) { Ember.defineProperty(this, 'content', undefined, Ember.A()); }
+ this.set('_subControllers', Ember.A());
},
controllerAt: function(idx, object, controllerClass) {
var container = get(this, 'container'),
- subContainers = get(this, 'subContainers'),
- subContainer = subContainers[idx],
- controller;
+ subControllers = get(this, '_subControllers'),
+ subController = subControllers[idx];
- if (!subContainer) {
- subContainer = subContainers[idx] = container.child();
+ if (!subController) {
+ subController = container.lookup("controller:" + controllerClass, { singleton: false });
+ subControllers[idx] = subController;
}
- controller = subContainer.lookup("controller:" + controllerClass);
- if (!controller) {
+ if (!subController) {
throw new Error('Could not resolve itemController: "' + controllerClass + '"');
}
- controller.set('target', this);
- controller.set('content', object);
+ subController.set('target', this);
+ subController.set('content', object);
- return controller;
+ return subController;
},
- subContainers: null,
+ _subControllers: null,
- _resetSubContainers: function() {
- var subContainers = get(this, 'subContainers');
+ _resetSubControllers: function() {
+ var subControllers = get(this, '_subControllers');
- if (subContainers) {
- forEach(subContainers, function(subContainer) {
- if (subContainer) { subContainer.destroy(); }
- });
- }
+ forEach(subControllers, function(subController) {
+ if (subController) { subController.destroy(); }
+ });
- this.set('subContainers', Ember.A());
+ this.set('_subControllers', Ember.A());
}
});
@@ -12504,15 +12689,16 @@ Ember.$ = jQuery;
@module ember
@submodule ember-views
*/
+if (Ember.$) {
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents
+ var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend');
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents
-var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend');
-
-// Copies the `dataTransfer` property from a browser event object onto the
-// jQuery event object for the specified events
-Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
- Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] };
-});
+ // Copies the `dataTransfer` property from a browser event object onto the
+ // jQuery event object for the specified events
+ Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
+ Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] };
+ });
+}
})();
@@ -12529,7 +12715,8 @@ Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use
-var needsShy = (function(){
+
+var needsShy = this.document && (function(){
var testEl = document.createElement('div');
testEl.innerHTML = "";
testEl.firstChild.innerHTML = "";
@@ -12539,7 +12726,7 @@ var needsShy = (function(){
// IE 8 (and likely earlier) likes to move whitespace preceeding
// a script tag to appear after it. This means that we can
// accidentally remove whitespace when updating a morph.
-var movesWhitespace = (function() {
+var movesWhitespace = this.document && (function() {
var testEl = document.createElement('div');
testEl.innerHTML = "Test: Value";
return testEl.childNodes[0].nodeValue === 'Test:' &&
@@ -13012,7 +13199,7 @@ Ember._RenderBuffer.prototype =
for (prop in props) {
if (props.hasOwnProperty(prop)) {
var value = props[prop];
- if (value) {
+ if (value || typeof(value) === 'number') {
if (value === true) {
buffer.push(' ' + prop + '="' + prop + '"');
} else {
@@ -13371,8 +13558,9 @@ Ember.EventDispatcher = Ember.Object.extend(
// Add a new named queue for rendering views that happens
// after bindings have synced, and a queue for scheduling actions
// that that should occur after view rendering.
-var queues = Ember.run.queues;
-queues.splice(Ember.$.inArray('actions', queues)+1, 0, 'render', 'afterRender');
+var queues = Ember.run.queues,
+ indexOf = Ember.ArrayPolyfills.indexOf;
+queues.splice(indexOf.call(queues, 'actions')+1, 0, 'render', 'afterRender');
})();
@@ -13457,7 +13645,7 @@ var childViewsProperty = Ember.computed(function() {
ret.replace = function (idx, removedCount, addedViews) {
if (view instanceof Ember.ContainerView) {
- Ember.deprecate("Manipulating a Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray.");
+ Ember.deprecate("Manipulating an Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray.");
return view.replace(idx, removedCount, addedViews);
}
throw new Error("childViews is immutable");
@@ -14716,7 +14904,6 @@ Ember.View = Ember.CoreView.extend(
// JavaScript property changes.
var observer = function() {
elem = this.$();
- if (!elem) { return; }
attributeValue = get(this, property);
@@ -15584,10 +15771,18 @@ Ember.View = Ember.CoreView.extend(
},
registerObserver: function(root, path, target, observer) {
- Ember.addObserver(root, path, target, observer);
+ if (!observer && 'function' === typeof target) {
+ observer = target;
+ target = null;
+ }
+ var view = this,
+ stateCheckedObserver = function(){
+ view.currentState.invokeObserver(this, observer);
+ };
+ Ember.addObserver(root, path, target, stateCheckedObserver);
this.one('willClearRender', function() {
- Ember.removeObserver(root, path, target, observer);
+ Ember.removeObserver(root, path, target, stateCheckedObserver);
});
}
@@ -15618,17 +15813,24 @@ Ember.View = Ember.CoreView.extend(
// once the view has been inserted into the DOM, legal manipulations
// are done on the DOM element.
+function notifyMutationListeners() {
+ Ember.run.once(Ember.View, 'notifyMutationListeners');
+}
+
var DOMManager = {
prepend: function(view, html) {
view.$().prepend(html);
+ notifyMutationListeners();
},
after: function(view, html) {
view.$().after(html);
+ notifyMutationListeners();
},
html: function(view, html) {
view.$().html(html);
+ notifyMutationListeners();
},
replace: function(view) {
@@ -15638,15 +15840,18 @@ var DOMManager = {
view._insertElementLater(function() {
Ember.$(element).replaceWith(get(view, 'element'));
+ notifyMutationListeners();
});
},
remove: function(view) {
view.$().remove();
+ notifyMutationListeners();
},
empty: function(view) {
view.$().empty();
+ notifyMutationListeners();
}
};
@@ -15761,6 +15966,20 @@ Ember.View.reopenClass({
}
});
+var mutation = Ember.Object.extend(Ember.Evented).create();
+
+Ember.View.addMutationListener = function(callback) {
+ mutation.on('change', callback);
+};
+
+Ember.View.removeMutationListener = function(callback) {
+ mutation.off('change', callback);
+};
+
+Ember.View.notifyMutationListeners = function() {
+ mutation.trigger('change');
+};
+
/**
Global views hash
@@ -15841,7 +16060,8 @@ Ember.View.states._default = {
return false;
},
- rerender: Ember.K
+ rerender: Ember.K,
+ invokeObserver: Ember.K
};
})();
@@ -15962,6 +16182,10 @@ Ember.merge(inBuffer, {
}
return value;
+ },
+
+ invokeObserver: function(target, observer) {
+ observer.call(target);
}
});
@@ -16049,6 +16273,10 @@ Ember.merge(hasElement, {
} else {
return true; // continue event propagation
}
+ },
+
+ invokeObserver: function(target, observer) {
+ observer.call(target);
}
});
@@ -16637,7 +16865,7 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
} else {
viewClass = App.SongView;
}
- this._super(viewClass, attrs);
+ return this._super(viewClass, attrs);
}
});
```
@@ -16920,15 +17148,15 @@ define("metamorph",
var K = function(){},
guid = 0,
- document = window.document,
+ document = this.document,
// Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
- supportsRange = ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
+ supportsRange = document && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use
- needsShy = (function(){
+ needsShy = document && (function(){
var testEl = document.createElement('div');
testEl.innerHTML = "";
testEl.firstChild.innerHTML = "";
@@ -16939,7 +17167,7 @@ define("metamorph",
// IE 8 (and likely earlier) likes to move whitespace preceeding
// a script tag to appear after it. This means that we can
// accidentally remove whitespace when updating a morph.
- movesWhitespace = (function() {
+ movesWhitespace = document && (function() {
var testEl = document.createElement('div');
testEl.innerHTML = "Test: Value";
return testEl.childNodes[0].nodeValue === 'Test:' &&
@@ -17383,8 +17611,12 @@ var objectCreate = Object.create || function(parent) {
return new F();
};
-var Handlebars = this.Handlebars || Ember.imports.Handlebars;
-Ember.assert("Ember Handlebars requires Handlebars 1.0.rc.2 or greater", Handlebars && Handlebars.VERSION.match(/^1\.0\.rc\.[23456789]+/));
+var Handlebars = this.Handlebars || (Ember.imports && Ember.imports.Handlebars);
+if(!Handlebars && typeof require === 'function') {
+ Handlebars = require('handlebars');
+}
+
+Ember.assert("Ember Handlebars requires Handlebars 1.0.rc.3 or greater", Handlebars && Handlebars.VERSION.match(/^1\.0(\.0)?(\.|-)rc\.[23456789]+/));
/**
Prepares the Handlebars templating library for use inside Ember's view
@@ -18043,22 +18275,30 @@ Ember.Handlebars.resolvePaths = function(options) {
var set = Ember.set, get = Ember.get;
var Metamorph = requireModule('metamorph');
+function notifyMutationListeners() {
+ Ember.run.once(Ember.View, 'notifyMutationListeners');
+}
+
// DOMManager should just abstract dom manipulation between jquery and metamorph
var DOMManager = {
remove: function(view) {
view.morph.remove();
+ notifyMutationListeners();
},
prepend: function(view, html) {
view.morph.prepend(html);
+ notifyMutationListeners();
},
after: function(view, html) {
view.morph.after(html);
+ notifyMutationListeners();
},
html: function(view, html) {
view.morph.html(html);
+ notifyMutationListeners();
},
// This is messed up.
@@ -18081,11 +18321,13 @@ var DOMManager = {
morph.replaceWith(buffer.string());
view.transitionTo('inDOM');
view.triggerRecursively('didInsertElement');
+ notifyMutationListeners();
});
},
empty: function(view) {
view.morph.html("");
+ notifyMutationListeners();
}
};
@@ -18977,7 +19219,9 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
// Add an observer to the view for when the property changes.
// When the observer fires, find the element using the
// unique data id and update the attribute to the new value.
- if (path !== 'this') {
+ // Note: don't add observer when path is 'this' or path
+ // is whole keyword e.g. {{#each x in list}} ... {{bindAttr attr="x"}}
+ if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) {
view.registerObserver(normalized.root, normalized.path, invoker);
}
@@ -20000,7 +20244,7 @@ GroupedEach.prototype = {
```handlebars
{{#view App.MyView }}
- {{each view.items itemViewClass="App.AnItemView"}}
+ {{each view.items itemViewClass="App.AnItemView"}}
{{/view}}
```
@@ -20031,7 +20275,7 @@ GroupedEach.prototype = {
Greetings Sara
```
-
+
### Representing each item with a Controller.
By default the controller lookup within an `{{#each}}` block will be
the controller of the template where the `{{#each}}` was used. If each
@@ -20039,10 +20283,10 @@ GroupedEach.prototype = {
`itemController` option which references a controller by lookup name.
Each item in the loop will be wrapped in an instance of this controller
and the item itself will be set to the `content` property of that controller.
-
+
This is useful in cases where properties of model objects need transformation
or synthesis for display:
-
+
```javascript
App.DeveloperController = Ember.ObjectController.extend({
isAvailableForHire: function(){
@@ -20050,17 +20294,17 @@ GroupedEach.prototype = {
}.property('isEmployed', 'isSeekingWork')
})
```
-
+
```handlebars
- {{#each person in Developers itemController="developer"}}
+ {{#each person in developers itemController="developer"}}
{{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
{{/each}}
```
-
+
@method each
@for Ember.Handlebars.helpers
@param [name] {String} name for item (used with `in`)
- @param path {String} path
+ @param [path] {String} path
@param [options] {Object} Handlebars key/value pairs of options
@param [options.itemViewClass] {String} a path to a view class used for each item
@param [options.itemController] {String} name of a controller to be created for each item
@@ -20119,6 +20363,14 @@ Ember.Handlebars.registerHelper('each', function(path, options) {
```
+ ```handlebars
+ {{#if isUser}}
+ {{template "user_info"}}
+ {{else}}
+ {{template "unlogged_user_info"}}
+ {{/if}}
+ ```
+
This helper looks for templates in the global `Ember.TEMPLATES` hash. If you
add `