1/*! 2 * Dialogs Manager v4.9.0 3 * https://github.com/kobizz/dialogs-manager 4 * 5 * Copyright Kobi Zaltzberg 6 * Released under the MIT license 7 * https://github.com/kobizz/dialogs-manager/blob/master/LICENSE.txt 8 */ 9 10(function($, global) { 11 'use strict'; 12 13 /* 14 * Dialog Manager 15 */ 16 var DialogsManager = { 17 widgetsTypes: {}, 18 createWidgetType: function(typeName, properties, Parent) { 19 20 if (!Parent) { 21 Parent = this.Widget; 22 } 23 24 var WidgetType = function() { 25 26 Parent.apply(this, arguments); 27 }; 28 29 var prototype = WidgetType.prototype = new Parent(typeName); 30 31 prototype.types = prototype.types.concat([typeName]); 32 33 $.extend(prototype, properties); 34 35 prototype.constructor = WidgetType; 36 37 WidgetType.extend = function(typeName, properties) { 38 39 return DialogsManager.createWidgetType(typeName, properties, WidgetType); 40 }; 41 42 return WidgetType; 43 }, 44 addWidgetType: function(typeName, properties, Parent) { 45 46 if (properties && properties.prototype instanceof this.Widget) { 47 return this.widgetsTypes[typeName] = properties; 48 } 49 50 return this.widgetsTypes[typeName] = this.createWidgetType(typeName, properties, Parent); 51 }, 52 getWidgetType: function(widgetType) { 53 54 return this.widgetsTypes[widgetType]; 55 } 56 }; 57 58 /* 59 * Dialog Manager instances constructor 60 */ 61 DialogsManager.Instance = function() { 62 63 var self = this, 64 elements = {}, 65 settings = {}; 66 67 var initElements = function() { 68 69 elements.body = $('body'); 70 }; 71 72 var initSettings = function(options) { 73 74 var defaultSettings = { 75 classPrefix: 'dialog', 76 effects: { 77 show: 'fadeIn', 78 hide: 'fadeOut' 79 } 80 }; 81 82 $.extend(settings, defaultSettings, options); 83 }; 84 85 this.createWidget = function(widgetType, properties) { 86 87 var WidgetTypeConstructor = DialogsManager.getWidgetType(widgetType), 88 widget = new WidgetTypeConstructor(widgetType); 89 90 properties = properties || {}; 91 92 widget.init(self, properties); 93 94 return widget; 95 }; 96 97 this.getSettings = function(property) { 98 99 if (property) { 100 return settings[property]; 101 } 102 103 return Object.create(settings); 104 }; 105 106 this.init = function(settings) { 107 108 initSettings(settings); 109 110 initElements(); 111 112 return self; 113 }; 114 115 self.init(); 116 }; 117 118 /* 119 * Widget types constructor 120 */ 121 DialogsManager.Widget = function(widgetName) { 122 123 var self = this, 124 settings = {}, 125 events = {}, 126 elements = {}, 127 hideTimeOut = 0, 128 baseClosureMethods = ['refreshPosition']; 129 130 var bindEvents = function() { 131 132 var windows = [elements.window]; 133 134 if (elements.iframe) { 135 windows.push(jQuery(elements.iframe[0].contentWindow)); 136 } 137 138 windows.forEach(function(window) { 139 if (settings.hide.onEscKeyPress) { 140 window.on('keyup', onWindowKeyUp); 141 } 142 143 if (settings.hide.onOutsideClick) { 144 window[0].addEventListener('click', hideOnOutsideClick, true); 145 } 146 147 if (settings.hide.onOutsideContextMenu) { 148 window[0].addEventListener('contextmenu', hideOnOutsideClick, true); 149 } 150 151 if (settings.position.autoRefresh) { 152 window.on('resize', self.refreshPosition); 153 } 154 }); 155 156 if (settings.hide.onClick || settings.hide.onBackgroundClick) { 157 elements.widget.on('click', hideOnClick); 158 } 159 }; 160 161 var callEffect = function(intent, params) { 162 163 var effect = settings.effects[intent], 164 $widget = elements.widget; 165 166 if ($.isFunction(effect)) { 167 effect.apply($widget, params); 168 } else { 169 170 if ($widget[effect]) { 171 $widget[effect].apply($widget, params); 172 } else { 173 throw 'Reference Error: The effect ' + effect + ' not found'; 174 } 175 } 176 }; 177 178 var ensureClosureMethods = function() { 179 180 var closureMethodsNames = baseClosureMethods.concat(self.getClosureMethods()); 181 182 $.each(closureMethodsNames, function() { 183 184 var methodName = this, 185 oldMethod = self[methodName]; 186 187 self[methodName] = function() { 188 189 oldMethod.apply(self, arguments); 190 }; 191 }); 192 }; 193 194 var fixIframePosition = function(position) { 195 if (! position.my) { 196 return; 197 } 198 199 var horizontalOffsetRegex = /left|right/, 200 extraOffsetRegex = /([+-]\d+)?$/, 201 iframeOffset = elements.iframe.offset(), 202 iframeWindow = elements.iframe[0].contentWindow, 203 myParts = position.my.split(' '), 204 fixedParts = []; 205 206 if (myParts.length === 1) { 207 if (horizontalOffsetRegex.test(myParts[0])) { 208 myParts.push('center'); 209 } else { 210 myParts.unshift('center'); 211 } 212 } 213
214 myParts.forEach(function(part, index) { 215 var fixedPart = part.replace(extraOffsetRegex, function(partOffset) { 216 partOffset = +partOffset || 0; 217 218 if (! index) { 219 partOffset += iframeOffset.left - iframeWindow.scrollX; 220 } else { 221 partOffset += iframeOffset.top - iframeWindow.scrollY; 222 } 223 224 if (partOffset >= 0) { 225 partOffset = '+' + partOffset; 226 } 227 228 return partOffset; 229 }); 230 231 fixedParts.push(fixedPart); 232 }); 233 234 position.my = fixedParts.join(' '); 235 }; 236 237 var hideOnClick = function(event) { 238 239 if (isContextMenuClickEvent(event)) { 240 return; 241 } 242 243 if (settings.hide.onClick) { 244 245 if ($(event.target).closest(settings.selectors.preventClose).length) { 246 return; 247 } 248 } else if (event.target !== this) { 249 return; 250 } 251 252 self.hide(); 253 }; 254 255 var isIgnoredTarget = function(event) { 256 257 if (! settings.hide.ignore) { 258 return false; 259 } 260 261 return !! $(event.target).closest(settings.hide.ignore).length; 262 }; 263 264 var hideOnOutsideClick = function(event) { 265 266 if (isContextMenuClickEvent(event) || $(event.target).closest(elements.widget).length || isIgnoredTarget(event)) { 267 return; 268 } 269 270 self.hide(); 271 }; 272 273 var initElements = function() { 274 275 self.addElement('widget'); 276 277 self.addElement('header'); 278 279 self.addElement('message'); 280 281 self.addElement('window', window); 282 283 self.addElement('body', document.body); 284 285 self.addElement('container', settings.container); 286 287 if (settings.iframe) { 288 self.addElement('iframe', settings.iframe); 289 } 290 291 if (settings.closeButton) { 292 if ( settings.closeButtonClass ) { 293 // Backwards compatibility 294 settings.closeButtonOptions.iconClass = settings.closeButtonClass; 295 } 296 297 const $button = $('<div>', settings.closeButtonOptions.attributes), 298 $buttonIcon = $(settings.closeButtonOptions.iconElement).addClass(settings.closeButtonOptions.iconClass); 299 300 $button.append($buttonIcon); 301 302 self.addElement('closeButton', $button); 303 } 304 305 var id = self.getSettings('id'); 306 307 if (id) { 308 self.setID(id); 309 } 310 311 var classes = []; 312 313 $.each(self.types, function() { 314 classes.push(settings.classes.globalPrefix + '-type-' + this); 315 }); 316 317 classes.push(self.getSettings('className')); 318
319 elements.widget.addClass(classes.join(' ')); 320 }; 321 322 var initSettings = function(parent, userSettings) { 323 324 var parentSettings = $.extend(true, {}, parent.getSettings()); 325 326 settings = { 327 headerMessage: '', 328 message: '', 329 effects: parentSettings.effects, 330 classes: { 331 globalPrefix: parentSettings.classPrefix, 332 prefix: parentSettings.classPrefix + '-' + widgetName, 333 preventScroll: parentSettings.classPrefix + '-prevent-scroll' 334 }, 335 selectors: { 336 preventClose: '.' + parentSettings.classPrefix + '-prevent-close' 337 }, 338 container: 'body', 339 preventScroll: false, 340 iframe: null, 341 closeButton: false, 342 closeButtonOptions: { 343 iconClass: parentSettings.classPrefix + '-close-button-icon', 344 attributes: {}, 345 iconElement: '<i>', 346 }, 347 position: { 348 element: 'widget', 349 my: 'center', 350 at: 'center', 351 enable: true, 352 autoRefresh: false 353 }, 354 hide: { 355 auto: false, 356 autoDelay: 5000, 357 onClick: false, 358 onOutsideClick: true, 359 onOutsideContextMenu: false, 360 onBackgroundClick: true, 361 onEscKeyPress: true, 362 ignore: '' 363 } 364 }; 365 366 $.extend(true, settings, self.getDefaultSettings(), userSettings); 367 368 initSettingsEvents(); 369 }; 370 371 var initSettingsEvents = function() { 372 373 $.each(settings, function(settingKey) { 374 375 var eventName = settingKey.match(/^on([A-Z].*)/); 376 377 if (!eventName) { 378 return; 379 } 380 381 eventName = eventName[1].charAt(0).toLowerCase() + eventName[1].slice(1); 382 383 self.on(eventName, this); 384 }); 385 }; 386 387 var isContextMenuClickEvent = function(event) { 388 // Firefox fires `click` event on every `contextmenu` event. 389 return event.type === 'click' && event.button === 2; 390 }; 391 392 var normalizeClassName = function(name) { 393 394 return name.replace(/([a-z])([A-Z])/g, function() { 395 396 return arguments[1] + '-' + arguments[2].toLowerCase(); 397 }); 398 }; 399 400 var onWindowKeyUp = function(event) { 401 var ESC_KEY = 27, 402 keyCode = event.which; 403 404 if (ESC_KEY === keyCode) { 405 self.hide(); 406 } 407 }; 408 409 var unbindEvents = function() { 410 411 var windows = [elements.window]; 412 413 if (elements.iframe) { 414 windows.push(jQuery(elements.iframe[0].contentWindow)); 415 } 416 417 windows.forEach(function(window) { 418 if (settings.hide.onEscKeyPress) { 419 window.off('keyup', onWindowKeyUp); 420 } 421 422 if (settings.hide.onOutsideClick) { 423 window[0].removeEventListener('click', hideOnOutsideClick, true); 424 } 425 426 if (settings.hide.onOutsideContextMenu) { 427 window[0].removeEventListener('contextmenu', hideOnOutsideClick, true); 428 } 429 430 if (settings.position.autoRefresh) { 431 window.off('resize', self.refreshPosition); 432 } 433 }); 434 435 if (settings.hide.onClick || settings.hide.onBackgroundClick) { 436 elements.widget.off('click', hideOnClick); 437 } 438 }; 439 440 this.addElement = function(name, element, classes) { 441 442 var $newElement = elements[name] = $(element || '<div>'), 443 normalizedName = normalizeClassName(name); 444 445 classes = classes ? classes + ' ' : ''; 446 447 classes += settings.classes.globalPrefix + '-' + normalizedName; 448 449 classes += ' ' + settings.classes.prefix + '-' + normalizedName; 450
451 $newElement.addClass(classes); 452 453 return $newElement; 454 }; 455 456 this.destroy = function() { 457 458 unbindEvents(); 459 460 elements.widget.remove(); 461 462 self.trigger('destroy'); 463 464 return self; 465 }; 466 467 this.getElements = function(item) { 468 469 return item ? elements[item] : elements; 470 }; 471 472 this.getSettings = function(setting) { 473 474 var copy = Object.create(settings); 475 476 if (setting) { 477 return copy[setting]; 478 } 479 480 return copy; 481 }; 482 483 this.hide = function() { 484 485 if (! self.isVisible()) { 486 return; 487 } 488 489 clearTimeout(hideTimeOut); 490 491 callEffect('hide', arguments); 492 493 unbindEvents(); 494 495 if (settings.preventScroll) { 496 self.getElements('body').removeClass(settings.classes.preventScroll); 497 } 498 499 self.trigger('hide'); 500 501 return self; 502 }; 503 504 this.init = function(parent, properties) { 505 506 if (!(parent instanceof DialogsManager.Instance)) { 507 throw 'The ' + self.widgetName + ' must to be initialized from an instance of DialogsManager.Instance'; 508 } 509 510 ensureClosureMethods(); 511 512 self.trigger('init', properties); 513 514 initSettings(parent, properties); 515 516 initElements(); 517 518 self.buildWidget(); 519 520 self.attachEvents(); 521 522 self.trigger('ready'); 523 524 return self; 525 }; 526 527 this.isVisible = function() { 528 529 return elements.widget.is(':visible'); 530 }; 531 532 this.on = function(eventName, callback) { 533 534 if ('object' === typeof eventName) { 535 $.each(eventName, function(singleEventName) { 536 self.on(singleEventName, this); 537 }); 538 539 return self; 540 } 541 542 var eventNames = eventName.split(' '); 543 544 eventNames.forEach(function(singleEventName) { 545 if (!events[singleEventName]) { 546 events[singleEventName] = []; 547 } 548 549 events[singleEventName].push(callback); 550 }); 551 552 return self; 553 }; 554 555 this.off = function(eventName, callback) { 556 557 if (! events[ eventName ]) { 558 return self; 559 } 560 561 if (! callback) { 562 delete events[eventName]; 563 564 return self; 565 } 566 567 var callbackIndex = events[eventName].indexOf(callback); 568 569 if (-1 !== callbackIndex) { 570 events[eventName].splice(callbackIndex, 1); 571 } 572 573 return self; 574 }; 575 576 this.refreshPosition = function() { 577 578 if (! settings.position.enable) { 579 return; 580 } 581 582 var position = $.extend({}, settings.position); 583 584 if (elements[position.of]) { 585 position.of = elements[position.of]; 586 } 587 588 if (! position.of) { 589 position.of = window; 590 } 591 592 if (settings.iframe) { 593 fixIframePosition(position); 594 } 595 596 elements[position.element].position(position); 597 }; 598 599 this.setID = function(id) { 600 601 elements.widget.attr('id', id); 602 603 return self; 604 }; 605 606 this.setHeaderMessage = function(message) { 607 608 self.getElements('header').html(message); 609 610 return self; 611 }; 612 613 this.setMessage = function(message) { 614 615 elements.message.html(message); 616 617 return self; 618 }; 619 620 this.setSettings = function(key, value) { 621 622 if (jQuery.isPlainObject(value)) { 623 $.extend(true, settings[key], value); 624 } else { 625 settings[key] = value; 626 } 627 628 return self; 629 }; 630 631 this.show = function() { 632 633 clearTimeout(hideTimeOut); 634 635 elements.widget.appendTo(elements.container).hide(); 636 637 callEffect('show', arguments); 638 639 self.refreshPosition(); 640 641 if (settings.hide.auto) { 642 hideTimeOut = setTimeout(self.hide, settings.hide.autoDelay); 643 } 644 645 bindEvents(); 646 647 if (settings.preventScroll) { 648 self.getElements('body').addClass(settings.classes.preventScroll); 649 } 650 651 self.trigger('show'); 652 653 return self; 654 }; 655 656 this.trigger = function(eventName, params) { 657 658 var methodName = 'on' + eventName[0].toUpperCase() + eventName.slice(1); 659 660 if (self[methodName]) { 661 self[methodName](params); 662 } 663 664 var callbacks = events[eventName]; 665 666 if (!callbacks) { 667 return; 668 } 669 670 $.each(callbacks, function(index, callback) { 671 672 callback.call(self, params); 673 }); 674 675 return self; 676 }; 677 }; 678 679 DialogsManager.Widget.prototype.types = []; 680 681 // Inheritable widget methods 682 DialogsManager.Widget.prototype.buildWidget = function() { 683 684 var elements = this.getElements(), 685 settings = this.getSettings(); 686 687 elements.widget.append(elements.header, elements.message); 688 689 this.setHeaderMessage(settings.headerMessage); 690 691 this.setMessage(settings.message); 692 693 if (this.getSettings('closeButton')) { 694 elements.widget.prepend(elements.closeButton); 695 } 696 }; 697 698 DialogsManager.Widget.prototype.attachEvents = function() { 699 700 var self = this; 701 702 if (self.getSettings('closeButton')) { 703 self.getElements('closeButton').on('click', function() { 704 self.hide(); 705 }); 706 } 707 }; 708 709 DialogsManager.Widget.prototype.getDefaultSettings = function() { 710 711 return {}; 712 }; 713 714 DialogsManager.Widget.prototype.getClosureMethods = function() { 715 716 return []; 717 }; 718 719 DialogsManager.Widget.prototype.onHide = function() { 720 }; 721 722 DialogsManager.Widget.prototype.onShow = function() { 723 }; 724 725 DialogsManager.Widget.prototype.onInit = function() { 726 }; 727 728 DialogsManager.Widget.prototype.onReady = function() { 729 }; 730 731 DialogsManager.widgetsTypes.simple = DialogsManager.Widget; 732 733 DialogsManager.addWidgetType('buttons', { 734 activeKeyUp: function(event) { 735 736 var TAB_KEY = 9; 737 738 if (event.which === TAB_KEY) { 739 event.preventDefault(); 740 } 741 742 if (this.hotKeys[event.which]) { 743 this.hotKeys[event.which](this); 744 } 745 }, 746 activeKeyDown: function(event) { 747 748 if (!this.focusedButton) { 749 return; 750 } 751 752 var TAB_KEY = 9; 753 754 if (event.which === TAB_KEY) { 755 event.preventDefault(); 756 757 var currentButtonIndex = this.focusedButton.index(), 758 nextButtonIndex; 759 760 if (event.shiftKey) { 761 762 nextButtonIndex = currentButtonIndex - 1; 763 764 if (nextButtonIndex < 0) { 765 nextButtonIndex = this.buttons.length - 1; 766 } 767 } else { 768 769 nextButtonIndex = currentButtonIndex + 1; 770 771 if (nextButtonIndex >= this.buttons.length) { 772 nextButtonIndex = 0; 773 } 774 } 775 776 this.focusedButton = this.buttons[nextButtonIndex].focus(); 777 } 778 }, 779 addButton: function(options) { 780 781 var self = this, 782 settings = self.getSettings(), 783 buttonSettings = jQuery.extend(settings.button, options); 784 785 var classes = options.classes ? options.classes + ' ' : ''; 786 787 classes += settings.classes.globalPrefix + '-button'; 788 789 var $button = self.addElement(options.name, $('<' + buttonSettings.tag + '>').html(options.text), classes); 790 791 self.buttons.push($button); 792 793 var buttonFn = function() { 794 795 if (settings.hide.onButtonClick) { 796 self.hide(); 797 } 798 799 if ($.isFunction(options.callback)) { 800 options.callback.call(this, self); 801 } 802 }; 803 804 $button.on('click', buttonFn); 805 806 if (options.hotKey) { 807 this.hotKeys[options.hotKey] = buttonFn; 808 } 809 810 this.getElements('buttonsWrapper').append($button); 811 812 if (options.focus) { 813 this.focusedButton = $button; 814 } 815 816 return self; 817 }, 818 bindHotKeys: function() { 819 820 this.getElements('window').on({ 821 keyup: this.activeKeyUp, 822 keydown: this.activeKeyDown 823 }); 824 }, 825 buildWidget: function() { 826 827 DialogsManager.Widget.prototype.buildWidget.apply(this, arguments); 828 829 var $buttonsWrapper = this.addElement('buttonsWrapper'); 830 831 this.getElements('widget').append($buttonsWrapper); 832 }, 833 getClosureMethods: function() { 834 835 return [ 836 'activeKeyUp', 837 'activeKeyDown' 838 ]; 839 }, 840 getDefaultSettings: function() { 841 842 return { 843 hide: { 844 onButtonClick: true 845 }, 846 button: { 847 tag: 'button' 848 } 849 }; 850 }, 851 onHide: function() { 852 853 this.unbindHotKeys(); 854 }, 855 onInit: function() { 856 857 this.buttons = []; 858 859 this.hotKeys = {}; 860 861 this.focusedButton = null; 862 }, 863 onShow: function() { 864 865 this.bindHotKeys(); 866 867 if (!this.focusedButton) { 868 this.focusedButton = this.buttons[0]; 869 } 870 871 if (this.focusedButton) { 872 this.focusedButton.focus(); 873 } 874 }, 875 unbindHotKeys: function() { 876 877 this.getElements('window').off({ 878 keyup: this.activeKeyUp, 879 keydown: this.activeKeyDown 880 }); 881 } 882 }); 883 884 DialogsManager.addWidgetType('lightbox', DialogsManager.getWidgetType('buttons').extend('lightbox', { 885 getDefaultSettings: function() { 886 887 var settings = DialogsManager.getWidgetType('buttons').prototype.getDefaultSettings.apply(this, arguments); 888 889 return $.extend(true, settings, { 890 contentWidth: 'auto', 891 contentHeight: 'auto', 892 position: { 893 element: 'widgetContent', 894 of: 'widget', 895 autoRefresh: true 896 } 897 }); 898 }, 899 buildWidget: function() { 900 901 DialogsManager.getWidgetType('buttons').prototype.buildWidget.apply(this, arguments); 902 903 var $widgetContent = this.addElement('widgetContent'), 904 elements = this.getElements(); 905 906 $widgetContent.append(elements.header, elements.message, elements.buttonsWrapper); 907 908 elements.widget.html($widgetContent); 909 910 if (elements.closeButton) {
911 $widgetContent.prepend(elements.closeButton); 912 } 913 }, 914 onReady: function() { 915 916 var elements = this.getElements(), 917 settings = this.getSettings(); 918 919 if ('auto' !== settings.contentWidth) { 920 elements.message.width(settings.contentWidth); 921 } 922 923 if ('auto' !== settings.contentHeight) { 924 elements.message.height(settings.contentHeight); 925 } 926 } 927 })); 928 929 DialogsManager.addWidgetType('confirm', DialogsManager.getWidgetType('lightbox').extend('confirm', { 930 onReady: function() { 931 932 DialogsManager.getWidgetType('lightbox').prototype.onReady.apply(this, arguments); 933 934 var strings = this.getSettings('strings'), 935 isDefaultCancel = this.getSettings('defaultOption') === 'cancel'; 936 937 this.addButton({ 938 name: 'cancel', 939 text: strings.cancel, 940 callback: function(widget) { 941 942 widget.trigger('cancel'); 943 }, 944 focus: isDefaultCancel 945 }); 946 947 this.addButton({ 948 name: 'ok', 949 text: strings.confirm, 950 callback: function(widget) { 951 952 widget.trigger('confirm'); 953 }, 954 focus: !isDefaultCancel 955 }); 956 }, 957 getDefaultSettings: function() { 958 959 var settings = DialogsManager.getWidgetType('lightbox').prototype.getDefaultSettings.apply(this, arguments); 960 961 settings.strings = { 962 confirm: 'OK', 963 cancel: 'Cancel' 964 }; 965 966 settings.defaultOption = 'cancel'; 967 968 return settings; 969 } 970 })); 971 972 DialogsManager.addWidgetType('alert', DialogsManager.getWidgetType('lightbox').extend('alert', { 973 onReady: function() { 974 975 DialogsManager.getWidgetType('lightbox').prototype.onReady.apply(this, arguments); 976 977 var strings = this.getSettings('strings'); 978 979 this.addButton({ 980 name: 'ok', 981 text: strings.confirm, 982 callback: function(widget) { 983 984 widget.trigger('confirm'); 985 } 986 }); 987 }, 988 getDefaultSettings: function() { 989 990 var settings = DialogsManager.getWidgetType('lightbox').prototype.getDefaultSettings.apply(this, arguments); 991 992 settings.strings = { 993 confirm: 'OK' 994 }; 995 996 return settings; 997 } 998 })); 999 1000 // Exporting the DialogsManager variable to global 1001 global.DialogsManager = DialogsManager; 1002})( 1003 typeof jQuery !== 'undefined' ? jQuery : typeof require === 'function' && require('jquery'), 1004 (typeof module !== 'undefined' && typeof module.exports !== 'undefined') ? module.exports : window 1005);
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.