; (function ($, window, document, undefined){ "use strict"; window = (typeof window != 'undefined' && window.Math == Math)? window: (typeof self != 'undefined' && self.Math == Math)? self: Function('return this')(); $.fn.modal = function (parameters){ var $allModules = $(this), $window = $(window), $document = $(document), $body = $('body'), moduleSelector = $allModules.selector || '', time = new Date().getTime(), performance = [] , query = arguments[0], methodInvoked = (typeof query == 'string'), queryArguments = [] .slice.call(arguments, 1), requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function (callback){ _AN_Call_settimeout('setTimeout', window, callback, 0); } , returnedValue; $allModules.each(function (){ var settings = ($.isPlainObject(parameters))? $.extend(true , { } , $.fn.modal.settings, parameters): $.extend({ } , $.fn.modal.settings), selector = settings.selector, className = settings.className, namespace = settings.namespace, error = settings.error, eventNamespace = '.' + namespace, moduleNamespace = 'module-' + namespace, $module = $(this), $context = $(settings.context), $close = $module.find(selector.close), $allModals, $otherModals, $focusedElement, $dimmable, $dimmer, element = this, instance = $module.data(moduleNamespace), ignoreRepeatedEvents = false , elementEventNamespace, id, observer, module; module = { initialize: function (){ module.verbose('Initializing dimmer', $context); module.create.id(); module.create.dimmer(); module.refreshModals(); module.bind.events(); if (settings.observeChanges) { module.observeChanges(); } module.instantiate(); } , instantiate: function (){ module.verbose('Storing instance of modal'); instance = module; $module.data(moduleNamespace, instance); } , create: { dimmer: function (){ var defaultSettings = { debug: settings.debug, dimmerName: 'modals', duration: { show: settings.duration, hide: settings.duration} } , dimmerSettings = $.extend(true , defaultSettings, settings.dimmerSettings); if (settings.inverted) { dimmerSettings.variation = (dimmerSettings.variation !== undefined)? dimmerSettings.variation + ' inverted': 'inverted'; } if ($.fn.dimmer === undefined) { module.error(error.dimmer); return ; } module.debug('Creating dimmer with settings', dimmerSettings); $dimmable = $context.dimmer(dimmerSettings); if (settings.detachable) { module.verbose('Modal is detachable, moving content into dimmer'); $dimmable.dimmer('add content', $module); } else { module.set.undetached(); } if (settings.blurring) { $dimmable.addClass(className.blurring); } $dimmer = $dimmable.dimmer('get dimmer'); } , id: function (){ id = (Math.random().toString(16) + '000000000').substr(2, 8); elementEventNamespace = '.' + id; module.verbose('Creating unique id for element', id); } } , destroy: function (){ module.verbose('Destroying previous modal'); $module.removeData(moduleNamespace).off(eventNamespace); $window.off(elementEventNamespace); $dimmer.off(elementEventNamespace); $close.off(eventNamespace); $context.dimmer('destroy'); } , observeChanges: function (){ if ('MutationObserver' in window) { observer = new MutationObserver(function (mutations){ module.debug('DOM tree modified, refreshing'); _AN_Call_refresh('refresh', module); } ); observer.observe(element, { childList: true , subtree: true } ); module.debug('Setting up mutation observer', observer); } } , refresh: function (){ module.remove.scrolling(); module.cacheSizes(); module.set.screenHeight(); module.set.type(); module.set.position(); } , refreshModals: function (){ $otherModals = $module.siblings(selector.modal); $allModals = $otherModals.add($module); } , attachEvents: function (selector, event){ var $toggle = $(selector); event = $.isFunction(module[event])? module[event]: module.toggle; if (_AN_Read_length('length', $toggle) > 0) { module.debug('Attaching modal events to element', selector, event); $toggle.off(eventNamespace).on('click' + eventNamespace, event); } else { module.error(error.notFound, selector); } } , bind: { events: function (){ module.verbose('Attaching events'); $module.on('click' + eventNamespace, selector.close, module.event.close).on('click' + eventNamespace, selector.approve, module.event.approve).on('click' + eventNamespace, selector.deny, module.event.deny); $window.on('resize' + elementEventNamespace, module.event.resize); } } , get: { id: function (){ return (Math.random().toString(16) + '000000000').substr(2, 8); } } , event: { approve: function (){ if (ignoreRepeatedEvents || settings.onApprove.call(element, $(this)) === false ) { module.verbose('Approve callback returned false cancelling hide'); return ; } ignoreRepeatedEvents = true ; module.hide(function (){ ignoreRepeatedEvents = false ; } ); } , deny: function (){ if (ignoreRepeatedEvents || settings.onDeny.call(element, $(this)) === false ) { module.verbose('Deny callback returned false cancelling hide'); return ; } ignoreRepeatedEvents = true ; module.hide(function (){ ignoreRepeatedEvents = false ; } ); } , close: function (){ module.hide(); } , click: function (event){ var $target = $(_AN_Read_target('target', event)), isInModal = (_AN_Read_length('length', $target.closest(selector.modal)) > 0), isInDOM = $.contains(document.documentElement, _AN_Read_target('target', event)); if (!isInModal && isInDOM) { module.debug('Dimmer clicked, hiding all modals'); if (module.is.active()) { module.remove.clickaway(); if (settings.allowMultiple) { module.hide(); } else { module.hideAll(); } } } } , debounce: function (method, delay){ clearTimeout(module.timer); module.timer = _AN_Call_settimeout('setTimeout', window, method, delay); } , keyboard: function (event){ var keyCode = event.which, escapeKey = 27; if (keyCode == escapeKey) { if (settings.closable) { module.debug('Escape key pressed hiding modal'); module.hide(); } else { module.debug('Escape key pressed, but closable is set to false'); } event.preventDefault(); } } , resize: function (){ if ($dimmable.dimmer('is active')) { requestAnimationFrame(module.refresh); } } } , toggle: function (){ if (module.is.active() || module.is.animating()) { module.hide(); } else { _AN_Call_show('show', module); } } , show: function (callback){ callback = $.isFunction(callback)? callback: function (){ } ; module.refreshModals(); module.showModal(callback); } , hide: function (callback){ callback = $.isFunction(callback)? callback: function (){ } ; module.refreshModals(); module.hideModal(callback); } , showModal: function (callback){ callback = $.isFunction(callback)? callback: function (){ } ; if (module.is.animating() || !module.is.active()) { module.showDimmer(); module.cacheSizes(); module.set.position(); module.set.screenHeight(); module.set.type(); module.set.clickaway(); if (!settings.allowMultiple && module.others.active()) { module.hideOthers(module.showModal); } else { settings.onShow.call(element); if (settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) { module.debug('Showing modal with css animations'); $module.transition({ debug: settings.debug, animation: settings.transition + ' in', queue: settings.queue, duration: settings.duration, useFailSafe: true , onComplete: function (){ settings.onVisible.apply(element); if (settings.keyboardShortcuts) { module.add.keyboardShortcuts(); } module.save.focus(); module.set.active(); if (settings.autofocus) { module.set.autofocus(); } callback(); } } ); } else { module.error(error.noTransition); } } } else { module.debug('Modal is already visible'); } } , hideModal: function (callback, keepDimmed){ callback = $.isFunction(callback)? callback: function (){ } ; module.debug('Hiding modal'); if (settings.onHide.call(element, $(this)) === false ) { module.verbose('Hide callback returned false cancelling hide'); return ; } if (module.is.animating() || module.is.active()) { if (settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) { module.remove.active(); $module.transition({ debug: settings.debug, animation: settings.transition + ' out', queue: settings.queue, duration: settings.duration, useFailSafe: true , onStart: function (){ if (!module.others.active() && !keepDimmed) { module.hideDimmer(); } if (settings.keyboardShortcuts) { module.remove.keyboardShortcuts(); } } , onComplete: function (){ settings.onHidden.call(element); module.restore.focus(); callback(); } } ); } else { module.error(error.noTransition); } } } , showDimmer: function (){ if ($dimmable.dimmer('is animating') || !$dimmable.dimmer('is active')) { module.debug('Showing dimmer'); $dimmable.dimmer('show'); } else { module.debug('Dimmer already visible'); } } , hideDimmer: function (){ if ($dimmable.dimmer('is animating') || ($dimmable.dimmer('is active'))) { $dimmable.dimmer('hide', function (){ module.remove.clickaway(); module.remove.screenHeight(); } ); } else { module.debug('Dimmer is not visible cannot hide'); return ; } } , hideAll: function (callback){ var $visibleModals = $allModals.filter('.' + className.active + ', .' + className.animating); callback = $.isFunction(callback)? callback: function (){ } ; if (_AN_Read_length('length', $visibleModals) > 0) { module.debug('Hiding all visible modals'); module.hideDimmer(); $visibleModals.modal('hide modal', callback); } } , hideOthers: function (callback){ var $visibleModals = $otherModals.filter('.' + className.active + ', .' + className.animating); callback = $.isFunction(callback)? callback: function (){ } ; if (_AN_Read_length('length', $visibleModals) > 0) { module.debug('Hiding other modals', $otherModals); $visibleModals.modal('hide modal', callback, true ); } } , others: { active: function (){ return (_AN_Read_length('length', $otherModals.filter('.' + className.active)) > 0); } , animating: function (){ return (_AN_Read_length('length', $otherModals.filter('.' + className.animating)) > 0); } } , add: { keyboardShortcuts: function (){ module.verbose('Adding keyboard shortcuts'); $document.on('keyup' + eventNamespace, module.event.keyboard); } } , save: { focus: function (){ $focusedElement = $(document.activeElement).blur(); } } , restore: { focus: function (){ if ($focusedElement && _AN_Read_length('length', $focusedElement) > 0) { $focusedElement.focus(); } } } , remove: { active: function (){ $module.removeClass(className.active); } , clickaway: function (){ if (settings.closable) { $dimmer.off('click' + elementEventNamespace); } } , bodyStyle: function (){ if ($body.attr('style') === '') { module.verbose('Removing style attribute'); $body.removeAttr('style'); } } , screenHeight: function (){ module.debug('Removing page height'); $body.css('height', ''); } , keyboardShortcuts: function (){ module.verbose('Removing keyboard shortcuts'); $document.off('keyup' + eventNamespace); } , scrolling: function (){ $dimmable.removeClass(className.scrolling); $module.removeClass(className.scrolling); } } , cacheSizes: function (){ var modalHeight = $module.outerHeight(); if (module.cache === undefined || modalHeight !== 0) { module.cache = { pageHeight: $(document).outerHeight(), height: modalHeight + settings.offset, contextHeight: (settings.context == 'body')? $(window).height(): $dimmable.height()} ; } module.debug('Caching modal and container sizes', module.cache); } , can: { fit: function (){ return ((module.cache.height + (settings.padding * 2)) < module.cache.contextHeight); } } , is: { active: function (){ return $module.hasClass(className.active); } , animating: function (){ return $module.transition('is supported')? $module.transition('is animating'): $module.is(':visible'); } , scrolling: function (){ return $dimmable.hasClass(className.scrolling); } , modernBrowser: function (){ return !(window.ActiveXObject || "ActiveXObject" in window); } } , set: { autofocus: function (){ var $inputs = $module.find('[tabindex], :input').filter(':visible'), $autofocus = $inputs.filter('[autofocus]'), $input = (_AN_Read_length('length', $autofocus) > 0)? $autofocus.first(): $inputs.first(); if (_AN_Read_length('length', $input) > 0) { $input.focus(); } } , clickaway: function (){ if (settings.closable) { $dimmer.on('click' + elementEventNamespace, module.event.click); } } , screenHeight: function (){ if (module.can.fit()) { $body.css('height', ''); } else { module.debug('Modal is taller than page content, resizing page height'); $body.css('height', module.cache.height + (settings.padding * 2)); } } , active: function (){ $module.addClass(className.active); } , scrolling: function (){ $dimmable.addClass(className.scrolling); $module.addClass(className.scrolling); } , type: function (){ if (module.can.fit()) { module.verbose('Modal fits on screen'); if (!module.others.active() && !module.others.animating()) { module.remove.scrolling(); } } else { module.verbose('Modal cannot fit on screen setting to scrolling'); module.set.scrolling(); } } , position: function (){ module.verbose('Centering modal on page', module.cache); if (module.can.fit()) { $module.css({ top: '', marginTop: - (module.cache.height / 2)} ); } else { $module.css({ marginTop: '', top: $document.scrollTop()} ); } } , undetached: function (){ $dimmable.addClass(className.undetached); } } , setting: function (name, value){ module.debug('Changing setting', name, value); if ($.isPlainObject(name)) { $.extend(true , settings, name); } else if (value !== undefined) { if ($.isPlainObject(settings[name])) { $.extend(true , settings[name], value); } else { settings[name] = value; } } else { return settings[name]; } } , internal: function (name, value){ if ($.isPlainObject(name)) { $.extend(true , module, name); } else if (value !== undefined) { module[name] = value; } else { return module[name]; } } , debug: function (){ if (!settings.silent && settings.debug) { if (settings.performance) { module.performance.log(arguments); } else { module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); module.debug.apply(console, arguments); } } } , verbose: function (){ if (!settings.silent && settings.verbose && settings.debug) { if (settings.performance) { module.performance.log(arguments); } else { module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); module.verbose.apply(console, arguments); } } } , error: function (){ if (!settings.silent) { module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); module.error.apply(console, arguments); } } , performance: { log: function (message){ var currentTime, executionTime, previousTime; if (settings.performance) { currentTime = new Date().getTime(); previousTime = time || currentTime; executionTime = currentTime - previousTime; time = currentTime; performance.push({ 'Name': message[0], 'Arguments': [] .slice.call(message, 1) || '', 'Element': element, 'Execution Time': executionTime} ); } clearTimeout(module.performance.timer); module.performance.timer = _AN_Call_settimeout('setTimeout', window, module.performance.display, 500); } , display: function (){ var title = settings.name + ':', totalTime = 0; time = false ; clearTimeout(module.performance.timer); $.each(performance, function (index, data){ totalTime += data["Execution Time"] ; } ); title += ' ' + totalTime + 'ms'; if (moduleSelector) { title += ' \'' + moduleSelector + '\''; } if ((console.group !== undefined || console.table !== undefined) && _AN_Read_length('length', performance) > 0) { console.groupCollapsed(title); if (console.table) { console.table(performance); } else { $.each(performance, function (index, data){ console.log(data.Name + ': ' + data["Execution Time"] + 'ms'); } ); } console.groupEnd(); } performance = [] ; } } , invoke: function (query, passedArguments, context){ var object = instance, maxDepth, found, response; passedArguments = passedArguments || queryArguments; context = element || context; if (typeof query == 'string' && object !== undefined) { query = query.split(/[\. ]/); maxDepth = _AN_Read_length('length', query) - 1; $.each(query, function (depth, value){ var camelCaseValue = (depth != maxDepth)? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1): query; if ($.isPlainObject(object[camelCaseValue]) && (depth != maxDepth)) { object = object[camelCaseValue]; } else if (object[camelCaseValue] !== undefined) { found = object[camelCaseValue]; return false ; } else if ($.isPlainObject(object[value]) && (depth != maxDepth)) { object = object[value]; } else if (object[value] !== undefined) { found = object[value]; return false ; } else { return false ; } } ); } if ($.isFunction(found)) { response = found.apply(context, passedArguments); } else if (found !== undefined) { response = found; } if ($.isArray(returnedValue)) { returnedValue.push(response); } else if (returnedValue !== undefined) { returnedValue = [returnedValue, response] ; } else if (response !== undefined) { returnedValue = response; } return found; } } ; if (methodInvoked) { if (instance === undefined) { module.initialize(); } module.invoke(query); } else { if (instance !== undefined) { instance.invoke('destroy'); } module.initialize(); } } ); return (returnedValue !== undefined)? returnedValue: this; } ; $.fn.modal.settings = { name: 'Modal', namespace: 'modal', silent: false , debug: false , verbose: false , performance: true , observeChanges: false , allowMultiple: false , detachable: true , closable: true , autofocus: true , inverted: false , blurring: false , dimmerSettings: { closable: false , useCSS: true } , keyboardShortcuts: true , context: 'body', queue: false , duration: 500, offset: 0, transition: 'scale', padding: 50, onShow: function (){ } , onVisible: function (){ } , onHide: function (){ return true ; } , onHidden: function (){ } , onApprove: function (){ return true ; } , onDeny: function (){ return true ; } , selector: { close: '> .close', approve: '.actions .positive, .actions .approve, .actions .ok', deny: '.actions .negative, .actions .deny, .actions .cancel', modal: '.ui.modal'} , error: { dimmer: 'UI Dimmer, a required component is not included in this page', method: 'The method you called is not defined.', notFound: 'The element you specified could not be found'} , className: { active: 'active', animating: 'animating', blurring: 'blurring', scrolling: 'scrolling', undetached: 'undetached'} } ; } )(jQuery, window, document);