ChangeListView.coffee 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. define [
  2. "moment"
  3. "libs/mustache"
  4. "libs/backbone"
  5. ], (moment)->
  6. moment.lang "en", calendar:
  7. lastDay : '[Yesterday at] h:mm a'
  8. sameDay : '[Today at] h:mm a'
  9. nextDay : '[Tomorrow at] h:mm a'
  10. lastWeek : "Do MMM YYYY, h:mm a"
  11. nextWeek : "Do MMM YYYY, h:mm a"
  12. sameElse : 'Do MMM YYYY, h:mm a'
  13. ChangeListView = Backbone.View.extend
  14. template: $("#changeListTemplate").html()
  15. events:
  16. "scroll" : () -> @loadUntilFull()
  17. initialize: () ->
  18. @itemViews = []
  19. @atEndOfCollection = false
  20. self = this
  21. @collection.on "add", (model) ->
  22. self.addItem model
  23. @collection.on "reset", (collection) ->
  24. self.addItem model for model in collection.models
  25. @selectedFromIndex = 0
  26. @selectedToIndex = 0
  27. @render()
  28. @hideLoading()
  29. render: ->
  30. @$el.html Mustache.to_html @template
  31. @$el.css
  32. overflow: "scroll"
  33. this
  34. addItem: (model) ->
  35. index = @collection.indexOf(model)
  36. view = new ChangeListItemView(model : model)
  37. @itemViews.push view
  38. elementAtIndex = @$(".change-list").children()[index]
  39. view.$el.insertBefore(elementAtIndex)
  40. view.on "click", (e, v) =>
  41. if e.shiftKey
  42. @selectRangeTo(index)
  43. else
  44. @setSelectionRange(index, index)
  45. view.on "selected:to", (e, v) =>
  46. @setSelectionRange(@selectedFromIndex, index)
  47. view.on "selected:from", (e, v) =>
  48. @setSelectionRange(index, @selectedToIndex)
  49. view.on "mouseenter:to", (e) =>
  50. @hoverToIndex = index
  51. @resetHoverStates()
  52. view.on "mouseleave:to", (e) =>
  53. delete @hoverToIndex
  54. @resetHoverStates()
  55. view.on "mouseenter:from", (e) =>
  56. @hoverFromIndex = index
  57. @resetHoverStates()
  58. view.on "mouseleave:from", (e) =>
  59. delete @hoverFromIndex
  60. @resetHoverStates()
  61. view.resetSelector(index, @selectedFromIndex, @selectedToIndex)
  62. setSelectionRange: (fromIndex, toIndex) ->
  63. @selectedFromIndex = fromIndex
  64. @selectedToIndex = toIndex
  65. @resetAllSelectors()
  66. @triggerChangeDiff()
  67. selectRangeTo: (index) ->
  68. return unless @selectedFromIndex? and @selectedToIndex?
  69. if index < @selectedToIndex
  70. @setSelectionRange(@selectedFromIndex, index)
  71. else
  72. @setSelectionRange(index, @selectedToIndex)
  73. resetAllSelectors: () ->
  74. for view, i in @itemViews
  75. view.resetSelector(i, @selectedFromIndex, @selectedToIndex)
  76. resetHoverStates: () ->
  77. if @hoverToIndex? and @hoverToIndex != @selectedToIndex
  78. @$("ul").addClass("hover-state")
  79. for view, i in @itemViews
  80. view.resetHoverState(i, @selectedFromIndex, @hoverToIndex)
  81. else if @hoverFromIndex? and @hoverFromIndex != @selectedFromIndex
  82. @$("ul").addClass("hover-state")
  83. for view, i in @itemViews
  84. view.resetHoverState(i, @hoverFromIndex, @selectedToIndex)
  85. else
  86. @$("ul").removeClass("hover-state")
  87. for view, i in @itemViews
  88. view.setHoverUnselected()
  89. triggerChangeDiff: () ->
  90. @trigger "change_diff", @selectedFromIndex, @selectedToIndex
  91. listShorterThanContainer: ->
  92. @$el.height() > @$(".change-list").height()
  93. atEndOfListView: ->
  94. @$el.scrollTop() + @$el.height() >= @$(".change-list").height() - 30
  95. loadUntilFull: (callback = (error) ->) ->
  96. if (@listShorterThanContainer() or @atEndOfListView()) and not @atEndOfCollection and not @loading
  97. @showLoading()
  98. @hideEmptyMessage()
  99. @collection.fetchNextBatch
  100. error: (error) =>
  101. @hideLoading()
  102. @showEmptyMessageIfCollectionEmpty()
  103. callback(error)
  104. success: (collection, response) =>
  105. @hideLoading()
  106. if @collection.isAtEnd()
  107. @atEndOfCollection = true
  108. @showEmptyMessageIfCollectionEmpty()
  109. callback()
  110. else
  111. @loadUntilFull(callback)
  112. else
  113. callback() if callback?
  114. showEmptyMessageIfCollectionEmpty: ()->
  115. if @collection.isEmpty()
  116. @$(".empty-message").show()
  117. else
  118. @$(".empty-message").hide()
  119. hideEmptyMessage: () ->
  120. @$(".empty-message").hide()
  121. showLoading: ->
  122. @loading = true
  123. @$(".loading-changes").show()
  124. hideLoading: ->
  125. @loading = false
  126. @$(".loading-changes").hide()
  127. ChangeListItemView = Backbone.View.extend
  128. tagName: "li"
  129. events:
  130. "click .change-description" : "onClick"
  131. "click .change-selector-from" : "onFromSelectorClick"
  132. "click .change-selector-to" : "onToSelectorClick"
  133. "mouseenter .change-selector-to": (args...) ->
  134. @trigger "mouseenter:to", args...
  135. "mouseleave .change-selector-to": (args...) ->
  136. @trigger "mouseleave:to", args...
  137. "mouseenter .change-selector-from": (args...) ->
  138. @trigger "mouseenter:from", args...
  139. "mouseleave .change-selector-from": (args...) ->
  140. @trigger "mouseleave:from", args...
  141. templates:
  142. item: $("#changeListItemTemplate").html()
  143. user: $("#changeListItemUserTemplate").html()
  144. initialize: ->
  145. @render()
  146. render: ->
  147. userHtml = for user in @model.get("users")
  148. Mustache.to_html @templates.user, {
  149. hue: user.hue()
  150. name: user.name()
  151. }
  152. docNames = []
  153. for doc in @model.get("docs")
  154. if doc.entity?
  155. docNames.push doc.entity.get("name")
  156. else
  157. docNames.push "deleted"
  158. data = {
  159. date: moment(parseInt(@model.get("end_ts"), 10)).calendar()
  160. users: userHtml.join("")
  161. docs: docNames.join(", ")
  162. }
  163. @$el.html Mustache.to_html(@templates.item, data)
  164. return this
  165. onClick: (e) ->
  166. e.preventDefault()
  167. @trigger "click", e, @
  168. onToSelectorClick: (e) ->
  169. @trigger "selected:to", e, @
  170. onFromSelectorClick: (e) ->
  171. @trigger "selected:from", e, @
  172. isSelectedFrom: () ->
  173. @$(".change-selector-from").is(":checked")
  174. isSelectedTo: () ->
  175. @$(".change-selector-to").is(":checked")
  176. hideFromSelector: () ->
  177. @$(".change-selector-from").hide()
  178. showFromSelector: () ->
  179. @$(".change-selector-from").show()
  180. hideToSelector: () ->
  181. @$(".change-selector-to").hide()
  182. showToSelector: () ->
  183. @$(".change-selector-to").show()
  184. setFromChecked: (checked) ->
  185. @$(".change-selector-from").prop("checked", checked)
  186. setToChecked: (checked) ->
  187. @$(".change-selector-to").prop("checked", checked)
  188. setSelected: (first, last) ->
  189. @$el.addClass("selected-change")
  190. if first
  191. @$el.addClass("selected-change-to")
  192. else
  193. @$el.removeClass("selected-change-to")
  194. if last
  195. @$el.addClass("selected-change-from")
  196. else
  197. @$el.removeClass("selected-change-from")
  198. setUnselected: () ->
  199. @$el.removeClass("selected-change-to")
  200. @$el.removeClass("selected-change-from")
  201. @$el.removeClass("selected-change")
  202. setHoverSelected: (first, last) ->
  203. @$el.addClass("hover-selected")
  204. if first
  205. @$el.addClass("hover-selected-to")
  206. else
  207. @$el.removeClass("hover-selected-to")
  208. if last
  209. @$el.addClass("hover-selected-from")
  210. else
  211. @$el.removeClass("hover-selected-from")
  212. setHoverUnselected: () ->
  213. @$el.removeClass("hover-selected-to")
  214. @$el.removeClass("hover-selected-from")
  215. @$el.removeClass("hover-selected")
  216. resetSelector: (myIndex, selectedFromIndex, selectedToIndex) ->
  217. if myIndex >= selectedToIndex
  218. @showFromSelector()
  219. else
  220. @hideFromSelector()
  221. if myIndex <= selectedFromIndex
  222. @showToSelector()
  223. else
  224. @hideToSelector()
  225. if selectedToIndex <= myIndex <= selectedFromIndex
  226. @setSelected(selectedToIndex == myIndex, selectedFromIndex == myIndex)
  227. else
  228. @setUnselected()
  229. @setFromChecked(myIndex == selectedFromIndex)
  230. @setToChecked(myIndex == selectedToIndex)
  231. resetHoverState: (myIndex, hoverFromIndex, hoverToIndex) ->
  232. if hoverToIndex <= myIndex <= hoverFromIndex
  233. @setHoverSelected(hoverToIndex == myIndex, hoverFromIndex == myIndex)
  234. else
  235. @setHoverUnselected()
  236. return ChangeListView