marionette.modal 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/Gemfile +4 -0
  4. data/Gruntfile.coffee +109 -0
  5. data/LICENSE +22 -0
  6. data/README.md +42 -0
  7. data/Rakefile +1 -0
  8. data/backbone.marionette.modals-min.js +1 -0
  9. data/backbone.marionette.modals.js +104 -0
  10. data/backbone.modal-min.js +1 -0
  11. data/backbone.modal.js +382 -0
  12. data/examples/1_single_view.html +71 -0
  13. data/examples/2_tab_based.html +104 -0
  14. data/examples/3_stacked_modal_with_marionette.html +105 -0
  15. data/examples/4_wizard.html +132 -0
  16. data/examples/css/style.css +45 -0
  17. data/examples/img/tab-icons.png +0 -0
  18. data/examples/style.css +35 -0
  19. data/examples/vendor/backbone.js +1571 -0
  20. data/examples/vendor/backbone.marionette.modals.js +104 -0
  21. data/examples/vendor/backbone.modal.css +24 -0
  22. data/examples/vendor/backbone.modal.js +382 -0
  23. data/examples/vendor/backbone.modal.theme.css +324 -0
  24. data/examples/vendor/jquery-1.9.1.js +9597 -0
  25. data/examples/vendor/marionette.js +2340 -0
  26. data/examples/vendor/marionette.modal.css +24 -0
  27. data/examples/vendor/marionette.modal.js +370 -0
  28. data/examples/vendor/marionette.modal.theme.css +324 -0
  29. data/examples/vendor/underscore.js +1227 -0
  30. data/lib/marionette.modal/version.rb +3 -0
  31. data/lib/marionette.modal.rb +5 -0
  32. data/marionette.modal-bundled-min.js +1 -0
  33. data/marionette.modal-bundled.js +858 -0
  34. data/marionette.modal-min.js +1 -0
  35. data/marionette.modal.css +24 -0
  36. data/marionette.modal.gemspec +23 -0
  37. data/marionette.modal.js +370 -0
  38. data/marionette.modal.theme.css +324 -0
  39. data/package.json +18 -0
  40. data/src/backbone.marionette.modals.coffee +67 -0
  41. data/src/backbone.modal.coffee +253 -0
  42. data/src/marionette.modal.coffee +248 -0
  43. data/src/marionette.modal.sass +26 -0
  44. data/src/marionette.modal.theme.sass +486 -0
  45. data/src/style.sass +48 -0
  46. data/test/spec/backbone.marionette.modals.spec.js +87 -0
  47. data/test/spec/backbone.modal.spec.js +224 -0
  48. data/test/spec.html +41 -0
  49. data/test/src/backbone.marionette.modals.spec.coffee +47 -0
  50. data/test/src/backbone.modal.spec.coffee +139 -0
  51. metadata +128 -0
