Переглянути джерело

Add spine-couch-changes adapter to all Spine models

Markus Ochel 12 роки тому
батько
коміт
5cb2d2a4ea

+ 2 - 0
admin/controllers/index.coffee

@@ -1,6 +1,8 @@
 Spine       = require('spine/core')
 require('spine/route')
 require('spine/manager')
+require('lib/spine-couch-ajax')
+require('lib/spine-couch-changes')
 require('lib/fastclick')
 
 templates   = require('duality/templates')

+ 5 - 3
admin/lib/spine-couch-ajax.coffee

@@ -85,7 +85,7 @@ CouchAjax =
       @requests.push(callback)
     else
       @pending = true
-      @request(callback)    
+      @request(callback)
     callback
     
 class Base
@@ -190,6 +190,8 @@ class Singleton extends Base
         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
@@ -209,7 +211,7 @@ class Singleton extends Base
       options.error?.apply(@record)
       
       # Popup an alert box that we could communicate with server
-      alert "Could NOT communicate with server for \"#{@record.title or @record.name}\".\n\nCheck your connection and try again."
+      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 = ''
@@ -223,7 +225,7 @@ Include =
     base += encodeURIComponent(@id)
     base
     
-Extend = 
+Extend =
   ajax: -> new Collection(this)
 
   url: ->

+ 76 - 0
admin/lib/spine-couch-changes.coffee

@@ -0,0 +1,76 @@
+db       = require "db"
+duality  = require "duality/core"
+session  = require "session"
+
+
+feeds = {} # Cache `_changes` feeds by their url
+
+
+Spine.Model.CouchChanges = (opts = {})->
+  opts.url = opts.url or duality.getDBURL()
+  opts.handler = Spine.Model.CouchChanges.Changes unless opts.handler
+  feeds[opts.url] or feeds[opts.url] =
+    changes: new opts.handler opts
+    extended: ->
+      # need to keep _rev around to support changes feed processing
+      @attributes.push "_rev" unless @attributes[ "_rev" ]
+      @changes.subscribe @className, @
+
+
+Spine.Model.CouchChanges.Changes = class Changes
+  subscribers: {}
+  query: include_docs: yes
+
+  constructor: (options = {})->
+    @url = options.url
+    @startListening()
+
+  subscribe: (classname, klass) =>
+    @subscribers[classname.toLowerCase()] = klass
+
+  startListening: =>
+    db.use(@url).changes @query, @handler()
+
+  # returns handler which you may disable by setting handler.disabled flag `true`
+  handler: -> self = (err, resp) =>
+    if self.disabled then false
+    else if err then false # TODO? @trigger error
+    else
+      @acceptChanges resp?.results
+      true
+
+  acceptChanges: (changes)->
+    return unless changes
+    Spine.CouchAjax.disable =>
+      for doc in changes
+        if modelname = doc.doc?.modelname
+          klass = @subscribers[modelname]
+        unless klass
+          console.warn "changes: can't find subscriber for #{doc.doc.modelname}"
+          continue
+        atts = doc.doc
+        atts.id = atts._id unless atts.id
+        try
+          obj = klass.find atts.id
+          if doc.deleted
+            obj.destroy()
+          else
+            unless obj._rev is atts._rev
+              obj.updateAttributes atts
+        catch e
+          klass.create atts unless doc.deleted
+
+
+# Start listening for _changes only when user is authenticated
+#   and stop listening for changes when he logged out
+Spine.Model.CouchChanges.PrivateChanges = class PrivateChanges extends Changes
+  startListening: =>
+    session.on "change", @authChanged
+
+  authChanged: (userCtx)=>
+    if userCtx.name
+      @currentHandler.disabled = true if @currentHandler
+      @currentHandler = @handler()
+      db.use(@url).changes @query, @currentHandler
+    else
+      @currentHandler.disabled = true if @currentHandler

+ 2 - 2
admin/models/author.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 
 BaseModel = require('models/base')
@@ -9,6 +7,8 @@ class Author extends BaseModel
   @configure "Author", "site", "name", "email", "bio", "links", "photo"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
   
   @queryOn: ['name','email']
     

