blob: f17fda2f049836d002fffc356d2427d862b7d489 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
define(function(require) {
var Backbone = require('backbone');
var template = require('hbs!tmpl/common/modal');
var Modal = Backbone.View.extend({
className: 'modal',
events: {
'click .close': function(event) {
event.preventDefault();
this.trigger('closeModal');
if (this.options.content && this.options.content.trigger) {
this.options.content.trigger('closeModal', this);
}
},
'click .cancel': function(event) {
event.preventDefault();
this.trigger('closeModal');
if (this.options.content && this.options.content.trigger) {
this.options.content.trigger('closeModal', this);
}
},
'click .ok': function(event) {
event.preventDefault();
this.trigger('ok');
if (this.options.content && this.options.content.trigger) {
this.options.content.trigger('ok', this);
}
if (this.options.okCloses) {
this.close();
}
}
},
/**
* Creates an instance of a Bootstrap Modal
*
* @see http://twitter.github.com/bootstrap/javascript.html#modals
*
* @param {Object} options
* @param {String|View} [options.content] Modal content. Default: none
* @param {String} [options.title] Title. Default: none
* @param {String} [options.okText] Text for the OK button. Default: 'OK'
* @param {String} [options.cancelText] Text for the cancel button. Default: 'Cancel'. If passed a falsey value, the button will be removed
* @param {Boolean} [options.allowCancel Whether the modal can be closed, other than by pressing OK. Default: true
* @param {Boolean} [options.escape] Whether the 'esc' key can dismiss the modal. Default: true, but false if options.cancellable is true
* @param {Boolean} [options.animate] Whether to animate in/out. Default: false
* @param {Function} [options.template] Compiled underscore template to override the default one
*/
initialize: function(options) {
this.options = _.extend({
title: null,
okText: 'OK',
focusOk: true,
okCloses: true,
cancelText: 'Cancel',
allowCancel: false,
showFooter: true,
escape: true,
animate: true,
contentWithFooter: false,
template: template
}, options);
},
/**
* Creates the DOM element
*
* @api private
*/
render: function() {
var $el = this.$el,
options = this.options,
content = options.content;
//Create the modal container
$el.html(options.template(options));
// var $content = this.$content = $el.find('.modal-body');
//Insert the main content if it's a view
if (content && content.$el) {
content.render();
if (options.contentWithFooter) {
$el.find('.modal-content').append(content.$el);
} else {
$el.find('.modal-body').html(content.$el);
}
} else {
if (options.htmlContent) {
$el.find('.modal-body').append(options.htmlContent);
}
}
// if (options.mainClass) $el.addClass(options.mainClass);
if (options.animate) $el.addClass('fade');
this.isRendered = true;
return this;
},
onClose: function() {
alert('close');
},
/**
* Renders and shows the modal
*
* @param {Function} [cb] Optional callback that runs only when OK is pressed.
*/
open: function(cb) {
if (!this.isRendered) this.render();
var self = this,
$el = this.$el;
//Create it
$el.modal(_.extend({
keyboard: this.options.allowCancel,
backdrop: this.options.allowCancel ? true : 'static'
}, this.options.modalOptions));
//Focus OK button
$el.one('shown', function() {
if (self.options.focusOk) {
$el.find('.btn.ok').focus();
}
if (self.options.content && self.options.content.trigger) {
self.options.content.trigger('shown', self);
}
self.trigger('shown');
});
//Adjust the modal and backdrop z-index; for dealing with multiple modals
var numModals = Modal.count,
$backdrop = $('.modal-backdrop:eq(' + numModals + ')'),
backdropIndex = parseInt($backdrop.css('z-index'), 10),
elIndex = parseInt($backdrop.css('z-index'), 10);
$backdrop.css('z-index', backdropIndex + numModals);
this.$el.css('z-index', elIndex + numModals);
if (this.options.allowCancel) {
$backdrop.one('click', function() {
if (self.options.content && self.options.content.trigger) {
self.options.content.trigger('closeModal', self);
}
self.trigger('closeModal');
});
$(document).one('keyup.dismiss.modal', function(e) {
e.which == 27 && self.trigger('closeModal');
if (self.options.content && self.options.content.trigger) {
e.which == 27 && self.options.content.trigger('shown', self);
}
});
}
this.on('cancel', function() {
self.close();
});
Modal.count++;
//Run callback on OK if provided
if (cb) {
self.on('ok', cb);
}
return this;
},
/**
* Closes the modal
*/
close: function() {
var self = this,
$el = this.$el;
//Check if the modal should stay open
if (this._preventClose) {
this._preventClose = false;
return;
}
$el.one('hidden.bs.modal', function onHidden(e) {
// Ignore events propagated from interior objects, like bootstrap tooltips
if (e.target !== e.currentTarget) {
return $el.one('hidden.bs.modal', onHidden);
}
self.remove();
if (self.options.content && self.options.content.trigger) {
self.options.content.trigger('hidden.bs.modal', self);
}
self.trigger('hidden.bs.modal');
});
$el.modal('hide');
Modal.count--;
},
/**
* Stop the modal from closing.
* Can be called from within a 'close' or 'ok' event listener.
*/
preventClose: function() {
this._preventClose = true;
}
}, {
//STATICS
//The number of modals on display
count: 0
});
return Modal;
});