marionette-modal 1.0.0.8

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 +111 -0
  5. data/LICENSE +22 -0
  6. data/README.md +42 -0
  7. data/Rakefile +1 -0
  8. data/dist/backbone.marionette.modals-min.js +1 -0
  9. data/dist/backbone.marionette.modals.js +104 -0
  10. data/dist/backbone.modal-min.js +1 -0
  11. data/dist/backbone.modal.js +382 -0
  12. data/dist/marionette.modal-bundled-min.js +1 -0
  13. data/dist/marionette.modal-bundled.js +858 -0
  14. data/dist/marionette.modal-min.js +1 -0
  15. data/dist/marionette.modal.css +24 -0
  16. data/dist/marionette.modal.js +370 -0
  17. data/dist/marionette.modal.theme.css +324 -0
  18. data/examples/1_single_view.html +71 -0
  19. data/examples/2_tab_based.html +104 -0
  20. data/examples/3_stacked_modal_with_marionette.html +105 -0
  21. data/examples/4_wizard.html +132 -0
  22. data/examples/css/style.css +45 -0
  23. data/examples/img/tab-icons.png +0 -0
  24. data/examples/style.css +35 -0
  25. data/examples/vendor/backbone.js +1591 -0
  26. data/examples/vendor/backbone.marionette.modals.js +104 -0
  27. data/examples/vendor/backbone.modal.css +24 -0
  28. data/examples/vendor/backbone.modal.js +382 -0
  29. data/examples/vendor/backbone.modal.theme.css +324 -0
  30. data/examples/vendor/jquery-1.9.1.js +9597 -0
  31. data/examples/vendor/marionette.js +2466 -0
  32. data/examples/vendor/marionette.modal.css +24 -0
  33. data/examples/vendor/marionette.modal.js +370 -0
  34. data/examples/vendor/marionette.modal.theme.css +324 -0
  35. data/examples/vendor/underscore.js +1314 -0
  36. data/lib/marionette-modal/version.rb +3 -0
  37. data/lib/marionette-modal.rb +22 -0
  38. data/marionette-modal.gemspec +23 -0
  39. data/package.json +19 -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 +120 -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 +56 -0
  50. data/test/src/backbone.modal.spec.coffee +139 -0
  51. metadata +128 -0
