Merge branch 'hotfix/21.56.9' into master
[gitter.git] / public / js / views / modals / modal.js
blob52d07f612aecc67c94f88b86049dea02844e6931
1 'use strict';
3 var $ = require('jquery');
4 var _ = require('lodash');
5 var Backbone = require('backbone');
6 var Marionette = require('backbone.marionette');
7 var modalTemplate = require('./tmpl/modal.hbs');
8 var ModalFooterButtonListView = require('./modal-footer-button-list-view');
9 var isCompact = require('../../utils/detect-compact');
11 require('../../template/helpers/all');
12 require('../behaviors/isomorphic');
13 require('@gitterhq/styleguide/css/components/modals.css');
15 var ModalView = Marionette.LayoutView.extend({
16   template: modalTemplate,
17   className: 'modal',
19   ui: {
20     title: '.js-modal-title-text'
21   },
23   events: {
24     'click .close': 'hide',
25     'click [data-action=close]': 'hide'
26   },
28   regions: {
29     modalBody: '#modal-body-region',
30     modalFooter: '#modal-footer-region'
31   },
33   initialize: function(options) {
34     this.options = {
35       // Backbone Collection or array of items
36       menuItems: [],
37       title: null,
38       modalClassVariation: null,
39       backdrop: true
40     };
41     _.extend(this.options, options);
43     this.view = this.options.view || this.view;
45     if (this.options.menuItems && this.options.menuItems.models) {
46       this.menuItemCollection = this.options.menuItems;
47     } else {
48       var menuItems = this.menuItems || this.options.menuItems || [];
49       if (typeof menuItems === 'function') {
50         menuItems = menuItems.call(this);
51       }
53       this.menuItemCollection = new Backbone.Collection(menuItems);
54     }
56     this.footerView = new ModalFooterButtonListView({
57       collection: this.menuItemCollection
58     });
59     this.listenTo(this.footerView, 'item:activate', this.onMenuItemActivated, this);
60   },
62   serializeData: function() {
63     return {
64       title: this.options.title,
65       modalClassVariation: this.options.modalClassVariation
66     };
67   },
69   onMenuItemActivated: function(itemModel) {
70     var action = itemModel.get('action');
71     this.view.trigger('menuItemClicked', action);
72     this.trigger('menuItemClicked', action);
73   },
75   onRender: function() {
76     var self = this;
77     this.$el.hide();
79     this.modalBody.show(this.view);
80     this.modalFooter.show(this.footerView);
82     if (!isCompact() && !this.disableAutoFocus) {
83       window.setTimeout(function() {
84         try {
85           var v = self.$el.find(
86             'input[type=text], input[type=url], input[type=tel], input[type=number], input[type=color], input[type=email]'
87           )[0];
88           if (v) {
89             v.focus();
90             v.select();
91           }
92         } catch (e) {
93           /* */
94         }
95       }, 100);
96     } else if (!isCompact()) {
97       // Focus the modal overall so you can start navigating to the controls
98       this.el.focus();
99     }
100   },
102   setButtonState: function(name, state) {
103     var $s = this.$el.find('button[data-action=' + name + ']');
104     if (state) {
105       $s.removeAttr('disabled');
106     } else {
107       $s.attr('disabled', true);
108     }
109   },
111   toggleButtonClass: function(name, className, enabled) {
112     var $s = this.$el.find('button[data-action=' + name + ']');
113     $s.toggleClass(className, enabled);
114   },
116   hideActions: function() {
117     var $s = this.$el.find('.modal-footer .action');
118     $s.hide();
119   },
121   showActions: function() {
122     var $s = this.$el.find('.modal-footer .action');
123     $s.show();
124   },
126   showPremium: function() {
127     var $s = this.$el.find('.premium');
128     $s.removeClass('hidden');
129     $s.show();
130   },
132   hidePremium: function() {
133     var $s = this.$el.find('.modal-footer .premium');
134     $s.addClass('hidden');
135     $s.hide();
136   },
138   onDestroy: function() {
139     this.view.destroy();
140     this.view.dialog = null;
141   },
143   prepare: function() {
144     if (!this.rendered) {
145       this.render();
146       this.rendered = true;
147     }
148   },
150   show: function() {
151     this.view.dialog = this;
153     var that = this;
154     if (this.isShown) return;
156     this.prepare();
158     $('body').addClass('modal-open');
160     this.isShown = true;
161     this.$el.trigger('show');
162     this.trigger('show');
164     this.escape();
165     this.backdrop(function() {
166       if (!that.$el.parent().length) {
167         that.$el.appendTo(that.$backdrop); //don't move modals dom position
168       }
170       that.$el.show();
171       that.$el.addClass('in');
172       that.$el.trigger('shown');
173       that.trigger('shown');
174     });
175   },
177   hide: function(e) {
178     if (e) e.preventDefault();
179     if (this.navigable) {
180       window.location = '#';
181       return;
182     }
183     this.hideInternal();
184   },
186   /* Called after navigation to destroy an navigable dialog box */
187   navigationalHide: function() {
188     this.hideInternal();
189   },
191   hideInternal: function() {
192     if (!this.isShown) return;
194     this.isShown = false;
196     $('body').removeClass('modal-open');
198     this.escape();
200     this.$el.trigger('hide').removeClass('in');
202     this.trigger('hide');
204     this.hideModal();
205   },
207   hideModal: function() {
208     this.$el.hide().trigger('hidden');
210     this.trigger('hidden');
211     this.backdrop();
213     this.destroy();
214   },
216   backdrop: function(callback) {
217     if (this.isShown && this.options.backdrop !== false) {
218       this.$backdrop = $('<div class="modal-backdrop" />').appendTo(document.body);
220       var bd = this.$backdrop;
221       this.$backdrop.click(function(e) {
222         if (e.target !== this) return;
223         bd.modal.hide();
224       });
225       this.$backdrop.modal = this;
226       this.$backdrop.addClass('in');
228       callback();
229     } else if (!this.isShown && this.$backdrop) {
230       this.$backdrop.removeClass('in');
232       this.removeBackdrop();
233     } else if (callback) {
234       callback();
235     }
236   },
238   removeBackdrop: function() {
239     this.$backdrop.remove();
240     this.$backdrop = null;
241   },
243   escape: function() {
244     var that = this;
245     if (this.isShown) {
246       $(document).on('keydown', keydown);
247     } else if (!this.isShown) {
248       $(document).off('keydown', keydown);
249     }
251     function keydown(e) {
252       if (e.which === 27) that.hide();
253     }
254   }
257 module.exports = ModalView;