src/pyams_skin/resources/js/ext/bootstrap-modal.js
changeset 557 bca7a7e058a3
equal deleted inserted replaced
-1:000000000000 557:bca7a7e058a3
       
     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 				if (body.css('overflow') === undefined) {
       
   140 					body.style('overflow', 'auto', 'important');
       
   141 				}
       
   142 				body.style(prop, (typeof(value) === 'function' ? value() : value) + 'px', 'important');
       
   143 			}
       
   144 
       
   145 			var modalOverflow = $(window).height() - 10 < this.$element.height();
       
   146 
       
   147 //			if (modalOverflow || this.options.modalOverflow) {
       
   148 				this.$element
       
   149 					.css('margin-top', 0)
       
   150 					.addClass('modal-overflow');
       
   151 //			} else {
       
   152 //				this.$element
       
   153 //					.css('margin-top', 0 - this.$element.height() / 2)
       
   154 //					.removeClass('modal-overflow');
       
   155 //			}
       
   156 		},
       
   157 
       
   158 		tab: function () {
       
   159 			var that = this;
       
   160 
       
   161 			if (this.isShown && this.options.consumeTab) {
       
   162 				this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) {
       
   163 					if (e.keyCode && e.keyCode == 9) {
       
   164 						var elements = [],
       
   165 							tabindex = Number($(this).data('tabindex'));
       
   166 
       
   167 						that.$element.find('[data-tabindex]:enabled:visible:not([readonly])').each(function (ev) {
       
   168 							elements.push(Number($(this).data('tabindex')));
       
   169 						});
       
   170 						elements.sort(function(a,b){return a-b});
       
   171 
       
   172 						var arrayPos = $.inArray(tabindex, elements);
       
   173 						if (!e.shiftKey){
       
   174 							arrayPos < elements.length-1 ?
       
   175 								that.$element.find('[data-tabindex='+elements[arrayPos+1]+']').focus() :
       
   176 								that.$element.find('[data-tabindex='+elements[0]+']').focus();
       
   177 						} else {
       
   178 							arrayPos == 0 ?
       
   179 								that.$element.find('[data-tabindex='+elements[elements.length-1]+']').focus() :
       
   180 								that.$element.find('[data-tabindex='+elements[arrayPos-1]+']').focus();
       
   181 						}
       
   182 
       
   183 						e.preventDefault();
       
   184 					}
       
   185 				});
       
   186 			} else if (!this.isShown) {
       
   187 				this.$element.off('keydown.tabindex.modal');
       
   188 			}
       
   189 		},
       
   190 
       
   191 		escape: function () {
       
   192 			var that = this;
       
   193 			if (this.isShown && this.options.keyboard) {
       
   194 				if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1);
       
   195 
       
   196 				this.$element.on('keyup.dismiss.modal', function (e) {
       
   197 					e.which == 27 && that.hide();
       
   198 				});
       
   199 			} else if (!this.isShown) {
       
   200 				this.$element.off('keyup.dismiss.modal')
       
   201 			}
       
   202 		},
       
   203 
       
   204 		hideWithTransition: function () {
       
   205 			var that = this
       
   206 				, timeout = setTimeout(function () {
       
   207 					that.$element.off($.support.transition.end);
       
   208 					that.hideModal();
       
   209 				}, 500);
       
   210 
       
   211 			this.$element.one($.support.transition.end, function () {
       
   212 				clearTimeout(timeout);
       
   213 				that.hideModal();
       
   214 			});
       
   215 		},
       
   216 
       
   217 		hideModal: function () {
       
   218 			var prop = this.options.height ? 'height' : 'max-height';
       
   219 			var value = this.options.height || this.options.maxHeight;
       
   220 
       
   221 			if (value) {
       
   222 				this.$element.find(this.options.overflow)
       
   223 					.css('overflow', '')
       
   224 					.css(prop, '');
       
   225 			}
       
   226 
       
   227 			this.$element
       
   228 				.hide()
       
   229 				.trigger('hidden');
       
   230 		},
       
   231 
       
   232 		removeLoading: function () {
       
   233 			this.$loading.remove();
       
   234 			this.$loading = null;
       
   235 			this.isLoading = false;
       
   236 		},
       
   237 
       
   238 		loading: function (callback) {
       
   239 			callback = callback || function () {};
       
   240 
       
   241 			var animate = this.$element.hasClass('fade') ? 'fade' : '';
       
   242 
       
   243 			if (!this.isLoading) {
       
   244 				var doAnimate = $.support.transition && animate;
       
   245 
       
   246 				this.$loading = $('<div class="loading-mask ' + animate + '">')
       
   247 					.append(this.options.spinner)
       
   248 					.appendTo(this.$element);
       
   249 
       
   250 				if (doAnimate) this.$loading[0].offsetWidth; // force reflow
       
   251 
       
   252 				this.$loading.addClass('in');
       
   253 
       
   254 				this.isLoading = true;
       
   255 
       
   256 				doAnimate ?
       
   257 					this.$loading.one($.support.transition.end, callback) :
       
   258 					callback();
       
   259 
       
   260 			} else if (this.isLoading && this.$loading) {
       
   261 				this.$loading.removeClass('in');
       
   262 
       
   263 				var that = this;
       
   264 				$.support.transition && this.$element.hasClass('fade') ?
       
   265 					this.$loading.one($.support.transition.end, function () {
       
   266 						that.removeLoading()
       
   267 					}) :
       
   268 					that.removeLoading();
       
   269 
       
   270 			} else if (callback) {
       
   271 				callback(this.isLoading);
       
   272 			}
       
   273 		},
       
   274 
       
   275 		focus: function () {
       
   276 			var $focusElem = this.$element.find(this.options.focusOn);
       
   277 
       
   278 			$focusElem = $focusElem.length ? $focusElem : this.$element;
       
   279 
       
   280 			$focusElem.focus();
       
   281 		},
       
   282 
       
   283 		attention: function () {
       
   284 			// NOTE: transitionEnd with keyframes causes odd behaviour
       
   285 
       
   286 			if (this.options.attentionAnimation) {
       
   287 				this.$element
       
   288 					.removeClass('animated')
       
   289 					.removeClass(this.options.attentionAnimation);
       
   290 
       
   291 				var that = this;
       
   292 
       
   293 				setTimeout(function () {
       
   294 					that.$element
       
   295 						.addClass('animated')
       
   296 						.addClass(that.options.attentionAnimation);
       
   297 				}, 0);
       
   298 			}
       
   299 
       
   300 
       
   301 			this.focus();
       
   302 		},
       
   303 
       
   304 
       
   305 		destroy: function () {
       
   306 			var e = $.Event('destroy');
       
   307 			this.$element.trigger(e);
       
   308 			if (e.isDefaultPrevented()) return;
       
   309 
       
   310 			this.$element
       
   311 				.off('.modal')
       
   312 				.removeData('modal')
       
   313 				.removeClass('in')
       
   314 				.attr('aria-hidden', true);
       
   315 
       
   316 			if (this.$parent !== this.$element.parent()) {
       
   317 				this.$element.appendTo(this.$parent);
       
   318 			} else if (!this.$parent.length) {
       
   319 				// modal is not part of the DOM so remove it.
       
   320 				this.$element.remove();
       
   321 				this.$element = null;
       
   322 			}
       
   323 
       
   324 			this.$element.trigger('destroyed');
       
   325 		}
       
   326 	};
       
   327 
       
   328 
       
   329 	/* MODAL PLUGIN DEFINITION
       
   330 	 * ======================= */
       
   331 
       
   332 	$.fn.modal = function (option, args) {
       
   333 		return this.each(function () {
       
   334 			var $this = $(this),
       
   335 				data = $this.data('modal'),
       
   336 				options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option);
       
   337 
       
   338 			if (!data) $this.data('modal', (data = new Modal(this, options)));
       
   339 			if (typeof option == 'string') data[option].apply(data, [].concat(args));
       
   340 			else if (options.show) data.show()
       
   341 		})
       
   342 	};
       
   343 
       
   344 	$.fn.modal.defaults = {
       
   345 		keyboard: true,
       
   346 		backdrop: true,
       
   347 		loading: false,
       
   348 		show: true,
       
   349 		width: null,
       
   350 		height: null,
       
   351 		maxHeight: null,
       
   352 		modalOverflow: false,
       
   353 		consumeTab: true,
       
   354 		focusOn: null,
       
   355 		replace: false,
       
   356 		resize: false,
       
   357 		overflow: '.modal-body',
       
   358 		attentionAnimation: 'shake',
       
   359 		manager: 'body',
       
   360 		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>',
       
   361 		backdropTemplate: '<div class="modal-backdrop" />'
       
   362 	};
       
   363 
       
   364 	$.fn.modal.Constructor = Modal;
       
   365 
       
   366 
       
   367 	/* MODAL DATA-API
       
   368 	 * ============== */
       
   369 
       
   370 	$(function () {
       
   371 		$(document).off('click.modal').on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
       
   372 			var $this = $(this),
       
   373 				href = $this.attr('href'),
       
   374 				$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7
       
   375 				option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());
       
   376 
       
   377 			e.preventDefault();
       
   378 			$target
       
   379 				.modal(option)
       
   380 				.one('hide', function () {
       
   381 					$this.focus();
       
   382 				});
       
   383 		});
       
   384 	});
       
   385 
       
   386 }(window.jQuery);