@@ -0,0 +1,3 @@
1
+ module MarionetteModal
2
+ VERSION = "1.0.0.8"
3
+ end
@@ -0,0 +1,22 @@
1
+ require "marionette-modal/version"
2
+
3
+ module MarionetteModal
4
+ module Assets
5
+ module Javascripts
6
+ module Marionette
7
+ FILE = File.open( File.expand_path('../dist/marionette.modal.js', File.dirname(__FILE__) ), 'r').read
8
+ REGION_FILE = File.open( File.expand_path('../dist/backbone.marionette.modals.js', File.dirname(__FILE__) ), 'r').read
9
+ end
10
+ module Backbone
11
+ FILE = File.open( File.expand_path('../dist/backbone.modal.js', File.dirname(__FILE__) ), 'r').read
12
+ end
13
+ module Bundle
14
+ FILE = File.open( File.expand_path('../dist/marionette.modal-bundled.js', File.dirname(__FILE__) ), 'r').read
15
+ end
16
+ end
17
+ module Stylesheets
18
+ CSS = File.open( File.expand_path('../dist/marionette.modal.css', File.dirname(__FILE__) ), 'r').read
19
+ THEME_CSS = File.open( File.expand_path('../dist/marionette.modal.theme.css', File.dirname(__FILE__) ), 'r').read
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'marionette-modal/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "marionette-modal"
8
+ spec.version = MarionetteModal::VERSION
9
+ spec.authors = ["Jared Smith"]
10
+ spec.email = ["jcsmith1859@gmail.com"]
11
+ spec.description = "Fork of Backbone.Modal Backbone.js plugin"
12
+ spec.summary = "Fork of the Backbone.Modal Backbone.js plugin that is more tightly integrated with Marionette.js"
13
+ spec.homepage = "https://github.com/Outcome-Engenuity/marionette-modal"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
data/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "Marionette.Modal",
3
+ "version": "1.0.0",
4
+ "description": "A plugin for Backbone.js that simplifies creating modals for your application.",
5
+ "devDependencies": {
6
+ "grunt": "~0.4.1",
7
+ "grunt-contrib-coffee": "~0.6.4",
8
+ "grunt-contrib-clean": "~0.5.0",
9
+ "grunt-regarde": "0.1.x",
10
+ "grunt-contrib-livereload": "0.1.x",
11
+ "grunt-contrib-jasmine": "~0.4.1",
12
+ "grunt-contrib-connect": "~0.2.0",
13
+ "grunt-open": "~0.2.0",
14
+ "grunt-contrib-uglify": "~0.2.0",
15
+ "grunt-contrib-sass": "~0.3.0",
16
+ "grunt-concurrent": "~0.2.0"
17
+ },
18
+ "author": "jcsmith1859"
19
+ }
@@ -0,0 +1,67 @@
1
+ unless Backbone?
2
+ throw new Error("Backbone is not defined. Please include the latest version from http://documentcloud.github.com/backbone/backbone.js")
3
+
4
+ class Backbone.Marionette.Modals extends Backbone.Marionette.Region
5
+ modals: []
6
+ zIndex: 0
7
+
8
+ show: (modal, options = {}) ->
9
+ @ensureEl()
10
+
11
+ if @modals.length > 0
12
+ lastModal = _.last(@modals)
13
+ lastModal.modalEl.addClass("#{lastModal.prefix}-modal--stacked")
14
+ secondLastModal = @modals[@modals.length-1]
15
+ secondLastModal?.modalEl.removeClass("#{secondLastModal.prefix}-modal--stacked-reverse")
16
+
17
+ modal.render()
18
+ modal.regionEnabled = true
19
+
20
+ @$el.show()
21
+ @$el.append modal.el
22
+
23
+ modal.$el.css(background: 'none') if @modals.length > 0
24
+
25
+ Marionette.triggerMethod.call(modal, "show")
26
+ Marionette.triggerMethod.call(this, "show", modal)
27
+
28
+ @currentView = modal
29
+
30
+ m.undelegateModalEvents() for m in @modals
31
+
32
+ modal.on('modal:close', @close)
33
+
34
+ @modals.push(modal)
35
+ @zIndex++
36
+
37
+ close: =>
38
+ modal = @currentView
39
+ return if !modal or modal.isClosed
40
+
41
+ if modal.close
42
+ modal.close()
43
+ else if modal.remove
44
+ modal.remove()
45
+
46
+ modal.off('modal:close', @close)
47
+
48
+ @modals.splice(_.indexOf(@modals, modal), 1)
49
+
50
+ @zIndex--
51
+
52
+ @currentView = @modals[@zIndex-1]
53
+
54
+ lastModal = _.last(@modals)
55
+
56
+ if lastModal
57
+ lastModal.modalEl.addClass("#{lastModal.prefix}-modal--stacked-reverse")
58
+ _.delay =>
59
+ lastModal.modalEl.removeClass("#{lastModal.prefix}-modal--stacked")
60
+ , 300
61
+
62
+ lastModal.delegateModalEvents() if @zIndex isnt 0
63
+
64
+ Marionette.triggerMethod.call(this, "close")
65
+
66
+ closeAll: ->
67
+ @close() for modal in @modals
@@ -0,0 +1,253 @@
1
+ unless Backbone?
2
+ throw new Error("Backbone is not defined. Please include the latest version from http://documentcloud.github.com/backbone/backbone.js")
3
+
4
+ class Backbone.Modal extends Backbone.View
5
+ prefix: 'bbm'
6
+ constructor: ->
7
+ @args = Array::slice.apply(arguments)
8
+ Backbone.View::constructor.apply(this, @args)
9
+
10
+ @setUIElements()
11
+ @delegateModalEvents()
12
+
13
+ render: (options = {}) ->
14
+ # use openAt or overwrite this with your own functionality
15
+ data = @serializeData()
16
+
17
+ @$el.addClass("#{@prefix}-wrapper")
18
+ @modalEl = Backbone.$('<div />').addClass("#{@prefix}-modal")
19
+ @modalEl.html @template(data) if @template
20
+ @$el.html @modalEl
21
+
22
+ # global events for key and click outside the modal
23
+ Backbone.$('body').on 'keyup', @checkKey
24
+ Backbone.$('body').on 'click', @clickOutside
25
+
26
+ if @viewContainer
27
+ @viewContainerEl = @modalEl.find(@viewContainer)
28
+ @viewContainerEl.addClass("#{@prefix}-modal__views")
29
+ else
30
+ @viewContainerEl = @modalEl
31
+
32
+ @$el.show()
33
+ @openAt(0) if @views?.length > 0
34
+ @onRender?()
35
+
36
+ @modalEl.css(opacity: 0)
37
+ @$el.fadeIn
38
+ duration: 100
39
+ complete: =>
40
+ @modalEl.css(opacity: 1).addClass("#{@prefix}-modal--open")
41
+
42
+ return this
43
+
44
+ setUIElements: ->
45
+ # get modal options
46
+ @template = @getOption('template')
47
+ @views = @getOption('views')
48
+ @views?.length = _.size(@views)
49
+ @viewContainer = @getOption('viewContainer')
50
+
51
+ # hide modal
52
+ @$el.hide()
53
+
54
+ throw new Error('No template or views defined for Backbone.Modal') if _.isUndefined(@template) and _.isUndefined(@views)
55
+ throw new Error('No viewContainer defined for Backbone.Modal') if @template and @views and _.isUndefined(@viewContainer)
56
+
57
+ getOption: (option) ->
58
+ # get class instance property
59
+ return unless option
60
+ if @options and option in @options and @options[option]?
61
+ return @options[option]
62
+ else
63
+ return @[option]
64
+
65
+ serializeData: ->
66
+ # return the appropriate data for this view
67
+ data = {}
68
+
69
+ data = _.extend(data, @model.toJSON()) if @model
70
+ data = _.extend(data, {items: @collection.toJSON()}) if @collection
71
+
72
+ return data
73
+
74
+ delegateModalEvents: ->
75
+ @active = true
76
+
77
+ # get elements
78
+ cancelEl = @getOption('cancelEl')
79
+ submitEl = @getOption('submitEl')
80
+
81
+ # set event handlers for submit and cancel
82
+ @$el.on('click', submitEl, @triggerSubmit) if submitEl
83
+ @$el.on('click', cancelEl, @triggerCancel) if cancelEl
84
+
85
+ # set event handlers for views
86
+ for key of @views
87
+ unless key is 'length'
88
+ match = key.match(/^(\S+)\s*(.*)$/)
89
+ trigger = match[1]
90
+ selector = match[2]
91
+
92
+ @$el.on trigger, selector, @views[key], @triggerView
93
+
94
+ undelegateModalEvents: ->
95
+ @active = false
96
+
97
+ # get elements
98
+ cancelEl = @getOption('cancelEl')
99
+ submitEl = @getOption('submitEl')
100
+
101
+ # remove event handlers for submit and cancel
102
+ @$el.off('click', submitEl, @triggerSubmit) if submitEl
103
+ @$el.off('click', cancelEl, @triggerCancel) if cancelEl
104
+
105
+ # remove event handlers for views
106
+ for key of @views
107
+ unless key is 'length'
108
+ match = key.match(/^(\S+)\s*(.*)$/)
109
+ trigger = match[1]
110
+ selector = match[2]
111
+
112
+ @$el.off trigger, selector, @views[key], @triggerView
113
+
114
+ checkKey: (e) =>
115
+ if @active
116
+ switch e.keyCode
117
+ when 27 then @triggerCancel()
118
+ when 13 then @triggerSubmit()
119
+
120
+ clickOutside: (e) =>
121
+ @triggerCancel(null, true) if Backbone.$(e.target).hasClass("#{@prefix}-wrapper") and @active
122
+
123
+ buildView: (viewType) ->
124
+ # returns a Backbone.View instance, a function or an object
125
+ return unless viewType
126
+ if _.isFunction(viewType)
127
+ view = new viewType(@args[0])
128
+
129
+ if view instanceof Backbone.View
130
+ return {el: view.render().$el, view: view}
131
+ else
132
+ return {el: viewType(@args[0])}
133
+
134
+ return {view: viewType, el: viewType.$el}
135
+
136
+ triggerView: (e) =>
137
+ # trigger what view should be rendered
138
+ e?.preventDefault?()
139
+ options = e.data
140
+ instance = @buildView(options.view)
141
+
142
+ @previousView = @currentView if @currentView
143
+ @currentView = instance.view || instance.el
144
+
145
+ index = 0
146
+ for key of @views
147
+ @currentIndex = index if options.view is @views[key].view
148
+ index++
149
+
150
+ if options.onActive
151
+ if _.isFunction(options.onActive)
152
+ options.onActive(this)
153
+ else if _.isString(options.onActive)
154
+ this[options.onActive].call(this, options)
155
+
156
+ if @shouldAnimate
157
+ @animateToView(instance.el)
158
+ else
159
+ @shouldAnimate = true
160
+ @$(@viewContainerEl).html instance.el
161
+
162
+ animateToView: (view) ->
163
+ style = position: 'relative', top: -9999, left: -9999
164
+ tester = Backbone.$('<tester/>').css(style)
165
+ tester.html @$el.clone().css(style)
166
+ if Backbone.$('tester').length isnt 0 then Backbone.$('tester').replaceWith tester else Backbone.$('body').append tester
167
+
168
+ if @viewContainer
169
+ container = tester.find(@viewContainer)
170
+ else
171
+ container = tester.find(".#{@prefix}-modal")
172
+
173
+ container.removeAttr('style')
174
+
175
+ previousHeight = container.outerHeight()
176
+ container.html(view)
177
+ newHeight = container.outerHeight()
178
+
179
+ if previousHeight is newHeight
180
+ @$(@viewContainerEl).html view
181
+ @previousView?.close?()
182
+ else
183
+ @$(@viewContainerEl).css(opacity: 0)
184
+
185
+ @$(@viewContainerEl).animate {height: newHeight}, 100, =>
186
+ @$(@viewContainerEl).css(opacity: 1).removeAttr('style')
187
+ @$(@viewContainerEl).html view
188
+ @previousView?.close?()
189
+
190
+ triggerSubmit: (e) =>
191
+ return unless e
192
+ # triggers submit
193
+ e?.preventDefault()
194
+
195
+ if @beforeSubmit
196
+ return if @beforeSubmit() is false
197
+
198
+ @submit?()
199
+
200
+ if @regionEnabled
201
+ @trigger('modal:close')
202
+ else
203
+ @close()
204
+
205
+ triggerCancel: (e) =>
206
+ # triggers cancel
207
+ e?.preventDefault()
208
+
209
+ if @beforeCancel
210
+ return if @beforeCancel() is false
211
+
212
+ @cancel?()
213
+
214
+ if @regionEnabled
215
+ @trigger('modal:close')
216
+ else
217
+ @close()
218
+
219
+ close: ->
220
+ # closes view
221
+ Backbone.$('body').off 'keyup', @checkKey
222
+ Backbone.$('body').off 'click', @clickOutside
223
+
224
+ @onClose?()
225
+
226
+ @shouldAnimate = false
227
+ @modalEl.addClass("#{@prefix}-modal--close")
228
+ @$el.fadeOut(duration: 200)
229
+
230
+ _.delay =>
231
+ @currentView?.remove?()
232
+ @remove()
233
+ , 200
234
+
235
+ openAt: (index) ->
236
+ # loop through views and trigger the index
237
+ i = 0
238
+ for key of @views
239
+ unless key is 'length'
240
+ view = @views[key] if i is index
241
+ i++
242
+
243
+ if view
244
+ @currentIndex = index
245
+ @triggerView(data: view)
246
+
247
+ return this
248
+
249
+ next: ->
250
+ @openAt(@currentIndex+1) if @currentIndex+1 < @views.length
251
+
252
+ previous: ->
253
+ @openAt(@currentIndex-1) if @currentIndex-1 < @views.length-1
@@ -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 Marionette.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