PageSourceSearch

https://www.e-hospitalservices.net/assets/js/ssi-modal.js

js e-hospitalservices.net collected 2026-10-09 22:46:52 UTC 72,903 bytes, 1,772 lines download raw bytes

1(function (root, factory) {
2    //@author http://ifandelse.com/its-not-hard-making-your-library-support-amd-and-commonjs/
3    if (typeof module === "object" && module.exports) {
4        module.exports = factory(require("jquery"));
5    } else {
6        root.ssi_modal = factory(root.jQuery);
7    }
8}(this, function ($) {
9    var animationSupport = checkAnimationSupport();
10    var openedModals = 0;
11    var sharedBackdrop = 0;
12    var byKindShare = {
13        stackModal: 0,
14        normalModal: 0
15    };
16    var uniqueId = 0;
17    var orphanBackdrop = false;
18
19    /**
20     * @constructor
21     * @param {object} options
22     * @return
23     */
24    var Ssi_modal = function (options) {
25        /**
26         * @namespace
27         * @property {object}  defaults               - The default options.
28         * @property {string}  defaults.content       - The main content of the modal.
29         * @property {boolean|(boolean|'shared'|'byKindShared')}  defaults.backdrop      - Enables disables the back drop. The shared option defines that the modal will open a back drop only if there is not anyone already in the dom.              * The byKindShared is similar to the shared but the already rendered backdrop must belong to the same kind of modals (normal modal,stack modal,imgBox modal) else will open new.
30         * @property {boolean}  defaults.outSideClose      - Close the modal when you click outside.
31         * @property {boolean}  defaults.bodyScroll    - Enables/disables the scroll bar of the document when the modal is opened.
32         * @property {boolean}  defaults.closeIcon      - Show/hide the close button
33         * @property {boolean}  defaults.keepContent   - Forces the modal to remove or not the content when it close.It not associated with stack modals
34         * @property {function}  defaults.beforeShow      - Callback when the modal opens.
35         * @property {function}  defaults.onShow      - Callback when the modal opens.
36         * @property {function}  defaults.beforeClose      - Callback when the modal closes.
37         * @property {function}  defaults.onClose      - Callback when the modal closes.
38         * @property {'right top'|'right bottom'|'left top'|'left bottom'|'center top'|'center bottom'}  defaults.position   - Sets the position of the modals.
39         * @property {boolean}  defaults.stack         - Make the modal a part of stack.For example toast/notification messages. Requires position.
40         * @property {boolean}  defaults.onClickClose  - Enables/Disables the ability to close the modal when you click in the main window.
41         * @property {string}  defaults.className      - Defines a class to the modal outer element.
42         * @property {string}  defaults.backdropClassName      - Defines a class to the backdrop element.
43         * @property {object}  defaults.preview      - Set the options and the state of a modal according to the preview
44         * @property {boolean} defaults.preview.icon - Generate an icon that allows the user to change display state
45         * @property {boolean} defaults.preview.hideIcons - Enables/disables the ability to hide the modal after a certain time when the modal is in fullScreen state.
46         * @property {'fullScreen' | 'normal'}  defaults.preview.state - The state tha the modal will have when opens.
47         * @property {object | 'false'}  defaults.closeAfter
48         * @property {number}  defaults.closeAfter.time      - After the defined time the modal will close.
49         * @property {boolean}  defaults.closeAfter.displayTime      - Display the in a span with class="ssi-displayTime" that you must set. In example <span class="ssi-displayTime"></span> .
50         * @property {boolean}  defaults.closeAfter.resetOnHover      -Reset the time that modal will close.
51
52         * @property {object}   defaults.iframe      - Options for iframe.
53         * @property {boolean}  defaults.iframe.allowFullScreen      - The default treasure.
54         * @property {string}   defaults.iframe.className      - Set a
55         * @property {boolean}  defaults.center      - Element centering.Not associated with positioned modals
56         * @property {boolean || string}  defaults.animation      - Enables/disables animations if you set a string all animation type will be set to that sting.
57         * @property {object || string || boolean}  defaults.modalAnimation      - Set the animations for the modal window.
58         * @property {string || boolean}  defaults.modalAnimation.show      - The animation tha start when the modal opens.
59         * @property {string || 'boolean}  defaults.modalAnimation.hide      - The animation tha start when the modal closes.
60         * @property {boolean}  defaults.backdropAnimation      - Set the animations for modal the back drop.
61         * @property {string || boolean}  defaults.backdropAnimation.show      - The animation tha start when the backdrop appears.
62         * @property {string || 'boolean}  defaults.backdropAnimation.hide      - The animation tha start when the modal closes.
63         * @property {Object[]}  defaults.buttons      - The buttons of modal.
64         * @property {'button' || 'link'}  defaults.buttons.type      - The type of button.
65         * @property {keycode}  defaults.buttons.keyPres      - Registers a keypress event  that will trigger the button's click method.
66         * @property {boolean}  defaults.buttons.className    - Defines a class to the button element.
67         * @property {number||false}  defaults.buttons.enableAfter      - Disables the button.if set a number the button will be enable after that time in seconds.
68         * @property {string}  defaults.buttons.id      - Defines an id to the button element.
69         * @property {string}  defaults.buttons.label      - The text of the button.
70         * @property {object || string || boolean}  defaults.buttons.modalAnimation      - Changes the animations of the modal.
71         * @property {object}  defaults.buttons.modalAnimation.show      - If you set this the next modal will open with this animation.
72         * @property {object}  defaults.buttons.modalAnimation.hide      - It changes the current modal hide animation.
73         * @property {object || string || boolean}  defaults.buttons.backdropAnimation      - Changes the animations of the backdrop.
74         * @property {object}  defaults.buttons.backdropAnimation.show      - If you set this the next backdrop will open with this animation.
75         * @property {object}  defaults.buttons.backdropAnimation.hide      - It changes the current backdrop hide animation.
76         * @property {boolean}  defaults.iconButtons      - Register a new icon in the top of the modal( where the x button is).You can modify it only with css using content and background properties.
77         * @property {boolean}  defaults.iconButtons.className      - Defines a class name to the element.
78         * @property {boolean}  defaults.iconButtons.method      - The function that will be fired when you press the icons.This function has access to the event object and the modal's object (ie function(event,modal){})
79         * @property {boolean}  defaults.title      - The title of the modal.
80         * @property {string}  defaults.sizeClass      - Defines the size of the modal.
81         * @property {boolean}  defaults.fixedHeight      - If modal height is bigger than the screen the height of modal will be fixed and will fit the screen also the content will be scrollable.
82         * @property {boolean}  defaults.fitScreen      - The modal min-height will be the height of screen.
83         * @property {boolean}  defaults.navigation      - Enables/disables the navigation of imgBox.
84         */
85
86        /**
87         * The unique id number of modal.
88         * @type {number}
89         */
90
91        this.numberId = uniqueId;
92        if (options.stack) {
93            this.pluginName = 'stackModal';
94        } else {
95            this.pluginName = 'normalModal';
96        }
97        /**
98         * The id of the backdrop.
99         * @type {string}
100         */
101        this.backdropId = '';
102        this.showbd = true;
103        this.setOptions(options);
104    };
105    Ssi_modal.prototype.setOptions = function (options, value) {
106        if (typeof options === 'object') {
107            var defaults = {
108                content: '',
109                bodyScroll: false,
110                keepContent: false,
111                position: '',
112                backdrop: true,
113                stack: false,
114                onClickClose: false,
115                bodyElement: false,
116                className: '',
117                backdropClassName: '',
118                preview: {
119                    icon: false,
120                    hideIcons: false,
121                    state: 'normal'//full
122                },
123                closeAfter: false, // time: 4, displayTime:false, resetOnHover:true }
124                outSideClose: true,
125                onClose: '',
126                onShow: '',
127                beforeClose: '',
128                beforeShow: '',
129                iframe: {//{className,allowfullscreen}
130                    allowFullScreen: true,
131                    className: ''
132                },
133                center: false,
134                closeIcon: true,
135                navigation: false,
136                sizeClass: 'medium',
137                animation: false,
138                modalAnimation: undefined,//{show:'',hide:''}
139                backdropAnimation: undefined,//{show:'',hide:''}
140                animationSpeed: 300,
141                buttons: [], //[{className: 'btn btn-danger', enableAfter:3, id: '', label: 'Open', modalReverseAnimation:true backdropReverseAnimation:true closeAfter:{ clearTimeOut:true, keepContent:true, method: function(){ } } ]
142                iconButtons: [],//[className:'',method:function(){}]
143                title: '',
144                fixedHeight: false,
145                fitScreen: false
146            };
147            var modalObj = this;
148            this.options = $.extend(true, defaults, options);
149            this.options.iconButtons = toArray(this.options.iconButtons);
150            if (this.options.preview.icon) {
151                this.options.iconButtons.push({
152                    className: 'ssi-displayIcon', method: function () {
153                        modalObj.changePreviewState();
154                    }
155                })
156            }
157            if (this.options.closeIcon) {
158                this.options.iconButtons.push({
159                    className: 'ssi-closeIcon', method: function () {
160                        modalObj.close();
161                    }
162                })
163            }
164            setAnimations(this);
165        } else {
166            this.options[options] = value;
167            if (options === 'animation' || 'modalAnimation' || 'backdropAnimation') {
168                setAnimations(this);
169            }
170        }
171        return this;
172    };
173    /**
174     * Initialize the modal and backdrop and expose them to the DOM
175     * @returns {Ssi_modal}
176     */
177    Ssi_modal.prototype.init = function () {
178        if (this.options.backdrop)
179            this.backdropInit();
180        this.modalInit();
181        uniqueId++;
182        return this;
183    };
184
185    /**
186     * Returns the content element of the modal.
187     * @returns {JQuery}
188     */
189    Ssi_modal.prototype.get$content = function () {
190        return this.get$modal().find('#ssi-modalContent');
191    };
192    //returns the outer element of the modal (ie if we use stack modals will return the window object else will return the modalOuter)
193    /**
194     * Returns the modal element of the modal.
195     * @returns {JQuery}
196     */
197    Ssi_modal.prototype.get$modal = function (id) {
198        id = id || this.modalId;
199        return this.$modal || $('#' + id);
200    };
201    /**
202     * Returns the title element of the modal.
203     * @returns {JQuery}
204     */
205    Ssi_modal.prototype.get$title = function () {
206        return this.get$modal().find('#ssi-modalTitle');
207    };
208    Ssi_modal.prototype.destroyTitle = function () {
209        this.get$title().remove();
210        this.options.title = '';
211        return this;
212    };
213    Ssi_modal.prototype.destroyContent = function () {
214        this.get$content().remove();
215        this.options.content = '';
216        return this;
217    };
218    Ssi_modal.prototype.destroyButtons = function (type) {
219        this.get$buttons(type).remove();
220        this.options.buttons = [];
221        return this;
222    };
223    Ssi_modal.prototype.destroyIcons = function () {
224        this.get$icons().remove();
225        this.options.icons = [];
226        return this;
227    };
228
229    /**
230     * Returns the title icons of the modal.
231     * @returns {JQuery}
232     */
233    Ssi_modal.prototype.get$icons = function () {
234        return this.get$modal().find('.ssi-topIcons');
235    };
236
237    /**
238     * Returns the buttons element of the modal.
239     * @returns {JQuery}
240     */
241    Ssi_modal.prototype.get$buttons = function (type) {
242        type = type || 'buttons';
243        return this.get$modal().find('#ssi-' + type);
244    };
245    /**
246     * Returns the window element of the modal.
247     * @returns {JQuery}
248     */
249    Ssi_modal.prototype.get$window = function () {
250        return this.get$modal().find('#ssi-modalWindow');
251    };
252
253    /**
254     * Returns the wrapper element of the modal.
255     * @returns {JQuery}
256     */
257    Ssi_modal.prototype.get$wrapper = function () {
258        if (this.options.stack) {
259            return this.get$modal().parent();
260        }
261        return this.get$modal().find('#ssi-modalWrapper');
262    };
263    //returns the Outer element
264    /**
265     * Returns the outer element of the modal.
266     * @returns {JQuery}
267     */
268    //returns the backdrop element
269    /**
270     * Returns the backdrop element of the modal.
271     * @returns {JQuery}
272     */
273    Ssi_modal.prototype.get$backdrop = function () {
274        return this.$backdrop || $('#' + this.backdropId);
275    };
276
277    var time = null;
278
279    //get/exit full screen state
280    /**
281     * Changes the previe state of the modal
282     * @returns {Ssi_modal}
283     */
284    Ssi_modal.prototype.changePreviewState = function () {
285        var $modalOuter = this.get$modal();
286        if (this.options.preview.state === 'fullScreen') {//if the current state is full
287            $modalOuter.removeClass('ssi-fullScreen');//remove class
288            this.options.preview.state = 'normal';//set state to normal
289            $modalOuter.find('#ssi-modalContent').css("height", "");
290            if (this.options.fixedHeight || this.options.fitScreen)
291                this.setModalHeight();//set height again
292            clearTimeout(time);
293            $modalOuter.off('mousemove.ssi-modal');
294        } else {//if current state is normal
295            if (this.options.preview.hideIcons) {
296                var $icons = $modalOuter.find('.ssi-topIcons');
297                if (this.options.buttons)
298                    var $buttons = $modalOuter.find('#ssi-buttons');//find the buttons area
299                $modalOuter.on('mousemove.ssi-modal', function () {//register mousemove event
300                    clearTimeout(time);
301                    $icons.fadeIn();//show the icons
302                    $buttons.slideDown();//and buttons
303                    time = setTimeout(function () {//after 2 seconds
304                        $buttons.slideUp();//hide them
305                        $icons.fadeOut()
306                    }, 2000)
307                });
308            }
309            this.setModalHeight(40, 'height');         //set the height
310            $modalOuter.addClass('ssi-fullScreen');
311            this.options.preview.state = 'fullScreen';//change state to full
312        }
313        return this;
314    };
315
316    Ssi_modal.prototype.setPluginName = function (name) {
317        this.pluginName = name;
318        byKindShare[name] = 0;
319        return this;
320    };
321
322    /**
323     *  Initialize the content element if it is necessary and registers tha content.
324     * @param {string} content  -The content of the element.
325     * @param{'html' || 'append' || 'prepend} method    -The jquery method tha will use to register the content to the modal.
326     * @returns {*}
327     */
328    Ssi_modal.prototype.setContent = function (content, method) {
329        method = method || 'html';
330        var $modalContent;
331        if (this.options.content !== true) {
332            $modalContent = $('<div id="ssi-modalContent" class="ssi-modalContent ' + (this.options.fixedHeight ? 'ssi-overflow ' : '') + '"></div>');
333            if (this.options.content === '') {
334                if (this.options.title === true) {
335                    this.get$title().after($modalContent)
336                } else {
337                    this.get$window().prepend($modalContent);
338                }
339                this.setModalHeight();
340            }
341            this.options.content = true;
342        } else {
343            $modalContent = this.get$content();
344        }
345        var theContent = content;
346        if (content instanceof $ && this.options.bodyElement === true) {
347            if (this.options.extendOriginalContent === true) {
348                var beforeClose = this.options.beforeClose;
349                this.options.beforeClose = function (modal) {
350                    var resume;
351                    if (typeof  beforeClose === 'function')
352                        resume = beforeClose(modal);
353                    if (resume !== false) {
354                        content.eq(0).after(modal.get$content().contents().unwrap().css('display', '')).remove();
355                    } else {
356                        return resume
357                    }
358
359                };
360            }
361
362            theContent = content.eq(0).clone();
363            if (!theContent.is(":visible")) {
364                theContent.show();
365            }
366        }
367        $modalContent[method](theContent);
368
369        return $modalContent
370    };
371
372    /**
373     * Initialize the buttons element if it is necessary and registers tha buttons.
374     * @param {object[]} buttons -The buttons that will be added to the element.
375     * @param {string} area -The area that we'll append the buttons.
376     * @returns {*}
377     */
378    Ssi_modal.prototype.setButtons = function (buttons, area) {
379        var $buttonsArea, fixHeight = false;
380        buttons = toArray(buttons);
381        if (area !== false) {
382            area = (typeof area !== 'undefined' ? $(area) : this.get$window());
383            $buttonsArea = area.find('#ssi-buttons');
384            $buttonsArea = $buttonsArea[0];
385        }
386
387        if (!$buttonsArea) {
388            $buttonsArea = $('<div id="ssi-buttons" class="ssi-buttons"><div  id="ssi-leftButtons" class="ssi-leftButtons"></div><div id="ssi-rightButtons" class="ssi-rightButtons"></div></div>');
389            if (area) {
390                fixHeight = true;
391                area.append($buttonsArea);
392            }
393
394            this.options.buttons = true;
395        }
396        var length = buttons.length;
397        var $leftArea = $buttonsArea.find('#ssi-leftButtons');
398        var $rightArea = $buttonsArea.find('#ssi-rightButtons');
399        var leftAreaArray = [];
400        var rightAreaArray = [];
401        for (var i = 0, $btn; i < length; i++) {
402            $btn = this.generateButton(buttons[i]);
403            if (buttons[i].side === 'left') {
404                leftAreaArray.push($btn);
405            } else {
406                rightAreaArray.push($btn);
407            }
408        }
409        $leftArea.append(leftAreaArray);
410        $rightArea.append(rightAreaArray);
411        if (fixHeight)this.setModalHeight();
412        return $buttonsArea;
413    };
414    /**
415     * Helps to define the animations
416     */
417    var changeAnimations = function (animations, type) {
418        switch (typeof animations) {
419            case 'boolean':
420                if (type === 'show') {
421                    animations = (animations ? 'anim ssi-fadeIn' : 'ssi-show')
422                } else {
423                    animations = (animations ? 'anim ssi-fadeOut' : 'ssi-hidden')
424                }
425                break;
426            case 'undefined':
427                if (type === 'show') {
428                    animations = 'ssi-show';
429                } else {
430                    animations = 'ssi-hidden';
431                }
432        }
433        return animations
434    };
435    /**
436     * Helps to define the animations
437     */
438    var setAnimations = function (modalObj) {
439        var modalAnim = (modalObj.options.modalAnimation || modalObj.options.animation || false);
440        var backdropAnim = (modalObj.options.backdropAnimation || modalObj.options.animation || false);
441        var inAnim,
442         outAnim;
443
444        inAnim = changeAnimations((typeof modalAnim.show !== 'undefined' ? modalAnim.show : modalAnim), 'show');
445        outAnim = changeAnimations((typeof modalAnim.hide !== 'undefined' ? modalAnim.hide : modalAnim), 'hide');
446        modalObj.options.modalAnimation = {
447            'show': inAnim,
448            'hide': outAnim
449        };
450
451        inAnim = changeAnimations((typeof backdropAnim.show !== 'undefined' ? backdropAnim.show : backdropAnim), 'show');
452        outAnim = changeAnimations((typeof backdropAnim.hide !== 'undefined' ? backdropAnim.hide : backdropAnim), 'hide');
453        modalObj.options.backdropAnimation = {
454            'show': inAnim,
455            'hide': outAnim
456        };
457        if (animationSupport === false) {
458            modalObj.options.modalAnimation = {
459                'show': (modalObj.options.modalAnimation.show !== 'ssi-show' ? 'anim ssi-fadeIn' : 'ssi-show'),
460                'hide': (modalObj.options.modalAnimation.hide !== 'ssi-hidden' ? 'anim ssi-fadeOut' : 'ssi-hidden')
461            };
462            modalObj.options.backdropAnimation = {
463                'show': (modalObj.options.backdropAnimation.show !== 'ssi-show' ? 'anim ssi-fadeIn' : 'ssi-show'),
464                'hide': (modalObj.options.backdropAnimation.hide !== 'ssi-hidden' ? 'anim ssi-fadeOut' : 'ssi-hidden')
465            };
466        }
467    };
468    /**
469     * Register events and timer for closeAfter property
470     * */
471    var setCloseAfter = function (modalObj) {
472        var $modal = modalObj.get$modal();
473        modalObj.time = setTimeout(function () {
474
475            modalObj.close();
476        }, (modalObj.options.closeAfter.time * 1000));
477        if (modalObj.options.closeAfter.displayTime && modalObj.options.title) {
478            var $displayTime = $modal.find('span.ssi-displayTime').html(modalObj.options.closeAfter.time);
479            updateTime(modalObj, $displayTime, function () {
480                modalObj.$displayTime.remove()
481            });
482        }
483        if (modalObj.options.closeAfter.resetOnHover) {
484            $modal.on('mouseenter.ssi-modal', function () {
485                clearTimeout(modalObj.time);
486                if ($displayTime) {
487                    $displayTime.html(modalObj.options.closeAfter.time);
488                    clearInterval(modalObj.countDown);
489                }
490            });
491            $modal.on('mouseleave.ssi-modal', function () {
492                modalObj.time = setTimeout(function () {
493                    modalObj.close();
494                }, (modalObj.options.closeAfter.time * 1000));
495                if (modalObj.options.closeAfter.displayTime && modalObj.options.title) {
496                    updateTime(modalObj, $displayTime, function () {
497                        $displayTime.parent().remove()
498                    });
499                }
500            });
501        }
502    };
503    /**
504     * Initialize the backdrop and append it to the DOM
505     *
506     * @return {JQuery}
507     */
508    Ssi_modal.prototype.backdropInit = function () {
509        var $backdrop;
510        if (typeof orphanBackdrop === 'string') {//if an orphan backdrop exists
511            var $orphanBackdrop = $('#' + orphanBackdrop);
512            this.backdropId = orphanBackdrop;//change the id to the same as the new modal
513            $backdrop = $orphanBackdrop.attr('class', 'ssi-backdrop ' + this.pluginName + ' ' + this.options.backdropClassName);
514            this.showbd = false;
515            orphanBackdrop = true;
516        } else {
517            $backdrop = $('<div id="ssi-backdrop' + this.numberId + '" class="ssi-backdrop ssi-hidden ' + (this.options.backdropClassName) + ' ' + this.pluginName + '"></div>');
518            if (this.options.backdrop === 'shared' || this.options.backdrop === 'byKindShared') {
519                var $sharedBackdrop;
520                if (this.options.backdrop === 'byKindShared') {
521                    $sharedBackdrop = $('.ssi-backdrop.ssi-openedDialog.' + this.pluginName);
522                } else {
523                    $sharedBackdrop = $('.ssi-backdrop.ssi-openedDialog');
524                }
525                if (!$sharedBackdrop[0]) {//check if backdrop already exists
526                    $('body').append($backdrop);//if not , append one
527                    this.backdropId = 'ssi-backdrop' + this.numberId;
528                    this.showbd = true;
529                } else {
530                    this.backdropId = $sharedBackdrop.attr('id');
531                    this.showbd = false;
532                    $backdrop = $sharedBackdrop;
533                }
534            } else if (this.options.backdrop === true) {
535                $('body').append($backdrop);
536                this.backdropId = 'ssi-backdrop' + this.numberId;
537                this.showbd = true;
538            }
539            this.$backdrop = $backdrop;
540        }
541        if (this.options.outSideClose && this.options.position) {//check for ie
542            var modal = this;
543            $backdrop.on('click.ssi-modal' + this.numberId, function (e) {
544                e.preventDefault();
545                modal.close();
546            });
547        }
548        return $backdrop;
549    };
550    /**
551     * Initialize the outer.
552     * @return {JQuery}
553     */
554    var setOuter = function (modalObj) {
555        return $('<div class="ssi-modalOuter ' + (modalObj.options.stack ? ' ssi-stack' : '' + modalObj.options.className) + (modalObj.options.center ? ' ssi-center ' : ' ') + ' ' + (modalObj.options.position ? ' ssi-modalPositioned ' + modalObj.options.position : '') + '"></div>');
556
557    };
558
559    /**
560     * Initialize the wrapper.
561     * @return $backdrop
562     */
563    var setWrapper = function (modalObj) {
564        return $('<div id="ssi-modalWrapper" class=" ssi-modalWrapper ' + modalObj.options.sizeClass + '"></div>');
565
566    };
567    /**
568     * Initialize the icons element if necessary and append the icons to the element.
569     * @param {object[]} icons -The icons that will  append to the icons element.
570     * @returns {jQuery}
571     */
572    Ssi_modal.prototype.setIcons = function (icons) {
573        var $icons, iconArray = [];
574        if (this.options.iconButtons !== true) {
575            $icons = $('<div class="ssi-topIcons"></div>');
576            this.options.iconButtons = true;
577        } else {
578            $icons = this.get$icons();
579        }
580        var modalObj = this;
581        var iconsLength = icons.length;
582        for (var i = 0, icon;
582 i < iconsLength; i++) {
583            icon = icons[i];
584            (function (icon) {
585                iconArray.push($('<a class="' + icon.className + '"></a>')
586                 .click(function (e) {
587                     e.preventDefault();
588                     if (typeof icon.method === 'function') {
589                         $.proxy(icon.method, this)(e, modalObj);
590                     }
591                 }))
592            })(icon)
593        }
594
595        $icons.append(iconArray);
596        return $icons;
597    };
598    /**
599     * Initialize the window
600     * @return {jQuery}
601     */
602    var setWindow = function (modalObj) {
603        var $modalWindow = $('<div id="ssi-modalWindow" class="ssi-modalWindow ' + (modalObj.options.center ? modalObj.options.sizeClass : '') + (modalObj.options.stack ? ' ' + modalObj.options.sizeClass + ' ' + modalObj.options.className + ' ' : '') + '"></div>'),
604         $modalContent = '',
605         windowContent = [];
606        if (modalObj.options.content) {
607            $modalContent = modalObj.setContent(modalObj.options.content, 'html')
608        }
609        if (modalObj.options.title) {
610            windowContent.push(modalObj.setTitle(modalObj.options.title));
611        }
612        if (modalObj.options.onClickClose) {
613            $modalWindow.addClass('ssi-hover').click(function (e) {
614                var $eTarget = $(e.target);
615                if (!$eTarget.is('a') && !$eTarget.is('button')) {
616                    modalObj.close();
617                }
618            })
619        }
620        if ((modalObj.options.iconButtons).length > 0) {
621            windowContent.push(modalObj.setIcons(modalObj.options.iconButtons, true));
622        }
623        windowContent.push($modalContent);
624        if (typeof modalObj.options.buttons !== 'undefined' && !$.isEmptyObject(modalObj.options.buttons)) {
625            windowContent.push(modalObj.setButtons(modalObj.options.buttons, false));
626        }
627        $modalWindow.append(windowContent);
628        return $modalWindow;
629    };
630
631    /**
632     *Generates a button according to the options.
633     * @param {object} buttonOptions -The button options.
634     * @constructor
635     * @returns {jQuery}
636     */
637
638    Ssi_modal.prototype.generateButton = function (buttonOptions) {
639        var defaults = {
640            className: '',
641            enableAfter: false,
642            method: function () {
643            },
644            type: 'button',
645            focused: false,
646            id: '',
647            label: '',
648            modalAnimation: '',
649            backdropAnimation: ''
650        };
651        buttonOptions = $.extend({}, defaults, buttonOptions);
652        var tag = 'button', href = '', modalObj = this, resume;
653        if (buttonOptions.type === 'link') {//set tag type (<a> or <button>)
654            tag = 'a';
655            href = ' href="#"';
656        }
657        var $btn = $('<' + tag + href + (buttonOptions.id ? ' id="' + buttonOptions.id + '"' : ' ') + (buttonOptions.enableAfter ? 'disabled ' : '') + ' class="ssi-modalBtn ' + (buttonOptions.className || '') + '">'
658         + buttonOptions.label +
659         '</' + tag + '>');
660        if (typeof buttonOptions.enableAfter === 'number') {
661            var $count = $('<span class="ssi-countDown">' + buttonOptions.enableAfter + '</span>');
662            updateTime(modalObj, $count, function () {
663                $btn.removeClass('disabled');
664                $btn.removeAttr('disabled');
665                $count.remove();
666            });
667            $btn.append($count);
668        }
669//append button to selected object and set click event
670        if (buttonOptions.keyPress) {
671            $('body').on('keydown.ssi_modal', function (e) {
672                if (e.keyCode == buttonOptions.keyPress && !$btn.is(':disabled')) {
673                    $btn.trigger('click');
674                }
675            });
676        }
677        if (buttonOptions.focused) {
678            setTimeout(function () {
679                $btn.focus();
680            }, 100)
681        }
682        return $btn.click(function (e) {
683            e.preventDefault();
684            if (buttonOptions.clearTimeOut) {
685                clearTimeOut(modalObj);
686            }
687            if (typeof buttonOptions.method === 'function') {
688                resume = $.proxy(buttonOptions.method, this)(e, modalObj);
689            }
690            if (resume === false) {
691                return;
692            }
693            if (typeof buttonOptions.keepContent === 'boolean' && buttonOptions.keepContent !== modalObj.options.keepContent) {
694                modalObj.options.keepContent = buttonOptions.keepContent; // change keepContent option according to button option
695            }
696            if (buttonOptions.closeAfter) {
697                modalObj.close();
698//finally close the modal if closeAfter option is true
699            }
700        });
701    };
702    /**
703     * Initialize the modal and append it to the DOM
704     */
705    Ssi_modal.prototype.modalInit = function () {
706        var $modalWindow = setWindow(this),
707         modalObj = this;
708        if (this.options.position) {
709            if (this.options.stack) {
710                var appendAction = 'append';
711                if (this.options.position.indexOf('bottom') >
711 -1) {//if we hava bottom position we want to prepend the window to appears in the top of stack
712                    appendAction = 'prepend';
713                }
714                var position = this.options.position.replace(" ", '.');//change the spaces with dot to make it a class selector
715                var positionedElement = $('div.ssi-modalOuter.ssi-stack' + '.' + position);
716                if (positionedElement[0]) {//check if this element with this position exists to the dom.
717                    positionedElement
718                     .find('#ssi-modalWrapper')//if exists append the window to the dom.
719                     [appendAction]($modalWindow);
720                }
721                this.$modal = $modalWindow;
722            }
723        }
724        if (!this.options.stack || !positionedElement[0]) {//if not stack modal or the element with this position dont exist to the dom create and append one.
725            var wrapper = setWrapper(this);
726            var $modal = setOuter(this)
727             .append(wrapper
728              .append($modalWindow))
729             .appendTo($('body'));
730            if (!this.options.stack) {//if not stack give a unique id to the outer
731                this.$modal = $modal;
732                $modal.one('onShow.ssi-modal', function () {
733                    if (modalObj.options.outSideClose === true) {
734                        $modal.click(function (e) {
735                            if (e.target === this) {
736                                e.preventDefault();
737                                modalObj.close();
738                            }
739                        });
740                        wrapper.click(function (e) {
741                            if (e.target === this) {
742                                e.preventDefault();
743                                modalObj.close();
744                            }
745
746                        });
747                    }
748                })
749
750            }
751        }
752        this.modalId = 'ssi-' + this.pluginName + this.numberId;
753        (this.$modal).attr('id', 'ssi-' + this.pluginName + this.numberId);
754        (this.$modal).addClass(this.pluginName + ' ssi-modal');
755        this.$modal.data('ssi-modal', this).addClass('ssi-hidden');
756        if (typeof orphanBackdrop === 'string')this.backdropInit();
757        return this.$modal;
758    };
759    /**
760     * Appends title to the modal.
761     * @param {string} title
762     * @return $title
763     */
764    Ssi_modal.prototype.setTitle = function (title) {
765        var $title, fixHeight = false;
766        if (this.options.title !== true) {
767            $title = $('<div id="ssi-modalTitle" class="ssi-modalTitle ' + (!this.options.content ? 'ssi-borderOut ' : '') + '">' + this.options.title + '</div>');
768            if (this.options.title === '') {
769                this.get$window().prepend($title);
770                fixHeight = true;
771            }
772            this.options.title = true;
773        } else {
774            $title = this.get$title();
775        }
776        $title.html(title);
777        if (fixHeight)this.setModalHeight();
778        return $title;
779    };
780
781    Ssi_modal.prototype.showModal = function () {
782        var $modal = this.get$modal(),
783         modalObj = this;
784
785        setTimeout(function () {
786            $modal.trigger("beforeShow.ssi-modal");//trigger show event
787        }, 0);
788        if (this.options.bodyScroll === false) {
789            $('body').addClass('ssi-modalOpen');//add this class to body to disable scrollbar
790            openedModals++;//calculate open modals
791        }
792        if (this.options.backdrop === 'shared') {
793            sharedBackdrop++;
794        } else if (this.options.backdrop === 'byKindShared') {
795            byKindShare[this.pluginName]++
796        }
797
798        $modal.addClass('ssi-openedDialog');
799        var callback = function () {
800            $(this).removeClass('ssi-hidden');
801            if (typeof modalObj.options.onShow === 'function') {
802                modalObj.options.onShow(modalObj);//execute onShow callback
803            }
804            setTimeout(function () {
805                $modal.trigger("onShow.ssi-modal");//trigger show event);
806            }, 0);
807        };
808        $modal.addAnimation(this.options.modalAnimation.show, function () {
809            callback();
810        }).removeClass('ssi-hidden');
811        if (this.options.center) {
812            $modal.css('display', '');
813        }
814        if (modalObj.options.preview.state === 'fullScreen') {//if the default state is fullscreen
815            modalObj.options.preview.state = 'normal';
816            modalObj.changePreviewState();
817        }
818
819        this.setModalHeight();
820
821        if (typeof this.options.closeAfter.time === 'number') {
822            setCloseAfter(this)
823        }
824        delete this.$modal;
825
826    };
827
828    /**
829     * Opens the modal.
830     * @return {Ssi_modal}
831     */
832    Ssi_modal.prototype.showBackdrop = function () {
833        var modalObj = this;
834        var $backdrop = this.get$backdrop().addClass('ssi-openedDialog');
835
836        $backdrop.addAnimation(this.options.backdropAnimation.show).removeClass('ssi-hidden');
837
838        delete this.$backdrop;
839    };
840
841    Ssi_modal.prototype.show = function () {
842
843        if (typeof this.options.beforeShow === 'function') {
844            var resume = this.options.beforeShow(this);
845            if (resume === false) {
846                return this;
847            }
848        }
849
850        this.showModal();
851
852        if (orphanBackdrop === false && this.options.backdrop && this.showbd === true) {
853            this.showBackdrop();
854        }
855
856        return this;
857    };
858
859    /**
860     * Closes the modal
861     * @return {Ssi_modal}
862     */
863    Ssi_modal.prototype.destroyBackdrop = function () {
864        var $backdrop = this.get$backdrop(), modalObj = this;
865        if (this.options.keepContent !== true) {
866            $backdrop.off('click.ssi-modal' + this.numberId);
867        }
868        var thisS = this
869        var closeBack = function () {
870            if ((thisS.options.backdrop === true || (    (   ( thisS.options.backdrop === 'shared' && sharedBackdrop < 1) || ( thisS.options.backdrop === 'byKindShared' && b
870yKindShare[thisS.pluginName] < 1)  ) && ( (!thisS.get$modal(thisS.modalId.replace(thisS.numberId.toString(), thisS.backdropId.replace('ssi-backdrop', '')))[0]) || thisS.backdropId.replace('ssi-backdrop', '') == thisS.numberId))  )) {//thisS maybe blow your mine
871                var closeBackdrop = function () {//thisS will execute when the hide animation end
872                    $backdrop.addClass('ssi-hidden').removeClass('ssi-openedDialog');
873                    $backdrop.trigger('backdropClose.ssi-modal');
874                    if (modalObj.options.keepContent !== true) $backdrop.remove();//remove backdrop if keepContent option is false
875                };
876                $backdrop.addAnimation(thisS.options.backdropAnimation.hide, closeBackdrop);
877            }
878            if (orphanBackdrop === thisS.backdropId) {
879                orphanBackdrop = false;
880            }
881        }
882        if (this.options.stack && this.options.outSideClose) {
883            setTimeout(closeBack, 10);
884        } else {
885            closeBack()
886        }
887        return this;
888    };
889
890    Ssi_modal.prototype.destroyModal = function () {
891        var $modal = this.get$modal(),
892         modalObj = this;
893        $modal.off('.ssi_modal');
894        $modal.trigger("beforeClose.ssi-modal"); //trigger close event
895        if (this.options.backdrop === 'shared') {
896            sharedBackdrop--;
897        } else if (this.options.backdrop === 'byKindShared') {
898            byKindShare[this.pluginName]--;
899        }
900
901        if ($modal.hasClass('ssi-openedDialog')) {
902            $modal.removeClass('ssi-openedDialog');
903            if (this.options.bodyScroll === false) {
904                openedModals--;// downgrade opened modals
905            }
906        }
907
908        var closeModal = function () {//this will execute as a callback when the hide animation end
909            $modal.addClass('ssi-hidden');
910            if (modalObj.options.stack) {
911                $modal.addClass('ssi-smoothSlide').slideUp('500', function () {
912                    $modal.removeClass('ssi-smoothSlide');
913                    $modal.trigger("onClose.ssi-modal"); //trigger close event
914                    if (modalObj.options.keepContent !== true) $modal.remove();//will remove modal from DOM if keepContent option is false
915
916                });
917            } else {
918                $modal.trigger("onClose.ssi-modal"); //trigger close event
919                if (modalObj.options.keepContent !== true)$modal.remove();//will remove modal from DOM if keepContent option is false
920            }
921            if (typeof modalObj.options.onClose === 'function')
922                modalObj.options.onClose(modalObj);//execute onClose callback
923
924            if (modalObj.options.keepContent !== true) {
925                $modal.off('.ssi-modal').find('#ssi-modalWrapper').off('.ssi-modal');
926            }
927        };
928
929        //close the modal window
930        $modal.addAnimation(this.options.modalAnimation.hide, closeModal);
931        this.options.icons = [];
932        this.options.buttons = [];
933        this.options.content = '';
934        this.options.title = '';
935        orphanBackdrop = this.backdropId;
936        return this;
937    };
938
939    Ssi_modal.prototype.close = function () {
940        if (typeof this.options.beforeClose === 'function') {
941            var resume = this.options.beforeClose(this);
942            if (resume === false) {
943                return this;
944            }
945        }
946        var $body = $('body');
947        $body.off('.ssi_modal');
948
949        this.destroyModal();
950        this.destroyBackdrop();
951
952        if (openedModals < 1) {//if no more modals left remove class from body and off events
953            $body.removeClass('ssi-modalOpen');
954        }
955        clearTimeOut(this);
956        return this;
957    };
958
959//calculates modals height
960    /**
961     * Sets the height of the modal
962     * @method setModalHeight
963     * @param {number} offset -Add more offset to the modal.
964     * @param {'height'||'min-height'||'max-height'} option -Force the function to excecute.
965     * @param {object} $content -The $content object of modal.
966     * @return
967     */
968    Ssi_modal.prototype.setModalHeight = function (offset, option) {
969        if (!this.options.fitScreen && !this.options.fixedHeight && !option) {
970            return this;
971        }
972
973        if (typeof offset !== 'number') {
974            offset = 100;
975        }
976
977        var $content = this.get$content();
978        var windowHeight = $(window).height(),
979         btnsHeight = 0, titleHeight = 0;
980        if (this.options.buttons)
981            btnsHeight = $content.next().innerHeight();
982        if (this.options.title)
983            titleHeight = this.get$title().innerHeight();
984        var totalHeight = btnsHeight + titleHeight + offset,
985         optionsOffset = 0;
986        if (!option) {
987
988            if (this.options.fitScreen && this.options.fixedHeight) {
989                if (typeof this.options.fitScreen === 'number') {
990                    optionsOffset = Math.abs((this.options.fitScreen + this.options.fixedHeight) / 2 - offset);
991                }
992                $content.css('height', windowHeight - totalHeight - optionsOffset); //add more margin down
993            } else {
994                if (this.options.fitScreen) {
995                    if (typeof this.options.fitScreen === 'number') {
996                        optionsOffset = Math.abs(this.options.fitScreen - offset);
997                    }
998                    $content.css('min-height', windowHeight - totalHeight - optionsOffset); //add more margin down
999                }
1000                if (this.options.fixedHeight) {
1001                    optionsOffset = 0;
1002                    if (typeof this.options.fixedHeight === 'number') {
1003                        optionsOffset = Math.abs(this.options.fixedHeight - offset);
1004                    }
1005                    $content.css('max-height', (windowHeight - totalHeight - optionsOffset)); //add more margin down
1006                }
1007            }
1008
1009        } else if (typeof option === 'string') {
1010            $content.css(option, (windowHeight - totalHeight)); //add more margin down
1011        }
1012        return totalHeight;
1013    };
1014    /**
1015     * Clears the timeout
1016     */
1017    var clearTimeOut = function (modalObj) {
1018        clearTimeout(modalObj.time);
1019        modalObj.time = null;
1020        clearInterval(modalObj.countDown);
1021
1022    };
1023
1024    /**
1025     * Updates the text of an element
1026     * @param {Ssi_modal} modalObj
1027     * @param {JQuery} $target -the element that will be updated
1028     * @param {function} callback -The function that will execute when the time expires;
1029     */
1030    var updateTime = function (modalObj, $target, callback) {
1031        var doUpdate = function () {
1032            var count = parseInt($target.html());
1033            if ((count - 1) !== 0) {
1034                $target.html(count - 1);
1035            } else {
1036                if (callback)
1037                    callback();
1038                clearInterval(modalObj.countDown);
1039            }
1040        };
1041        modalObj.countDown = setInterval(doUpdate, 1000);
1042    };
1043
1044//--------------------------------------------------------------------------------------------------------------
1045
1046    /**
1047     * Creates a new modal window.
1048     * @param {object} options -The options of the modal
1049     * @param {string} element -The id or class name om the element that trigger the modal.
1050     * @return {Ssi_modal}
1051     */
1052
1053    /**
1054     * @author http://stackoverflow.com/a/8015864/4801797
1055     */
1056    $.fn.extend({
1057        hasClasses: function (selectors) {
1058            var self = this;
1059            for (var i in selectors) {
1060                if ($(self).hasClass(selectors[i]))
1061                    return true;
1062            }
1063            return false;
1064        }
1065    });
1066
1067    var ssi_modal = {
1068        checkElement: function (element) {
1069            var $element = $(element);
1070            if ($element[0]) {
1071                var data = $element.data('ssi-modal');//then check if object exists in data-ssi-modal
1072                if (data) {
1073                    if (!$('#' + data.modalId)[0]) {// if data exists but no modal exists(probably removed by button)
1074                        $element.data('ssi-modal', '');//then remove data-ssi-modal
1075                        return false
1076                    }
1077                }
1078            }
1079            if (data) {
1080                return data
1081            } else {
1082                return false;
1083            }
1084        },
1085        createObject: function (options, element) {
1086            var $element, obj, data;
1087            if (typeof element !== 'undefined') { //this means that we use jquery method(see line 406)
1088                $element = $(element);
1089                data = $element.data('ssi-modal');//then check if object exists in data-ssi-modal
1090            } else {
1091                options.keepContent = false;
1092            }
1093            if (data) {
1094                obj = data
1095            } else {
1096                obj = new Ssi_modal(options);
1097                if (typeof element !== 'undefined') {
1098                    $element.data('ssi-modal', obj);// save the object to the target
1099                }
1100            }
1101            return obj;
1102        },
1103        /**
1104         * Opens the modal
1105         * @param {object} options -The options of the modal.
1106         * @param {string} element -The id or class name om the element that trigger the modal.
1107         *@returns {Ssi_modal}
1108         */
1109        show: function (options, element) {
1110            var obj = false;
1111            if (element) {
1112                obj = this.checkElement(element);
1113            }
1114            if (obj === false) {
1115                return this.createObject(options, element).init().show();
1116            } else if (typeof obj === 'object') {
1117                return obj.show();
1118            }
1119
1120        },
1121        /**
1122         * Closes the targeted modal or the very top
1123         * @param {string} $target
1124         */
1125        close: function ($target) {
1126            if (!$target) {
1127                var modal = $('.ssi-modalOuter');
1128                $target = modal.eq(modal.length - 1);
1129            }
1130            return $target.data('ssi-modal')
1131             .close();
1132        },
1133        /**
1134         * Closes all or a group of modals.
1135         * @param {'normalModal'||'pluginName'} group
1136         * @param {className} except -The modal with this class will not close
1137         */
1138        proto: Ssi_modal.prototype,
1139        closeAll: function (group, except) {//close all opened modal with the right order and all callbacks will execute normally
1140            except = toArray(except);
1141            var $activeModals;
1142            var groupVarType = typeof group;
1143            if ((groupVarType === 'string' && group !== '') || groupVarType === 'array') {
1144                group = toArray(group);
1145                var groupLength = group.length;
1146                for (var i = 0; i < groupLength; i++) {
1147                    $activeModals = $('.ssi-modal.ssi-openedDialog.' + group[i]);
1148                    close($activeModals);
1149                }
1150            } else {
1151                $activeModals = $('.ssi-modal.ssi-openedDialog');
1152                close($activeModals);
1153            }
1154
1155            function close($modals) {
1156                var modalsLength = $modals.length;
1157                for (var i = modalsLength - 1; i >= 0; i--) {
1158                    var $modal = $modals.eq(i);
1159                    if (!$modal.hasClasses(except)) {
1160                        $modal.data('ssi-modal').close();
1161                    }
1162
1163                }
1164            }
1165        },
1166        /**
1167         * Remove immediately all the modals from the dom. No modal callbacks will execute.
1168         * @param {function} callback -Just a callback
1169         */
1170        removeAll: function () {//close all opened modal no callbacks and no keepContent will execute you can determine one callback
1171            $('.ssi-modalOuter').addClass('ssi-hidden').remove();
1172            $('.ssi-backdrop').addClass('ssi-hidden').remove();
1173            $('body').removeClass('ssi-modalOpen');
1174            openedModals = 0;
1175            sharedBackdrop = 0;
1176            byKindShare = {
1177                stackModal: 0,
1178                normalModal: 0
1179            };
1180            uniqueId = 0;
1181        }
1182    };
1183
1184//-----------------------------Start of confirm plugin------------------------------------------------------------------
1185
1186    ssi_modal.dialog = function (options, method) {
1187        var defaults = {
1188            sizeClass: 'dialog',
1189            okBtn: {
1190                className: '',
1191                label: 'Ok'
1192            },
1193            title: '',
1194            closeIcon: false,
1195            outSideClose: false
1196        };
1197        options.okBtn = $.extend({}, defaults.okBtn, options.okBtn);
1198        options = $.extend({}, defaults, options);
1199        options.buttons = [{
1200            className: options.okBtn.className,
1201            label: options.okBtn.label,
1202            closeAfter: true,
1203            method: method
1204        }];
1205        return new Ssi_modal(options).init().show();
1206    };
1207
1208    //-----------------------------End of dialog plugin------------------------------------------------------------------
1209
1210//-----------------------------Start of confirm plugin------------------------------------------------------------------
1211
1212    ssi_modal.confirm = function (options, method) {
1213        var defaults = {
1214            okBtn: {
1215                className: '',
1216                label: 'Ok'
1217            },
1218            cancelBtn: {
1219                className: '',
1220                label: 'Cancel'
1221            },
1222            closeIcon: false,
1223            sizeClass: 'dialog',
1224            title: '',
1225
1226            outSideClose: false
1227        };
1228        options.okBtn = $.extend({}, defaults.okBtn, options.okBtn);
1229        options.cancelBtn = $.extend({}, defaults.cancelBtn, options.cancelBtn);
1230        options = $.extend({}, defaults, options);
1231        options.buttons = [{
1232            className: options.okBtn.className,
1233            label: options.okBtn.label,
1234            closeAfter: true,
1235            method: function (e, modal) {
1236                if (typeof method === 'function')
1237                    method(true, e, modal);
1238            }
1239        }, {
1240            className: options.cancelBtn.className,
1241            label: options.cancelBtn.label,
1242            closeAfter: true,
1243            method: function (e, modal) {
1244                if (typeof method === 'function')
1245                    method(false, e, modal);
1246            }
1247        }];
1248        return new Ssi_modal(options).init().show();
1249    };
1250
1251    //--------------------------------End of confirm plugin--------------------------------------------------
1252
1253//-----------------------------Start of imgBox plugin------------------------------------------------------------------
1254    function isDataURL(s) {
1255        return !!s.match(isDataURL.regex);
1256    }
1257
1258    isDataURL.regex = /^\s*data:([a-z]+\/[a-z0-9\-\+]+(;[a-z\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
1259
1260    var imgBoxOptions = {'ssi-mainOption': {}};//this will hold the imgbox options when will call ssi_modal.imgBox function
1261    ssi_modal.imgBox = function (options, group) {//set options for the image box
1262        group = group || 'ssi-mainOption';
1263        imgBoxOptions[group] = $.extend({}, imgBoxOptions['ssi-mainOption'], options);
1264    };
1265
1266    var currentIndex,
1267     $elementsLength,
1268     $eventTarget;
1269
1270    /**
1271     *  Navigates to the next/previous image.
1272     * @param {'next' || 'prev'} direction -The navigation direction
1273     * @returns {Ssi_modal}
1274     */
1275    ssi_modal.proto.navigate = function (direction) {
1276        var $groupElements = $('a[data-ssi_imgGroup="' + $eventTarget.attr('data-ssi_imgGroup') + '"]');
1277        if (!currentIndex)currentIndex = $groupElements.index($eventTarget);
1278        if (!$elementsLength)$elementsLength = $groupElements.length;
1279        if ((direction === 'next' && currentIndex + 1 >= $elementsLength) || (direction === 'prev' && currentIndex < 0)) {
1280            return this;
1281        }
1282
1283        this.destroyModal();
1284        if (direction === 'next') {//next image
1285            currentIndex++;
1286        } else if (direction === 'prev') {//previous image
1287            currentIndex--;
1288        }
1289        $groupElements.eq(currentIndex).trigger('click.ssi-imgBox');
1290        return this;
1291    };
1292
1293    ssi_modal.imgBox.show = function (url, options) {
1294        var defaults = {//set defaults
1295            backdrop: 'byKindShared',
1296            fixedHeight: true,
1297            navigation: true,
1298            closeIcon: true,
1299            title: false,
1300            allowIframe:true,
1301            hideImgButtons: true
1302        };
1303        options = $.extend(true, defaults, options);
1304        $.extend(options, {
1305            img: true,
1306            content: '<div class="ssi-loader"></div>',
1307            sizeClass: ''
1308        });
1309        var imgBox = ssi_modal.createObject(options)
1310         .setPluginName('imgBox');
1311        imgBox.imgUrl = url;
1312        imgBox.imgTitle = options.title;
1313        imgBox.init();
1314        if (options.title) {
1315            imgBox.get$icons().addClass('inTitle');
1316        }
1317
1318        imgBox.show();
1319        setImg(imgBox, url);
1320
1321    };
1322    $('body').on('click.ssi-imgBox', 'a.ssi-imgBox', function (e) {//click event handler for all links with ssi-imgbox class
1323        e.preventDefault();
1324        e.stopPropagation();
1325        $eventTarget = $(e.currentTarget);
1326        var group = $eventTarget.attr('data-ssi_imgGroup') || 'ssi-mainOption';//get the options of the right group
1327        var options = imgBoxOptions[group] || imgBoxOptions['ssi-mainOption'];
1328        var url = $eventTarget.attr('href');
1329        if (options.imgButtons !== '' && !$.isEmptyObject(options.imgButtons)) {
1330            for (var i = 0; i < options.imgButtons.length; i++) { //check if the current button is in the exclude list
1331                if (options.imgButtons[i].exclude) {
1332                    var btnClass = options.imgButtons[i].exclude.split(',');
1333                    for (var y = 0; y < btnClass.length; y++) {
1334                        if ($eventTarget.hasClass(btnClass[y])) {
1335                            options.imgButtons.splice(i, 1);
1336                            break;
1337                        }
1338                    }
1339                }
1340            }
1341        }
1342        if (options.title) {
1343            if (options.title === true) {
1344                options.title = $eventTarget.attr('title');//get title of the target
1345            }
1346        }
1347        ssi_modal.imgBox.show(url, options, $eventTarget);
1348    });
1349
1350    function setImg(imgBox, url) {
1351
1352        var $modalWrapper = imgBox.get$wrapper(),
1353         $content = $modalWrapper.find('#ssi-modalContent');
1354        if (!url || url == '#') {
1355            var alt = ($eventTarget ? $eventTarget.attr('data-alt') : '');
1356            $img = '<h3>Image not found</h3><br>' + (typeof alt !== 'undefined' ? '<h4>' + alt + '</h4>' : '');
1357            placeImg(true);
1358            return;
1359        }
1360        var interval,
1361         startInterval,
1362         supportsNatural = ("naturalWidth" in (new Image())),
1363         windowHeight = $(window).height(),
1364         windowWidth = $(window).width(),
1365         $img = [''],
1366         i = 0;
1367        if (imgBox.options.navigation && $eventTarget) {
1368            $content.append(setImgNavigation);
1369        }
1370        var imgTypes = [
1371            'jpg',
1372            'jpeg',
1373            'png',
1374            'gif',
1375            'bmp'
1376        ];
1377        if (!imgBox.options.allowIframe||$.inArray(url.split('.').pop().toLowerCase(), imgTypes) !== -1||isDataURL(url)) {
1378            $img = $('<img src="' + url + '" class="ssi-modalImg"/>')
1379             .on('load', function () {
1380                 if (!supportsNatural) {
1381                     var ghost = new Image();
1382                     ghost.src = $img.attr('src');
1383                     var width = ghost.width;
1384                     var height = ghost.height;
1385                     onHasSize(width, height);
1386                 }
1387             })
1388             .error(function () {
1389                 var alt = ($eventTarget ? $eventTarget.attr('data-alt') : '');
1390                 $img = '<h3>Image not found</h3><br>' + (typeof alt !== 'undefined' ? '<h4>' + alt + '</h4>' : '');
1391                 placeImg(true);
1392             });
1393            checkSize();
1394            if (startInterval) {
1395                interval = setInterval(function () {
1396                    $modalWrapper.addClass('ssi-imgBorder');
1397                    checkSize();
1398                    i++
1399                }, 50);
1400            }
1401
1402        } else {
1403            if (typeof imgBox.options.iframe.allowFullScreen !== 'boolean') {
1404                imgBox.options.iframe.allowFullScreen = true;
1405            }
1406            imgBox.options.iframe.className = imgBox.options.iframe.className || '';
1407            $img = $('<iframe src="' + url + '" frameborder="0" ' + (imgBox.options.iframe.allowFullScreen ? 'allowfullscreen' : '') + '></iframe>');
1408
1409            if (imgBox.options.center) {
1410                $modalWrapper.addClass('ssi-iframe ').find('#ssi-modalWindow' + imgBox.numberId).addClass(imgBox.options.iframe.className);
1411            } else {
1412                $modalWrapper.addClass('ssi-iframe ' + imgBox.options.iframe.className);
1413            }
1414            placeImg();
1415        }
1416
1417        function setImgNavigation() {
1418            var $groupElements = $('a[data-ssi_imgGroup="' + $eventTarget.attr('data-ssi_imgGroup') + '"]');
1419            if (!$groupElements.length)return;
1420            var index = $groupElements.index($eventTarget),
1421             $elementLength = $groupElements.length;
1422            if (index + 1 >= $elementLength && index < 1)return;
1423            var $nav = $('<div class="ssi-modalNavigation"></divid>').mouseover(function () {
1424                 $nav.addClass('ssi-navFadeIn');
1425             }).mouseleave(function () {
1426                 $nav.removeClass('ssi-navFadeIn');
1427             }),
1428             $next = $('<div class="ssi-modalNext ' + (index + 1 >= $elementLength ? 'ssi-hidden' : '') + '"><span></span></div>'),
1429             $prev = $('<div class="ssi-modalPrev ' + (index < 1 ? 'ssi-hidden' : '') + '"><span></span></div>');
1430            $nav.append($next, $prev);
1431            imgBox.get$backdrop().one('backdropClose.ssi-modal', function () {
1432
1433                $elementsLength = '';
1434                currentIndex = '';
1435            });
1436            imgBox.get$modal().one('beforeClose.ssi-modal', function () {
1437                $nav.remove();
1438            }).one('onShow.ssi-modal', function () {
1439                $next.one('click', function (e) {
1440                    e.preventDefault();
1441                    imgBox.navigate('next');
1442                    $(this).off('click.ssi_modal');
1443                });
1444                $prev.one('click', function (e) {
1445                    e.preventDefault();
1446                    imgBox.navigate('prev');
1447                    $(this).off('click.ssi_modal');
1448                });
1449            });
1450
1451            return $nav;
1452        }
1453
1454        function placeImg(error) {
1455            $content.find('.ssi-loader').remove();
1456            var content = [];
1457            if (!error && imgBox.options.imgButtons !== '' && !$.isEmptyObject(imgBox.options.imgButtons)) {
1458                var imgButtons = imgBox.setButtons(imgBox.options.imgButtons, imgBox.get$content()).addClass('ssi-imgButtons');
1459                if (imgBox.options.hideImgButtons === true) {
1460                    imgButtons.addClass('ssi-navFade ssi-navFadeOut');
1461                    imgBox.get$wrapper().mouseover(function () {
1462                        imgButtons.addClass('ssi-navFadeIn');
1463                    }).mouseleave(function () {
1464                        imgButtons.removeClass('ssi-navFadeIn');
1465                    })
1466                }
1467
1468                content.push(imgButtons);
1469
1470            }
1471            content.push($img);
1472            $content.append(content);
1473        }
1474
1475        function AspectRatio(srcWidth, srcHeight, maxWidth, maxHeight) {//find the aspect ration
1476            var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
1477            return {width: srcWidth * ratio, height: srcHeight * ratio};
1478        }
1479
1480        function onHasSize(width, height) {
1481            clearInterval(interval);
1482            var naturalWidth = width || (supportsNatural ? $img[0].naturalWidth : $img.width());
1483            var naturalHeight = height || (supportsNatural ? $img[0].naturalHeight : $img.height());
1484
1485            var imgHeight = imgBox.setModalHeight(120, true);
1486            if ((naturalHeight > windowHeight - imgHeight || naturalWidth > windowWidth) && imgBox.options.fixedHeight === true) {
1487                var dimensions = AspectRatio(naturalWidth, naturalHeight, windowWidth - 100, windowHeight - imgHeight);
1488                naturalWidth = dimensions.width;
1489                naturalHeight = dimensions.height;
1490                if (i > 2) {
1491                    $modalWrapper.addClass('ssi-overHeight')
1492                }
1493            }
1494            $content.css('height', naturalHeight);
1495            if (imgBox.options.center) {
1496                $content.parent().css({'width': naturalWidth, 'height': naturalHeight});
1497            }
1498            $modalWrapper.css('width', naturalWidth);
1499            placeImg();
1500
1501            $modalWrapper.addClass('ssi-imgBorder')
1502
1503        }
1504
1505        /**
1506         * Initialize the arrows of navigation.
1507         * @param {Ssi_modal}modalObj
1508         * @returns {*|HTMLElement}
1509         */
1510
1511        /**
1512         * checks when the image's size is available
1513         */
1514        function checkSize() {
1515            if (supportsNatural) {
1516                if ($img[0].naturalWidth > 0) {
1517                    onHasSize();
1518                    return;
1519                }
1520            } else {
1521                clearInterval(interval);
1522                if ($img.width() > 50) {
1523                    onHasSize();
1524                    return;
1525                }
1526            }
1527            startInterval = true;
1528        }
1529
1530    }
1531
1532//-----------------------------End of imgBox plugin------------------------------------------------------------------
1533
1534//--------------------------------Start of notify plugin--------------------------------------------------
1535    ssi_modal.notify = function (type, options, callback) {
1536        var defaults = {
1537            closeIcon: false,
1538            overrideOther: false,
1539            sizeClass: 'dialog',
1540            onClickClose: true,
1541            bodyScroll: true,
1542            animation: true,
1543            className: '',
1544            backdrop: false,
1545            outSideClose: false,
1546            position: 'right top',
1547            topZIndex: true,
1548            okBtn: {
1549                className: '',
1550                label: 'Ok'
1551            },
1552            cancelBtn: {
1553                className: '',
1554                label: 'Cancel'
1555            },
1556            stack: true,
1557            closeAfter: {
1558                time: 4,
1559                resetOnHover: true
1560            }
1561        };
1562        if (type === 'confirm' || 'dialog') {
1563            options.okBtn = $.extend({}, defaults.okBtn, options.okBtn);
1564            options.cancelBtn = $.extend({}, defaults.cancelBtn, options.cancelBtn);
1565        }
1566
1567        var generateIcon = function (className) {
1568            if (className === '')return '';
1569            return '<span class="ssi-icon ' + className + '"></span>'
1570        };
1571
1572        var icon = '', title = '';
1573        switch (type) {
1574            case 'success':
1575                defaults.className = ' ssi-success';
1576                break;
1577            case 'error':
1578                defaults.className = ' ssi-error';
1579                break;
1580            case 'info':
1581                defaults.className = ' ssi-info';
1582                break;
1583            case 'warning':
1584                defaults.className = ' ssi-warning';
1585                break;
1586            case 'confirm':
1587                defaults.closeAfter = false;
1588                defaults.onClickClose = false;
1589                defaults.outSideClose = false;
1590                defaults.icon = false;
1591                defaults.title = false;
1592
1593                defaults.buttons = [{
1594                    className: options.okBtn.className,
1595                    label: options.okBtn.label,
1596                    closeAfter: true,
1597                    method: function () {
1598                        if (typeof callback === 'function') {
1599                            callback(true);
1600                        }
1601                    }
1602                }, {
1603                    className: options.cancelBtn.className,
1604                    label: options.cancelBtn.label,
1605                    closeAfter: true,
1606                    method: function () {
1607                        if (typeof callback === 'function') {
1608                            callback(false);
1609                        }
1610                    }
1611                }];
1612                break;
1613            case 'dialog':
1614                defaults.onClickClose = false;
1615                defaults.closeAfter = false;
1616                defaults.outSideClose = false;
1617                defaults.title = false;
1618                defaults.icon = false;
1619                defaults.buttons = [{
1620                    className: options.okBtn.className,
1621                    label: options.okBtn.label,
1622                    closeAfter: true,
1623                    method: callback
1624                }];
1625                break;
1626            default:
1627                defaults.className = type;
1628        }
1629        if (options.className) {
1630            options.className += defaults.className || '';
1631        }
1632        options = $.extend(true, defaults, options);
1633
1634        if (options.icon != false) {
1635            icon = options.icon || type || '';
1636        }
1637        if (options.title != false) {
1638            title = options.title || type;
1639        }
1640        if ((options.icon != false && options.title != false) && icon != '') {
1641            options.title = generateIcon(icon) + ' ' + title;
1642        }
1643        if (options.backdrop === true) {
1644            options.backdrop = 'byKndShared'
1645        }
1646        options.keepContent = false;
1647        if (options.overrideOther) {
1648            var classes = options.position.split(' ');
1649            $('body').find('div.' + classes[0] + '.' + classes[1]).children().empty()
1650        }
1651
1652        return ssi_modal.createObject(options)
1653         .setPluginName('notify').init().show();
1654    };
1655//--------------------------------End of notify plugin--------------------------------------------------
1656
1657//--------------------------------Start of jquery selector plugin--------------------------------------------------
1658
1659    $.fn.ssi_modal = function () {
1660        var opts;
1661        if (typeof arguments[1] === 'object') {
1662            var action = arguments[0];
1663            opts = arguments[1] || {};
1664            var callback = arguments[2];
1665        } else {
1666            opts = arguments[0] || {};
1667        }
1668        return this.each(function () {
1669            var element = $(this), options;
1670            if (opts.content) {//that means that we will not use any div element for content
1671                element.click(function () {
1672                    switch (action) {//action could be show,dialog or confirm
1673                        case 'show':
1674                            ssi_modal['show'](opts, element);
1675                            break;
1676                        default:
1677                            ssi_modal[action](opts, callback);
1678                    }
1679                })
1680            } else {
1681                var content, def, dataAttr = element.attr('data-ssi_modal');
1682                if (dataAttr) {// that means the content is an element.  data-ssi_modal shows the elements selector
1683                    element.click(function () {//set click event
1684                        content = $(dataAttr);
1685                        def = {
1686                            content: content
1687                        };
1688                        options = $.extend({}, opts, def);
1689                        ssi_modal.createObject(options).init().show();
1690                    });
1691                } else {//that means the target is the element that contains the content
1692                    def = {
1693                        content: element
1694                    };
1695                    options = $.extend({}, opts, def);
1696                    ssi_modal.createObject(options).init().show();
1697                }
1698            }
1699        });
1700    };
1701//--------------------------------End of jquery selector plugin--------------------------------------------------
1702
1703    /**
1704     * Adds animation to an element
1705     * @method addAnimation
1706     * @param {string} animationName
1707     * @param {function} callback
1708     * @return CallExpression
1709     */
1710
1711//@author https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Detecting_CSS_animation_support
1712    function checkAnimationSupport() {
1713        var animation = false,
1714         animationstring = 'animation',
1715         keyframeprefix = '',
1716         domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
1717         pfx = '',
1718         elm = document.createElement('div');
1719
1720        if (elm.style.animationName !== undefined) {
1721            animation = true;
1722        }
1723
1724        if (animation === false) {
1725            for (var i = 0; i < domPrefixes.length; i++) {
1726                if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
1727                    pfx = domPrefixes[i];
1728                    animationstring = pfx + 'Animation';
1729                    keyframeprefix = '-' + pfx.toLowerCase() + '-';
1730                    animation = true;
1731                    break;
1732                }
1733            }
1734        }
1735        return animation;
1736    }
1737
1738    $.fn.addAnimation = function (animationName, callback) {
1739        var animationEnd = 'mozAnimationEnd webkitAnimationEnd  MSAnimationEnd oanimationend animationend';
1740        if (animationName.indexOf('ssi-fade') !== -1 && animationSupport === false) {
1741            return $(this)[animationName.replace('anim ssi-', '')](300, function () {
1742                if (typeof callback === 'function') {
1743                    callback();
1744                }
1745            });
1746        } else {
1747            $(this).addClass(animationName).one(animationEnd, function () {
1748                $(this).removeClass(animationName);
1749                if (typeof callback === 'function') {
1750                    callback();
1751                }
1752            });
1753
1754            if (animationName === 'ssi-show' || animationName === 'ssi-hidden' || animationName === '') {
1755                $(this).trigger('animationend');
1756            }
1757            return this.each(function () {
1758                $(this)
1759            })
1760        }
1761    };
1762
1763    function toArray(value) {//if the value is not array returns an array with the value
1764        if (!(value instanceof Array)) {
1765            value = [value];
1766        }
1767        return value;
1768    }
1769
1770    return ssi_modal;
1771
1772}));

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.