marionette.modal 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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