@@ -0,0 +1,248 @@
1
+ unless Marionette?
2
+ throw new Error("Marionette is not defined. Please include the latest version from https://github.com/marionettejs/backbone.marionette")
3
+
4
+ class Backbone.Modal extends Marionette.View
5
+ prefix: 'bbm'
6
+
7
+ constructor: ->
8
+ @args = Array::slice.apply(arguments)
9
+ Marionette.View::constructor.apply(this, @args)
10
+
11
+ @setUIElements()
12
+ @delegateModalEvents()
13
+
14
+ render: (options = {}) ->
15
+ # use openAt or overwrite this with your own functionality
16
+ data = @serializeData()
17
+
18
+ @$el.addClass("#{@prefix}-wrapper")
19
+ @modalEl = Marionette.$('<div />').addClass("#{@prefix}-modal")
20
+ @modalEl.html @template(data) if @template
21
+ @$el.html @modalEl
22
+
23
+ # global events for key and click outside the modal
24
+ Marionette.$('body').on 'keyup', @checkKey
25
+ Marionette.$('body').on 'click', @clickOutside
26
+
27
+ if @viewContainer
28
+ @viewContainerEl = @modalEl.find(@viewContainer)
29
+ @viewContainerEl.addClass("#{@prefix}-modal__views")
30
+ else
31
+ @viewContainerEl = @modalEl
32
+
33
+ @$el.show()
34
+ @openAt(0) if @views?.length > 0
35
+ @onRender?()
36
+
37
+ @modalEl.css(opacity: 0)
38
+ @$el.fadeIn
39
+ duration: 100
40
+ complete: =>
41
+ @modalEl.css(opacity: 1).addClass("#{@prefix}-modal--open")
42
+
43
+ return this
44
+
45
+ setUIElements: ->
46
+ # get modal options
47
+ @template = Marionette.getOption(this, 'template')
48
+ @views = Marionette.getOption(this, 'views')
49
+ @views?.length = _.size(@views)
50
+ @viewContainer = Marionette.getOption(this, 'viewContainer')
51
+
52
+ # hide modal
53
+ @$el.hide()
54
+
55
+ throw new Error('No template or views defined for Backbone.Modal') if _.isUndefined(@template) and _.isUndefined(@views)
56
+ throw new Error('No viewContainer defined for Backbone.Modal') if @template and @views and _.isUndefined(@viewContainer)
57
+
58
+ serializeData: ->
59
+ # return the appropriate data for this view
60
+ data = {}
61
+
62
+ data = _.extend(data, @model.toJSON()) if @model
63
+ data = _.extend(data, {items: @collection.toJSON()}) if @collection
64
+
65
+ return data
66
+
67
+ delegateModalEvents: ->
68
+ @active = true
69
+
70
+ # get elements
71
+ cancelEl = Marionette.getOption(this, 'cancelEl')
72
+ submitEl = Marionette.getOption(this, 'submitEl')
73
+
74
+ # set event handlers for submit and cancel
75
+ @$el.on('click', submitEl, @triggerSubmit) if submitEl
76
+ @$el.on('click', cancelEl, @triggerCancel) if cancelEl
77
+
78
+ # set event handlers for views
79
+ for key of @views
80
+ unless key is 'length'
81
+ match = key.match(/^(\S+)\s*(.*)$/)
82
+ trigger = match[1]
83
+ selector = match[2]
84
+
85
+ @$el.on trigger, selector, @views[key], @triggerView
86
+
87
+ undelegateModalEvents: ->
88
+ @active = false
89
+
90
+ # get elements
91
+ cancelEl = @getOption('cancelEl')
92
+ submitEl = @getOption('submitEl')
93
+
94
+ # remove event handlers for submit and cancel
95
+ @$el.off('click', submitEl, @triggerSubmit) if submitEl
96
+ @$el.off('click', cancelEl, @triggerCancel) if cancelEl
97
+
98
+ # remove event handlers for views
99
+ for key of @views
100
+ unless key is 'length'
101
+ match = key.match(/^(\S+)\s*(.*)$/)
102
+ trigger = match[1]
103
+ selector = match[2]
104
+
105
+ @$el.off trigger, selector, @views[key], @triggerView
106
+
107
+ checkKey: (e) =>
108
+ if @active
109
+ switch e.keyCode
110
+ when 27 then @triggerCancel()
111
+ when 13 then @triggerSubmit()
112
+
113
+ clickOutside: (e) =>
114
+ @triggerCancel(null, true) if Marionette.$(e.target).hasClass("#{@prefix}-wrapper") and @active
115
+
116
+ buildView: (viewType) ->
117
+ # returns a Backbone.View instance, a function or an object
118
+ return unless viewType
119
+ if _.isFunction(viewType)
120
+ view = new viewType(@args[0])
121
+
122
+ if view instanceof Backbone.View
123
+ return {el: view.render().$el, view: view}
124
+ else
125
+ return {el: viewType(@args[0])}
126
+
127
+ return {view: viewType, el: viewType.$el}
128
+
129
+ triggerView: (e) =>
130
+ # trigger what view should be rendered
131
+ e?.preventDefault?()
132
+ options = e.data
133
+ instance = @buildView(options.view)
134
+
135
+ @previousView = @currentView if @currentView
136
+ @currentView = instance.view || instance.el
137
+
138
+ index = 0
139
+ for key of @views
140
+ @currentIndex = index if options.view is @views[key].view
141
+ index++
142
+
143
+ if options.onActive
144
+ if _.isFunction(options.onActive)
145
+ options.onActive(this)
146
+ else if _.isString(options.onActive)
147
+ this[options.onActive].call(this, options)
148
+
149
+ if @shouldAnimate
150
+ @animateToView(instance.el)
151
+ else
152
+ @shouldAnimate = true
153
+ @$(@viewContainerEl).html instance.el
154
+
155
+ animateToView: (view) ->
156
+ style = position: 'relative', top: -9999, left: -9999
157
+ tester = Marionette.$('<tester/>').css(style)
158
+ tester.html @$el.clone().css(style)
159
+ if Marionette.$('tester').length isnt 0 then Marionette.$('tester').replaceWith tester else Marionette.$('body').append tester
160
+
161
+ if @viewContainer
162
+ container = tester.find(@viewContainer)
163
+ else
164
+ container = tester.find(".#{@prefix}-modal")
165
+
166
+ container.removeAttr('style')
167
+
168
+ previousHeight = container.outerHeight()
169
+ container.html(view)
170
+ newHeight = container.outerHeight()
171
+
172
+ if previousHeight is newHeight
173
+ @$(@viewContainerEl).html view
174
+ @previousView?.close?()
175
+ else
176
+ @$(@viewContainerEl).css(opacity: 0)
177
+
178
+ @$(@viewContainerEl).animate {height: newHeight}, 100, =>
179
+ @$(@viewContainerEl).css(opacity: 1).removeAttr('style')
180
+ @$(@viewContainerEl).html view
181
+ @previousView?.close?()
182
+
183
+ # jQuery style event handler
184
+ triggerSubmit: (e) =>
185
+ return unless e
186
+ # triggers submit
187
+ e?.preventDefault()
188
+
189
+ if @beforeSubmit
190
+ return if @beforeSubmit() is false
191
+
192
+ @submit?()
193
+
194
+ if @regionEnabled
195
+ @trigger('modal:close')
196
+ else
197
+ @close()
198
+
199
+ # jQuery style event handler
200
+ triggerCancel: (e) =>
201
+ # triggers cancel
202
+ e?.preventDefault()
203
+
204
+ if @beforeCancel
205
+ return if @beforeCancel() is false
206
+
207
+ @cancel?()
208
+
209
+ if @regionEnabled
210
+ @triggerMethod 'modal:close'
211
+ else
212
+ @close()
213
+
214
+ close: ->
215
+ # closes view
216
+ Marionette.$('body').off 'keyup', @checkKey
217
+ Marionette.$('body').off 'click', @clickOutside
218
+
219
+ @onClose?()
220
+
221
+ @shouldAnimate = false
222
+ @modalEl.addClass("#{@prefix}-modal--close")
223
+ @$el.fadeOut(duration: 200)
224
+
225
+ _.delay =>
226
+ @currentView?.remove?()
227
+ @remove()
228
+ , 200
229
+
230
+ openAt: (index) ->
231
+ # loop through views and trigger the index
232
+ i = 0
233
+ for key of @views
234
+ unless key is 'length'
235
+ view = @views[key] if i is index
236
+ i++
237
+
238
+ if view
239
+ @currentIndex = index
240
+ @triggerView(data: view)
241
+
242
+ return this
243
+
244
+ next: ->
245
+ @openAt(@currentIndex + 1) if @currentIndex + 1 < @views.length
246
+
247
+ previous: ->
248
+ @openAt(@currentIndex - 1) if @currentIndex - 1 < @views.length - 1
@@ -0,0 +1,26 @@
1
+ /* Modal positioning */
2
+ .bbm-wrapper
3
+ box-sizing: border-box
4
+ position: absolute
5
+ left: 0
6
+ top: 0
7
+ width: 100%
8
+ height: 100%
9
+ z-index: 100
10
+ padding: 50px 10px
11
+
12
+ *
13
+ box-sizing: border-box
14
+
15
+ overflow-x: auto
16
+ overflow-y: scroll
17
+
18
+ .bbm-modal
19
+ border-radius: 3px
20
+ margin: auto
21
+ width: auto
22
+ max-width: 550px
23
+
24
+ .bbm-views
25
+ width: 100%
26
+ box-sizing: border-box