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.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/Gemfile +4 -0
- data/Gruntfile.coffee +111 -0
- data/LICENSE +22 -0
- data/README.md +42 -0
- data/Rakefile +1 -0
- data/dist/backbone.marionette.modals-min.js +1 -0
- data/dist/backbone.marionette.modals.js +104 -0
- data/dist/backbone.modal-min.js +1 -0
- data/dist/backbone.modal.js +382 -0
- data/dist/marionette.modal-bundled-min.js +1 -0
- data/dist/marionette.modal-bundled.js +858 -0
- data/dist/marionette.modal-min.js +1 -0
- data/dist/marionette.modal.css +24 -0
- data/dist/marionette.modal.js +370 -0
- data/dist/marionette.modal.theme.css +324 -0
- data/examples/1_single_view.html +71 -0
- data/examples/2_tab_based.html +104 -0
- data/examples/3_stacked_modal_with_marionette.html +105 -0
- data/examples/4_wizard.html +132 -0
- data/examples/css/style.css +45 -0
- data/examples/img/tab-icons.png +0 -0
- data/examples/style.css +35 -0
- data/examples/vendor/backbone.js +1591 -0
- data/examples/vendor/backbone.marionette.modals.js +104 -0
- data/examples/vendor/backbone.modal.css +24 -0
- data/examples/vendor/backbone.modal.js +382 -0
- data/examples/vendor/backbone.modal.theme.css +324 -0
- data/examples/vendor/jquery-1.9.1.js +9597 -0
- data/examples/vendor/marionette.js +2466 -0
- data/examples/vendor/marionette.modal.css +24 -0
- data/examples/vendor/marionette.modal.js +370 -0
- data/examples/vendor/marionette.modal.theme.css +324 -0
- data/examples/vendor/underscore.js +1314 -0
- data/lib/marionette-modal/version.rb +3 -0
- data/lib/marionette-modal.rb +22 -0
- data/marionette-modal.gemspec +23 -0
- data/package.json +19 -0
- data/src/backbone.marionette.modals.coffee +67 -0
- data/src/backbone.modal.coffee +253 -0
- data/src/marionette.modal.coffee +248 -0
- data/src/marionette.modal.sass +26 -0
- data/src/marionette.modal.theme.sass +486 -0
- data/src/style.sass +48 -0
- data/test/spec/backbone.marionette.modals.spec.js +120 -0
- data/test/spec/backbone.modal.spec.js +224 -0
- data/test/spec.html +41 -0
- data/test/src/backbone.marionette.modals.spec.coffee +56 -0
- data/test/src/backbone.modal.spec.coffee +139 -0
- metadata +128 -0
@@ -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
|