scenes.coffee 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. Spine = require('spine/core')
  2. $ = Spine.$
  3. templates = require('duality/templates')
  4. utils = require('lib/utils')
  5. MultiSelectUI = require('controllers/ui/multi-select')
  6. FileUploadUI = require('controllers/ui/file-upload')
  7. PreviewUI = require('controllers/ui/preview')
  8. Scene = require('models/scene')
  9. Author = require('models/author')
  10. Collection = require('models/collection')
  11. Sponsor = require('models/sponsor')
  12. Site = require('models/site')
  13. class SceneForm extends Spine.Controller
  14. className: 'scene form panel'
  15. elements:
  16. '.item-title': 'itemTitle'
  17. '.error-message': 'errorMessage'
  18. 'form': 'form'
  19. 'select[name=site]': 'formSite'
  20. 'select[name=author_id]': 'formAuthorId'
  21. 'select[name=sponsor_id]': 'formSponsorId'
  22. 'input[name=title]': 'formTitle'
  23. 'input[name=published]': 'formPublished'
  24. 'textarea[name=body]': 'formBody'
  25. '.collections-list': 'collectionsList'
  26. '.upload-ui': 'fileUploadContainer'
  27. '.save-button': 'saveButton'
  28. '.cancel-button': 'cancelButton'
  29. 'button.fullscreen-button': 'fullscreenButton'
  30. events:
  31. 'submit form': 'preventSubmit'
  32. 'change *[name]': 'markAsDirty'
  33. 'keyup *[name]': 'markAsDirty'
  34. 'click .save-button': 'save'
  35. 'click .cancel-button': 'cancel'
  36. 'click .delete-button': 'destroy'
  37. 'change select[name=site]': 'siteChange'
  38. 'blur input[name=slug]': 'updateSlug'
  39. 'click .fullscreen-button': 'fullscreen'
  40. constructor: ->
  41. super
  42. @active @render
  43. render: (params) ->
  44. @dirtyForm = false
  45. @editing = params.id?
  46. if @editing
  47. @copying = params.id.split('-')[0] is 'copy'
  48. if @copying
  49. @title = 'Copy Scene'
  50. @item = Scene.find(params.id.split('-')[1]).dup()
  51. # Important to indicate that we are creating a new record
  52. @editing = false
  53. else
  54. @item = Scene.find(params.id)
  55. @title = @item.name
  56. # Fetch missing data if need be
  57. if not @item.body?
  58. @item.ajax().reload {},
  59. success: =>
  60. @formBody.val(@item.body)
  61. else
  62. @title = 'New Scene'
  63. @item = {}
  64. @item.collections ?= []
  65. @item._attachments ?= {}
  66. @item.sites = Site.all().sort(Site.alphaSort)
  67. @item.sponsors = Sponsor.all().sort(Sponsor.alphaSort)
  68. @html templates.render('scene-form.html', {}, @item)
  69. @itemTitle.html @title
  70. # Set few initial form values
  71. if @editing or @copying
  72. @formSite.val(@item.site)
  73. @formSponsorId.val(@item.sponsor_id)
  74. @formPublished.prop('checked', @item.published)
  75. else
  76. @formSite.val(@stack.stack.filterBox.siteId)
  77. # @formPublished.prop('checked', true)
  78. @siteChange()
  79. # Files upload area
  80. @fileUploadUI = new FileUploadUI
  81. docId: @item.id
  82. selectedFile: @item.photo
  83. attachments: @item._attachments
  84. changeCallback: @markAsDirty
  85. @fileUploadContainer.html @fileUploadUI.el
  86. return @
  87. siteChange: ->
  88. $siteSelected = @formSite.parents('.field').find('.site-selected')
  89. site = Site.exists(@formSite.val())
  90. if site
  91. $siteSelected.html "<div class=\"site-name theme-#{site.theme}\">#{site.name_html}</div>"
  92. @makeAuthorsList(site)
  93. @makeCollectionsList(site)
  94. else
  95. $siteSelected.html ""
  96. makeAuthorsList: (site) ->
  97. authors = Author.findAllByAttribute('site', site.id).sort(Author.alphaSort)
  98. @formAuthorId.empty()
  99. .append "<option value=\"\">Select an author...</option>"
  100. for author in authors
  101. @formAuthorId.append "<option value=\"#{author.id}\">#{author.name}</option>"
  102. @formAuthorId.val(@item.author_id)
  103. makeCollectionsList: (site) ->
  104. collections = Collection.findAllByAttribute('site', site.id).sort(Collection.alphaSort)
  105. @collectionSelectUI = new MultiSelectUI
  106. items: collections
  107. selectedItems: (c.id for c in @item.collections)
  108. valueFields: ['id','slug']
  109. changeCallback: @markAsDirty
  110. @collectionsList.html @collectionSelectUI.el
  111. updateSlug: (e) =>
  112. slug = $(e.currentTarget)
  113. unless slug.val()
  114. slug.val utils.cleanSlug(@formTitle.val())
  115. fullscreen: (e) =>
  116. e?.preventDefault()
  117. @fullscreenButtonText ?= @fullscreenButton.html()
  118. if @form.hasClass('fullscreen')
  119. @form.removeClass('fullscreen')
  120. @fullscreenButton.html @fullscreenButtonText
  121. @previewUI?.close()
  122. else
  123. @form.addClass('fullscreen')
  124. @fullscreenButton.html "Exit #{@fullscreenButtonText}"
  125. @previewUI = new PreviewUI field: @formBody
  126. save: (e) ->
  127. e.preventDefault()
  128. if not navigator.onLine
  129. alert "Can not save. You are OFFLINE."
  130. return
  131. if @editing
  132. @item.fromForm(@form)
  133. else
  134. @item = new Scene().fromForm(@form)
  135. @item.collections = @collectionSelectUI.selected()
  136. @item._attachments = @fileUploadUI.attachments
  137. # Take care of some boolean checkboxes
  138. @item.published = @formPublished.is(':checked')
  139. # Save the item and make sure it validates
  140. if @item.save()
  141. @back()
  142. else
  143. msg = @item.validate()
  144. @showError msg
  145. return @
  146. showError: (msg) ->
  147. @errorMessage.html(msg).show()
  148. @el.scrollTop(0)
  149. destroy: (e) ->
  150. e.preventDefault()
  151. if @item and confirm "Are you sure you want to delete this item?"
  152. @item.destroy()
  153. @back()
  154. markAsDirty: =>
  155. @dirtyForm = true
  156. @saveButton.addClass('glow')
  157. cancel: (e) ->
  158. e.preventDefault()
  159. if @dirtyForm
  160. if confirm "You may have some unsaved changes.\nAre you sure you want to proceed?"
  161. @back()
  162. else
  163. @back()
  164. back: ->
  165. @navigate('/scenes/list')
  166. preventSubmit: (e) ->
  167. e.preventDefault()
  168. return false
  169. deactivate: ->
  170. @el.scrollTop(0)
  171. super
  172. class SceneList extends Spine.Controller
  173. className: 'scene list panel fixed-header'
  174. events:
  175. 'click h1 .count': 'reload'
  176. constructor: ->
  177. super
  178. # @active @render
  179. Scene.bind 'change refresh', @render
  180. Spine.bind 'filterbox:change', @filter
  181. render: =>
  182. sortFunc = if @filterObj?.sortBy then Scene[@filterObj.sortBy] else Scene.dateSort
  183. context =
  184. scenes: Scene.filter(@filterObj).sort(sortFunc)
  185. @html templates.render('scenes.html', {}, context)
  186. filter: (@filterObj) =>
  187. @render()
  188. @el.scrollTop(0)
  189. reload: ->
  190. Scene.fetch()
  191. class Scenes extends Spine.Stack
  192. className: 'scenes panel'
  193. controllers:
  194. list: SceneList
  195. form: SceneForm
  196. default: 'list'
  197. routes:
  198. '/scenes/list': 'list'
  199. '/scene/new': 'form'
  200. '/scene/:id': 'form'
  201. constructor: ->
  202. super
  203. for k, v of @controllers
  204. @[k].active => @active()
  205. module.exports = Scenes