src/pyams_skin/resources/js/ext/bootstrap-modal.js
changeset 0 bb4aabe07487
child 151 2c67b6c103bb
equal deleted inserted replaced
-1:000000000000 0:bb4aabe07487
       
     1 /* ===========================================================
       
     2  * bootstrap-modal.js v2.2.5
       
     3  * ===========================================================
       
     4  * Copyright 2012 Jordan Schroter
       
     5  *
       
     6  * Modified in january 2014 by Thierry Florac <tflorac@ulthar.net>
       
     7  *  - add 'overflow' selector to handle selection of overflow content
       
     8  *  - use '$.fn.style' function (define in MyAMS package) to define '!important' priority
       
     9  *    when defining CSS styles
       
    10  *
       
    11  * Licensed under the Apache License, Version 2.0 (the "License");
       
    12  * you may not use this file except in compliance with the License.
       
    13  * You may obtain a copy of the License at
       
    14  *
       
    15  * http://www.apache.org/licenses/LICENSE-2.0
       
    16  *
       
    17  * Unless required by applicable law or agreed to in writing, software
       
    18  * distributed under the License is distributed on an "AS IS" BASIS,
       
    19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    20  * See the License for the specific language governing permissions and
       
    21  * limitations under the License.
       
    22  * ========================================================== */
       
    23 
       
    24 
       
    25 !function ($) {
       
    26 
       
    27 	"use strict"; // jshint ;_;
       
    28 
       
    29 	/* MODAL CLASS DEFINITION
       
    30 	 * ====================== */
       
    31 
       
    32 	var Modal = function (element, options) {
       
    33 		this.init(element, options);
       
    34 	};
       
    35 
       
    36 	Modal.prototype = {
       
    37 
       
    38 		constructor: Modal,
       
    39 
       
    40 		init: function (element, options) {
       
    41 			var that = this;
       
    42 
       
    43 			this.options = options;
       
    44 
       
    45 			this.$element = $(element)
       
    46 				.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this));
       
    47 
       
    48 			this.options.remote && this.$element.find('.modal-body').load(this.options.remote, function () {
       
    49 				var e = $.Event('loaded');
       
    50 				that.$element.trigger(e);
       
    51 			});
       
    52 
       
    53 			var manager = typeof this.options.manager === 'function' ?
       
    54 				this.options.manager.call(this) : this.options.manager;
       
    55 
       
    56 			manager = manager.appendModal ?
       
    57 				manager : $(manager).modalmanager().data('modalmanager');
       
    58 
       
    59 			manager.appendModal(this);
       
    60 		},
       
    61 
       
    62 		toggle: function () {
       
    63 			return this[!this.isShown ? 'show' : 'hide']();
       
    64 		},
       
    65 
       
    66 		show: function () {
       
    67 			var e = $.Event('show');
       
    68 
       
    69 			if (this.isShown) return;
       
    70 
       
    71 			this.$element.trigger(e);
       
    72 
       
    73 			if (e.isDefaultPrevented()) return;
       
    74 
       
    75 			this.escape();
       
    76 
       
    77 			this.tab();
       
    78 
       
    79 			this.options.loading && this.loading();
       
    80 		},
       
    81 
       
    82 		hide: function (e) {
       
    83 			e && e.preventDefault();
       
    84 
       
    85 			e = $.Event('hide');
       
    86 
       
    87 			this.$element.trigger(e);
       
    88 
       
    89 			if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false);
       
    90 
       
    91 			this.isShown = false;
       
    92 
       
    93 			this.escape();
       
    94 
       
    95 			this.tab();
       
    96 
       
    97 			this.isLoading && this.loading();
       
    98 
       
    99 			$(document).off('focusin.modal');
       
   100 
       
   101 			this.$element
       
   102 				.removeClass('in')
       
   103 				.removeClass('animated')
       
   104 				.removeClass(this.options.attentionAnimation)
       
   105 				.removeClass('modal-overflow')
       
   106 				.attr('aria-hidden', true);
       
   107 
       
   108 			$.support.transition && this.$element.hasClass('fade') ?
       
   109 				this.hideWithTransition() :
       
   110 				this.hideModal();
       
   111 		},
       
   112 
       
   113 		layout: function () {
       
   114 			var prop = this.options.height ? 'height' : 'max-height',
       
   115 				value = this.options.height || this.options.maxHeight;
       
   116 
       
   117 			if (this.options.width) {
       
   118 				this.$element.css('width', this.options.width);
       
   119 
       
   120 				var that = this;
       
   121 				this.$element.css('margin-left', function () {
       
   122 					if (/%/ig.test(that.options.width)) {
       
   123 						return -(parseInt(that.options.width) / 2) + '%';
       
   124 					} else {
       
   125 						return -($(this).width() / 2) + 'px';
       
   126 					}
       
   127 				});
       
   128 			} else {
       
   129 				this.$element.css('width', '');
       
   130 				this.$element.css('margin-left', '');
       
   131 			}
       
   132 
       
   133 			this.$element.find(this.options.overflow)
       
   134 				.css('overflow', '')
       
   135 				.css(prop, '');
       
   136 
       
   137 			if (value) {
       
   138 				var body = this.$element.find(this.options.overflow);
       
   139 				body.style('overflow', 'auto', 'important')
       
   140 					.style(prop, (typeof(value) == 'function' ? value() : value) + 'px', 'important');
       
   141 			}
       
   142 
       
   143 			var modalOverflow = $(window).height() - 10 < this.$element.height();
       
   144 
       
   145 //			if (modalOverflow || this.options.modalOverflow) {
       
   146 				this.$element
       
   147 					.css('margin-top', 0)
       
   148 					.addClass('modal-overflow');
       
   149 //			} else {
       
   150 //				this.$element
       
   151 //					.css('margin-top', 0 - this.$element.height() / 2)
       
   152 //					.removeClass('modal-overflow');
       
   153 //			}
       
   154 		},
       
   155 
       
   156 		tab: function () {
       
   157 			var that = this;
       
   158 
       
   159 			if (this.isShown && this.options.consumeTab) {
       
   160 				this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) {
       
   161 					if (e.keyCode && e.keyCode == 9) {
       
   162 						var elements = [],
       
   163 							tabindex = Number($(this).data('tabindex'));
       
   164 
       
   165 						that.$element.find('[data-tabindex]:enabled:visible:not([readonly])').each(function (ev) {
       
   166 							elements.push(Number($(this).data('tabindex')));
       
   167 						});
       
   168 						elements.sort(function(a,b){return a-b});
       
   169 
       
   170 						var arrayPos = $.inArray(tabindex, elements);
       
   171 						if (!e.shiftKey){
       
   172 							arrayPos < elements.length-1 ?
       
   173 								that.$element.find('[data-tabindex='+elements[arrayPos+1]+']').focus() :
       
   174 								that.$element.find('[data-tabindex='+elements[0]+']').focus();
       
   175 						} else {
       
   176 							arrayPos == 0 ?
       
   177 								that.$element.find('[data-tabindex='+elements[elements.length-1]+']').focus() :
       
   178 								that.$element.find('[data-tabindex='+elements[arrayPos-1]+']').focus();
       
   179 						}
       
   180 
       
   181 						e.preventDefault();
       
   182 					}
       
   183 				});
       
   184 			} else if (!this.isShown) {
       
   185 				this.$element.off('keydown.tabindex.modal');
       
   186 			}
       
   187 		},
       
   188 
       
   189 		escape: function () {
       
   190 			var that = this;
       
   191 			if (this.isShown && this.options.keyboard) {
       
   192 				if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1);
       
   193 
       
   194 				this.$element.on('keyup.dismiss.modal', function (e) {
       
   195 					e.which == 27 && that.hide();
       
   196 				});
       
   197 			} else if (!this.isShown) {
       
   198 				this.$element.off('keyup.dismiss.modal')
       
   199 			}
       
   200 		},
       
   201 
       
   202 		hideWithTransition: function () {
       
   203 			var that = this
       
   204 				, timeout = setTimeout(function () {
       
   205 					that.$element.off($.support.transition.end);
       
   206 					that.hideModal();
       
   207 				}, 500);
       
   208 
       
   209 			this.$element.one($.support.transition.end, function () {
       
   210 				clearTimeout(timeout);
       
   211 				that.hideModal();
       
   212 			});
       
   213 		},
       
   214 
       
   215 		hideModal: function () {
       
   216 			var prop = this.options.height ? 'height' : 'max-height';
       
   217 			var value = this.options.height || this.options.maxHeight;
       
   218 
       
   219 			if (value) {
       
   220 				this.$element.find(this.options.overflow)
       
   221 					.css('overflow', '')
       
   222 					.css(prop, '');
       
   223 			}
       
   224 
       
   225 			this.$element
       
   226 				.hide()
       
   227 				.trigger('hidden');
       
   228 		},
       
   229 
       
   230 		removeLoading: function () {
       
   231 			this.$loading.remove();
       
   232 			this.$loading = null;
       
   233 			this.isLoading = false;
       
   234 		},
       
   235 
       
   236 		loading: function (callback) {
       
   237 			callback = callback || function () {};
       
   238 
       
   239 			var animate = this.$element.hasClass('fade') ? 'fade' : '';
       
   240 
       
   241 			if (!this.isLoading) {
       
   242 				var doAnimate = $.support.transition && animate;
       
   243 
       
   244 				this.$loading = $('<div class="loading-mask ' + animate + '">')
       
   245 					.append(this.options.spinner)
       
   246 					.appendTo(this.$element);
       
   247 
       
   248 				if (doAnimate) this.$loading[0].offsetWidth; // force reflow
       
   249 
       
   250 				this.$loading.addClass('in');
       
   251 
       
   252 				this.isLoading = true;
       
   253 
       
   254 				doAnimate ?
       
   255 					this.$loading.one($.support.transition.end, callback) :
       
   256 					callback();
       
   257 
       
   258 			} else if (this.isLoading && this.$loading) {
       
   259 				this.$loading.removeClass('in');
       
   260 
       
   261 				var that = this;
       
   262 				$.support.transition && this.$element.hasClass('fade') ?
       
   263 					this.$loading.one($.support.transition.end, function () {
       
   264 						that.removeLoading()
       
   265 					}) :
       
   266 					that.removeLoading();
       
   267 
       
   268 			} else if (callback) {
       
   269 				callback(this.isLoading);
       
   270 			}
       
   271 		},
       
   272 
       
   273 		focus: function () {
       
   274 			var $focusElem = this.$element.find(this.options.focusOn);
       
   275 
       
   276 			$focusElem = $focusElem.length ? $focusElem : this.$element;
       
   277 
       
   278 			$focusElem.focus();
       
   279 		},
       
   280 
       
   281 		attention: function () {
       
   282 			// NOTE: transitionEnd with keyframes causes odd behaviour
       
   283 
       
   284 			if (this.options.attentionAnimation) {
       
   285 				this.$element
       
   286 					.removeClass('animated')
       
   287 					.removeClass(this.options.attentionAnimation);
       
   288 
       
   289 				var that = this;
       
   290 
       
   291 				setTimeout(function () {
       
   292 					that.$element
       
   293 						.addClass('animated')
       
   294 						.addClass(that.options.attentionAnimation);
       
   295 				}, 0);
       
   296 			}
       
   297 
       
   298 
       
   299 			this.focus();
       
   300 		},
       
   301 
       
   302 
       
   303 		destroy: function () {
       
   304 			var e = $.Event('destroy');
       
   305 			this.$element.trigger(e);
       
   306 			if (e.isDefaultPrevented()) return;
       
   307 
       
   308 			this.$element
       
   309 				.off('.modal')
       
   310 				.removeData('modal')
       
   311 				.removeClass('in')
       
   312 				.attr('aria-hidden', true);
       
   313 
       
   314 			if (this.$parent !== this.$element.parent()) {
       
   315 				this.$element.appendTo(this.$parent);
       
   316 			} else if (!this.$parent.length) {
       
   317 				// modal is not part of the DOM so remove it.
       
   318 				this.$element.remove();
       
   319 				this.$element = null;
       
   320 			}
       
   321 
       
   322 			this.$element.trigger('destroyed');
       
   323 		}
       
   324 	};
       
   325 
       
   326 
       
   327 	/* MODAL PLUGIN DEFINITION
       
   328 	 * ======================= */
       
   329 
       
   330 	$.fn.modal = function (option, args) {
       
   331 		return this.each(function () {
       
   332 			var $this = $(this),
       
   333 				data = $this.data('modal'),
       
   334 				options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option);
       
   335 
       
   336 			if (!data) $this.data('modal', (data = new Modal(this, options)));
       
   337 			if (typeof option == 'string') data[option].apply(data, [].concat(args));
       
   338 			else if (options.show) data.show()
       
   339 		})
       
   340 	};
       
   341 
       
   342 	$.fn.modal.defaults = {
       
   343 		keyboard: true,
       
   344 		backdrop: true,
       
   345 		loading: false,
       
   346 		show: true,
       
   347 		width: null,
       
   348 		height: null,
       
   349 		maxHeight: null,
       
   350 		modalOverflow: false,
       
   351 		consumeTab: true,
       
   352 		focusOn: null,
       
   353 		replace: false,
       
   354 		resize: false,
       
   355 		overflow: '.modal-body',
       
   356 		attentionAnimation: 'shake',
       
   357 		manager: 'body',
       
   358 		spinner: '<div class="loading-spinner" style="width: 200px; margin-left: -100px;"><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div></div>',
       
   359 		backdropTemplate: '<div class="modal-backdrop" />'
       
   360 	};
       
   361 
       
   362 	$.fn.modal.Constructor = Modal;
       
   363 
       
   364 
       
   365 	/* MODAL DATA-API
       
   366 	 * ============== */
       
   367 
       
   368 	$(function () {
       
   369 		$(document).off('click.modal').on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
       
   370 			var $this = $(this),
       
   371 				href = $this.attr('href'),
       
   372 				$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7
       
   373 				option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());
       
   374 
       
   375 			e.preventDefault();
       
   376 			$target
       
   377 				.modal(option)
       
   378 				.one('hide', function () {
       
   379 					$this.focus();
       
   380 				});
       
   381 		});
       
   382 	});
       
   383 
       
   384 }(window.jQuery);