+ 2 - 2
admin/models/block.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 
 BaseModel = require('models/base')
@@ -9,6 +7,8 @@ class Block extends BaseModel
   @configure "Block", "site", "code", "name", "content", "photo", "enabled", "_attachments"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
   
   @queryOn: ['name','code']
     

+ 2 - 2
admin/models/collection.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils  = require('lib/utils')
 moment = require('lib/moment')
 
@@ -10,6 +8,8 @@ class Collection extends BaseModel
   @configure "Collection", "site", "slug", "name", "intro", "photo", "pinned", "hidden", "updated_at", "sponsor_id", "sponsor_start", "sponsor_end", "sponsor_propagate", "sponsors_history", "_attachments"
 
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
 
   @dateSort: (a, b) ->
     if (a.updated_at or a.name) < (b.updated_at or b.name) then 1 else -1

+ 2 - 2
admin/models/contact.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 
 BaseModel = require('models/base')
@@ -9,6 +7,8 @@ class Contact extends BaseModel
   @configure "Contact", "name", "email", "note"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
   
   @queryOn: ['name','email']
     

+ 2 - 2
admin/models/essay.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 moment = require('lib/moment')
 
@@ -10,6 +8,8 @@ class Essay extends BaseModel
   @configure "Essay", "site", "slug", "title", "intro", "body", "photo", "published", "published_at", "updated_at", "author_id", "sponsor_id", "sponsor_start", "sponsor_end", "sponsors_history", "collections", "_attachments"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
   
   @alphaSort: (a, b) ->
     if (a.title or a.published_at) > (b.title or b.published_at) then 1 else -1

+ 2 - 2
admin/models/redirect.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 
 BaseModel = require('models/base')
@@ -9,6 +7,8 @@ class Redirect extends BaseModel
   @configure "Redirect", "_id", "site", "slug", "location"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
   
   @queryOn: ['slug','location']
     

+ 2 - 2
admin/models/scene.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 moment = require('lib/moment')
 
@@ -10,6 +8,8 @@ class Scene extends BaseModel
   @configure "Scene", "site", "slug", "title", "body", "photo", "published", "published_at", "updated_at", "author_id", "sponsor_id", "sponsor_start", "sponsor_end", "sponsors_history", "collections", "_attachments"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
   
   @alphaSort: (a, b) ->
     if (a.title or a.published_at) > (b.title or b.published_at) then 1 else -1

+ 2 - 2
admin/models/site.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 
 BaseModel = require('models/base')
@@ -9,6 +7,8 @@ class Site extends BaseModel
   @configure "Site", "_id", "name", "name_html", "tagline", "menu_html", "header_html", "bottom_html", "footer_html", "link", "social_links", "theme", "css", "seo_description", "seo_keywords", "google_analytics_code", "editor_email", "admin_email", "default_ad_unit", "default_ad_enabled"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
   
   @queryOn: ['name','tagline','_id']
     

+ 2 - 2
admin/models/sponsor.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 
 BaseModel = require('models/base')
@@ -11,6 +9,8 @@ class Sponsor extends BaseModel
   @configure "Sponsor", "format", "name", "link", "label", "show_label", "content", "include_default_ad_unit", "image", "note", "contact_id", "_attachments"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
 
   @queryOn: ['name','content','link','format']
     

+ 2 - 2
admin/models/video.coffee

@@ -1,6 +1,4 @@
 Spine = require('spine/core')
-require('lib/spine-couch-ajax')
-
 utils = require('lib/utils')
 moment = require('lib/moment')
 
@@ -10,6 +8,8 @@ class Video extends BaseModel
   @configure "Video", "site", "slug", "title", "intro", "body", "video", "photo", "published", "published_at", "updated_at", "author_id", "sponsor_id", "sponsor_start", "sponsor_end", "sponsors_history", "collections", "_attachments"
   
   @extend @CouchAjax
+  @extend @CouchChanges
+    handler: @CouchChanges.PrivateChanges
   
   @alphaSort: (a, b) ->
     if (a.title or a.published_at) > (b.title or b.published_at) then 1 else -1