stuff
This commit is contained in:
parent
2437f79845
commit
f7aeda897b
|
@ -1,3 +1,7 @@
|
||||||
|
# TODO add neuter for production
|
||||||
|
# https://github.com/wycats/rake-pipeline-web-filters/blob/master/lib/rake-pipeline-web-filters/neuter_filter.rb
|
||||||
|
# http://blog.nulayer.com/post/23294069876/building-simple-javascript-libraries-with-rake-pipeline?15bb0420
|
||||||
|
|
||||||
require 'rake-pipeline-web-filters'
|
require 'rake-pipeline-web-filters'
|
||||||
|
|
||||||
output 'public/javascripts'
|
output 'public/javascripts'
|
||||||
|
|
|
@ -1,8 +1,42 @@
|
||||||
|
$.mockjax
|
||||||
|
url: '/repositories',
|
||||||
|
responseTime: 0,
|
||||||
|
responseText:
|
||||||
|
repositories: [
|
||||||
|
{ 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 },
|
||||||
|
{ id: 2, owner: 'travis-ci', name: 'travis-assets', slug: 'travis-ci/travis-assets', build_ids: [3], last_build_id: 3, last_build_number: 3},
|
||||||
|
{ id: 3, owner: 'travis-ci', name: 'travis-hub', slug: 'travis-ci/travis-hub', build_ids: [4], last_build_id: 4, last_build_number: 4},
|
||||||
|
],
|
||||||
|
|
||||||
|
$.mockjax
|
||||||
|
url: '/travis-ci/travis-core',
|
||||||
|
responseTime: 0,
|
||||||
|
responseText:
|
||||||
|
repository: { 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 }
|
||||||
|
|
||||||
|
$.mockjax
|
||||||
|
url: '/travis-ci/travis-assets',
|
||||||
|
responseTime: 0,
|
||||||
|
responseText:
|
||||||
|
repository: { 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 }
|
||||||
|
|
||||||
|
$.mockjax
|
||||||
|
url: '/builds/1',
|
||||||
|
resposeTime: 0,
|
||||||
|
responseText:
|
||||||
|
build: { id: 1, repository_id: 'travis-ci/travis-core', commit_id: 1, job_ids: [1, 2], number: 1, event_type: 'push', config: { rvm: ['rbx', '1.9.3'] }, finished_at: '2012-06-20T00:21:20Z', duration: 35, result: 0 }
|
||||||
|
|
||||||
|
$.mockjax
|
||||||
|
url: '/builds/2',
|
||||||
|
resposeTime: 0,
|
||||||
|
responseText:
|
||||||
|
build: { id: 1, repository_id: 'travis-ci/travis-assets', commit_id: 1, job_ids: [1, 2], number: 1, event_type: 'push', config: { rvm: ['rbx'] }, finished_at: '2012-06-20T00:21:20Z', duration: 35, result: 0 }
|
||||||
|
|
||||||
@Travis = Em.Application.create()
|
@Travis = Em.Application.create()
|
||||||
|
|
||||||
require 'ext/jquery'
|
require 'ext/jquery'
|
||||||
require 'locales'
|
require 'locales'
|
||||||
require 'travis/data_store_adapter'
|
require 'travis/data_store/rest_adapter'
|
||||||
require 'helpers'
|
require 'helpers'
|
||||||
require 'models'
|
require 'models'
|
||||||
require 'views'
|
require 'views'
|
||||||
|
@ -13,14 +47,8 @@ require 'routes'
|
||||||
# Travis = window.Travis
|
# Travis = window.Travis
|
||||||
Travis.store = DS.Store.extend(
|
Travis.store = DS.Store.extend(
|
||||||
revision: 4
|
revision: 4
|
||||||
adapter: Travis.FixtureAdapter.create()
|
adapter: Travis.RestAdapter.create()
|
||||||
|
# adapter: Travis.FixtureAdapter.create()
|
||||||
).create()
|
).create()
|
||||||
|
|
||||||
# apparently fixtures behave weird unless preloaded :/ should move to mockjax for testing
|
|
||||||
Travis.Repository.find()
|
|
||||||
Travis.Build.find()
|
|
||||||
Travis.Commit.find()
|
|
||||||
Travis.Job.find()
|
|
||||||
Travis.Artifact.find()
|
|
||||||
|
|
||||||
Travis.initialize()
|
Travis.initialize()
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
window.Util = window.Util || {}
|
|
||||||
|
|
||||||
window.Util.counter = (function () {
|
|
||||||
var value = 0;
|
|
||||||
|
|
||||||
return {
|
|
||||||
getValue: function () {
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
increment: function (i) {
|
|
||||||
if (!i) i = 1;
|
|
||||||
return value += i;
|
|
||||||
},
|
|
||||||
decrement: function (i) {
|
|
||||||
if (!i) i = 1;
|
|
||||||
return value -= i;
|
|
||||||
},
|
|
||||||
reset: function (i) {
|
|
||||||
if (!i) i = 0;
|
|
||||||
return value = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}());
|
|
|
@ -28,30 +28,30 @@ require 'travis/model'
|
||||||
@getPath('data.job_ids.length') > 1
|
@getPath('data.job_ids.length') > 1
|
||||||
).property('data.job_ids.length')
|
).property('data.job_ids.length')
|
||||||
|
|
||||||
isFailureMatrix: (->
|
# isFailureMatrix: (->
|
||||||
@getPath('allowedFailureJobs.length') > 0
|
# @getPath('allowedFailureJobs.length') > 0
|
||||||
).property('allowedFailureJobs.length')
|
# ).property('allowedFailureJobs.length')
|
||||||
|
|
||||||
# TODO why does the hasMany association not work?
|
# # TODO why does the hasMany association not work?
|
||||||
jobs: (->
|
# jobs: (->
|
||||||
Travis.Job.findMany(@getPath('data.job_ids'))
|
# Travis.Job.findMany(@getPath('data.job_ids') || [])
|
||||||
).property('data.job_ids.length')
|
# ).property('data.job_ids.length')
|
||||||
|
|
||||||
requiredJobs: (->
|
# requiredJobs: (->
|
||||||
@get('jobs').filter (job) -> job.get('allow_failure') != true
|
# @get('jobs').filter (job) -> job.get('allow_failure') != true
|
||||||
).property('jobs')
|
# ).property('jobs')
|
||||||
|
|
||||||
allowedFailureJobs: (->
|
# allowedFailureJobs: (->
|
||||||
@get('jobs').filter (job) -> job.get 'allow_failure'
|
# @get('jobs').filter (job) -> job.get 'allow_failure'
|
||||||
).property('jobs')
|
# ).property('jobs')
|
||||||
|
|
||||||
configKeys: (->
|
# configKeys: (->
|
||||||
config = @get('config')
|
# config = @get('config')
|
||||||
return [] unless config
|
# return [] unless config
|
||||||
keys = $.keys($.only(config, 'rvm', 'gemfile', 'env', 'otp_release', 'php', 'node_js', 'perl', 'python', 'scala'))
|
# keys = $.keys($.only(config, 'rvm', 'gemfile', 'env', 'otp_release', 'php', 'node_js', 'perl', 'python', 'scala'))
|
||||||
headers = [I18n.t('build.job'), I18n.t('build.duration'), I18n.t('build.finished_at')]
|
# headers = [I18n.t('build.job'), I18n.t('build.duration'), I18n.t('build.finished_at')]
|
||||||
$.map(headers.concat(keys), (key) -> return $.camelize(key))
|
# $.map(headers.concat(keys), (key) -> return $.camelize(key))
|
||||||
).property('config')
|
# ).property('config')
|
||||||
|
|
||||||
tick: ->
|
tick: ->
|
||||||
@notifyPropertyChange 'duration'
|
@notifyPropertyChange 'duration'
|
||||||
|
|
|
@ -11,8 +11,6 @@ require 'travis/model'
|
||||||
|
|
||||||
primaryKey: 'slug'
|
primaryKey: 'slug'
|
||||||
|
|
||||||
lastBuild: DS.belongsTo('Travis.Build')
|
|
||||||
|
|
||||||
builds: (->
|
builds: (->
|
||||||
Travis.Build.byRepositoryId @get('id'), event_type: 'push'
|
Travis.Build.byRepositoryId @get('id'), event_type: 'push'
|
||||||
).property()
|
).property()
|
||||||
|
@ -22,13 +20,22 @@ require 'travis/model'
|
||||||
).property()
|
).property()
|
||||||
|
|
||||||
owner: (->
|
owner: (->
|
||||||
(@get('slug') || '').split('/')[0]
|
(@get('slug') || @_id).split('/')[0]
|
||||||
).property('owner', 'name'),
|
).property('owner', 'name'),
|
||||||
|
|
||||||
name: (->
|
name: (->
|
||||||
(@get('slug') || '').split('/')[1]
|
(@get('slug') || @_id).split('/')[1]
|
||||||
).property('owner', 'name'),
|
).property('owner', 'name'),
|
||||||
|
|
||||||
|
# TODO this is used in router#serializeObject for the last_build links in the
|
||||||
|
# repositories list. should be in some item controller i guess, but i'm not
|
||||||
|
# sure how to use one with #each
|
||||||
|
lastBuild: (->
|
||||||
|
owner: @get('owner')
|
||||||
|
name: @get('name')
|
||||||
|
id: @get('last_build_id')
|
||||||
|
).property('last_build_id')
|
||||||
|
|
||||||
last_build_duration: (->
|
last_build_duration: (->
|
||||||
duration = @getPath('data.last_build_duration')
|
duration = @getPath('data.last_build_duration')
|
||||||
duration = Travis.Helpers.durationFrom(@get('last_build_started_at'), @get('last_build_finished_at')) unless duration
|
duration = Travis.Helpers.durationFrom(@get('last_build_started_at'), @get('last_build_finished_at')) unless duration
|
||||||
|
@ -67,10 +74,7 @@ require 'travis/model'
|
||||||
@find().forEach (repository) ->
|
@find().forEach (repository) ->
|
||||||
repository.set 'selected', repository.get('id') is id
|
repository.set 'selected', repository.get('id') is id
|
||||||
|
|
||||||
@Travis.Repository.FIXTURES = [
|
buildURL: (slug) ->
|
||||||
{ 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 },
|
if slug then slug else 'repositories'
|
||||||
{ id: 2, owner: 'travis-ci', name: 'travis-assets', slug: 'travis-ci/travis-assets', build_ids: [3], last_build_id: 3, last_build_number: 3},
|
|
||||||
{ id: 3, owner: 'travis-ci', name: 'travis-hub', slug: 'travis-ci/travis-hub', build_ids: [4], last_build_id: 4, last_build_number: 4},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,83 +5,98 @@ require 'hax0rs'
|
||||||
location: 'hash'
|
location: 'hash'
|
||||||
|
|
||||||
root: Em.Route.extend
|
root: Em.Route.extend
|
||||||
viewCurrent: Ember.Route.transitionTo('current')
|
default: Em.Route.extend
|
||||||
viewBuilds: Ember.Route.transitionTo('builds')
|
|
||||||
viewBuild: Ember.Route.transitionTo('build')
|
|
||||||
viewJob: Ember.Route.transitionTo('job')
|
|
||||||
|
|
||||||
index: Em.Route.extend
|
|
||||||
route: '/'
|
route: '/'
|
||||||
|
|
||||||
|
viewCurrent: Ember.Route.transitionTo('current')
|
||||||
|
viewBuilds: Ember.Route.transitionTo('builds')
|
||||||
|
viewBuild: Ember.Route.transitionTo('build')
|
||||||
|
viewJob: Ember.Route.transitionTo('job')
|
||||||
|
|
||||||
connectOutlets: (router) ->
|
connectOutlets: (router) ->
|
||||||
repositories = Travis.Repository.find()
|
repositories = Travis.Repository.find()
|
||||||
router.connectLeft(repositories)
|
router.connectLeft(repositories)
|
||||||
onceLoaded repositories, =>
|
router.set('repositories', repositories)
|
||||||
repository = repositories.get('firstObject')
|
|
||||||
|
index: Em.Route.extend
|
||||||
|
route: '/'
|
||||||
|
|
||||||
|
connectOutlets: (router) ->
|
||||||
|
repositories = router.get('repositories')
|
||||||
|
onceLoaded repositories, =>
|
||||||
|
repository = repositories.get('firstObject')
|
||||||
|
router.connectRepository repository
|
||||||
|
router.connectTabs repository
|
||||||
|
router.connectCurrent repository.get('lastBuild')
|
||||||
|
|
||||||
|
current: Em.Route.extend
|
||||||
|
route: '/:owner/:name'
|
||||||
|
|
||||||
|
serialize: (router, repository) ->
|
||||||
|
router.serializeRepository(repository)
|
||||||
|
|
||||||
|
deserialize: (router, params) ->
|
||||||
|
router.deserializeRepository(params)
|
||||||
|
|
||||||
|
connectOutlets: (router, repository) ->
|
||||||
router.connectRepository repository
|
router.connectRepository repository
|
||||||
router.connectTabs repository
|
router.connectTabs repository
|
||||||
router.connectCurrent repository.get('lastBuild')
|
router.connectCurrent repository.get('lastBuild')
|
||||||
|
|
||||||
current: Em.Route.extend
|
builds: Em.Route.extend
|
||||||
route: '/:owner/:name'
|
route: '/:owner/:name/builds'
|
||||||
|
|
||||||
serialize: (router, repository) ->
|
serialize: (router, repository) ->
|
||||||
router.serializeRepository repository
|
router.serializeRepository repository
|
||||||
|
|
||||||
connectOutlets: (router, repository) ->
|
deserialize: (router, params) ->
|
||||||
repositories = Travis.Repository.find()
|
router.deserializeRepository(params)
|
||||||
router.connectLeft(repositories)
|
|
||||||
onceLoaded repository, =>
|
|
||||||
router.connectRepository repository
|
|
||||||
router.connectTabs repository
|
|
||||||
router.connectCurrent repository.get('lastBuild')
|
|
||||||
|
|
||||||
builds: Em.Route.extend
|
connectOutlets: (router, repository) ->
|
||||||
route: '/:owner/:name/builds'
|
|
||||||
|
|
||||||
serialize: (router, repository) ->
|
|
||||||
router.serializeRepository repository
|
|
||||||
|
|
||||||
connectOutlets: (router, repository) ->
|
|
||||||
repositories = Travis.Repository.find()
|
|
||||||
router.connectLeft(repositories)
|
|
||||||
onceLoaded repository, =>
|
|
||||||
router.connectRepository repository
|
router.connectRepository repository
|
||||||
router.connectTabs repository
|
router.connectTabs repository
|
||||||
router.connectBuilds repository.get('builds')
|
router.connectBuilds repository.get('builds')
|
||||||
|
|
||||||
build: Em.Route.extend
|
build: Em.Route.extend
|
||||||
route: '/:owner/:name/builds/:id'
|
route: '/:owner/:name/builds/:id'
|
||||||
|
|
||||||
serialize: (router, build) ->
|
serialize: (router, build) ->
|
||||||
router.serializeObject build
|
r = router.serializeObject build
|
||||||
|
console.log(r.owner, r.name, r.id)
|
||||||
|
r
|
||||||
|
|
||||||
connectOutlets: (router, build) ->
|
deserialize: (router, params) ->
|
||||||
repositories = Travis.Repository.find()
|
router.deserializeBuild(params)
|
||||||
repository = build.get('repository')
|
|
||||||
|
|
||||||
router.connectLeft(repositories)
|
connectOutlets: (router, build) ->
|
||||||
onceLoaded repository, =>
|
build = Travis.Build.find(build.id) unless build instanceof Travis.Build
|
||||||
router.connectRepository repository
|
onceLoaded build, =>
|
||||||
router.connectTabs repository, build
|
repository = build.get('repository')
|
||||||
router.connectBuild build
|
onceLoaded repository, =>
|
||||||
|
router.connectRepository repository
|
||||||
|
router.connectTabs repository, build
|
||||||
|
router.connectBuild build
|
||||||
|
|
||||||
job: Em.Route.extend
|
job: Em.Route.extend
|
||||||
route: '/:owner/:name/jobs/:id'
|
route: '/:owner/:name/jobs/:id'
|
||||||
|
|
||||||
serialize: (router, job) ->
|
serialize: (router, job) ->
|
||||||
router.serializeObject job
|
router.serializeObject job
|
||||||
|
|
||||||
connectOutlets: (router, job) ->
|
deserialize: (router, params) ->
|
||||||
repositories = Travis.Repository.find()
|
router.deserializeBuild(params)
|
||||||
repository = job.get('repository')
|
|
||||||
build = job.get('build')
|
|
||||||
|
|
||||||
router.connectLeft(repositories)
|
connectOutlets: (router, job) ->
|
||||||
onceLoaded repository, build, =>
|
# repositories = Travis.Repository.find()
|
||||||
router.connectRepository repository
|
# job = Travis.Job.find(job.id) unless job instanceof Travis.Job
|
||||||
router.connectTabs repository, build, job
|
# repository = job.get('repository')
|
||||||
router.connectJob job
|
# build = job.get('build')
|
||||||
|
|
||||||
|
# router.connectLeft(repositories)
|
||||||
|
# onceLoaded repository, build, =>
|
||||||
|
# router.connectRepository repository
|
||||||
|
# router.connectTabs repository, build, job
|
||||||
|
# router.connectJob job
|
||||||
|
|
||||||
|
|
||||||
connectLeft: (repositories) ->
|
connectLeft: (repositories) ->
|
||||||
|
@ -109,17 +124,30 @@ require 'hax0rs'
|
||||||
@get('repositoryController').connectOutlet outletName: 'tab', name: 'job', context: job
|
@get('repositoryController').connectOutlet outletName: 'tab', name: 'job', context: job
|
||||||
|
|
||||||
|
|
||||||
serializeRepository: (repository) ->
|
serializeRepository: (object) ->
|
||||||
if repository instanceof DS.Model
|
if object instanceof DS.Model
|
||||||
repository.getProperties 'owner', 'name'
|
slug = object.get('slug') || object._id # wat.
|
||||||
|
parts = slug.split('/')
|
||||||
|
{ owner: parts[0], name: parts[1] }
|
||||||
else
|
else
|
||||||
repository or {}
|
object || {}
|
||||||
|
|
||||||
serializeObject: (object) ->
|
serializeObject: (object) ->
|
||||||
if object instanceof DS.Model
|
if object instanceof DS.Model
|
||||||
repository = object.get('repository')
|
repository = object.get('repository')
|
||||||
params = @serializeRepository(repository)
|
params = @serializeRepository(repository)
|
||||||
|
object.get('id') || debugger
|
||||||
$.extend params,
|
$.extend params,
|
||||||
id: object.get('id')
|
id: object.get('id')
|
||||||
else
|
else
|
||||||
object or {}
|
object or {}
|
||||||
|
|
||||||
|
deserializeRepository: (params) ->
|
||||||
|
Travis.Repository.find("#{params.owner}/#{params.name}")
|
||||||
|
|
||||||
|
deserializeBuild: (params) ->
|
||||||
|
Travis.Build.find(params.id)
|
||||||
|
|
||||||
|
deserializeJob: (params) ->
|
||||||
|
Travis.Job.find(params.id)
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,48 @@
|
||||||
<div {{bindAttr class="classes"}}>
|
{{#if isLoaded}}
|
||||||
<dl class="summary clearfix">
|
<div {{bindAttr class="classes"}}>
|
||||||
<div class="left">
|
<dl class="summary clearfix">
|
||||||
<dt>{{t builds.name}}</dt>
|
<div class="left">
|
||||||
<dd class="number"><a {{bindAttr href="urlBuild"}}>{{number}}</a></dd>
|
<dt>{{t builds.name}}</dt>
|
||||||
<dt class="finished_at_label">{{t builds.finished_at}}</dt>
|
<dd class="number"><a {{bindAttr href="urlBuild"}}>{{number}}</a></dd>
|
||||||
<dd class="finished_at timeago" {{bindAttr title="finished_at"}}>{{formatTime finished_at}}</dd>
|
<dt class="finished_at_label">{{t builds.finished_at}}</dt>
|
||||||
<dt>{{t builds.duration}}</dt>
|
<dd class="finished_at timeago" {{bindAttr title="finished_at"}}>{{formatTime finished_at}}</dd>
|
||||||
<dd class="duration" {{bindAttr title="started_at"}}>{{formatDuration duration}}</dd>
|
<dt>{{t builds.duration}}</dt>
|
||||||
</div>
|
<dd class="duration" {{bindAttr title="started_at"}}>{{formatDuration duration}}</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<dt>{{t builds.commit}}</dt>
|
<dt>{{t builds.commit}}</dt>
|
||||||
<dd class="commit-hash"><a {{bindAttr href="urlGithubCommit"}}>{{formatCommit commit}}</a></dd>
|
<dd class="commit-hash"><a {{bindAttr href="urlGithubCommit"}}>{{formatCommit commit}}</a></dd>
|
||||||
{{#if commit.compare_url}}
|
{{#if commit.compare_url}}
|
||||||
<dt>{{t builds.compare}}</dt>
|
<dt>{{t builds.compare}}</dt>
|
||||||
<dd class="compare_view"><a {{bindAttr href="commit.compare_url"}}>{{pathFrom commit.compare_url}}</a></dd>
|
<dd class="compare_view"><a {{bindAttr href="commit.compare_url"}}>{{pathFrom commit.compare_url}}</a></dd>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if commit.author_name}}
|
{{#if commit.author_name}}
|
||||||
<dt>{{t builds.author}}</dt>
|
<dt>{{t builds.author}}</dt>
|
||||||
<dd class="author"><a {{bindAttr href="view.urlAuthor"}}>{{commit.author_name}}</a></dd>
|
<dd class="author"><a {{bindAttr href="view.urlAuthor"}}>{{commit.author_name}}</a></dd>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if commit.committer_name}}
|
{{#if commit.committer_name}}
|
||||||
<dt>{{t builds.committer}}</dt>
|
<dt>{{t builds.committer}}</dt>
|
||||||
<dd class="committer"><a {{bindAttr href="urlCommitter"}}>{{commit.committer_name}}</a></dd>
|
<dd class="committer"><a {{bindAttr href="urlCommitter"}}>{{commit.committer_name}}</a></dd>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<dt>{{t builds.message}}</dt>
|
<dt>{{t builds.message}}</dt>
|
||||||
<dd class="commit-message">{{{formatMessage commit.message}}}</dd>
|
<dd class="commit-message">{{{formatMessage commit.message}}}</dd>
|
||||||
|
|
||||||
{{#if isMatrix}}
|
{{#if isMatrix}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<dt>{{t builds.config}}</dt>
|
<dt>{{t builds.config}}</dt>
|
||||||
<dd class="config">{{formatConfig config}}</dd>
|
<dd class="config">{{formatConfig config}}</dd>
|
||||||
|
{{/if}}
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
{{#if isLoaded}}
|
||||||
|
{{#if isMatrix}}
|
||||||
|
{{view Travis.JobsView}}
|
||||||
|
{{else}}
|
||||||
|
{{view Travis.LogView}}
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</dl>
|
</div>
|
||||||
|
{{/if}}
|
||||||
{{#if isLoaded}}
|
|
||||||
{{#if isMatrix}}
|
|
||||||
{{view Travis.JobsView}}
|
|
||||||
{{else}}
|
|
||||||
{{view Travis.LogView}}
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
<ul>
|
{{#if content.lastObject.isLoaded}}
|
||||||
{{#each content}}
|
<ul>
|
||||||
<li>
|
{{#each content}}
|
||||||
<div class="wrapper">
|
<li>
|
||||||
<a {{action viewCurrent href=true}} class="slug">{{slug}}</a>
|
<div class="wrapper">
|
||||||
<a {{action viewBuild href=true context="lastBuild"}} class="build">#{{last_build_number}}</a>
|
<a {{action viewCurrent href=true}} class="slug">{{slug}}</a>
|
||||||
</div>
|
<a {{action viewBuild href=true context="lastBuild"}} class="build">#{{last_build_number}}</a>
|
||||||
<p class="summary">
|
</div>
|
||||||
<span class="duration_label">{{t repositories.duration}}:</span>
|
<p class="summary">
|
||||||
<abbr class="duration" {{bindAttr title="last_build_started_at"}}>{{formatDuration last_build_duration}}</abbr>,
|
<span class="duration_label">{{t repositories.duration}}:</span>
|
||||||
<span class="finished_at_label">{{t repositories.finished_at}}:</span>
|
<abbr class="duration" {{bindAttr title="last_build_started_at"}}>{{formatDuration last_build_duration}}</abbr>,
|
||||||
<abbr class="finished_at timeago" {{bindAttr title="last_build_finished_at"}}>{{formatTime last_build_finished_at}}</abbr>
|
<span class="finished_at_label">{{t repositories.finished_at}}:</span>
|
||||||
</p>
|
<abbr class="finished_at timeago" {{bindAttr title="last_build_finished_at"}}>{{formatTime last_build_finished_at}}</abbr>
|
||||||
{{#if description}}
|
</p>
|
||||||
<p class="description">{{description}}</p>
|
{{#if description}}
|
||||||
{{/if}}
|
<p class="description">{{description}}</p>
|
||||||
<span class="indicator"></span>
|
{{/if}}
|
||||||
</li>
|
<span class="indicator"></span>
|
||||||
{{/each}}
|
</li>
|
||||||
<ul>
|
{{/each}}
|
||||||
|
<ul>
|
||||||
|
{{/if}}
|
||||||
|
|
|
@ -12,7 +12,7 @@ window.onceLoaded = ->
|
||||||
callback = objects.pop()
|
callback = objects.pop()
|
||||||
|
|
||||||
# sadly Ember.Enumerable.compact does not remove undefined values
|
# sadly Ember.Enumerable.compact does not remove undefined values
|
||||||
objects = (if object then object else null for object in objects).compact()
|
objects = ((object || null) for object in objects).compact()
|
||||||
object = objects.shift()
|
object = objects.shift()
|
||||||
|
|
||||||
if object
|
if object
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
@Travis.FixtureAdapter = DS.Adapter.extend
|
||||||
|
find: (store, type, id) ->
|
||||||
|
fixtures = type.FIXTURES
|
||||||
|
Ember.assert "Unable to find fixtures for model type " + type.toString(), !!fixtures
|
||||||
|
return if fixtures.hasLoaded
|
||||||
|
setTimeout (->
|
||||||
|
store.loadMany type, fixtures
|
||||||
|
fixtures.hasLoaded = true
|
||||||
|
), 300
|
||||||
|
|
||||||
|
findMany: ->
|
||||||
|
@find.apply this, arguments
|
||||||
|
|
||||||
|
findAll: (store, type) ->
|
||||||
|
fixtures = type.FIXTURES
|
||||||
|
Ember.assert "Unable to find fixtures for model type " + type.toString(), !!fixtures
|
||||||
|
ids = fixtures.map (item, index, self) ->
|
||||||
|
item.id
|
||||||
|
store.loadMany type, ids, fixtures
|
||||||
|
|
||||||
|
findQuery: (store, type, params, array) ->
|
||||||
|
fixtures = type.FIXTURES
|
||||||
|
Ember.assert "Unable to find fixtures for model type " + type.toString(), !!fixtures
|
||||||
|
hashes = for fixture in fixtures
|
||||||
|
matches = for key, value of params
|
||||||
|
key == 'orderBy' || fixture[key] == value
|
||||||
|
if matches.reduce((a, b) -> a && b) then fixture else null
|
||||||
|
array.load(hashes.compact())
|
||||||
|
|
||||||
|
|
76
assets/javascripts/lib/travis/data_store/rest_adapter.coffee
Normal file
76
assets/javascripts/lib/travis/data_store/rest_adapter.coffee
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
@Travis.RestAdapter = DS.RESTAdapter.extend
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
# TODO should be able to specify these as strings
|
||||||
|
@set 'mappings',
|
||||||
|
builds: Travis.Build,
|
||||||
|
commits: Travis.Commit,
|
||||||
|
jobs: Travis.Job
|
||||||
|
service_hooks: Travis.ServiceHook
|
||||||
|
|
||||||
|
plurals:
|
||||||
|
repository: 'repositories',
|
||||||
|
branch: 'branches'
|
||||||
|
|
||||||
|
find: (store, type, id) ->
|
||||||
|
url = '/' + type.buildURL(id)
|
||||||
|
console.log "find: #{url} (#{id})"
|
||||||
|
|
||||||
|
@ajax url, 'GET',
|
||||||
|
success: (json) ->
|
||||||
|
root = type.singularName()
|
||||||
|
@sideload(store, type, json, root)
|
||||||
|
store.load(type, json[root])
|
||||||
|
accepts:
|
||||||
|
json: 'application/vnd.travis-ci.2+json'
|
||||||
|
|
||||||
|
findMany: (store, type, ids) ->
|
||||||
|
url = '/' + type.buildURL()
|
||||||
|
console.log "findMany: #{url} (#{ids})"
|
||||||
|
|
||||||
|
@ajax url, 'GET',
|
||||||
|
data:
|
||||||
|
ids: ids
|
||||||
|
success: (json) ->
|
||||||
|
root = type.pluralName()
|
||||||
|
@sideload(store, type, json, root)
|
||||||
|
store.loadMany(type, json[root])
|
||||||
|
accepts:
|
||||||
|
json: 'application/vnd.travis-ci.2+json'
|
||||||
|
|
||||||
|
findAll: (store, type) ->
|
||||||
|
url = '/' + type.buildURL()
|
||||||
|
console.log "findAll: #{url}"
|
||||||
|
|
||||||
|
@ajax url, 'GET',
|
||||||
|
success: (json) ->
|
||||||
|
root = type.pluralName()
|
||||||
|
@sideload(store, type, json, root)
|
||||||
|
store.loadMany(type, json[root])
|
||||||
|
accepts:
|
||||||
|
json: 'application/vnd.travis-ci.2+json'
|
||||||
|
|
||||||
|
findQuery: (store, type, query, recordArray) ->
|
||||||
|
url = '/' + type.buildURL(id)
|
||||||
|
console.log "findQuery: #{url} (#{query})"
|
||||||
|
|
||||||
|
@ajax url, 'GET',
|
||||||
|
data: query,
|
||||||
|
success: (json) ->
|
||||||
|
root = type.pluralName()
|
||||||
|
@sideload(store, type, json, root)
|
||||||
|
recordArray.load(json[root])
|
||||||
|
accepts:
|
||||||
|
json: 'application/vnd.travis-ci.2+json'
|
||||||
|
|
||||||
|
updateRecord: (store, type, record) ->
|
||||||
|
id = get(record, record.get('primaryKey') || 'id')
|
||||||
|
url = '/' + type.buildURL(id)
|
||||||
|
data = root: record.toJSON()
|
||||||
|
|
||||||
|
@ajax url, 'PUT',
|
||||||
|
data: data
|
||||||
|
success: (json) ->
|
||||||
|
root = type.singularName()
|
||||||
|
@sideload(store, type, json, root)
|
||||||
|
store.didUpdateRecord(record, json && json[root])
|
|
@ -1,127 +0,0 @@
|
||||||
@Travis.FixtureAdapter = DS.Adapter.extend
|
|
||||||
find: (store, type, id) ->
|
|
||||||
fixtures = type.FIXTURES
|
|
||||||
Ember.assert "Unable to find fixtures for model type " + type.toString(), !!fixtures
|
|
||||||
return if fixtures.hasLoaded
|
|
||||||
setTimeout (->
|
|
||||||
store.loadMany type, fixtures
|
|
||||||
fixtures.hasLoaded = true
|
|
||||||
), 300
|
|
||||||
|
|
||||||
findMany: ->
|
|
||||||
@find.apply this, arguments
|
|
||||||
|
|
||||||
findAll: (store, type) ->
|
|
||||||
fixtures = type.FIXTURES
|
|
||||||
Ember.assert "Unable to find fixtures for model type " + type.toString(), !!fixtures
|
|
||||||
ids = fixtures.map (item, index, self) ->
|
|
||||||
item.id
|
|
||||||
store.loadMany type, ids, fixtures
|
|
||||||
|
|
||||||
findQuery: (store, type, params, array) ->
|
|
||||||
fixtures = type.FIXTURES
|
|
||||||
Ember.assert "Unable to find fixtures for model type " + type.toString(), !!fixtures
|
|
||||||
hashes = for fixture in fixtures
|
|
||||||
matches = for key, value of params
|
|
||||||
key == 'orderBy' || fixture[key] == value
|
|
||||||
if matches.reduce((a, b) -> a && b) then fixture else null
|
|
||||||
array.load(hashes.compact())
|
|
||||||
|
|
||||||
@Travis.DataStoreAdapter = DS.RESTAdapter.extend
|
|
||||||
init: ->
|
|
||||||
@_super()
|
|
||||||
# TODO should be able to specify these as strings
|
|
||||||
@set 'mappings',
|
|
||||||
builds: Travis.Build,
|
|
||||||
commits: Travis.Commit,
|
|
||||||
jobs: Travis.Job
|
|
||||||
service_hooks: Travis.ServiceHook
|
|
||||||
|
|
||||||
plurals:
|
|
||||||
repository: 'repositories',
|
|
||||||
branch: 'branches'
|
|
||||||
|
|
||||||
updateRecord: (store, type, record) ->
|
|
||||||
id = get(record, record.get('primaryKey') || 'id')
|
|
||||||
root = @rootForType(type)
|
|
||||||
plural = @pluralize(root)
|
|
||||||
url = @buildURL(type.url || plural, id)
|
|
||||||
data = root: record.toJSON()
|
|
||||||
|
|
||||||
@ajax url, 'PUT',
|
|
||||||
data: data
|
|
||||||
success: (json) ->
|
|
||||||
@sideload(store, type, json, root)
|
|
||||||
store.didUpdateRecord(record, json && json[root])
|
|
||||||
|
|
||||||
find: (store, type, id) ->
|
|
||||||
root = @rootForType(type)
|
|
||||||
plural = @pluralize(root)
|
|
||||||
url = @buildURL(type.url || plural, id)
|
|
||||||
|
|
||||||
@ajax url, 'GET',
|
|
||||||
success: (json) ->
|
|
||||||
@sideload(store, type, json, root)
|
|
||||||
store.load(type, json[root])
|
|
||||||
accepts:
|
|
||||||
json: 'application/vnd.travis-ci.2+json'
|
|
||||||
|
|
||||||
findMany: (store, type, ids) ->
|
|
||||||
root = @rootForType(type)
|
|
||||||
plural = @pluralize(root)
|
|
||||||
url = @buildURL(type.url || plural)
|
|
||||||
|
|
||||||
@ajax url, 'GET',
|
|
||||||
data:
|
|
||||||
ids: ids
|
|
||||||
success: (json) ->
|
|
||||||
@sideload(store, type, json, plural)
|
|
||||||
store.loadMany(type, json[plural])
|
|
||||||
accepts:
|
|
||||||
json: 'application/vnd.travis-ci.2+json'
|
|
||||||
|
|
||||||
findAll: (store, type) ->
|
|
||||||
root = @rootForType(type)
|
|
||||||
plural = @pluralize(root)
|
|
||||||
url = @buildURL(type.url || plural)
|
|
||||||
|
|
||||||
@ajax url, 'GET',
|
|
||||||
success: (json) ->
|
|
||||||
@sideload(store, type, json, plural)
|
|
||||||
store.loadMany(type, json[plural])
|
|
||||||
accepts:
|
|
||||||
json: 'application/vnd.travis-ci.2+json'
|
|
||||||
|
|
||||||
findQuery: (store, type, query, recordArray) ->
|
|
||||||
root = @rootForType(type)
|
|
||||||
plural = @pluralize(root)
|
|
||||||
url = @buildURL(type.url || plural)
|
|
||||||
|
|
||||||
@ajax url, 'GET',
|
|
||||||
data: query,
|
|
||||||
success: (json) ->
|
|
||||||
@sideload(store, type, json, plural)
|
|
||||||
recordArray.load(json[plural])
|
|
||||||
accepts:
|
|
||||||
json: 'application/vnd.travis-ci.2+json'
|
|
||||||
|
|
||||||
rootForType: (type) ->
|
|
||||||
# sorry, but this seems very weird, really
|
|
||||||
# return type.url if (type.url)
|
|
||||||
|
|
||||||
parts = type.toString().split('.')
|
|
||||||
name = parts[parts.length - 1]
|
|
||||||
name.replace(/([A-Z])/g, '_$1').toLowerCase().slice(1)
|
|
||||||
|
|
||||||
buildURL: (record, suffix) ->
|
|
||||||
Ember.assert('Namespace URL (' + @namespace + ') must not start with slash', !@namespace || @namespace.toString().charAt(0) != '/')
|
|
||||||
Ember.assert('Record URL (' + record + ') must not start with slash', !record || record.toString().charAt(0) != '/')
|
|
||||||
Ember.assert('URL suffix (' + suffix + ') must not start with slash', !suffix || suffix.toString().charAt(0) != '/')
|
|
||||||
|
|
||||||
url = ['']
|
|
||||||
url.push(@namespace) if (@namespace != undefined)
|
|
||||||
url.push(record)
|
|
||||||
url.push(suffix) if (suffix != undefined)
|
|
||||||
url.join('/')
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
refresh: ->
|
refresh: ->
|
||||||
id = @get('id')
|
id = @get('id')
|
||||||
Travis.app.store.adapter.find(Travis.app.store, @constructor, id) if id
|
Travis.store.adapter.find(Travis.store, @constructor, id) if id
|
||||||
|
|
||||||
update: (attrs) ->
|
update: (attrs) ->
|
||||||
$.each attrs, (key, value) =>
|
$.each attrs, (key, value) =>
|
||||||
|
@ -13,5 +13,21 @@
|
||||||
|
|
||||||
@Travis.Model.reopenClass
|
@Travis.Model.reopenClass
|
||||||
load: (attrs) ->
|
load: (attrs) ->
|
||||||
Travis.app.store.load(this, attrs)
|
Travis.store.load(this, attrs)
|
||||||
|
|
||||||
|
buildURL: (suffix) ->
|
||||||
|
base = @url || @pluralName()
|
||||||
|
Ember.assert('Base URL (' + base + ') must not start with slash', !base || base.toString().charAt(0) != '/')
|
||||||
|
Ember.assert('URL suffix (' + suffix + ') must not start with slash', !suffix || suffix.toString().charAt(0) != '/')
|
||||||
|
url = [base]
|
||||||
|
url.push(suffix) if (suffix != undefined)
|
||||||
|
url.join('/')
|
||||||
|
|
||||||
|
singularName: ->
|
||||||
|
parts = @toString().split('.')
|
||||||
|
name = parts[parts.length - 1]
|
||||||
|
name.replace(/([A-Z])/g, '_$1').toLowerCase().slice(1)
|
||||||
|
|
||||||
|
pluralName: ->
|
||||||
|
Travis.store.adapter.pluralize(@singularName())
|
||||||
|
|
||||||
|
|
500
assets/javascripts/vendor/ember-data.js
vendored
500
assets/javascripts/vendor/ember-data.js
vendored
|
@ -102,7 +102,7 @@ DS.AdapterPopulatedRecordArray = DS.RecordArray.extend({
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor;
|
var get = Ember.get, set = Ember.set, getPath = Ember.getPath, guidFor = Ember.guidFor;
|
||||||
|
|
||||||
var Set = function() {
|
var Set = function() {
|
||||||
this.hash = {};
|
this.hash = {};
|
||||||
|
@ -138,7 +138,7 @@ Set.prototype = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var ManyArrayState = Ember.State.extend({
|
var LoadedState = Ember.State.extend({
|
||||||
recordWasAdded: function(manager, record) {
|
recordWasAdded: function(manager, record) {
|
||||||
var dirty = manager.dirty, observer;
|
var dirty = manager.dirty, observer;
|
||||||
dirty.add(record);
|
dirty.add(record);
|
||||||
|
@ -167,7 +167,21 @@ var ManyArrayState = Ember.State.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
var states = {
|
var states = {
|
||||||
clean: ManyArrayState.create({
|
loading: Ember.State.create({
|
||||||
|
isLoaded: false,
|
||||||
|
isDirty: false,
|
||||||
|
|
||||||
|
loadedRecords: function(manager, count) {
|
||||||
|
manager.decrement(count);
|
||||||
|
},
|
||||||
|
|
||||||
|
becameLoaded: function(manager) {
|
||||||
|
manager.transitionTo('clean');
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
clean: LoadedState.create({
|
||||||
|
isLoaded: true,
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
|
|
||||||
recordWasAdded: function(manager, record) {
|
recordWasAdded: function(manager, record) {
|
||||||
|
@ -181,7 +195,8 @@ var states = {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
dirty: ManyArrayState.create({
|
dirty: LoadedState.create({
|
||||||
|
isLoaded: true,
|
||||||
isDirty: true,
|
isDirty: true,
|
||||||
|
|
||||||
childWasSaved: function(manager, child) {
|
childWasSaved: function(manager, child) {
|
||||||
|
@ -199,12 +214,32 @@ var states = {
|
||||||
|
|
||||||
DS.ManyArrayStateManager = Ember.StateManager.extend({
|
DS.ManyArrayStateManager = Ember.StateManager.extend({
|
||||||
manyArray: null,
|
manyArray: null,
|
||||||
initialState: 'clean',
|
initialState: 'loading',
|
||||||
states: states,
|
states: states,
|
||||||
|
|
||||||
|
/**
|
||||||
|
This number is used to keep track of the number of outstanding
|
||||||
|
records that must be loaded before the array is considered
|
||||||
|
loaded. As results stream in, this number is decremented until
|
||||||
|
it becomes zero, at which case the `isLoaded` flag will be set
|
||||||
|
to true
|
||||||
|
*/
|
||||||
|
counter: 0,
|
||||||
|
|
||||||
init: function() {
|
init: function() {
|
||||||
this._super();
|
this._super();
|
||||||
this.dirty = new Set();
|
this.dirty = new Set();
|
||||||
|
this.counter = getPath(this, 'manyArray.length');
|
||||||
|
},
|
||||||
|
|
||||||
|
decrement: function(count) {
|
||||||
|
var counter = this.counter = this.counter - count;
|
||||||
|
|
||||||
|
Ember.assert("Somehow the ManyArray loaded counter went below 0. This is probably an ember-data bug. Please report it at https://github.com/emberjs/data/issues", counter >= 0);
|
||||||
|
|
||||||
|
if (counter === 0) {
|
||||||
|
this.send('becameLoaded');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -213,7 +248,7 @@ DS.ManyArrayStateManager = Ember.StateManager.extend({
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
|
var get = Ember.get, set = Ember.set, getPath = Ember.getPath, setPath = Ember.setPath;
|
||||||
|
|
||||||
DS.ManyArray = DS.RecordArray.extend({
|
DS.ManyArray = DS.RecordArray.extend({
|
||||||
init: function() {
|
init: function() {
|
||||||
|
@ -228,20 +263,24 @@ DS.ManyArray = DS.RecordArray.extend({
|
||||||
return getPath(this, 'stateManager.currentState.isDirty');
|
return getPath(this, 'stateManager.currentState.isDirty');
|
||||||
}).property('stateManager.currentState').cacheable(),
|
}).property('stateManager.currentState').cacheable(),
|
||||||
|
|
||||||
|
isLoaded: Ember.computed(function() {
|
||||||
|
return getPath(this, 'stateManager.currentState.isLoaded');
|
||||||
|
}).property('stateManager.currentState').cacheable(),
|
||||||
|
|
||||||
|
send: function(event, context) {
|
||||||
|
this.get('stateManager').send(event, context);
|
||||||
|
},
|
||||||
|
|
||||||
fetch: function() {
|
fetch: function() {
|
||||||
var clientIds = get(this, 'content'),
|
var clientIds = get(this, 'content'),
|
||||||
store = get(this, 'store'),
|
store = get(this, 'store'),
|
||||||
type = get(this, 'type');
|
type = get(this, 'type');
|
||||||
|
|
||||||
var ids = clientIds.map(function(clientId) {
|
store.fetchUnloadedClientIds(type, clientIds);
|
||||||
return store.clientIdToId[clientId];
|
|
||||||
});
|
|
||||||
|
|
||||||
store.fetchMany(type, ids);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Overrides Ember.Array's replace method to implement
|
// Overrides Ember.Array's replace method to implement
|
||||||
replace: function(index, removed, added) {
|
replaceContent: function(index, removed, added) {
|
||||||
var parentRecord = get(this, 'parentRecord');
|
var parentRecord = get(this, 'parentRecord');
|
||||||
var pendingParent = parentRecord && !get(parentRecord, 'id');
|
var pendingParent = parentRecord && !get(parentRecord, 'id');
|
||||||
var stateManager = get(this, 'stateManager');
|
var stateManager = get(this, 'stateManager');
|
||||||
|
@ -258,7 +297,10 @@ DS.ManyArray = DS.RecordArray.extend({
|
||||||
record.send('waitingOn', parentRecord);
|
record.send('waitingOn', parentRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.assignInverse(record, parentRecord);
|
var oldParent = this.assignInverse(record, parentRecord);
|
||||||
|
|
||||||
|
record.get('transaction')
|
||||||
|
.relationshipBecameDirty(record, oldParent, parentRecord);
|
||||||
|
|
||||||
stateManager.send('recordWasAdded', record);
|
stateManager.send('recordWasAdded', record);
|
||||||
|
|
||||||
|
@ -271,7 +313,10 @@ DS.ManyArray = DS.RecordArray.extend({
|
||||||
for (var i = index; i < len; i++) {
|
for (var i = index; i < len; i++) {
|
||||||
// TODO: null out inverse FK
|
// TODO: null out inverse FK
|
||||||
record = this.objectAt(i);
|
record = this.objectAt(i);
|
||||||
this.assignInverse(record, parentRecord, true);
|
var oldParent = this.assignInverse(record, parentRecord, true);
|
||||||
|
|
||||||
|
record.get('transaction')
|
||||||
|
.relationshipBecameDirty(record, parentRecord, null);
|
||||||
|
|
||||||
// If we put the child record into a pending state because
|
// If we put the child record into a pending state because
|
||||||
// we were waiting on the parent record to get an id, we
|
// we were waiting on the parent record to get an id, we
|
||||||
|
@ -289,7 +334,7 @@ DS.ManyArray = DS.RecordArray.extend({
|
||||||
assignInverse: function(record, parentRecord, remove) {
|
assignInverse: function(record, parentRecord, remove) {
|
||||||
var associationMap = get(record.constructor, 'associations'),
|
var associationMap = get(record.constructor, 'associations'),
|
||||||
possibleAssociations = associationMap.get(parentRecord.constructor),
|
possibleAssociations = associationMap.get(parentRecord.constructor),
|
||||||
possible, actual;
|
possible, actual, oldParent;
|
||||||
|
|
||||||
if (!possibleAssociations) { return; }
|
if (!possibleAssociations) { return; }
|
||||||
|
|
||||||
|
@ -303,7 +348,9 @@ DS.ManyArray = DS.RecordArray.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actual) {
|
if (actual) {
|
||||||
|
oldParent = get(record, actual.name);
|
||||||
set(record, actual.name, remove ? null : parentRecord);
|
set(record, actual.name, remove ? null : parentRecord);
|
||||||
|
return oldParent;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -334,7 +381,8 @@ DS.ManyArray = DS.RecordArray.extend({
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var get = Ember.get, set = Ember.set, getPath = Ember.getPath, fmt = Ember.String.fmt;
|
var get = Ember.get, set = Ember.set, getPath = Ember.getPath, fmt = Ember.String.fmt,
|
||||||
|
removeObject = Ember.EnumerableUtils.removeObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A transaction allows you to collect multiple records into a unit of work
|
A transaction allows you to collect multiple records into a unit of work
|
||||||
|
@ -429,6 +477,12 @@ DS.Transaction = Ember.Object.extend({
|
||||||
deleted: Ember.Map.create(),
|
deleted: Ember.Map.create(),
|
||||||
inflight: Ember.Map.create()
|
inflight: Ember.Map.create()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.dirtyRelationships = {
|
||||||
|
byChild: Ember.Map.create(),
|
||||||
|
byNewParent: Ember.Map.create(),
|
||||||
|
byOldParent: Ember.Map.create()
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -668,6 +722,113 @@ DS.Transaction = Ember.Object.extend({
|
||||||
records.remove(record);
|
records.remove(record);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
@private
|
||||||
|
|
||||||
|
Called by a ManyArray when a new record is added to it. This
|
||||||
|
method will index a relationship description by the child
|
||||||
|
record, its old parent, and its new parent.
|
||||||
|
|
||||||
|
The store will provide this description to the adapter's
|
||||||
|
shouldCommit method, so it can determine whether any of
|
||||||
|
the records is pending another record. The store will also
|
||||||
|
provide a list of these descriptions to the adapter's commit
|
||||||
|
method.
|
||||||
|
|
||||||
|
@param {DS.Model} record the new child record
|
||||||
|
@param {DS.Model} oldParent the parent that the child is
|
||||||
|
moving from, or null
|
||||||
|
@param {DS.Model} newParent the parent that the child is
|
||||||
|
moving to, or null
|
||||||
|
*/
|
||||||
|
relationshipBecameDirty: function(child, oldParent, newParent) {
|
||||||
|
var relationships = this.dirtyRelationships, relationship;
|
||||||
|
|
||||||
|
var relationshipsForChild = relationships.byChild.get(child),
|
||||||
|
possibleRelationship,
|
||||||
|
needsNewEntries = true;
|
||||||
|
|
||||||
|
// If the child has any existing dirty relationships in this
|
||||||
|
// transaction, we need to collapse the old relationship
|
||||||
|
// into the new one. For example, if we change the parent of
|
||||||
|
// a child record before saving, there is no need to save the
|
||||||
|
// record that was its parent temporarily.
|
||||||
|
if (relationshipsForChild) {
|
||||||
|
|
||||||
|
// Loop through all of the relationships we know about that
|
||||||
|
// contain the same child as the new relationship.
|
||||||
|
for (var i=0, l=relationshipsForChild.length; i<l; i++) {
|
||||||
|
relationship = relationshipsForChild[i];
|
||||||
|
|
||||||
|
// If the parent of the child record has changed, there is
|
||||||
|
// no need to update the old parent that had not yet been saved.
|
||||||
|
//
|
||||||
|
// This case is two changes in a record's parent:
|
||||||
|
//
|
||||||
|
// A -> B
|
||||||
|
// B -> C
|
||||||
|
//
|
||||||
|
// In this case, there is no need to remember the A->B
|
||||||
|
// change. We can collapse both changes into:
|
||||||
|
//
|
||||||
|
// A -> C
|
||||||
|
//
|
||||||
|
// Another possible case is:
|
||||||
|
//
|
||||||
|
// A -> B
|
||||||
|
// B -> A
|
||||||
|
//
|
||||||
|
// In this case, we don't need to do anything. We can
|
||||||
|
// simply remove the original A->B change and call it
|
||||||
|
// a day.
|
||||||
|
if (relationship.newParent === oldParent) {
|
||||||
|
oldParent = relationship.oldParent;
|
||||||
|
this.removeRelationship(relationship);
|
||||||
|
|
||||||
|
// This is the case of A->B followed by B->A.
|
||||||
|
if (relationship.oldParent === newParent) {
|
||||||
|
needsNewEntries = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relationship = {
|
||||||
|
child: child,
|
||||||
|
oldParent: oldParent,
|
||||||
|
newParent: newParent
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we didn't go A->B and then B->A, add new dirty relationship
|
||||||
|
// entries.
|
||||||
|
if (needsNewEntries) {
|
||||||
|
this.addRelationshipTo('byChild', child, relationship);
|
||||||
|
this.addRelationshipTo('byOldParent', oldParent, relationship);
|
||||||
|
this.addRelationshipTo('byNewParent', newParent, relationship);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeRelationship: function(relationship) {
|
||||||
|
var relationships = this.dirtyRelationships;
|
||||||
|
|
||||||
|
removeObject(relationships.byOldParent.get(relationship.oldParent), relationship);
|
||||||
|
removeObject(relationships.byNewParent.get(relationship.newParent), relationship);
|
||||||
|
removeObject(relationships.byChild.get(relationship.child), relationship);
|
||||||
|
},
|
||||||
|
|
||||||
|
addRelationshipTo: function(type, record, description) {
|
||||||
|
var map = this.dirtyRelationships[type];
|
||||||
|
|
||||||
|
var relationships = map.get(record);
|
||||||
|
|
||||||
|
if (!relationships) {
|
||||||
|
relationships = [ description ];
|
||||||
|
map.set(record, relationships);
|
||||||
|
} else {
|
||||||
|
relationships.push(description);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@private
|
@private
|
||||||
|
|
||||||
|
@ -796,6 +957,13 @@ DS.Store = Ember.Object.extend({
|
||||||
this.clientIdToId = {};
|
this.clientIdToId = {};
|
||||||
this.recordArraysByClientId = {};
|
this.recordArraysByClientId = {};
|
||||||
|
|
||||||
|
// Internally, we maintain a map of all unloaded IDs requested by
|
||||||
|
// a ManyArray. As the adapter loads hashes into the store, the
|
||||||
|
// store notifies any interested ManyArrays. When the ManyArray's
|
||||||
|
// total number of loading records drops to zero, it becomes
|
||||||
|
// `isLoaded` and fires a `didLoad` event.
|
||||||
|
this.loadingRecordArrays = {};
|
||||||
|
|
||||||
set(this, 'defaultTransaction', this.transaction());
|
set(this, 'defaultTransaction', this.transaction());
|
||||||
|
|
||||||
return this._super();
|
return this._super();
|
||||||
|
@ -1060,78 +1228,121 @@ DS.Store = Ember.Object.extend({
|
||||||
/**
|
/**
|
||||||
@private
|
@private
|
||||||
|
|
||||||
Ask the adapter to fetch IDs that are not already loaded.
|
Given a type and array of `clientId`s, determines which of those
|
||||||
|
`clientId`s has not yet been loaded.
|
||||||
|
|
||||||
This method will convert `id`s to `clientId`s, filter out
|
In preparation for loading, this method also marks any unloaded
|
||||||
`clientId`s that already have a data hash present, and pass
|
`clientId`s as loading.
|
||||||
the remaining `id`s to the adapter.
|
|
||||||
|
|
||||||
@param {Class} type A model class
|
|
||||||
@param {Array} ids An array of ids
|
|
||||||
@param {Object} query
|
|
||||||
|
|
||||||
@returns {Array} An Array of all clientIds for the
|
|
||||||
specified ids.
|
|
||||||
*/
|
*/
|
||||||
fetchMany: function(type, ids, query) {
|
neededClientIds: function(type, clientIds) {
|
||||||
var typeMap = this.typeMapFor(type),
|
var neededClientIds = [],
|
||||||
idToClientIdMap = typeMap.idToCid,
|
typeMap = this.typeMapFor(type),
|
||||||
dataCache = typeMap.cidToHash,
|
dataCache = typeMap.cidToHash,
|
||||||
data = typeMap.cidToHash,
|
clientId;
|
||||||
needed;
|
|
||||||
|
|
||||||
var clientIds = Ember.A([]);
|
for (var i=0, l=clientIds.length; i<l; i++) {
|
||||||
|
clientId = clientIds[i];
|
||||||
if (ids) {
|
if (dataCache[clientId] === UNLOADED) {
|
||||||
needed = [];
|
neededClientIds.push(clientId);
|
||||||
|
dataCache[clientId] = LOADING;
|
||||||
ids.forEach(function(id) {
|
}
|
||||||
// Get the clientId for the given id
|
|
||||||
var clientId = idToClientIdMap[id];
|
|
||||||
|
|
||||||
// If there is no `clientId` yet
|
|
||||||
if (clientId === undefined) {
|
|
||||||
// Create a new `clientId`, marking its data hash
|
|
||||||
// as loading. Once the adapter returns the data
|
|
||||||
// hash, it will be updated
|
|
||||||
clientId = this.pushHash(LOADING, id, type);
|
|
||||||
needed.push(id);
|
|
||||||
|
|
||||||
// If there is a clientId, but its data hash is
|
|
||||||
// marked as unloaded (this happens when a
|
|
||||||
// hasMany association creates clientIds for its
|
|
||||||
// referenced ids before they were loaded)
|
|
||||||
} else if (clientId && data[clientId] === UNLOADED) {
|
|
||||||
// change the data hash marker to loading
|
|
||||||
dataCache[clientId] = LOADING;
|
|
||||||
needed.push(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this method is expected to return a list of
|
|
||||||
// all of the clientIds for the specified ids,
|
|
||||||
// unconditionally add it.
|
|
||||||
clientIds.push(clientId);
|
|
||||||
}, this);
|
|
||||||
} else {
|
|
||||||
needed = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are any needed ids, ask the adapter to load them
|
return neededClientIds;
|
||||||
if ((needed && get(needed, 'length') > 0) || query) {
|
|
||||||
var adapter = get(this, '_adapter');
|
|
||||||
if (adapter && adapter.findMany) { adapter.findMany(this, type, needed, query); }
|
|
||||||
else { throw fmt("Adapter is either null or does not implement `findMany` method", this); }
|
|
||||||
}
|
|
||||||
|
|
||||||
return clientIds;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @private
|
/**
|
||||||
*/
|
@private
|
||||||
findMany: function(type, ids, query) {
|
|
||||||
var clientIds = this.fetchMany(type, ids, query);
|
|
||||||
|
|
||||||
return this.createManyArray(type, clientIds);
|
This method is the entry point that associations use to update
|
||||||
|
themselves when their underlying data changes.
|
||||||
|
|
||||||
|
First, it determines which of its `clientId`s are still unloaded,
|
||||||
|
then converts the needed `clientId`s to IDs and invokes `findMany`
|
||||||
|
on the adapter.
|
||||||
|
*/
|
||||||
|
fetchUnloadedClientIds: function(type, clientIds) {
|
||||||
|
var neededClientIds = this.neededClientIds(type, clientIds);
|
||||||
|
this.fetchMany(type, neededClientIds);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
@private
|
||||||
|
|
||||||
|
This method takes a type and list of `clientId`s, converts the
|
||||||
|
`clientId`s into IDs, and then invokes the adapter's `findMany`
|
||||||
|
method.
|
||||||
|
|
||||||
|
It is used both by a brand new association (via the `findMany`
|
||||||
|
method) or when the data underlying an existing association
|
||||||
|
changes (via the `fetchUnloadedClientIds` method).
|
||||||
|
*/
|
||||||
|
fetchMany: function(type, clientIds) {
|
||||||
|
var clientIdToId = this.clientIdToId;
|
||||||
|
|
||||||
|
var neededIds = Ember.EnumerableUtils.map(clientIds, function(clientId) {
|
||||||
|
return clientIdToId[clientId];
|
||||||
|
});
|
||||||
|
|
||||||
|
var adapter = get(this, '_adapter');
|
||||||
|
if (adapter && adapter.findMany) { adapter.findMany(this, type, neededIds); }
|
||||||
|
else { throw fmt("Adapter is either null or does not implement `findMany` method", this); }
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
@private
|
||||||
|
|
||||||
|
`findMany` is the entry point that associations use to generate a
|
||||||
|
new `ManyArray` for the list of IDs specified by the server for
|
||||||
|
the association.
|
||||||
|
|
||||||
|
Its responsibilities are:
|
||||||
|
|
||||||
|
* convert the IDs into clientIds
|
||||||
|
* determine which of the clientIds still need to be loaded
|
||||||
|
* create a new ManyArray whose content is *all* of the clientIds
|
||||||
|
* notify the ManyArray of the number of its elements that are
|
||||||
|
already loaded
|
||||||
|
* insert the unloaded clientIds into the `loadingRecordArrays`
|
||||||
|
bookkeeping structure, which will allow the `ManyArray` to know
|
||||||
|
when all of its loading elements are loaded from the server.
|
||||||
|
* ask the adapter to load the unloaded elements, by invoking
|
||||||
|
findMany with the still-unloaded IDs.
|
||||||
|
*/
|
||||||
|
findMany: function(type, ids) {
|
||||||
|
// 1. Convert ids to client ids
|
||||||
|
// 2. Determine which of the client ids need to be loaded
|
||||||
|
// 3. Create a new ManyArray whose content is ALL of the clientIds
|
||||||
|
// 4. Decrement the ManyArray's counter by the number of loaded clientIds
|
||||||
|
// 5. Put the ManyArray into our bookkeeping data structure, keyed on
|
||||||
|
// the needed clientIds
|
||||||
|
// 6. Ask the adapter to load the records for the unloaded clientIds (but
|
||||||
|
// convert them back to ids)
|
||||||
|
|
||||||
|
var clientIds = this.clientIdsForIds(type, ids);
|
||||||
|
|
||||||
|
var neededClientIds = this.neededClientIds(type, clientIds),
|
||||||
|
manyArray = this.createManyArray(type, Ember.A(clientIds)),
|
||||||
|
loadedCount = clientIds.length - neededClientIds.length,
|
||||||
|
loadingRecordArrays = this.loadingRecordArrays,
|
||||||
|
clientId, i, l;
|
||||||
|
|
||||||
|
manyArray.send('loadedRecords', loadedCount);
|
||||||
|
|
||||||
|
if (neededClientIds.length) {
|
||||||
|
for (i=0, l=neededClientIds.length; i<l; i++) {
|
||||||
|
clientId = neededClientIds[i];
|
||||||
|
if (loadingRecordArrays[clientId]) {
|
||||||
|
loadingRecordArrays[clientId].push(manyArray);
|
||||||
|
} else {
|
||||||
|
this.loadingRecordArrays[clientId] = [ manyArray ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fetchMany(type, neededClientIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return manyArray;
|
||||||
},
|
},
|
||||||
|
|
||||||
findQuery: function(type, query) {
|
findQuery: function(type, query) {
|
||||||
|
@ -1368,6 +1579,18 @@ DS.Store = Ember.Object.extend({
|
||||||
filter = get(array, 'filterFunction');
|
filter = get(array, 'filterFunction');
|
||||||
this.updateRecordArray(array, filter, type, clientId, dataProxy);
|
this.updateRecordArray(array, filter, type, clientId, dataProxy);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
// loop through all manyArrays containing an unloaded copy of this
|
||||||
|
// clientId and notify them that the record was loaded.
|
||||||
|
var manyArrays = this.loadingRecordArrays[clientId], manyArray;
|
||||||
|
|
||||||
|
if (manyArrays) {
|
||||||
|
for (var i=0, l=manyArrays.length; i<l; i++) {
|
||||||
|
manyArrays[i].send('loadedRecords', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingRecordArrays[clientId] = null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
updateRecordArray: function(array, filter, type, clientId, dataProxy) {
|
updateRecordArray: function(array, filter, type, clientId, dataProxy) {
|
||||||
|
@ -1453,6 +1676,24 @@ DS.Store = Ember.Object.extend({
|
||||||
return this.pushHash(UNLOADED, id, type);
|
return this.pushHash(UNLOADED, id, type);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
@private
|
||||||
|
|
||||||
|
This method works exactly like `clientIdForId`, but does not
|
||||||
|
require looking up the `typeMap` for every `clientId` and
|
||||||
|
invoking a method per `clientId`.
|
||||||
|
*/
|
||||||
|
clientIdsForIds: function(type, ids) {
|
||||||
|
var typeMap = this.typeMapFor(type),
|
||||||
|
idToClientIdMap = typeMap.idToCid;
|
||||||
|
|
||||||
|
return Ember.EnumerableUtils.map(ids, function(id) {
|
||||||
|
var clientId = idToClientIdMap[id];
|
||||||
|
if (clientId) { return clientId; }
|
||||||
|
return this.pushHash(UNLOADED, id, type);
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
// ................
|
// ................
|
||||||
// . LOADING DATA .
|
// . LOADING DATA .
|
||||||
// ................
|
// ................
|
||||||
|
@ -1869,7 +2110,7 @@ var waitingOn = function(manager, object) {
|
||||||
// super points to the class definition.
|
// super points to the class definition.
|
||||||
var Uncommitted = Ember.Mixin.create({
|
var Uncommitted = Ember.Mixin.create({
|
||||||
setProperty: setProperty,
|
setProperty: setProperty,
|
||||||
setAssociation: setAssociation,
|
setAssociation: setAssociation
|
||||||
});
|
});
|
||||||
|
|
||||||
// These mixins are mixed into substates of the concrete
|
// These mixins are mixed into substates of the concrete
|
||||||
|
@ -2883,12 +3124,18 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
||||||
cachedValue = this.cacheFor(name);
|
cachedValue = this.cacheFor(name);
|
||||||
|
|
||||||
if (cachedValue) {
|
if (cachedValue) {
|
||||||
var key = association.options.key || name,
|
var key = association.options.key || get(this, 'namingConvention').keyToJSONKey(name),
|
||||||
ids = data.get(key) || [];
|
ids = data.get(key) || [];
|
||||||
var clientIds = Ember.EnumerableUtils.map(ids, function(id) {
|
|
||||||
return store.clientIdForId(association.type, id);
|
var clientIds;
|
||||||
});
|
if(association.options.embedded) {
|
||||||
|
clientIds = store.loadMany(association.type, ids).clientIds;
|
||||||
|
} else {
|
||||||
|
clientIds = Ember.EnumerableUtils.map(ids, function(id) {
|
||||||
|
return store.clientIdForId(association.type, id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
set(cachedValue, 'content', Ember.A(clientIds));
|
set(cachedValue, 'content', Ember.A(clientIds));
|
||||||
cachedValue.fetch();
|
cachedValue.fetch();
|
||||||
}
|
}
|
||||||
|
@ -3132,7 +3379,7 @@ var hasAssociation = function(type, options, one) {
|
||||||
|
|
||||||
if (arguments.length === 2) {
|
if (arguments.length === 2) {
|
||||||
key = options.key || get(this, 'namingConvention').foreignKey(key);
|
key = options.key || get(this, 'namingConvention').foreignKey(key);
|
||||||
this.send('setAssociation', { key: key, value: value === null ? null : get(value, 'clientId') });
|
this.send('setAssociation', { key: key, value: Ember.none(value) ? null : get(value, 'clientId') });
|
||||||
//data.setAssociation(key, get(value, 'clientId'));
|
//data.setAssociation(key, get(value, 'clientId'));
|
||||||
// put the client id in `key` in the data hash
|
// put the client id in `key` in the data hash
|
||||||
return value;
|
return value;
|
||||||
|
@ -3194,7 +3441,7 @@ var hasAssociation = function(type, options) {
|
||||||
|
|
||||||
key = options.key || get(this, 'namingConvention').keyToJSONKey(key);
|
key = options.key || get(this, 'namingConvention').keyToJSONKey(key);
|
||||||
ids = findRecord(store, type, data, key);
|
ids = findRecord(store, type, data, key);
|
||||||
association = store.findMany(type, ids);
|
association = store.findMany(type, ids || []);
|
||||||
set(association, 'parentRecord', this);
|
set(association, 'parentRecord', this);
|
||||||
|
|
||||||
return association;
|
return association;
|
||||||
|
@ -3420,6 +3667,20 @@ Ember.onLoad('application', function(app) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.registerInjection({
|
||||||
|
name: "giveStoreToControllers",
|
||||||
|
|
||||||
|
injection: function(app, stateManager, property) {
|
||||||
|
if (property.match(/Controller$/)) {
|
||||||
|
var controllerName = property.charAt(0).toLowerCase() + property.substr(1);
|
||||||
|
var store = stateManager.get('store');
|
||||||
|
var controller = stateManager.get(controllerName);
|
||||||
|
|
||||||
|
controller.set('store', store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -3466,7 +3727,7 @@ var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
|
||||||
|
|
||||||
DS.RESTAdapter = DS.Adapter.extend({
|
DS.RESTAdapter = DS.Adapter.extend({
|
||||||
bulkCommit: false,
|
bulkCommit: false,
|
||||||
|
|
||||||
createRecord: function(store, type, record) {
|
createRecord: function(store, type, record) {
|
||||||
var root = this.rootForType(type);
|
var root = this.rootForType(type);
|
||||||
|
|
||||||
|
@ -3475,13 +3736,20 @@ DS.RESTAdapter = DS.Adapter.extend({
|
||||||
|
|
||||||
this.ajax(this.buildURL(root), "POST", {
|
this.ajax(this.buildURL(root), "POST", {
|
||||||
data: data,
|
data: data,
|
||||||
|
context: this,
|
||||||
success: function(json) {
|
success: function(json) {
|
||||||
this.sideload(store, type, json, root);
|
this.didCreateRecord(store, type, record, json);
|
||||||
store.didCreateRecord(record, json[root]);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didCreateRecord: function(store, type, record, json) {
|
||||||
|
var root = this.rootForType(type);
|
||||||
|
|
||||||
|
this.sideload(store, type, json, root);
|
||||||
|
store.didCreateRecord(record, json[root]);
|
||||||
|
},
|
||||||
|
|
||||||
createRecords: function(store, type, records) {
|
createRecords: function(store, type, records) {
|
||||||
if (get(this, 'bulkCommit') === false) {
|
if (get(this, 'bulkCommit') === false) {
|
||||||
return this._super(store, type, records);
|
return this._super(store, type, records);
|
||||||
|
@ -3497,14 +3765,20 @@ DS.RESTAdapter = DS.Adapter.extend({
|
||||||
|
|
||||||
this.ajax(this.buildURL(root), "POST", {
|
this.ajax(this.buildURL(root), "POST", {
|
||||||
data: data,
|
data: data,
|
||||||
|
context: this,
|
||||||
success: function(json) {
|
success: function(json) {
|
||||||
this.sideload(store, type, json, plural);
|
this.didCreateRecords(store, type, records, json);
|
||||||
store.didCreateRecords(type, records, json[plural]);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didCreateRecords: function(store, type, records, json) {
|
||||||
|
var root = this.pluralize(this.rootForType(type));
|
||||||
|
|
||||||
|
this.sideload(store, type, json, root);
|
||||||
|
store.didCreateRecords(type, records, json[root]);
|
||||||
|
},
|
||||||
|
|
||||||
updateRecord: function(store, type, record) {
|
updateRecord: function(store, type, record) {
|
||||||
var id = get(record, 'id');
|
var id = get(record, 'id');
|
||||||
var root = this.rootForType(type);
|
var root = this.rootForType(type);
|
||||||
|
@ -3514,13 +3788,20 @@ DS.RESTAdapter = DS.Adapter.extend({
|
||||||
|
|
||||||
this.ajax(this.buildURL(root, id), "PUT", {
|
this.ajax(this.buildURL(root, id), "PUT", {
|
||||||
data: data,
|
data: data,
|
||||||
|
context: this,
|
||||||
success: function(json) {
|
success: function(json) {
|
||||||
this.sideload(store, type, json, root);
|
this.didUpdateRecord(store, type, record, json);
|
||||||
store.didUpdateRecord(record, json && json[root]);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didUpdateRecord: function(store, type, record, json) {
|
||||||
|
var root = this.rootForType(type);
|
||||||
|
|
||||||
|
this.sideload(store, type, json, root);
|
||||||
|
store.didUpdateRecord(record, json && json[root]);
|
||||||
|
},
|
||||||
|
|
||||||
updateRecords: function(store, type, records) {
|
updateRecords: function(store, type, records) {
|
||||||
if (get(this, 'bulkCommit') === false) {
|
if (get(this, 'bulkCommit') === false) {
|
||||||
return this._super(store, type, records);
|
return this._super(store, type, records);
|
||||||
|
@ -3536,25 +3817,37 @@ DS.RESTAdapter = DS.Adapter.extend({
|
||||||
|
|
||||||
this.ajax(this.buildURL(root, "bulk"), "PUT", {
|
this.ajax(this.buildURL(root, "bulk"), "PUT", {
|
||||||
data: data,
|
data: data,
|
||||||
|
context: this,
|
||||||
success: function(json) {
|
success: function(json) {
|
||||||
this.sideload(store, type, json, plural);
|
this.didUpdateRecords(store, type, records, json);
|
||||||
store.didUpdateRecords(records, json[plural]);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didUpdateRecords: function(store, type, records, json) {
|
||||||
|
var root = this.pluralize(this.rootForType(type));
|
||||||
|
|
||||||
|
this.sideload(store, type, json, root);
|
||||||
|
store.didUpdateRecords(records, json[root]);
|
||||||
|
},
|
||||||
|
|
||||||
deleteRecord: function(store, type, record) {
|
deleteRecord: function(store, type, record) {
|
||||||
var id = get(record, 'id');
|
var id = get(record, 'id');
|
||||||
var root = this.rootForType(type);
|
var root = this.rootForType(type);
|
||||||
|
|
||||||
this.ajax(this.buildURL(root, id), "DELETE", {
|
this.ajax(this.buildURL(root, id), "DELETE", {
|
||||||
|
context: this,
|
||||||
success: function(json) {
|
success: function(json) {
|
||||||
if (json) { this.sideload(store, type, json); }
|
this.didDeleteRecord(store, type, record, json);
|
||||||
store.didDeleteRecord(record);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didDeleteRecord: function(store, type, record, json) {
|
||||||
|
if (json) { this.sideload(store, type, json); }
|
||||||
|
store.didDeleteRecord(record);
|
||||||
|
},
|
||||||
|
|
||||||
deleteRecords: function(store, type, records) {
|
deleteRecords: function(store, type, records) {
|
||||||
if (get(this, 'bulkCommit') === false) {
|
if (get(this, 'bulkCommit') === false) {
|
||||||
return this._super(store, type, records);
|
return this._super(store, type, records);
|
||||||
|
@ -3570,13 +3863,18 @@ DS.RESTAdapter = DS.Adapter.extend({
|
||||||
|
|
||||||
this.ajax(this.buildURL(root, 'bulk'), "DELETE", {
|
this.ajax(this.buildURL(root, 'bulk'), "DELETE", {
|
||||||
data: data,
|
data: data,
|
||||||
|
context: this,
|
||||||
success: function(json) {
|
success: function(json) {
|
||||||
if (json) { this.sideload(store, type, json); }
|
this.didDeleteRecords(store, type, records, json);
|
||||||
store.didDeleteRecords(records);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didDeleteRecords: function(store, type, records, json) {
|
||||||
|
if (json) { this.sideload(store, type, json); }
|
||||||
|
store.didDeleteRecords(records);
|
||||||
|
},
|
||||||
|
|
||||||
find: function(store, type, id) {
|
find: function(store, type, id) {
|
||||||
var root = this.rootForType(type);
|
var root = this.rootForType(type);
|
||||||
|
|
||||||
|
|
521
assets/javascripts/vendor/jquery.mockjax.js
vendored
Normal file
521
assets/javascripts/vendor/jquery.mockjax.js
vendored
Normal file
|
@ -0,0 +1,521 @@
|
||||||
|
/*!
|
||||||
|
* MockJax - jQuery Plugin to Mock Ajax requests
|
||||||
|
*
|
||||||
|
* Version: 1.5.0pre
|
||||||
|
* Released:
|
||||||
|
* Home: http://github.com/appendto/jquery-mockjax
|
||||||
|
* Author: Jonathan Sharp (http://jdsharp.com)
|
||||||
|
* License: MIT,GPL
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 appendTo LLC.
|
||||||
|
* Dual licensed under the MIT or GPL licenses.
|
||||||
|
* http://appendto.com/open-source-licenses
|
||||||
|
*/
|
||||||
|
(function($) {
|
||||||
|
var _ajax = $.ajax,
|
||||||
|
mockHandlers = [],
|
||||||
|
CALLBACK_REGEX = /=\?(&|$)/,
|
||||||
|
jsc = (new Date()).getTime();
|
||||||
|
|
||||||
|
|
||||||
|
// Parse the given XML string.
|
||||||
|
function parseXML(xml) {
|
||||||
|
if ( window['DOMParser'] == undefined && window.ActiveXObject ) {
|
||||||
|
DOMParser = function() { };
|
||||||
|
DOMParser.prototype.parseFromString = function( xmlString ) {
|
||||||
|
var doc = new ActiveXObject('Microsoft.XMLDOM');
|
||||||
|
doc.async = 'false';
|
||||||
|
doc.loadXML( xmlString );
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' );
|
||||||
|
if ( $.isXMLDoc( xmlDoc ) ) {
|
||||||
|
var err = $('parsererror', xmlDoc);
|
||||||
|
if ( err.length == 1 ) {
|
||||||
|
throw('Error: ' + $(xmlDoc).text() );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw('Unable to parse XML');
|
||||||
|
}
|
||||||
|
} catch( e ) {
|
||||||
|
var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
|
||||||
|
$(document).trigger('xmlParseError', [ msg ]);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return xmlDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger a jQuery event
|
||||||
|
function trigger(s, type, args) {
|
||||||
|
(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the data field on the mock handler and the request match. This
|
||||||
|
// can be used to restrict a mock handler to being used only when a certain
|
||||||
|
// set of data is passed to it.
|
||||||
|
function isMockDataEqual( mock, live ) {
|
||||||
|
var identical = false;
|
||||||
|
// Test for situations where the data is a querystring (not an object)
|
||||||
|
if (typeof live === 'string') {
|
||||||
|
// Querystring may be a regex
|
||||||
|
return $.isFunction( mock.test ) ? mock.test(live) : mock == live;
|
||||||
|
}
|
||||||
|
$.each(mock, function(k, v) {
|
||||||
|
if ( live[k] === undefined ) {
|
||||||
|
identical = false;
|
||||||
|
return identical;
|
||||||
|
} else {
|
||||||
|
identical = true;
|
||||||
|
if ( typeof live[k] == 'object' ) {
|
||||||
|
return isMockDataEqual(mock[k], live[k]);
|
||||||
|
} else {
|
||||||
|
if ( $.isFunction( mock[k].test ) ) {
|
||||||
|
identical = mock[k].test(live[k]);
|
||||||
|
} else {
|
||||||
|
identical = ( mock[k] == live[k] );
|
||||||
|
}
|
||||||
|
return identical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return identical;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the given handler should mock the given request
|
||||||
|
function getMockForRequest( handler, requestSettings ) {
|
||||||
|
// If the mock was registered with a function, let the function decide if we
|
||||||
|
// want to mock this request
|
||||||
|
if ( $.isFunction(handler) ) {
|
||||||
|
return handler( requestSettings );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspect the URL of the request and check if the mock handler's url
|
||||||
|
// matches the url for this ajax request
|
||||||
|
if ( $.isFunction(handler.url.test) ) {
|
||||||
|
// The user provided a regex for the url, test it
|
||||||
|
if ( !handler.url.test( requestSettings.url ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Look for a simple wildcard '*' or a direct URL match
|
||||||
|
var star = handler.url.indexOf('*');
|
||||||
|
if (handler.url !== requestSettings.url && star === -1 ||
|
||||||
|
!new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace('*', '.+')).test(requestSettings.url)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspect the data submitted in the request (either POST body or GET query string)
|
||||||
|
if ( handler.data && requestSettings.data ) {
|
||||||
|
if ( !isMockDataEqual(handler.data, requestSettings.data) ) {
|
||||||
|
// They're not identical, do not mock this request
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Inspect the request type
|
||||||
|
if ( handler && handler.type &&
|
||||||
|
handler.type.toLowerCase() != requestSettings.type.toLowerCase() ) {
|
||||||
|
// The request type doesn't match (GET vs. POST)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If logging is enabled, log the mock to the console
|
||||||
|
function logMock( mockHandler, requestSettings ) {
|
||||||
|
var c = $.extend({}, $.mockjaxSettings, mockHandler);
|
||||||
|
if ( c.log && $.isFunction(c.log) ) {
|
||||||
|
c.log('MOCK ' + requestSettings.type.toUpperCase() + ': ' + requestSettings.url, $.extend({}, requestSettings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the xhr objects send operation
|
||||||
|
function _xhrSend(mockHandler, requestSettings, origSettings) {
|
||||||
|
|
||||||
|
// This is a substitute for < 1.4 which lacks $.proxy
|
||||||
|
var process = (function(that) {
|
||||||
|
return function() {
|
||||||
|
return (function() {
|
||||||
|
// The request has returned
|
||||||
|
this.status = mockHandler.status;
|
||||||
|
this.statusText = mockHandler.statusText;
|
||||||
|
this.readyState = 4;
|
||||||
|
|
||||||
|
// We have an executable function, call it to give
|
||||||
|
// the mock handler a chance to update it's data
|
||||||
|
if ( $.isFunction(mockHandler.response) ) {
|
||||||
|
mockHandler.response(origSettings);
|
||||||
|
}
|
||||||
|
// Copy over our mock to our xhr object before passing control back to
|
||||||
|
// jQuery's onreadystatechange callback
|
||||||
|
if ( requestSettings.dataType == 'json' && ( typeof mockHandler.responseText == 'object' ) ) {
|
||||||
|
this.responseText = JSON.stringify(mockHandler.responseText);
|
||||||
|
} else if ( requestSettings.dataType == 'xml' ) {
|
||||||
|
if ( typeof mockHandler.responseXML == 'string' ) {
|
||||||
|
this.responseXML = parseXML(mockHandler.responseXML);
|
||||||
|
} else {
|
||||||
|
this.responseXML = mockHandler.responseXML;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.responseText = mockHandler.responseText;
|
||||||
|
}
|
||||||
|
if( typeof mockHandler.status == 'number' || typeof mockHandler.status == 'string' ) {
|
||||||
|
this.status = mockHandler.status;
|
||||||
|
}
|
||||||
|
if( typeof mockHandler.statusText === "string") {
|
||||||
|
this.statusText = mockHandler.statusText;
|
||||||
|
}
|
||||||
|
// jQuery < 1.4 doesn't have onreadystate change for xhr
|
||||||
|
if ( $.isFunction(this.onreadystatechange) ) {
|
||||||
|
if( mockHandler.isTimeout) {
|
||||||
|
this.status = -1;
|
||||||
|
}
|
||||||
|
this.onreadystatechange( mockHandler.isTimeout ? 'timeout' : undefined );
|
||||||
|
} else if ( mockHandler.isTimeout ) {
|
||||||
|
// Fix for 1.3.2 timeout to keep success from firing.
|
||||||
|
this.status = -1;
|
||||||
|
}
|
||||||
|
}).apply(that);
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
|
||||||
|
if ( mockHandler.proxy ) {
|
||||||
|
// We're proxying this request and loading in an external file instead
|
||||||
|
_ajax({
|
||||||
|
global: false,
|
||||||
|
url: mockHandler.proxy,
|
||||||
|
type: mockHandler.proxyType,
|
||||||
|
data: mockHandler.data,
|
||||||
|
dataType: requestSettings.dataType === "script" ? "text/plain" : requestSettings.dataType,
|
||||||
|
complete: function(xhr, txt) {
|
||||||
|
mockHandler.responseXML = xhr.responseXML;
|
||||||
|
mockHandler.responseText = xhr.responseText;
|
||||||
|
mockHandler.status = xhr.status;
|
||||||
|
mockHandler.statusText = xhr.statusText;
|
||||||
|
this.responseTimer = setTimeout(process, mockHandler.responseTime || 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// type == 'POST' || 'GET' || 'DELETE'
|
||||||
|
if ( requestSettings.async === false ) {
|
||||||
|
// TODO: Blocking delay
|
||||||
|
process();
|
||||||
|
} else {
|
||||||
|
this.responseTimer = setTimeout(process, mockHandler.responseTime || 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct a mocked XHR Object
|
||||||
|
function xhr(mockHandler, requestSettings, origSettings, origHandler) {
|
||||||
|
// Extend with our default mockjax settings
|
||||||
|
mockHandler = $.extend({}, $.mockjaxSettings, mockHandler);
|
||||||
|
|
||||||
|
if (typeof mockHandler.headers === 'undefined') {
|
||||||
|
mockHandler.headers = {};
|
||||||
|
}
|
||||||
|
if ( mockHandler.contentType ) {
|
||||||
|
mockHandler.headers['content-type'] = mockHandler.contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: mockHandler.status,
|
||||||
|
statusText: mockHandler.statusText,
|
||||||
|
readyState: 1,
|
||||||
|
open: function() { },
|
||||||
|
send: function() {
|
||||||
|
origHandler.fired = true;
|
||||||
|
_xhrSend.call(this, mockHandler, requestSettings, origSettings);
|
||||||
|
},
|
||||||
|
abort: function() {
|
||||||
|
clearTimeout(this.responseTimer);
|
||||||
|
},
|
||||||
|
setRequestHeader: function(header, value) {
|
||||||
|
mockHandler.headers[header] = value;
|
||||||
|
},
|
||||||
|
getResponseHeader: function(header) {
|
||||||
|
// 'Last-modified', 'Etag', 'content-type' are all checked by jQuery
|
||||||
|
if ( mockHandler.headers && mockHandler.headers[header] ) {
|
||||||
|
// Return arbitrary headers
|
||||||
|
return mockHandler.headers[header];
|
||||||
|
} else if ( header.toLowerCase() == 'last-modified' ) {
|
||||||
|
return mockHandler.lastModified || (new Date()).toString();
|
||||||
|
} else if ( header.toLowerCase() == 'etag' ) {
|
||||||
|
return mockHandler.etag || '';
|
||||||
|
} else if ( header.toLowerCase() == 'content-type' ) {
|
||||||
|
return mockHandler.contentType || 'text/plain';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAllResponseHeaders: function() {
|
||||||
|
var headers = '';
|
||||||
|
$.each(mockHandler.headers, function(k, v) {
|
||||||
|
headers += k + ': ' + v + "\n";
|
||||||
|
});
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process a JSONP mock request.
|
||||||
|
function processJsonpMock( requestSettings, mockHandler, origSettings ) {
|
||||||
|
// Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here
|
||||||
|
// because there isn't an easy hook for the cross domain script tag of jsonp
|
||||||
|
|
||||||
|
processJsonpUrl( requestSettings );
|
||||||
|
|
||||||
|
requestSettings.dataType = "json";
|
||||||
|
if(requestSettings.data && CALLBACK_REGEX.test(requestSettings.data) || CALLBACK_REGEX.test(requestSettings.url)) {
|
||||||
|
createJsonpCallback(requestSettings, mockHandler);
|
||||||
|
|
||||||
|
// We need to make sure
|
||||||
|
// that a JSONP style response is executed properly
|
||||||
|
|
||||||
|
var rurl = /^(\w+:)?\/\/([^\/?#]+)/,
|
||||||
|
parts = rurl.exec( requestSettings.url ),
|
||||||
|
remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
|
||||||
|
|
||||||
|
requestSettings.dataType = "script";
|
||||||
|
if(requestSettings.type.toUpperCase() === "GET" && remote ) {
|
||||||
|
var newMockReturn = processJsonpRequest( requestSettings, mockHandler, origSettings );
|
||||||
|
|
||||||
|
// Check if we are supposed to return a Deferred back to the mock call, or just
|
||||||
|
// signal success
|
||||||
|
if(newMockReturn) {
|
||||||
|
return newMockReturn;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the required callback parameter to the end of the request URL, for a JSONP request
|
||||||
|
function processJsonpUrl( requestSettings ) {
|
||||||
|
if ( requestSettings.type.toUpperCase() === "GET" ) {
|
||||||
|
if ( !CALLBACK_REGEX.test( requestSettings.url ) ) {
|
||||||
|
requestSettings.url += (/\?/.test( requestSettings.url ) ? "&" : "?") +
|
||||||
|
(requestSettings.jsonp || "callback") + "=?";
|
||||||
|
}
|
||||||
|
} else if ( !requestSettings.data || !CALLBACK_REGEX.test(requestSettings.data) ) {
|
||||||
|
requestSettings.data = (requestSettings.data ? requestSettings.data + "&" : "") + (requestSettings.jsonp || "callback") + "=?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process a JSONP request by evaluating the mocked response text
|
||||||
|
function processJsonpRequest( requestSettings, mockHandler, origSettings ) {
|
||||||
|
// Synthesize the mock request for adding a script tag
|
||||||
|
var callbackContext = origSettings && origSettings.context || requestSettings,
|
||||||
|
newMock = null;
|
||||||
|
|
||||||
|
|
||||||
|
// If the response handler on the moock is a function, call it
|
||||||
|
if ( mockHandler.response && $.isFunction(mockHandler.response) ) {
|
||||||
|
mockHandler.response(origSettings);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Evaluate the responseText javascript in a global context
|
||||||
|
if( typeof mockHandler.responseText === 'object' ) {
|
||||||
|
$.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')');
|
||||||
|
} else {
|
||||||
|
$.globalEval( '(' + mockHandler.responseText + ')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successful response
|
||||||
|
jsonpSuccess( requestSettings, mockHandler );
|
||||||
|
jsonpComplete( requestSettings, mockHandler );
|
||||||
|
|
||||||
|
// If we are running under jQuery 1.5+, return a deferred object
|
||||||
|
if(jQuery.Deferred){
|
||||||
|
newMock = new jQuery.Deferred();
|
||||||
|
if(typeof mockHandler.responseText == "object"){
|
||||||
|
newMock.resolve( mockHandler.responseText );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
newMock.resolve( jQuery.parseJSON( mockHandler.responseText ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newMock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create the required JSONP callback function for the request
|
||||||
|
function createJsonpCallback( requestSettings, mockHandler ) {
|
||||||
|
jsonp = requestSettings.jsonpCallback || ("jsonp" + jsc++);
|
||||||
|
|
||||||
|
// Replace the =? sequence both in the query string and the data
|
||||||
|
if ( requestSettings.data ) {
|
||||||
|
requestSettings.data = (requestSettings.data + "").replace(CALLBACK_REGEX, "=" + jsonp + "$1");
|
||||||
|
}
|
||||||
|
|
||||||
|
requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, "=" + jsonp + "$1");
|
||||||
|
|
||||||
|
|
||||||
|
// Handle JSONP-style loading
|
||||||
|
window[ jsonp ] = window[ jsonp ] || function( tmp ) {
|
||||||
|
data = tmp;
|
||||||
|
jsonpSuccess( requestSettings, mockHandler );
|
||||||
|
jsonpComplete( requestSettings, mockHandler );
|
||||||
|
// Garbage collect
|
||||||
|
window[ jsonp ] = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
delete window[ jsonp ];
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
if ( head ) {
|
||||||
|
head.removeChild( script );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// The JSONP request was successful
|
||||||
|
function jsonpSuccess(requestSettings, mockHandler) {
|
||||||
|
// If a local callback was specified, fire it and pass it the data
|
||||||
|
if ( requestSettings.success ) {
|
||||||
|
requestSettings.success.call( callbackContext, ( mockHandler.response ? mockHandler.response.toString() : mockHandler.responseText || ''), status, {} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire the global callback
|
||||||
|
if ( requestSettings.global ) {
|
||||||
|
trigger(requestSettings, "ajaxSuccess", [{}, requestSettings] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The JSONP request was completed
|
||||||
|
function jsonpComplete(requestSettings, mockHandler) {
|
||||||
|
// Process result
|
||||||
|
if ( requestSettings.complete ) {
|
||||||
|
requestSettings.complete.call( callbackContext, {} , status );
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request was completed
|
||||||
|
if ( requestSettings.global ) {
|
||||||
|
trigger( "ajaxComplete", [{}, requestSettings] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the global AJAX counter
|
||||||
|
if ( requestSettings.global && ! --jQuery.active ) {
|
||||||
|
jQuery.event.trigger( "ajaxStop" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The core $.ajax replacement.
|
||||||
|
function handleAjax( url, origSettings ) {
|
||||||
|
var mockRequest, requestSettings, mockHandler;
|
||||||
|
|
||||||
|
// If url is an object, simulate pre-1.5 signature
|
||||||
|
if ( typeof url === "object" ) {
|
||||||
|
origSettings = url;
|
||||||
|
url = undefined;
|
||||||
|
} else {
|
||||||
|
// work around to support 1.5 signature
|
||||||
|
origSettings.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend the original settings for the request
|
||||||
|
requestSettings = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);
|
||||||
|
|
||||||
|
// Iterate over our mock handlers (in registration order) until we find
|
||||||
|
// one that is willing to intercept the request
|
||||||
|
for(var k = 0; k < mockHandlers.length; k++) {
|
||||||
|
if ( !mockHandlers[k] ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mockHandler = getMockForRequest( mockHandlers[k], requestSettings );
|
||||||
|
if(!mockHandler) {
|
||||||
|
// No valid mock found for this request
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle console logging
|
||||||
|
logMock( mockHandler, requestSettings );
|
||||||
|
|
||||||
|
|
||||||
|
if ( requestSettings.dataType === "jsonp" ) {
|
||||||
|
if ((mockRequest = processJsonpMock( requestSettings, mockHandler, origSettings ))) {
|
||||||
|
// This mock will handle the JSONP request
|
||||||
|
return mockRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Removed to fix #54 - keep the mocking data object intact
|
||||||
|
//mockHandler.data = requestSettings.data;
|
||||||
|
|
||||||
|
mockHandler.cache = requestSettings.cache;
|
||||||
|
mockHandler.timeout = requestSettings.timeout;
|
||||||
|
mockHandler.global = requestSettings.global;
|
||||||
|
|
||||||
|
(function(mockHandler, requestSettings, origSettings, origHandler) {
|
||||||
|
mockRequest = _ajax.call($, $.extend(true, {}, origSettings, {
|
||||||
|
// Mock the XHR object
|
||||||
|
xhr: function() { return xhr( mockHandler, requestSettings, origSettings, origHandler ) }
|
||||||
|
}));
|
||||||
|
})(mockHandler, requestSettings, origSettings, mockHandlers[k]);
|
||||||
|
|
||||||
|
return mockRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't have a mock request, trigger a normal request
|
||||||
|
return _ajax.apply($, [origSettings]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Public
|
||||||
|
|
||||||
|
$.extend({
|
||||||
|
ajax: handleAjax
|
||||||
|
});
|
||||||
|
|
||||||
|
$.mockjaxSettings = {
|
||||||
|
//url: null,
|
||||||
|
//type: 'GET',
|
||||||
|
log: function(msg) {
|
||||||
|
window['console'] && window.console.log && window.console.log(msg);
|
||||||
|
},
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
responseTime: 500,
|
||||||
|
isTimeout: false,
|
||||||
|
contentType: 'text/plain',
|
||||||
|
response: '',
|
||||||
|
responseText: '',
|
||||||
|
responseXML: '',
|
||||||
|
proxy: '',
|
||||||
|
proxyType: 'GET',
|
||||||
|
|
||||||
|
lastModified: null,
|
||||||
|
etag: '',
|
||||||
|
headers: {
|
||||||
|
etag: 'IJF@H#@923uf8023hFO@I#H#',
|
||||||
|
'content-type' : 'text/plain'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.mockjax = function(settings) {
|
||||||
|
var i = mockHandlers.length;
|
||||||
|
mockHandlers[i] = settings;
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
$.mockjaxClear = function(i) {
|
||||||
|
if ( arguments.length == 1 ) {
|
||||||
|
mockHandlers[i] = null;
|
||||||
|
} else {
|
||||||
|
mockHandlers = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$.mockjax.handler = function(i) {
|
||||||
|
if ( arguments.length == 1 ) {
|
||||||
|
return mockHandlers[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(jQuery);
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['application']=Ember.Handlebars.compile("<div id=\"head\">\n <a href=\"/\">Travis CI</a>\n <a href=\"#\">#</a>\n</div>\n\n<div id=\"left\">\n {{outlet left}}\n</div>\n\n<div id=\"main\">\n {{outlet main}}\n</div>\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['list']=Ember.Handlebars.compile("<table id=\"builds\">\n <thead>\n <tr>\n <th>{{t builds.name}}</th>\n <th>{{t builds.commit}}</th>\n <th>{{t builds.message}}</th>\n <th>{{t builds.duration}}</th>\n <th>{{t builds.finished_at}}</th>\n </tr>\n </thead>\n\n {{#collection tagName=\"tbody\" contentBinding=\"content\" itemViewClass=\"Travis.BuildsItemView\" itemClassBinding=\"color\"}}\n {{#with view.content}}\n <td class=\"number\"><a {{action viewBuild href=true context=\"content\"}}>{{number}}</a></td>\n <td class=\"commit\"><a {{bindAttr href=\"urlGithubCommit\"}}>{{formatCommit commit}}</a> {{commit.sha}}</td>\n <td class=\"message\">{{{formatMessage commit.message short=\"true\"}}}</td>\n <td class=\"duration\" {{bindAttr title=\"started_at\"}}>{{formatDuration duration}}</td>\n <td class=\"finished_at timeago\" {{bindAttr title=\"finished_at\"}}>{{formatTime finished_at}}</td>\n {{/with}}\n {{/collection}}\n</table>\n\n<p>\n <button {{action showMore on=\"click\" target=\"builds\" isVisibleBinding=\"hasMore\"}}>\n {{t builds.show_more}}\n </button>\n</p>\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['show']=Ember.Handlebars.compile("<div {{bindAttr class=\"classes\"}}>\n <dl class=\"summary clearfix\">\n <div class=\"left\">\n <dt>{{t builds.name}}</dt>\n <dd class=\"number\"><a {{bindAttr href=\"urlBuild\"}}>{{number}}</a></dd>\n <dt class=\"finished_at_label\">{{t builds.finished_at}}</dt>\n <dd class=\"finished_at timeago\" {{bindAttr title=\"finished_at\"}}>{{formatTime finished_at}}</dd>\n <dt>{{t builds.duration}}</dt>\n <dd class=\"duration\" {{bindAttr title=\"started_at\"}}>{{formatDuration duration}}</dd>\n </div>\n\n <div class=\"right\">\n <dt>{{t builds.commit}}</dt>\n <dd class=\"commit-hash\"><a {{bindAttr href=\"urlGithubCommit\"}}>{{formatCommit commit}}</a></dd>\n {{#if commit.compare_url}}\n <dt>{{t builds.compare}}</dt>\n <dd class=\"compare_view\"><a {{bindAttr href=\"commit.compare_url\"}}>{{pathFrom commit.compare_url}}</a></dd>\n {{/if}}\n {{#if commit.author_name}}\n <dt>{{t builds.author}}</dt>\n <dd class=\"author\"><a {{bindAttr href=\"view.urlAuthor\"}}>{{commit.author_name}}</a></dd>\n {{/if}}\n {{#if commit.committer_name}}\n <dt>{{t builds.committer}}</dt>\n <dd class=\"committer\"><a {{bindAttr href=\"urlCommitter\"}}>{{commit.committer_name}}</a></dd>\n {{/if}}\n </div>\n\n <dt>{{t builds.message}}</dt>\n <dd class=\"commit-message\">{{{formatMessage commit.message}}}</dd>\n\n {{#if isMatrix}}\n {{else}}\n <dt>{{t builds.config}}</dt>\n <dd class=\"config\">{{formatConfig config}}</dd>\n {{/if}}\n </dl>\n\n {{#if isLoaded}}\n {{#if isMatrix}}\n {{view Travis.JobsView}}\n {{else}}\n {{view Travis.LogView}}\n {{/if}}\n {{/if}}\n</div>\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['list']=Ember.Handlebars.compile("<table id=\"jobs\">\n <caption>{{t jobs.build_matrix}}</caption>\n <thead>\n <tr>\n {{#each configKeys}}\n <th>{{this}}</th>\n {{/each}}\n </tr>\n </thead>\n <tbody>\n {{#each requiredJobs}}\n <tr {{bindAttr class=\"color\"}}>\n <td class=\"number\"><a {{action viewJob href=true context=this}}>#{{number}}</a></td>\n <td class=\"duration\" {{bindAttr title=\"started_at\"}}>{{formatDuration duration}}</td>\n <td class=\"finished_at timeago\" {{bindAttr title=\"finished_at\"}}>{{formatTime finished_at}}</td>\n {{#each configValues}}\n <td>{{this}}</td>\n {{/each}}\n </tr>\n {{/each}}\n </tbody>\n</table>\n\n{{#if isFailureMatrix}}\n <table id=\"allow_failure_builds\">\n <caption>\n {{t jobs.allowed_failures}}{{whats_this allow_failure_help}}\n </caption>\n <thead>\n <tr>\n {{#each configKeys}}\n <th>{{this}}</th>\n {{/each}}\n </tr>\n </thead>\n <tbody>\n {{#each allowedFailureJobs}}\n <tr {{bindAttr class=\"color\"}}>\n <td class=\"number\"><a {{action viewJob href=true}}>#{{number}}</a></td>\n <td class=\"duration\" {{bindAttr title=\"started_at\"}}>{{formatDuration duration}}</td>\n <td class=\"finished_at timeago\" {{bindAttr title=\"finished_at\"}}>{{formatTime finished_at}}</td>\n {{#each configValues}}\n <td>{{this}}</td>\n {{/each}}\n </tr>\n {{/each}}\n </tbody>\n </table>\n\n <div id=\"allow_failure_help\" class=\"context_help\">\n <div class=\"context_help_caption\">{{t \"jobs.allowed_failures\"}}</div>\n <div class=\"context_help_body\">\n <p>\n Allowed Failures are items in your build matrix that are allowed to\n fail without causing the entire build to be shown as failed. This lets you add\n in experimental and preparatory builds to test against versions or\n configurations that you are not ready to officially support.\n </p>\n <p>\n You can define allowed failures in the build matrix as follows:\n </p>\n <pre>\n matrix:\n allow_failures:\n - rvm: ruby-head\n </pre>\n </div>\n </div>\n{{/if}}\n\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['log']=Ember.Handlebars.compile("{{! ugh ... }}\n{{#with jobs.firstObject}}\n <pre class=\"log\">{{{formatLog log.body}}}</pre>\n\n {{#if sponsor.name}}\n <p class=\"sponsor\">\n {{t builds.messages.sponsored_by}}\n <a {{bindAttr href=\"sponsor.url\"}}>{{sponsor.name}}</a>\n </p>\n {{/if}}\n{{/with}}\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['show']=Ember.Handlebars.compile("<div {{bindAttr class=\"color\"}}>\n <dl class=\"summary clearfix\">\n <div class=\"left\">\n <dt>Job</dt>\n <dd class=\"number\"><a {{bindAttr href=\"urlJob\"}}>{{number}}</a></dd>\n <dt class=\"finished_at_label\">{{t jobs.finished_at}}</dt>\n <dd class=\"finished_at timeago\" {{bindAttr title=\"finished_at\"}}>{{formatTime finished_at}}</dd>\n <dt>{{t jobs.duration}}</dt>\n <dd class=\"duration\" {{bindAttr title=\"started_at\"}}>{{formatDuration duration}}</dd>\n </div>\n\n <div class=\"right\">\n <dt>{{t jobs.commit}}</dt>\n <dd class=\"commit-hash\"><a {{bindAttr href=\"urlGithubCommit\"}}>{{formatCommit commit}}</a></dd>\n {{#if commit.compare_url}}\n <dt>{{t jobs.compare}}</dt>\n <dd class=\"compare_view\"><a {{bindAttr href=\"commit.compare_url\"}}>{{pathFrom commit.compare_url}}</a></dd>\n {{/if}}\n {{#if commit.author_name}}\n <dt>{{t jobs.author}}</dt>\n <dd class=\"author\"><a {{bindAttr href=\"urlAuthor\"}}>{{commit.author_name}}</a></dd>\n {{/if}}\n {{#if commit.committer_name}}\n <dt>{{t jobs.committer}}</dt>\n <dd class=\"committer\"><a {{bindAttr href=\"urlCommitter\"}}>{{commit.committer_name}}</a></dd>\n {{/if}}\n </div>\n\n <dt>{{t jobs.message}}</dt>\n <dd class=\"commit-message\">{{formatMessage commit.message}}</dd>\n <dt>{{t jobs.config}}</dt>\n <dd class=\"config\">{{formatConfig config}}</dd>\n </dl>\n\n {{view Travis.LogView}}\n</div>\n\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['loading']=Ember.Handlebars.compile("loading stuff ...\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['list']=Ember.Handlebars.compile("{{#collection tagName=\"ul\" id=\"repositories\" contentBinding=\"content\" itemViewClass=\"Travis.RepositoriesItemView\" itemClassBinding=\"classes\"}}\n {{#with view.content}}\n <div class=\"wrapper\">\n <a {{action viewCurrent href=true context=\"content\"}} class=\"slug\">{{slug}}</a>\n <a {{action viewBuild href=true context=\"lastBuild\"}} class=\"build\">#{{last_build_number}}</a>\n <p class=\"summary\">\n <span class=\"duration_label\">{{t repositories.duration}}:</span>\n <abbr class=\"duration\" {{bindAttr title=\"last_build_started_at\"}}>{{formatDuration last_build_duration}}</abbr>,\n <span class=\"finished_at_label\">{{t repositories.finished_at}}:</span>\n <abbr class=\"finished_at timeago\" {{bindAttr title=\"last_build_finished_at\"}}>{{formatTime last_build_finished_at}}</abbr>\n </p>\n {{#if description}}\n <p class=\"description\">{{description}}</p>\n {{/if}}\n <span class=\"indicator\"></span>\n </div>\n {{/with}}\n{{/collection}}\n\n{{^collection contentBinding=\"repositories\" id=\"list\" class=\"loading\"}}\n <p></p>\n{{/collection}}\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['show']=Ember.Handlebars.compile("<h3>\n <a {{bindAttr href=\"urlGithub\"}}>{{slug}}</a>\n</h3>\n\n<p class=\"description\">{{description}}</p>\n\n<ul class=\"github-stats\">\n <li class=\"language\">{{last_build_language}}</li>\n <li><a class=\"watchers\" title=\"Watches\" {{bindAttr href=\"urlGithubWatchers\"}}>{{stats.watchers}}</a></li>\n <li><a class=\"forks\" title=\"Forks\" {{bindAttr href=\"urlGithubNetwork\"}}>{{stats.forks}}</a></li>\n</ul>\n\n{{outlet tabs}}\n\n<div class=\"tab\">\n {{outlet tab}}\n</div>\n");
|
|
|
@ -1 +0,0 @@
|
||||||
Ember.TEMPLATES['tabs']=Ember.Handlebars.compile("<ul class=\"tabs\">\n <li><a {{action viewCurrent href=true context=\"repository\"}} class=\"current\">Current</a></li>\n <li><a {{action viewHistory href=true context=\"repository\"}} class=\"history\">History</a></li>\n {{#if build}}\n <li><a {{action viewBuild href=true context=\"build\"}} class=\"build\">Build #{{build.number}}</a></li>\n {{/if}}\n {{#if job}}\n <li><a {{action viewJob href=true context=\"job\"}} class=\"job\">Job #{{job.number}}</a></li>\n {{/if}}\n</ul>\n");
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user