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,324 @@
1
+ .bbm-wrapper {
2
+ background: rgba(0, 0, 0, 0.75);
3
+ -webkit-transition: background-color 0.3s; }
4
+
5
+ .bbm-modal {
6
+ background: white;
7
+ box-shadow: 0 0px 6px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.9); }
8
+
9
+ /* BLOCKS */
10
+ .bbm-modal__topbar,
11
+ .bbm-modal__bottombar {
12
+ padding: 0 30px; }
13
+
14
+ .bbm-modal__topbar {
15
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
16
+ margin-bottom: 30px; }
17
+ .bbm-modal__topbar > ul {
18
+ list-style: none;
19
+ text-align: center;
20
+ padding: 0;
21
+ margin: 0; }
22
+
23
+ .bbm-modal__tab {
24
+ display: inline-block;
25
+ padding: 15px 10px; }
26
+ .bbm-modal__tab a {
27
+ font-size: 16px;
28
+ font-weight: bold;
29
+ color: #999999; }
30
+ .bbm-modal__tab a:hover, .bbm-modal__tab a.active {
31
+ color: #222222; }
32
+
33
+ .bbm-modal__title {
34
+ padding: 20px 0 19px;
35
+ margin: 0;
36
+ font-weight: normal;
37
+ font-size: 22px;
38
+ line-height: 1em;
39
+ color: #312d3a; }
40
+
41
+ .bbm-modal__section {
42
+ padding: 0 30px;
43
+ margin-top: 0px;
44
+ font-size: 16px;
45
+ line-height: 26px;
46
+ color: #575656; }
47
+ .bbm-modal__section p {
48
+ font-size: 16px;
49
+ line-height: 26px;
50
+ color: #575656; }
51
+ .bbm-modal__section p:last-child {
52
+ padding: 0;
53
+ margin-bottom: 0; }
54
+ .bbm-modal__section a {
55
+ color: #ff643c; }
56
+ .bbm-modal__section h3 {
57
+ margin: 0;
58
+ font-size: 20px;
59
+ line-height: 1em; }
60
+
61
+ .bbm-modal__bottombar {
62
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
63
+ padding: 18px;
64
+ text-align: right;
65
+ margin-top: 30px; }
66
+
67
+ /* MODULES */
68
+ .bbm-group {
69
+ content: "";
70
+ display: table;
71
+ clear: both; }
72
+
73
+ .bbm-button {
74
+ display: inline-block;
75
+ color: rgba(49, 45, 58, 0.8);
76
+ text-decoration: none;
77
+ font-size: 14px;
78
+ font-weight: 500;
79
+ position: relative;
80
+ line-height: 1em;
81
+ padding: 10px 14px;
82
+ border-radius: 3px;
83
+ background: #fcfcfc;
84
+ background-image: -o-linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.15) 100%);
85
+ background-image: -moz-linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.15) 100%);
86
+ background-image: -webkit-linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.15) 100%);
87
+ background-image: -ms-linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.15) 100%);
88
+ background-image: linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.15) 100%);
89
+ -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.1), inset 0px 0px 0px 1px rgba(0, 0, 0, 0.2);
90
+ -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.1), inset 0px 0px 0px 1px rgba(0, 0, 0, 0.2);
91
+ box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.1), inset 0px 0px 0px 1px rgba(0, 0, 0, 0.2); }
92
+ .bbm-button.inactive {
93
+ opacity: 0.5;
94
+ pointer-events: none; }
95
+ .bbm-button:active {
96
+ background-image: -o-linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.25) 100%);
97
+ background-image: -moz-linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.25) 100%);
98
+ background-image: -webkit-linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.25) 100%);
99
+ background-image: -ms-linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.25) 100%);
100
+ background-image: linear-gradient(rgba(70, 30, 170, 0) 0%, rgba(65, 61, 75, 0.25) 100%);
101
+ -moz-box-shadow: inset 0px 1px 2px 0px rgba(0, 0, 0, 0.5), inset 0px 0px 0px 1px rgba(0, 0, 0, 0.2);
102
+ -webkit-box-shadow: inset 0px 1px 2px 0px rgba(0, 0, 0, 0.5), inset 0px 0px 0px 1px rgba(0, 0, 0, 0.2);
103
+ box-shadow: inset 0px 1px 2px 0px rgba(0, 0, 0, 0.5), inset 0px 0px 0px 1px rgba(0, 0, 0, 0.2); }
104
+
105
+ /* ANIMATIONS */
106
+ /* Open modal */
107
+ @-webkit-keyframes bbm-open {
108
+ 0% {
109
+ -webkit-transform: matrix(0.99126, 0, 0, 0.99126, 0, 43.8813);
110
+ opacity: 0.1259; }
111
+
112
+ 4% {
113
+ -webkit-transform: matrix(0.99295, 0, 0, 0.99295, 0, 45.06809);
114
+ opacity: 0.29544; }
115
+
116
+ 8% {
117
+ -webkit-transform: matrix(0.99467, 0, 0, 0.99467, 0, 46.26922);
118
+ opacity: 0.46703; }
119
+
120
+ 12% {
121
+ -webkit-transform: matrix(0.99619, 0, 0, 0.99619, 0, 47.33355);
122
+ opacity: 0.61908; }
123
+
124
+ 16% {
125
+ -webkit-transform: matrix(0.99743, 0, 0, 0.99743, 0, 48.19991);
126
+ opacity: 0.74284; }
127
+
128
+ 20% {
129
+ -webkit-transform: matrix(0.99837, 0, 0, 0.99837, 0, 48.86067);
130
+ opacity: 0.83724; }
131
+
132
+ 24% {
133
+ -webkit-transform: matrix(0.99905, 0, 0, 0.99905, 0, 49.33658);
134
+ opacity: 0.90523; }
135
+
136
+ 28% {
137
+ -webkit-transform: matrix(0.99952, 0, 0, 0.99952, 0, 49.66049);
138
+ opacity: 0.9515; }
139
+
140
+ 32% {
141
+ -webkit-transform: matrix(0.99981, 0, 0, 0.99981, 0, 49.8675);
142
+ opacity: 0.98107; }
143
+
144
+ 36% {
145
+ -webkit-transform: matrix(0.99999, 0, 0, 0.99999, 0, 49.98966);
146
+ opacity: 0.99852; }
147
+
148
+ 40% {
149
+ -webkit-transform: matrix(1.00008, 0, 0, 1.00008, 0, 50.05361);
150
+ opacity: 1.00766; }
151
+
152
+ 44% {
153
+ -webkit-transform: matrix(1.00011, 0, 0, 1.00011, 0, 50.08);
154
+ opacity: 1.01143; }
155
+
156
+ 48% {
157
+ -webkit-transform: matrix(1.00012, 0, 0, 1.00012, 0, 50.08394);
158
+ opacity: 1.01199; }
159
+
160
+ 52% {
161
+ -webkit-transform: matrix(1.00011, 0, 0, 1.00011, 0, 50.07589);
162
+ opacity: 1.01084; }
163
+
164
+ 56% {
165
+ -webkit-transform: matrix(1.00009, 0, 0, 1.00009, 0, 50.06265);
166
+ opacity: 1.00895; }
167
+
168
+ 60% {
169
+ -webkit-transform: matrix(1.00007, 0, 0, 1.00007, 0, 50.04833);
170
+ opacity: 1.0069; }
171
+
172
+ 64% {
173
+ -webkit-transform: matrix(1.00005, 0, 0, 1.00005, 0, 50.03518);
174
+ opacity: 1.00503; }
175
+
176
+ 68% {
177
+ -webkit-transform: matrix(1.00004, 0, 0, 1.00004, 0, 50.02421);
178
+ opacity: 1.00346; }
179
+
180
+ 72% {
181
+ -webkit-transform: matrix(1.00002, 0, 0, 1.00002, 0, 50.01567);
182
+ opacity: 1.00224; }
183
+
184
+ 76% {
185
+ -webkit-transform: matrix(1.00001, 0, 0, 1.00001, 0, 50.00941);
186
+ opacity: 1.00134; }
187
+
188
+ 80% {
189
+ -webkit-transform: matrix(1.00001, 0, 0, 1.00001, 0, 50.00506);
190
+ opacity: 1.00072; }
191
+
192
+ 84% {
193
+ -webkit-transform: matrix(1, 0, 0, 1, 0, 50.00223);
194
+ opacity: 1.00032; }
195
+
196
+ 88% {
197
+ -webkit-transform: matrix(1, 0, 0, 1, 0, 50.0005);
198
+ opacity: 1.00007; }
199
+
200
+ 92% {
201
+ -webkit-transform: matrix(1, 0, 0, 1, 0, 49.99956);
202
+ opacity: 0.99994; }
203
+
204
+ 96% {
205
+ -webkit-transform: matrix(1, 0, 0, 1, 0, 49.99913);
206
+ opacity: 0.99988; }
207
+
208
+ 100% {
209
+ -webkit-transform: matrix(1, 0, 0, 1, 0, 50);
210
+ opacity: 1; } }
211
+
212
+ .bbm-modal--open {
213
+ -webkit-animation-duration: 0.3s;
214
+ -webkit-animation-name: bbm-open;
215
+ -webkit-animation-timing-function: linear;
216
+ -webkit-animation-fill-mode: both;
217
+ -webkit-transform-origin: 50% 50%;
218
+ -webkit-backface-visibility: hidden; }
219
+
220
+ /* Open a stacked modal */
221
+ @-webkit-keyframes bbm-stacked {
222
+ 0% {
223
+ -webkit-transform: matrix(0.99874, 0, 0, 0.99874, 0, 49.1187);
224
+ opacity: 0.93705; }
225
+
226
+ 4% {
227
+ -webkit-transform: matrix(0.99705, 0, 0, 0.99705, 0, 47.93192);
228
+ opacity: 0.85228; }
229
+
230
+ 8% {
231
+ -webkit-transform: matrix(0.99533, 0, 0, 0.99533, 0, 46.73078);
232
+ opacity: 0.76648; }
233
+
234
+ 12% {
235
+ -webkit-transform: matrix(0.99381, 0, 0, 0.99381, 0, 45.66645);
236
+ opacity: 0.69046; }
237
+
238
+ 16% {
239
+ -webkit-transform: matrix(0.99257, 0, 0, 0.99257, 0, 44.80009);
240
+ opacity: 0.62858; }
241
+
242
+ 20% {
243
+ -webkit-transform: matrix(0.99163, 0, 0, 0.99163, 0, 44.13933);
244
+ opacity: 0.58138; }
245
+
246
+ 24% {
247
+ -webkit-transform: matrix(0.99095, 0, 0, 0.99095, 0, 43.66342);
248
+ opacity: 0.54739; }
249
+
250
+ 28% {
251
+ -webkit-transform: matrix(0.99049, 0, 0, 0.99049, 0, 43.33951);
252
+ opacity: 0.52425; }
253
+
254
+ 32% {
255
+ -webkit-transform: matrix(0.99019, 0, 0, 0.99019, 0, 43.1325);
256
+ opacity: 0.50946; }
257
+
258
+ 36% {
259
+ -webkit-transform: matrix(0.99002, 0, 0, 0.99002, 0, 43.01034);
260
+ opacity: 0.50074; }
261
+
262
+ 40% {
263
+ -webkit-transform: matrix(0.98992, 0, 0, 0.98992, 0, 42.94639);
264
+ opacity: 0.49617; }
265
+
266
+ 44% {
267
+ -webkit-transform: matrix(0.98989, 0, 0, 0.98989, 0, 42.92001);
268
+ opacity: 0.49429; }
269
+
270
+ 48% {
271
+ -webkit-transform: matrix(0.98988, 0, 0, 0.98988, 0, 42.91606);
272
+ opacity: 0.494; }
273
+
274
+ 52% {
275
+ -webkit-transform: matrix(0.98989, 0, 0, 0.98989, 0, 42.92411);
276
+ opacity: 0.49458; }
277
+
278
+ 56% {
279
+ -webkit-transform: matrix(0.98991, 0, 0, 0.98991, 0, 42.93736);
280
+ opacity: 0.49553; }
281
+
282
+ 60% {
283
+ -webkit-transform: matrix(0.98993, 0, 0, 0.98993, 0, 42.95167);
284
+ opacity: 0.49655; }
285
+
286
+ 64% {
287
+ -webkit-transform: matrix(0.98995, 0, 0, 0.98995, 0, 42.96482);
288
+ opacity: 0.49749; }
289
+
290
+ 68% {
291
+ -webkit-transform: matrix(0.98997, 0, 0, 0.98997, 0, 42.97579);
292
+ opacity: 0.49827; }
293
+
294
+ 72% {
295
+ -webkit-transform: matrix(0.98998, 0, 0, 0.98998, 0, 42.98433);
296
+ opacity: 0.49888; }
297
+
298
+ 76% {
299
+ -webkit-transform: matrix(0.98999, 0, 0, 0.98999, 0, 42.99059);
300
+ opacity: 0.49933; }
301
+
302
+ 80% {
303
+ -webkit-transform: matrix(0.98999, 0, 0, 0.98999, 0, 42.99494);
304
+ opacity: 0.49964; }
305
+
306
+ 84% {
307
+ -webkit-transform: matrix(0.99, 0, 0, 0.99, 0, 42.99777);
308
+ opacity: 0.49984; }
309
+
310
+ 88% {
311
+ -webkit-transform: matrix(0.99, 0, 0, 0.99, 0, 42.9995);
312
+ opacity: 0.49996; }
313
+
314
+ 92% {
315
+ -webkit-transform: matrix(0.99, 0, 0, 0.99, 0, 43.00044);
316
+ opacity: 0.50003; }
317
+
318
+ 96% {
319
+ -webkit-transform: matrix(0.99, 0, 0, 0.99, 0, 43.00088);
320
+ opacity: 0.50006; }
321
+
322
+ 100% {
323
+ -webkit-transform: matrix(0.99, 0, 0, 0.99, 0, 43);
324
+ opacity: 0.5; } }
data/package.json ADDED
@@ -0,0 +1,18 @@
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-regarde": "0.1.x",
9
+ "grunt-contrib-livereload": "0.1.x",
10
+ "grunt-contrib-jasmine": "~0.4.1",
11
+ "grunt-contrib-connect": "~0.2.0",
12
+ "grunt-open": "~0.2.0",
13
+ "grunt-contrib-uglify": "~0.2.0",
14
+ "grunt-contrib-sass": "~0.3.0",
15
+ "grunt-concurrent": "~0.2.0"
16
+ },
17
+ "author": "jcsmith1859"
18
+ }
@@ -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