123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- Spine = require('spine/core')
- $ = Spine.$
- Model = Spine.Model
- {_} = require("underscore")
- duality = require("duality/core")
- Spine.Model.include
- toJSON: ->
- result = {}
- for key in @constructor.attributes when key of @
- if typeof @[key] is 'function'
- result[key] = @[key]()
- else
- result[key] = @[key]
- result.id = result._id = @_id if @_id
- result
- changeID: (id) ->
- # Markus: Needed to refresh the client records
- # since this is a new record with changed ID
- records = @constructor.records
- crecords = @constructor.crecords
- record = records[@id].dup(false)
- record.id = id
- record._id = id
- records[record.id] = record
- crecords[record.cid] = record
- delete records[@id]
- @id = id
- @_id = id
- @save()
- @constructor.trigger('refresh', @constructor.cloneArray([record]))
- # ... or fetch again from server which also works
- # super
- # @constructor.ajax().fetch({id: id})
- Spine.Model.extend
- fromJSON: (objects) ->
- make_object = (val) =>
- val.id = val._id unless val.id
- val._id = val.id unless val._id
- new @(val)
- return unless objects
- if typeof objects is 'string'
- objects = JSON.parse(objects)
- if Spine.isArray(objects)
- (make_object(value) for value in objects)
- else
- make_object(objects)
- CouchAjax =
- getURL: (object) ->
- object and object.url?() or object.url
- enabled: true
- pending: false
- requests: []
- disable: (callback) ->
- if @enabled
- @enabled = false
- try
- do callback
- catch e
- throw e
- finally
- @enabled = true
- else
- do callback
- requestNext: ->
- next = @requests.shift()
- if next
- @request(next)
- else
- @pending = false
- request: (callback) ->
- (do callback).complete(=> do @requestNext)
-
- queue: (callback) ->
- return unless @enabled
- if @pending
- @requests.push(callback)
- else
- @pending = true
- @request(callback)
- callback
-
- class Base
- defaults:
- contentType: 'application/json'
- dataType: 'json'
- processData: false
- headers: {'X-Requested-With': 'XMLHttpRequest'}
-
- ajax: (params, defaults) ->
- $.ajax($.extend({}, @defaults, defaults, params))
-
- queue: (callback) ->
- CouchAjax.queue(callback)
- class Collection extends Base
- constructor: (@model) ->
-
- find: (id, params) ->
- record = new @model(id: id)
- @ajax(
- params,
- type: 'GET',
- url: CouchAjax.getURL(record)
- ).success(@recordsResponse)
- .error(@errorResponse)
-
- all: (params) ->
- @ajax(
- params,
- type: 'GET',
- url: CouchAjax.getURL(@model)
- ).success(@recordsResponse)
- .error(@errorResponse)
-
- fetch: (params = {}) ->
- if id = params.id
- delete params.id
- @find(id, params).success (record) =>
- @model.refresh(_.pluck(record.rows, "doc"))
- else
- @all(params).success (records) =>
- @model.refresh(_.pluck(records.rows, "doc"))
-
- # Private
- recordsResponse: (data, status, xhr) =>
- @model.trigger('ajaxSuccess', null, status, xhr)
- errorResponse: (xhr, statusText, error) =>
- @model.trigger('ajaxError', null, xhr, statusText, error)
- class Singleton extends Base
- constructor: (@record) ->
- @model = @record.constructor
-
- reload: (params, options) ->
- @queue =>
- @ajax(
- params,
- type: 'GET'
- url: CouchAjax.getURL(@record)
- ).success(@recordResponse(options))
- .error(@errorResponse(options))
-
- create: (params, options) ->
- @queue =>
- @ajax(
- params,
- type: 'POST'
- data: JSON.stringify(@record)
- url: CouchAjax.getURL(@model)
- ).success(@recordResponse(options))
- .error(@errorResponse(options))
- update: (params, options) ->
- @queue =>
- @ajax(
- params,
- type: 'PUT'
- data: JSON.stringify(@record)
- url: CouchAjax.getURL(@record)
- ).success(@recordResponse(options))
- .error(@errorResponse(options))
-
- destroy: (params, options) ->
- @queue =>
- @ajax(
- params,
- type: 'DELETE'
- url: CouchAjax.getURL(@record)
- ).success(@recordResponse(options))
- .error(@errorResponse(options))
- # Private
- recordResponse: (options = {}) =>
- (data, status, xhr) =>
- if Spine.isBlank(data)
- data = false
- else if data.rows
- data = @model.fromJSON(_.pluck(data.rows, "doc")[0])
- else
- data = @model.fromJSON(data)
- data._rev = xhr.getResponseHeader( 'X-Couch-Update-NewRev' )
-
- CouchAjax.disable =>
- if data
- # ID change, need to do some shifting
- if data.id and @record.id isnt data.id
- @record.changeID(data.id)
- # Update with latest data
- @record.updateAttributes(data.attributes())
-
- @record.trigger('ajaxSuccess', data, status, xhr)
- options.success?.apply(@record)
-
- errorResponse: (options = {}) =>
- (xhr, statusText, error) =>
- @record.trigger('ajaxError', xhr, statusText, error)
- options.error?.apply(@record)
-
- # Popup an alert box that we could communicate with server
- alert "#{statusText}\n#{error}\nSomehting may have gone wrong with an action for \"#{@record.title or @record.name}\".\n\nCheck your connection and try again."
- # CouchAjax endpoint
- Model.host = ''
- Include =
- ajax: -> new Singleton(this)
- url: ->
- base = CouchAjax.getURL(@constructor)
- base += '/' unless base.charAt(base.length - 1) is '/'
- base += encodeURIComponent(@id)
- base
-
- Extend =
- ajax: -> new Collection(this)
- url: ->
- "#{duality.getBaseURL()}/spine-adapter/#{@className.toLowerCase()}"
-
- Model.CouchAjax =
- extended: ->
- @fetch @ajaxFetch
- @change @ajaxChange
-
- @extend Extend
- @include Include
-
- # Private
- ajaxFetch: ->
- @ajax().fetch(arguments...)
-
- ajaxChange: (record, type, options = {}) ->
- return if options.ajax is false
- record.ajax()[type](options.ajax, options)
-
- Model.CouchAjax.Methods =
- extended: ->
- @extend Extend
- @include Include
-
- # Globals
- CouchAjax.defaults = Base::defaults
- Spine.CouchAjax = CouchAjax
- module?.exports = CouchAjax
|