1(function(root, factory) { 2 if (typeof define === 'function' && define.amd) { 3 define(['jquery'], function($) { 4 return factory(root, $); 5 }); 6 } else if (typeof exports === 'object') { 7 factory(root, require('jquery')); 8 } else { 9 factory(root, root.jQuery || root.Zepto); 10 } 11})(this, function(global, $) { 12 13 'use strict'; 14 15 /** 16 * Name of the plugin 17 * @private 18 * @type {String} 19 */ 20 var pluginName = 'remodal'; 21 22 /** 23 * Namespace for CSS and events 24 * @private 25 * @type {String} 26 */ 27 var namespace = global.remodalGlobals && global.remodalGlobals.namespace || pluginName; 28 29 /** 30 * Default settings 31 * @private 32 * @type {Object} 33 */ 34 var defaults = $.extend({ 35 hashTracking: true, 36 closeOnConfirm: true, 37 closeOnCancel: true, 38 closeOnEscape: true, 39 closeOnAnyClick: true 40 }, global.remodalGlobals && global.remodalGlobals.defaults); 41 42 /** 43 * Current modal 44 * @private 45 * @type {Remodal} 46 */ 47 var current; 48 49 /** 50 * Scrollbar position 51 * @private 52 * @type {Number} 53 */ 54 var scrollTop; 55 56 /** 57 * Get a transition duration in ms 58 * @private 59 * @param {jQuery} $elem 60 * @return {Number} 61 */ 62 function getTransitionDuration($elem) { 63 var duration = $elem.css('transition-duration') || 64 $elem.css('-webkit-transition-duration') || 65 $elem.css('-moz-transition-duration') || 66 $elem.css('-o-transition-duration') || 67 $elem.css('-ms-transition-duration') || 68 '0s'; 69 70 var delay = $elem.css('transition-delay') || 71 $elem.css('-webkit-transition-delay') || 72 $elem.css('-moz-transition-delay') || 73 $elem.css('-o-transition-delay') || 74 $elem.css('-ms-transition-delay') || 75 '0s'; 76 77 var max; 78 var len; 79 var num; 80 var i; 81 82 duration = duration.split(', '); 83 delay = delay.split(', '); 84 85 // The duration length is the same as the delay length 86 for (i = 0, len = duration.length, max = Number.NEGATIVE_INFINITY; i < len; i++) { 87 num = parseFloat(duration[i]) + parseFloat(delay[i]); 88 89 if (num > max) { 90 max = num; 91 } 92 } 93 94 return num * 1000; 95 } 96 97 /** 98 * Get a scrollbar width 99 * @private 100 * @return {Number} 101 */ 102 function getScrollbarWidth() { 103 if ($(document.body).height() <= $(window).height()) { 104 return 0; 105 } 106 107 var outer = document.createElement('div'); 108 var inner = document.createElement('div'); 109 var widthNoScroll; 110 var widthWithScroll; 111 112 outer.style.visibility = 'hidden'; 113 outer.style.width = '100px'; 114 document.body.appendChild(outer); 115 116 widthNoScroll = outer.offsetWidth; 117 118 // Force scrollbars 119 outer.style.overflow = 'scroll'; 120 121 // Add inner div 122 inner.style.width = '100%'; 123 outer.appendChild(inner); 124 125 widthWithScroll = inner.offsetWidth; 126 127 // Remove divs 128 outer.parentNode.removeChild(outer); 129 130 return widthNoScroll - widthWithScroll; 131 } 132 133 /** 134 * Lock the screen 135 * @private 136 */ 137 function lockScreen() { 138 var $html = $('html'); 139 var lockedClass = namespace + '-is-locked'; 140 var paddingRight; 141 var $body; 142 143 if (!$html.hasClass(lockedClass)) { 144 $body = $(document.body); 145 146 // Zepto does not support '-=', '+=' in the `css` method 147 paddingRight = parseInt($body.css('padding-right'), 10) + getScrollbarWidth(); 148 149 $body.css('padding-right', paddingRight + 'px'); 150 $html.addClass(lockedClass); 151 } 152 } 153 154 /** 155 * Unlock the screen 156 * @private 157 */ 158 function unlockScreen() { 159 var $html = $('html'); 160 var lockedClass = namespace + '-is-locked'; 161 var paddingRight; 162 var $body; 163 164 if ($html.hasClass(lockedClass)) { 165 $body = $(document.body); 166 167 // Zepto does not support '-=', '+=' in the `css` method 168 paddingRight = parseInt($body.css('padding-right'), 10) - getScrollbarWidth(); 169 170 $body.css('padding-right', paddingRight + 'px'); 171 $html.removeClass(lockedClass); 172 } 173 } 174 175 /** 176 * Parse a string with options 177 * @private 178 * @param str 179 * @returns {Object} 180 */ 181 function parseOptions(str) { 182 var obj = {}; 183 var arr; 184 var len; 185 var val; 186 var i; 187 188 // Remove spaces before and after delimiters 189 str = str.replace(/\s*:\s*/g, ':').replace(/\s*,\s*/g, ','); 190 191 // Parse a string 192 arr = str.split(','); 193 for (i = 0, len = arr.length; i < len; i++) { 194 arr[i] = arr[i].split(':'); 195 val = arr[i][1]; 196 197 // Convert a string value if it is like a boolean 198 if (typeof val === 'string' || val instanceof String) { 199 val = val === 'true' || (val === 'false' ? false : val); 200 } 201 202 // Convert a string value if it is like a number 203 if (typeof val === 'string' || val instanceof String) { 204 val = !isNaN(val) ? +val : val; 205 } 206 207 obj[arr[i][0]] = val; 208 } 209 210 return obj; 211 } 212 213 /** 214 * Remodal constructor 215 * @param {jQuery} $modal 216 * @param {Object} options 217 * @constructor 218 */ 219 function Remodal($modal, options) { 220 var remodal = this; 221 var tdOverlay; 222 var tdModal; 223 var tdBg; 224 225 remodal.settings = $.extend({}, defaults, options); 226 227 // Build DOM 228 remodal.$body = $(document.body);
229 remodal.$overlay = $('.' + namespace + '-overlay'); 230 231 if (!remodal.$overlay.length) { 232 remodal.$overlay = $('<div>').addClass(namespace + '-overlay'); 233 remodal.$body.append(remodal.$overlay); 234 } 235 236 remodal.$bg = $('.' + namespace + '-bg'); 237 //remodal.$closeButton = $('<a href="#"></a>').addClass(namespace + '-close'); 238 remodal.$wrapper = $('<div>').addClass(namespace + '-wrapper'); 239 remodal.$modal = $modal; 240 remodal.$modal.addClass(namespace); 241 remodal.$modal.css('visibility', 'visible'); 242 243 remodal.$modal.append(remodal.$closeButton); 244 remodal.$wrapper.append(remodal.$modal); 245 remodal.$body.append(remodal.$wrapper); 246 remodal.$confirmButton = remodal.$modal.find('.' + namespace + '-confirm'); 247 remodal.$cancelButton = remodal.$modal.find('.' + namespace + '-cancel'); 248 249 // Calculate timeouts 250 tdOverlay = getTransitionDuration(remodal.$overlay); 251 tdModal = getTransitionDuration(remodal.$modal); 252 tdBg = getTransitionDuration(remodal.$bg); 253 remodal.td = Math.max(tdOverlay, tdModal, tdBg); 254 255 // Add the close button event listener 256 remodal.$wrapper.on('click.' + namespace, '.' + namespace + '-close', function(e) { 257 e.preventDefault(); 258 259 remodal.close(); 260 }); 261 262 // Add the cancel button event listener 263 remodal.$wrapper.on('click.' + namespace, '.' + namespace + '-cancel', function(e) { 264 e.preventDefault(); 265 266 remodal.$modal.trigger('cancel'); 267 268 if (remodal.settings.closeOnCancel) { 269 remodal.close('cancellation'); 270 } 271 }); 272 273 // Add the confirm button event listener 274 remodal.$wrapper.on('click.' + namespace, '.' + namespace + '-confirm', function(e) { 275 e.preventDefault(); 276 277 remodal.$modal.trigger('confirm'); 278 279 if (remodal.settings.closeOnConfirm) { 280 remodal.close('confirmation'); 281 } 282 }); 283 284 // Add the keyboard event listener 285 $(document).on('keyup.' + namespace, function(e) { 286 if (e.keyCode === 27 && remodal.settings.closeOnEscape) { 287 remodal.close(); 288 } 289 }); 290 291 // Add the overlay event listener 292 remodal.$wrapper.on('click.' + namespace, function(e) { 293 var $target = $(e.target); 294 295 if (!$target.hasClass(namespace + '-wrapper')) { 296 return; 297 } 298 299 if (remodal.settings.closeOnAnyClick) { 300 remodal.close(); 301 } 302 }); 303 304 remodal.index = $[pluginName].lookup.push(remodal) - 1; 305 remodal.busy = false; 306 } 307 308 /** 309 * Open a modal window 310 * @public 311 */ 312 Remodal.prototype.open = function() { 313 314 // Check if the animation was completed 315 if (this.busy) { 316 return; 317 } 318 319 var remodal = this; 320 var id; 321 322 remodal.busy = true; 323 remodal.$modal.trigger('open'); 324 325 id = remodal.$modal.attr('data-' + pluginName + '-id'); 326 327 if (id && remodal.settings.hashTracking) { 328 scrollTop = $(window).scrollTop(); 329 location.hash = id; 330 } 331 332 if (current && current !== remodal) { 333 current.$overlay.hide(); 334 current.$wrapper.hide(); 335 current.$body.removeClass(namespace + '-is-active'); 336 } 337 338 current = remodal; 339 340 lockScreen(); 341 remodal.$overlay.show(); 342 remodal.$wrapper.show(); 343 344 setTimeout(function() { 345 remodal.$body.addClass(namespace + '-is-active'); 346 remodal.$wrapper.scrollTop(0); 347 348 setTimeout(function() { 349 remodal.busy = false; 350 remodal.$modal.trigger('opened'); 351 }, remodal.td + 50); 352 }, 25); 353 }; 354 355 /** 356 * Close a modal window 357 * @public 358 * @param {String|undefined} reason A reason to close 359 */ 360 Remodal.prototype.close = function(reason) { 361 362 // Check if the animation was completed 363 if (this.busy) { 364 return; 365 } 366 367 var remodal = this; 368 369 remodal.busy = true; 370 remodal.$modal.trigger({ 371 type: 'close', 372 reason: reason 373 }); 374 375 if ( 376 remodal.settings.hashTracking && 377 remodal.$modal.attr('data-' + pluginName + '-id') === location.hash.substr(1) 378 ) { 379 location.hash = ''; 380 $(window).scrollTop(scrollTop); 381 } 382 383 remodal.$body.removeClass(namespace + '-is-active'); 384 385 setTimeout(function() { 386 remodal.$overlay.hide(); 387 remodal.$wrapper.hide(); 388 unlockScreen(); 389 390 remodal.busy = false;
391 remodal.$modal.trigger({ 392 type: 'closed', 393 reason: reason 394 }); 395 }, remodal.td + 50); 396 }; 397 398 /** 399 * Special plugin object for instances. 400 * @public 401 * @type {Object} 402 */ 403 $[pluginName] = { 404 lookup: [] 405 }; 406 407 /** 408 * Plugin constructor 409 * @param {Object} options 410 * @returns {JQuery} 411 * @constructor 412 */ 413 $.fn[pluginName] = function(opts) { 414 var instance; 415 var $elem; 416 417 this.each(function(index, elem) { 418 $elem = $(elem); 419 420 if ($elem.data(pluginName) == null) { 421 instance = new Remodal($elem, opts); 422 $elem.data(pluginName, instance.index); 423 424 if ( 425 instance.settings.hashTracking && 426 $elem.attr('data-' + pluginName + '-id') === location.hash.substr(1) 427 ) { 428 instance.open(); 429 } 430 } else { 431 instance = $[pluginName].lookup[$elem.data(pluginName)]; 432 } 433 }); 434 435 return instance; 436 }; 437 438 $(document).ready(function() { 439 440 // data-remodal-target opens a modal window with the special Id. 441 $(document).on('click', '[data-' + pluginName + '-target]', function(e) { 442 e.preventDefault(); 443 444 var elem = e.currentTarget; 445 var id = elem.getAttribute('data-' + pluginName + '-target'); 446 var $target = $('[data-' + pluginName + '-id=' + id + ']'); 447 448 $[pluginName].lookup[$target.data(pluginName)].open(); 449 }); 450 451 // Auto initialization of modal windows. 452 // They should have the 'remodal' class attribute. 453 // Also you can write `data-remodal-options` attribute to pass params into the modal. 454 $(document).find('.' + namespace).each(function(i, container) { 455 var $container = $(container); 456 var options = $container.data(pluginName + '-options'); 457 458 if (!options) { 459 options = {}; 460 } else if (typeof options === 'string' || options instanceof String) { 461 options = parseOptions(options); 462 } 463 464 $container[pluginName](options); 465 }); 466 }); 467 468 /** 469 * Hashchange handler 470 * @private 471 * @param {Event} e 472 * @param {Boolean} [closeOnEmptyHash=true] 473 */ 474 function hashHandler(e, closeOnEmptyHash) { 475 var id = location.hash.replace('#', ''); 476 var instance; 477 var $elem; 478 479 if (typeof closeOnEmptyHash === 'undefined') { 480 closeOnEmptyHash = true; 481 } 482 483 if (!id) { 484 if (closeOnEmptyHash) { 485 486 // Check if we have currently opened modal and animation was completed 487 if (current && !current.busy && current.settings.hashTracking) { 488 current.close(); 489 } 490 } 491 } else { 492 493 // Catch syntax error if your hash is bad 494 try { 495 $elem = $( 496 '[data-' + pluginName + '-id=' + 497 id.replace(new RegExp('/', 'g'), '\\/') + ']' 498 ); 499 } catch (err) {} 500 501 if ($elem && $elem.length) { 502 instance = $[pluginName].lookup[$elem.data(pluginName)]; 503 504 if (instance && instance.settings.hashTracking) { 505 instance.open(); 506 } 507 } 508 509 } 510 } 511 512 $(window).bind('hashchange.' + namespace, hashHandler); 513 514});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.