14362 lines
483 KiB
JavaScript
14362 lines
483 KiB
JavaScript
/*
|
|
* # Fomantic UI - 2.8.8
|
|
* https://github.com/fomantic/Fomantic-UI
|
|
* http://fomantic-ui.com/
|
|
*
|
|
* Copyright 2022 Contributors
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Site
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
$.site = $.fn.site = function(parameters) {
|
|
var
|
|
time = new Date().getTime(),
|
|
performance = [],
|
|
|
|
query = arguments[0],
|
|
methodInvoked = (typeof query == 'string'),
|
|
queryArguments = [].slice.call(arguments, 1),
|
|
|
|
settings = ( $.isPlainObject(parameters) )
|
|
? $.extend(true, {}, $.site.settings, parameters)
|
|
: $.extend({}, $.site.settings),
|
|
|
|
namespace = settings.namespace,
|
|
error = settings.error,
|
|
|
|
moduleNamespace = 'module-' + namespace,
|
|
|
|
$document = $(document),
|
|
$module = $document,
|
|
element = this,
|
|
instance = $module.data(moduleNamespace),
|
|
|
|
module,
|
|
returnedValue
|
|
;
|
|
module = {
|
|
|
|
initialize: function() {
|
|
module.instantiate();
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of site', module);
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, module)
|
|
;
|
|
},
|
|
|
|
normalize: function() {
|
|
module.fix.console();
|
|
module.fix.requestAnimationFrame();
|
|
},
|
|
|
|
fix: {
|
|
console: function() {
|
|
module.debug('Normalizing window.console');
|
|
if (console === undefined || console.log === undefined) {
|
|
module.verbose('Console not available, normalizing events');
|
|
module.disable.console();
|
|
}
|
|
if (typeof console.group == 'undefined' || typeof console.groupEnd == 'undefined' || typeof console.groupCollapsed == 'undefined') {
|
|
module.verbose('Console group not available, normalizing events');
|
|
window.console.group = function() {};
|
|
window.console.groupEnd = function() {};
|
|
window.console.groupCollapsed = function() {};
|
|
}
|
|
if (typeof console.markTimeline == 'undefined') {
|
|
module.verbose('Mark timeline not available, normalizing events');
|
|
window.console.markTimeline = function() {};
|
|
}
|
|
},
|
|
consoleClear: function() {
|
|
module.debug('Disabling programmatic console clearing');
|
|
window.console.clear = function() {};
|
|
},
|
|
requestAnimationFrame: function() {
|
|
module.debug('Normalizing requestAnimationFrame');
|
|
if(window.requestAnimationFrame === undefined) {
|
|
module.debug('RequestAnimationFrame not available, normalizing event');
|
|
window.requestAnimationFrame = window.requestAnimationFrame
|
|
|| window.mozRequestAnimationFrame
|
|
|| window.webkitRequestAnimationFrame
|
|
|| window.msRequestAnimationFrame
|
|
|| function(callback) { setTimeout(callback, 0); }
|
|
;
|
|
}
|
|
}
|
|
},
|
|
|
|
moduleExists: function(name) {
|
|
return ($.fn[name] !== undefined && $.fn[name].settings !== undefined);
|
|
},
|
|
|
|
enabled: {
|
|
modules: function(modules) {
|
|
var
|
|
enabledModules = []
|
|
;
|
|
modules = modules || settings.modules;
|
|
$.each(modules, function(index, name) {
|
|
if(module.moduleExists(name)) {
|
|
enabledModules.push(name);
|
|
}
|
|
});
|
|
return enabledModules;
|
|
}
|
|
},
|
|
|
|
disabled: {
|
|
modules: function(modules) {
|
|
var
|
|
disabledModules = []
|
|
;
|
|
modules = modules || settings.modules;
|
|
$.each(modules, function(index, name) {
|
|
if(!module.moduleExists(name)) {
|
|
disabledModules.push(name);
|
|
}
|
|
});
|
|
return disabledModules;
|
|
}
|
|
},
|
|
|
|
change: {
|
|
setting: function(setting, value, modules, modifyExisting) {
|
|
modules = (typeof modules === 'string')
|
|
? (modules === 'all')
|
|
? settings.modules
|
|
: [modules]
|
|
: modules || settings.modules
|
|
;
|
|
modifyExisting = (modifyExisting !== undefined)
|
|
? modifyExisting
|
|
: true
|
|
;
|
|
$.each(modules, function(index, name) {
|
|
var
|
|
namespace = (module.moduleExists(name))
|
|
? $.fn[name].settings.namespace || false
|
|
: true,
|
|
$existingModules
|
|
;
|
|
if(module.moduleExists(name)) {
|
|
module.verbose('Changing default setting', setting, value, name);
|
|
$.fn[name].settings[setting] = value;
|
|
if(modifyExisting && namespace) {
|
|
$existingModules = $(':data(module-' + namespace + ')');
|
|
if($existingModules.length > 0) {
|
|
module.verbose('Modifying existing settings', $existingModules);
|
|
$existingModules[name]('setting', setting, value);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
},
|
|
settings: function(newSettings, modules, modifyExisting) {
|
|
modules = (typeof modules === 'string')
|
|
? [modules]
|
|
: modules || settings.modules
|
|
;
|
|
modifyExisting = (modifyExisting !== undefined)
|
|
? modifyExisting
|
|
: true
|
|
;
|
|
$.each(modules, function(index, name) {
|
|
var
|
|
$existingModules
|
|
;
|
|
if(module.moduleExists(name)) {
|
|
module.verbose('Changing default setting', newSettings, name);
|
|
$.extend(true, $.fn[name].settings, newSettings);
|
|
if(modifyExisting && namespace) {
|
|
$existingModules = $(':data(module-' + namespace + ')');
|
|
if($existingModules.length > 0) {
|
|
module.verbose('Modifying existing settings', $existingModules);
|
|
$existingModules[name]('setting', newSettings);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
enable: {
|
|
console: function() {
|
|
module.console(true);
|
|
},
|
|
debug: function(modules, modifyExisting) {
|
|
modules = modules || settings.modules;
|
|
module.debug('Enabling debug for modules', modules);
|
|
module.change.setting('debug', true, modules, modifyExisting);
|
|
},
|
|
verbose: function(modules, modifyExisting) {
|
|
modules = modules || settings.modules;
|
|
module.debug('Enabling verbose debug for modules', modules);
|
|
module.change.setting('verbose', true, modules, modifyExisting);
|
|
}
|
|
},
|
|
disable: {
|
|
console: function() {
|
|
module.console(false);
|
|
},
|
|
debug: function(modules, modifyExisting) {
|
|
modules = modules || settings.modules;
|
|
module.debug('Disabling debug for modules', modules);
|
|
module.change.setting('debug', false, modules, modifyExisting);
|
|
},
|
|
verbose: function(modules, modifyExisting) {
|
|
modules = modules || settings.modules;
|
|
module.debug('Disabling verbose debug for modules', modules);
|
|
module.change.setting('verbose', false, modules, modifyExisting);
|
|
}
|
|
},
|
|
|
|
console: function(enable) {
|
|
if(enable) {
|
|
if(instance.cache.console === undefined) {
|
|
module.error(error.console);
|
|
return;
|
|
}
|
|
module.debug('Restoring console function');
|
|
window.console = instance.cache.console;
|
|
}
|
|
else {
|
|
module.debug('Disabling console function');
|
|
instance.cache.console = window.console;
|
|
window.console = {
|
|
clear : function(){},
|
|
error : function(){},
|
|
group : function(){},
|
|
groupCollapsed : function(){},
|
|
groupEnd : function(){},
|
|
info : function(){},
|
|
log : function(){},
|
|
markTimeline : function(){},
|
|
warn : function(){}
|
|
};
|
|
}
|
|
},
|
|
|
|
destroy: function() {
|
|
module.verbose('Destroying previous site for', $module);
|
|
$module
|
|
.removeData(moduleNamespace)
|
|
;
|
|
},
|
|
|
|
cache: {},
|
|
|
|
setting: function(name, value) {
|
|
if( $.isPlainObject(name) ) {
|
|
$.extend(true, settings, name);
|
|
}
|
|
else if(value !== undefined) {
|
|
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.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.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() {
|
|
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({
|
|
'Element' : element,
|
|
'Name' : message[0],
|
|
'Arguments' : [].slice.call(message, 1) || '',
|
|
'Execution Time' : executionTime
|
|
});
|
|
}
|
|
clearTimeout(module.performance.timer);
|
|
module.performance.timer = setTimeout(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( (console.group !== undefined || console.table !== undefined) && performance.length > 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 = query.length - 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 {
|
|
module.error(error.method, query);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
if ( $.isFunction( found ) ) {
|
|
response = found.apply(context, passedArguments);
|
|
}
|
|
else if(found !== undefined) {
|
|
response = found;
|
|
}
|
|
if(Array.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) {
|
|
module.destroy();
|
|
}
|
|
module.initialize();
|
|
}
|
|
return (returnedValue !== undefined)
|
|
? returnedValue
|
|
: this
|
|
;
|
|
};
|
|
|
|
$.site.settings = {
|
|
|
|
name : 'Site',
|
|
namespace : 'site',
|
|
|
|
error : {
|
|
console : 'Console cannot be restored, most likely it was overwritten outside of module',
|
|
method : 'The method you called is not defined.'
|
|
},
|
|
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
modules: [
|
|
'accordion',
|
|
'api',
|
|
'calendar',
|
|
'checkbox',
|
|
'dimmer',
|
|
'dropdown',
|
|
'embed',
|
|
'form',
|
|
'modal',
|
|
'nag',
|
|
'popup',
|
|
'slider',
|
|
'rating',
|
|
'shape',
|
|
'sidebar',
|
|
'state',
|
|
'sticky',
|
|
'tab',
|
|
'toast',
|
|
'transition',
|
|
'visibility',
|
|
'visit'
|
|
],
|
|
|
|
siteNamespace : 'site',
|
|
namespaceStub : {
|
|
cache : {},
|
|
config : {},
|
|
sections : {},
|
|
section : {},
|
|
utilities : {}
|
|
}
|
|
|
|
};
|
|
|
|
// allows for selection of elements with data attributes
|
|
$.extend($.expr[ ":" ], {
|
|
data: ($.expr.createPseudo)
|
|
? $.expr.createPseudo(function(dataName) {
|
|
return function(elem) {
|
|
return !!$.data(elem, dataName);
|
|
};
|
|
})
|
|
: function(elem, i, match) {
|
|
// support: jQuery < 1.8
|
|
return !!$.data(elem, match[ 3 ]);
|
|
}
|
|
});
|
|
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Dimmer
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
window = (typeof window != 'undefined' && window.Math == Math)
|
|
? window
|
|
: (typeof self != 'undefined' && self.Math == Math)
|
|
? self
|
|
: Function('return this')()
|
|
;
|
|
|
|
$.fn.dimmer = function(parameters) {
|
|
var
|
|
$allModules = $(this),
|
|
|
|
time = new Date().getTime(),
|
|
performance = [],
|
|
|
|
query = arguments[0],
|
|
methodInvoked = (typeof query == 'string'),
|
|
queryArguments = [].slice.call(arguments, 1),
|
|
|
|
returnedValue
|
|
;
|
|
|
|
$allModules
|
|
.each(function() {
|
|
var
|
|
settings = ( $.isPlainObject(parameters) )
|
|
? $.extend(true, {}, $.fn.dimmer.settings, parameters)
|
|
: $.extend({}, $.fn.dimmer.settings),
|
|
|
|
selector = settings.selector,
|
|
namespace = settings.namespace,
|
|
className = settings.className,
|
|
error = settings.error,
|
|
|
|
eventNamespace = '.' + namespace,
|
|
moduleNamespace = 'module-' + namespace,
|
|
moduleSelector = $allModules.selector || '',
|
|
|
|
clickEvent = ('ontouchstart' in document.documentElement)
|
|
? 'touchstart'
|
|
: 'click',
|
|
|
|
$module = $(this),
|
|
$dimmer,
|
|
$dimmable,
|
|
|
|
element = this,
|
|
instance = $module.data(moduleNamespace),
|
|
module
|
|
;
|
|
|
|
module = {
|
|
|
|
preinitialize: function() {
|
|
if( module.is.dimmer() ) {
|
|
|
|
$dimmable = $module.parent();
|
|
$dimmer = $module;
|
|
}
|
|
else {
|
|
$dimmable = $module;
|
|
if( module.has.dimmer() ) {
|
|
if(settings.dimmerName) {
|
|
$dimmer = $dimmable.find(selector.dimmer).filter('.' + settings.dimmerName);
|
|
}
|
|
else {
|
|
$dimmer = $dimmable.find(selector.dimmer);
|
|
}
|
|
}
|
|
else {
|
|
$dimmer = module.create();
|
|
}
|
|
}
|
|
},
|
|
|
|
initialize: function() {
|
|
module.debug('Initializing dimmer', settings);
|
|
|
|
module.bind.events();
|
|
module.set.dimmable();
|
|
module.instantiate();
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of module', module);
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, instance)
|
|
;
|
|
},
|
|
|
|
destroy: function() {
|
|
module.verbose('Destroying previous module', $dimmer);
|
|
module.unbind.events();
|
|
module.remove.variation();
|
|
$dimmable
|
|
.off(eventNamespace)
|
|
;
|
|
},
|
|
|
|
bind: {
|
|
events: function() {
|
|
if(settings.on == 'hover') {
|
|
$dimmable
|
|
.on('mouseenter' + eventNamespace, module.show)
|
|
.on('mouseleave' + eventNamespace, module.hide)
|
|
;
|
|
}
|
|
else if(settings.on == 'click') {
|
|
$dimmable
|
|
.on(clickEvent + eventNamespace, module.toggle)
|
|
;
|
|
}
|
|
if( module.is.page() ) {
|
|
module.debug('Setting as a page dimmer', $dimmable);
|
|
module.set.pageDimmer();
|
|
}
|
|
|
|
if( module.is.closable() ) {
|
|
module.verbose('Adding dimmer close event', $dimmer);
|
|
$dimmable
|
|
.on(clickEvent + eventNamespace, selector.dimmer, module.event.click)
|
|
;
|
|
}
|
|
}
|
|
},
|
|
|
|
unbind: {
|
|
events: function() {
|
|
$module
|
|
.removeData(moduleNamespace)
|
|
;
|
|
$dimmable
|
|
.off(eventNamespace)
|
|
;
|
|
}
|
|
},
|
|
|
|
event: {
|
|
click: function(event) {
|
|
module.verbose('Determining if event occurred on dimmer', event);
|
|
if( $dimmer.find(event.target).length === 0 || $(event.target).is(selector.content) ) {
|
|
module.hide();
|
|
event.stopImmediatePropagation();
|
|
}
|
|
}
|
|
},
|
|
|
|
addContent: function(element) {
|
|
var
|
|
$content = $(element)
|
|
;
|
|
module.debug('Add content to dimmer', $content);
|
|
if($content.parent()[0] !== $dimmer[0]) {
|
|
$content.detach().appendTo($dimmer);
|
|
}
|
|
},
|
|
|
|
create: function() {
|
|
var
|
|
$element = $( settings.template.dimmer(settings) )
|
|
;
|
|
if(settings.dimmerName) {
|
|
module.debug('Creating named dimmer', settings.dimmerName);
|
|
$element.addClass(settings.dimmerName);
|
|
}
|
|
$element
|
|
.appendTo($dimmable)
|
|
;
|
|
return $element;
|
|
},
|
|
|
|
show: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
module.debug('Showing dimmer', $dimmer, settings);
|
|
module.set.variation();
|
|
if( (!module.is.dimmed() || module.is.animating()) && module.is.enabled() ) {
|
|
module.animate.show(callback);
|
|
settings.onShow.call(element);
|
|
settings.onChange.call(element);
|
|
}
|
|
else {
|
|
module.debug('Dimmer is already shown or disabled');
|
|
}
|
|
},
|
|
|
|
hide: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if( module.is.dimmed() || module.is.animating() ) {
|
|
module.debug('Hiding dimmer', $dimmer);
|
|
module.animate.hide(callback);
|
|
settings.onHide.call(element);
|
|
settings.onChange.call(element);
|
|
}
|
|
else {
|
|
module.debug('Dimmer is not visible');
|
|
}
|
|
},
|
|
|
|
toggle: function() {
|
|
module.verbose('Toggling dimmer visibility', $dimmer);
|
|
if( !module.is.dimmed() ) {
|
|
module.show();
|
|
}
|
|
else {
|
|
if ( module.is.closable() ) {
|
|
module.hide();
|
|
}
|
|
}
|
|
},
|
|
|
|
animate: {
|
|
show: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
|
|
if(settings.useFlex) {
|
|
module.debug('Using flex dimmer');
|
|
module.remove.legacy();
|
|
}
|
|
else {
|
|
module.debug('Using legacy non-flex dimmer');
|
|
module.set.legacy();
|
|
}
|
|
if(settings.opacity !== 'auto') {
|
|
module.set.opacity();
|
|
}
|
|
$dimmer
|
|
.transition({
|
|
displayType : settings.useFlex
|
|
? 'flex'
|
|
: 'block',
|
|
animation : (settings.transition.showMethod || settings.transition) + ' in',
|
|
queue : false,
|
|
duration : module.get.duration(),
|
|
useFailSafe : true,
|
|
onStart : function() {
|
|
module.set.dimmed();
|
|
},
|
|
onComplete : function() {
|
|
module.set.active();
|
|
callback();
|
|
}
|
|
})
|
|
;
|
|
}
|
|
else {
|
|
module.verbose('Showing dimmer animation with javascript');
|
|
module.set.dimmed();
|
|
if(settings.opacity == 'auto') {
|
|
settings.opacity = 0.8;
|
|
}
|
|
$dimmer
|
|
.stop()
|
|
.css({
|
|
opacity : 0,
|
|
width : '100%',
|
|
height : '100%'
|
|
})
|
|
.fadeTo(module.get.duration(), settings.opacity, function() {
|
|
$dimmer.removeAttr('style');
|
|
module.set.active();
|
|
callback();
|
|
})
|
|
;
|
|
}
|
|
},
|
|
hide: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
|
|
module.verbose('Hiding dimmer with css');
|
|
$dimmer
|
|
.transition({
|
|
displayType : settings.useFlex
|
|
? 'flex'
|
|
: 'block',
|
|
animation : (settings.transition.hideMethod || settings.transition) + ' out',
|
|
queue : false,
|
|
duration : module.get.duration(),
|
|
useFailSafe : true,
|
|
onComplete : function() {
|
|
module.remove.dimmed();
|
|
module.remove.variation();
|
|
module.remove.active();
|
|
callback();
|
|
}
|
|
})
|
|
;
|
|
}
|
|
else {
|
|
module.verbose('Hiding dimmer with javascript');
|
|
$dimmer
|
|
.stop()
|
|
.fadeOut(module.get.duration(), function() {
|
|
module.remove.dimmed();
|
|
module.remove.active();
|
|
$dimmer.removeAttr('style');
|
|
callback();
|
|
})
|
|
;
|
|
}
|
|
}
|
|
},
|
|
|
|
get: {
|
|
dimmer: function() {
|
|
return $dimmer;
|
|
},
|
|
duration: function() {
|
|
if( module.is.active() ) {
|
|
return settings.transition.hideDuration || settings.duration.hide || settings.duration;
|
|
}
|
|
else {
|
|
return settings.transition.showDuration || settings.duration.show || settings.duration;
|
|
}
|
|
}
|
|
},
|
|
|
|
has: {
|
|
dimmer: function() {
|
|
if(settings.dimmerName) {
|
|
return ($module.find(selector.dimmer).filter('.' + settings.dimmerName).length > 0);
|
|
}
|
|
else {
|
|
return ( $module.find(selector.dimmer).length > 0 );
|
|
}
|
|
}
|
|
},
|
|
|
|
is: {
|
|
active: function() {
|
|
return $dimmer.hasClass(className.active);
|
|
},
|
|
animating: function() {
|
|
return ( $dimmer.is(':animated') || $dimmer.hasClass(className.animating) );
|
|
},
|
|
closable: function() {
|
|
if(settings.closable == 'auto') {
|
|
if(settings.on == 'hover') {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return settings.closable;
|
|
},
|
|
dimmer: function() {
|
|
return $module.hasClass(className.dimmer);
|
|
},
|
|
dimmable: function() {
|
|
return $module.hasClass(className.dimmable);
|
|
},
|
|
dimmed: function() {
|
|
return $dimmable.hasClass(className.dimmed);
|
|
},
|
|
disabled: function() {
|
|
return $dimmable.hasClass(className.disabled);
|
|
},
|
|
enabled: function() {
|
|
return !module.is.disabled();
|
|
},
|
|
page: function () {
|
|
return $dimmable.is('body');
|
|
},
|
|
pageDimmer: function() {
|
|
return $dimmer.hasClass(className.pageDimmer);
|
|
}
|
|
},
|
|
|
|
can: {
|
|
show: function() {
|
|
return !$dimmer.hasClass(className.disabled);
|
|
}
|
|
},
|
|
|
|
set: {
|
|
opacity: function(opacity) {
|
|
var
|
|
color = $dimmer.css('background-color'),
|
|
colorArray = color.split(','),
|
|
isRGB = (colorArray && colorArray.length >= 3)
|
|
;
|
|
opacity = settings.opacity === 0 ? 0 : settings.opacity || opacity;
|
|
if(isRGB) {
|
|
colorArray[2] = colorArray[2].replace(')','');
|
|
colorArray[3] = opacity + ')';
|
|
color = colorArray.join(',');
|
|
}
|
|
else {
|
|
color = 'rgba(0, 0, 0, ' + opacity + ')';
|
|
}
|
|
module.debug('Setting opacity to', opacity);
|
|
$dimmer.css('background-color', color);
|
|
},
|
|
legacy: function() {
|
|
$dimmer.addClass(className.legacy);
|
|
},
|
|
active: function() {
|
|
$dimmer.addClass(className.active);
|
|
},
|
|
dimmable: function() {
|
|
$dimmable.addClass(className.dimmable);
|
|
},
|
|
dimmed: function() {
|
|
$dimmable.addClass(className.dimmed);
|
|
},
|
|
pageDimmer: function() {
|
|
$dimmer.addClass(className.pageDimmer);
|
|
},
|
|
disabled: function() {
|
|
$dimmer.addClass(className.disabled);
|
|
},
|
|
variation: function(variation) {
|
|
variation = variation || settings.variation;
|
|
if(variation) {
|
|
$dimmer.addClass(variation);
|
|
}
|
|
}
|
|
},
|
|
|
|
remove: {
|
|
active: function() {
|
|
$dimmer
|
|
.removeClass(className.active)
|
|
;
|
|
},
|
|
legacy: function() {
|
|
$dimmer.removeClass(className.legacy);
|
|
},
|
|
dimmed: function() {
|
|
$dimmable.removeClass(className.dimmed);
|
|
},
|
|
disabled: function() {
|
|
$dimmer.removeClass(className.disabled);
|
|
},
|
|
variation: function(variation) {
|
|
variation = variation || settings.variation;
|
|
if(variation) {
|
|
$dimmer.removeClass(variation);
|
|
}
|
|
}
|
|
},
|
|
|
|
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 = setTimeout(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($allModules.length > 1) {
|
|
title += ' ' + '(' + $allModules.length + ')';
|
|
}
|
|
if( (console.group !== undefined || console.table !== undefined) && performance.length > 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 = query.length - 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 {
|
|
module.error(error.method, query);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
if ( $.isFunction( found ) ) {
|
|
response = found.apply(context, passedArguments);
|
|
}
|
|
else if(found !== undefined) {
|
|
response = found;
|
|
}
|
|
if(Array.isArray(returnedValue)) {
|
|
returnedValue.push(response);
|
|
}
|
|
else if(returnedValue !== undefined) {
|
|
returnedValue = [returnedValue, response];
|
|
}
|
|
else if(response !== undefined) {
|
|
returnedValue = response;
|
|
}
|
|
return found;
|
|
}
|
|
};
|
|
|
|
module.preinitialize();
|
|
|
|
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.dimmer.settings = {
|
|
|
|
name : 'Dimmer',
|
|
namespace : 'dimmer',
|
|
|
|
silent : false,
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
// whether should use flex layout
|
|
useFlex : true,
|
|
|
|
// name to distinguish between multiple dimmers in context
|
|
dimmerName : false,
|
|
|
|
// whether to add a variation type
|
|
variation : false,
|
|
|
|
// whether to bind close events
|
|
closable : 'auto',
|
|
|
|
// whether to use css animations
|
|
useCSS : true,
|
|
|
|
// css animation to use
|
|
transition : 'fade',
|
|
|
|
// event to bind to
|
|
on : false,
|
|
|
|
// overriding opacity value
|
|
opacity : 'auto',
|
|
|
|
// transition durations
|
|
duration : {
|
|
show : 500,
|
|
hide : 500
|
|
},
|
|
// whether the dynamically created dimmer should have a loader
|
|
displayLoader: false,
|
|
loaderText : false,
|
|
loaderVariation : '',
|
|
|
|
onChange : function(){},
|
|
onShow : function(){},
|
|
onHide : function(){},
|
|
|
|
error : {
|
|
method : 'The method you called is not defined.'
|
|
},
|
|
|
|
className : {
|
|
active : 'active',
|
|
animating : 'animating',
|
|
dimmable : 'dimmable',
|
|
dimmed : 'dimmed',
|
|
dimmer : 'dimmer',
|
|
disabled : 'disabled',
|
|
hide : 'hide',
|
|
legacy : 'legacy',
|
|
pageDimmer : 'page',
|
|
show : 'show',
|
|
loader : 'ui loader'
|
|
},
|
|
|
|
selector: {
|
|
dimmer : '> .ui.dimmer',
|
|
content : '.ui.dimmer > .content, .ui.dimmer > .content > .center'
|
|
},
|
|
|
|
template: {
|
|
dimmer: function(settings) {
|
|
var d = $('<div/>').addClass('ui dimmer'),l;
|
|
if(settings.displayLoader) {
|
|
l = $('<div/>')
|
|
.addClass(settings.className.loader)
|
|
.addClass(settings.loaderVariation);
|
|
if(!!settings.loaderText){
|
|
l.text(settings.loaderText);
|
|
l.addClass('text');
|
|
}
|
|
d.append(l);
|
|
}
|
|
return d;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Dropdown
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
window = (typeof window != 'undefined' && window.Math == Math)
|
|
? window
|
|
: (typeof self != 'undefined' && self.Math == Math)
|
|
? self
|
|
: Function('return this')()
|
|
;
|
|
|
|
$.fn.dropdown = function(parameters) {
|
|
var
|
|
$allModules = $(this),
|
|
$document = $(document),
|
|
|
|
moduleSelector = $allModules.selector || '',
|
|
|
|
hasTouch = ('ontouchstart' in document.documentElement),
|
|
clickEvent = hasTouch
|
|
? 'touchstart'
|
|
: 'click',
|
|
|
|
time = new Date().getTime(),
|
|
performance = [],
|
|
|
|
query = arguments[0],
|
|
methodInvoked = (typeof query == 'string'),
|
|
queryArguments = [].slice.call(arguments, 1),
|
|
returnedValue
|
|
;
|
|
|
|
$allModules
|
|
.each(function(elementIndex) {
|
|
var
|
|
settings = ( $.isPlainObject(parameters) )
|
|
? $.extend(true, {}, $.fn.dropdown.settings, parameters)
|
|
: $.extend({}, $.fn.dropdown.settings),
|
|
|
|
className = settings.className,
|
|
message = settings.message,
|
|
fields = settings.fields,
|
|
keys = settings.keys,
|
|
metadata = settings.metadata,
|
|
namespace = settings.namespace,
|
|
regExp = settings.regExp,
|
|
selector = settings.selector,
|
|
error = settings.error,
|
|
templates = settings.templates,
|
|
|
|
eventNamespace = '.' + namespace,
|
|
moduleNamespace = 'module-' + namespace,
|
|
|
|
$module = $(this),
|
|
$context = $(settings.context),
|
|
$text = $module.find(selector.text),
|
|
$search = $module.find(selector.search),
|
|
$sizer = $module.find(selector.sizer),
|
|
$input = $module.find(selector.input),
|
|
$icon = $module.find(selector.icon),
|
|
$clear = $module.find(selector.clearIcon),
|
|
|
|
$combo = ($module.prev().find(selector.text).length > 0)
|
|
? $module.prev().find(selector.text)
|
|
: $module.prev(),
|
|
|
|
$menu = $module.children(selector.menu),
|
|
$item = $menu.find(selector.item),
|
|
$divider = settings.hideDividers ? $item.parent().children(selector.divider) : $(),
|
|
|
|
activated = false,
|
|
itemActivated = false,
|
|
internalChange = false,
|
|
iconClicked = false,
|
|
element = this,
|
|
focused = false,
|
|
instance = $module.data(moduleNamespace),
|
|
|
|
selectActionActive,
|
|
initialLoad,
|
|
pageLostFocus,
|
|
willRefocus,
|
|
elementNamespace,
|
|
id,
|
|
selectObserver,
|
|
menuObserver,
|
|
classObserver,
|
|
module
|
|
;
|
|
|
|
module = {
|
|
|
|
initialize: function() {
|
|
module.debug('Initializing dropdown', settings);
|
|
|
|
if( module.is.alreadySetup() ) {
|
|
module.setup.reference();
|
|
}
|
|
else {
|
|
if (settings.ignoreDiacritics && !String.prototype.normalize) {
|
|
settings.ignoreDiacritics = false;
|
|
module.error(error.noNormalize, element);
|
|
}
|
|
|
|
module.setup.layout();
|
|
|
|
if(settings.values) {
|
|
module.set.initialLoad();
|
|
module.change.values(settings.values);
|
|
module.remove.initialLoad();
|
|
}
|
|
|
|
module.refreshData();
|
|
|
|
module.save.defaults();
|
|
module.restore.selected();
|
|
|
|
module.create.id();
|
|
module.bind.events();
|
|
|
|
module.observeChanges();
|
|
module.instantiate();
|
|
}
|
|
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of dropdown', module);
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, module)
|
|
;
|
|
},
|
|
|
|
destroy: function() {
|
|
module.verbose('Destroying previous dropdown', $module);
|
|
module.remove.tabbable();
|
|
module.remove.active();
|
|
$menu.transition('stop all');
|
|
$menu.removeClass(className.visible).addClass(className.hidden);
|
|
$module
|
|
.off(eventNamespace)
|
|
.removeData(moduleNamespace)
|
|
;
|
|
$menu
|
|
.off(eventNamespace)
|
|
;
|
|
$document
|
|
.off(elementNamespace)
|
|
;
|
|
module.disconnect.menuObserver();
|
|
module.disconnect.selectObserver();
|
|
module.disconnect.classObserver();
|
|
},
|
|
|
|
observeChanges: function() {
|
|
if('MutationObserver' in window) {
|
|
selectObserver = new MutationObserver(module.event.select.mutation);
|
|
menuObserver = new MutationObserver(module.event.menu.mutation);
|
|
classObserver = new MutationObserver(module.event.class.mutation);
|
|
module.debug('Setting up mutation observer', selectObserver, menuObserver, classObserver);
|
|
module.observe.select();
|
|
module.observe.menu();
|
|
module.observe.class();
|
|
}
|
|
},
|
|
|
|
disconnect: {
|
|
menuObserver: function() {
|
|
if(menuObserver) {
|
|
menuObserver.disconnect();
|
|
}
|
|
},
|
|
selectObserver: function() {
|
|
if(selectObserver) {
|
|
selectObserver.disconnect();
|
|
}
|
|
},
|
|
classObserver: function() {
|
|
if(classObserver) {
|
|
classObserver.disconnect();
|
|
}
|
|
}
|
|
},
|
|
observe: {
|
|
select: function() {
|
|
if(module.has.input() && selectObserver) {
|
|
selectObserver.observe($module[0], {
|
|
childList : true,
|
|
subtree : true
|
|
});
|
|
}
|
|
},
|
|
menu: function() {
|
|
if(module.has.menu() && menuObserver) {
|
|
menuObserver.observe($menu[0], {
|
|
childList : true,
|
|
subtree : true
|
|
});
|
|
}
|
|
},
|
|
class: function() {
|
|
if(module.has.search() && classObserver) {
|
|
classObserver.observe($module[0], {
|
|
attributes : true
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
create: {
|
|
id: function() {
|
|
id = (Math.random().toString(16) + '000000000').substr(2, 8);
|
|
elementNamespace = '.' + id;
|
|
module.verbose('Creating unique id for element', id);
|
|
},
|
|
userChoice: function(values) {
|
|
var
|
|
$userChoices,
|
|
$userChoice,
|
|
isUserValue,
|
|
html
|
|
;
|
|
values = values || module.get.userValues();
|
|
if(!values) {
|
|
return false;
|
|
}
|
|
values = Array.isArray(values)
|
|
? values
|
|
: [values]
|
|
;
|
|
$.each(values, function(index, value) {
|
|
if(module.get.item(value) === false) {
|
|
html = settings.templates.addition( module.add.variables(message.addResult, value) );
|
|
$userChoice = $('<div />')
|
|
.html(html)
|
|
.attr('data-' + metadata.value, value)
|
|
.attr('data-' + metadata.text, value)
|
|
.addClass(className.addition)
|
|
.addClass(className.item)
|
|
;
|
|
if(settings.hideAdditions) {
|
|
$userChoice.addClass(className.hidden);
|
|
}
|
|
$userChoices = ($userChoices === undefined)
|
|
? $userChoice
|
|
: $userChoices.add($userChoice)
|
|
;
|
|
module.verbose('Creating user choices for value', value, $userChoice);
|
|
}
|
|
});
|
|
return $userChoices;
|
|
},
|
|
userLabels: function(value) {
|
|
var
|
|
userValues = module.get.userValues()
|
|
;
|
|
if(userValues) {
|
|
module.debug('Adding user labels', userValues);
|
|
$.each(userValues, function(index, value) {
|
|
module.verbose('Adding custom user value');
|
|
module.add.label(value, value);
|
|
});
|
|
}
|
|
},
|
|
menu: function() {
|
|
$menu = $('<div />')
|
|
.addClass(className.menu)
|
|
.appendTo($module)
|
|
;
|
|
},
|
|
sizer: function() {
|
|
$sizer = $('<span />')
|
|
.addClass(className.sizer)
|
|
.insertAfter($search)
|
|
;
|
|
}
|
|
},
|
|
|
|
search: function(query) {
|
|
query = (query !== undefined)
|
|
? query
|
|
: module.get.query()
|
|
;
|
|
module.verbose('Searching for query', query);
|
|
if(settings.fireOnInit === false && module.is.initialLoad()) {
|
|
module.verbose('Skipping callback on initial load', settings.onSearch);
|
|
} else if(module.has.minCharacters(query) && settings.onSearch.call(element, query) !== false) {
|
|
module.filter(query);
|
|
}
|
|
else {
|
|
module.hide(null,true);
|
|
}
|
|
},
|
|
|
|
select: {
|
|
firstUnfiltered: function() {
|
|
module.verbose('Selecting first non-filtered element');
|
|
module.remove.selectedItem();
|
|
$item
|
|
.not(selector.unselectable)
|
|
.not(selector.addition + selector.hidden)
|
|
.eq(0)
|
|
.addClass(className.selected)
|
|
;
|
|
},
|
|
nextAvailable: function($selected) {
|
|
$selected = $selected.eq(0);
|
|
var
|
|
$nextAvailable = $selected.nextAll(selector.item).not(selector.unselectable).eq(0),
|
|
$prevAvailable = $selected.prevAll(selector.item).not(selector.unselectable).eq(0),
|
|
hasNext = ($nextAvailable.length > 0)
|
|
;
|
|
if(hasNext) {
|
|
module.verbose('Moving selection to', $nextAvailable);
|
|
$nextAvailable.addClass(className.selected);
|
|
}
|
|
else {
|
|
module.verbose('Moving selection to', $prevAvailable);
|
|
$prevAvailable.addClass(className.selected);
|
|
}
|
|
}
|
|
},
|
|
|
|
setup: {
|
|
api: function() {
|
|
var
|
|
apiSettings = {
|
|
debug : settings.debug,
|
|
urlData : {
|
|
value : module.get.value(),
|
|
query : module.get.query()
|
|
},
|
|
on : false
|
|
}
|
|
;
|
|
module.verbose('First request, initializing API');
|
|
$module
|
|
.api(apiSettings)
|
|
;
|
|
},
|
|
layout: function() {
|
|
if( $module.is('select') ) {
|
|
module.setup.select();
|
|
module.setup.returnedObject();
|
|
}
|
|
if( !module.has.menu() ) {
|
|
module.create.menu();
|
|
}
|
|
if ( module.is.clearable() && !module.has.clearItem() ) {
|
|
module.verbose('Adding clear icon');
|
|
$clear = $('<i />')
|
|
.addClass('remove icon')
|
|
.insertBefore($text)
|
|
;
|
|
}
|
|
if( module.is.search() && !module.has.search() ) {
|
|
module.verbose('Adding search input');
|
|
$search = $('<input />')
|
|
.addClass(className.search)
|
|
.prop('autocomplete', module.is.chrome() ? 'fomantic-search' : 'off')
|
|
.insertBefore($text)
|
|
;
|
|
}
|
|
if( module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
|
|
module.create.sizer();
|
|
}
|
|
if(settings.allowTab) {
|
|
module.set.tabbable();
|
|
}
|
|
},
|
|
select: function() {
|
|
var
|
|
selectValues = module.get.selectValues()
|
|
;
|
|
module.debug('Dropdown initialized on a select', selectValues);
|
|
if( $module.is('select') ) {
|
|
$input = $module;
|
|
}
|
|
// see if select is placed correctly already
|
|
if($input.parent(selector.dropdown).length > 0) {
|
|
module.debug('UI dropdown already exists. Creating dropdown menu only');
|
|
$module = $input.closest(selector.dropdown);
|
|
if( !module.has.menu() ) {
|
|
module.create.menu();
|
|
}
|
|
$menu = $module.children(selector.menu);
|
|
module.setup.menu(selectValues);
|
|
}
|
|
else {
|
|
module.debug('Creating entire dropdown from select');
|
|
$module = $('<div />')
|
|
.attr('class', $input.attr('class') )
|
|
.addClass(className.selection)
|
|
.addClass(className.dropdown)
|
|
.html( templates.dropdown(selectValues, fields, settings.preserveHTML, settings.className) )
|
|
.insertBefore($input)
|
|
;
|
|
if($input.hasClass(className.multiple) && $input.prop('multiple') === false) {
|
|
module.error(error.missingMultiple);
|
|
$input.prop('multiple', true);
|
|
}
|
|
if($input.is('[multiple]')) {
|
|
module.set.multiple();
|
|
}
|
|
if ($input.prop('disabled')) {
|
|
module.debug('Disabling dropdown');
|
|
$module.addClass(className.disabled);
|
|
}
|
|
$input
|
|
.removeAttr('required')
|
|
.removeAttr('class')
|
|
.detach()
|
|
.prependTo($module)
|
|
;
|
|
}
|
|
module.refresh();
|
|
},
|
|
menu: function(values) {
|
|
$menu.html( templates.menu(values, fields,settings.preserveHTML,settings.className));
|
|
$item = $menu.find(selector.item);
|
|
$divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
|
|
},
|
|
reference: function() {
|
|
module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
|
|
// replace module reference
|
|
$module = $module.parent(selector.dropdown);
|
|
instance = $module.data(moduleNamespace);
|
|
element = $module.get(0);
|
|
module.refresh();
|
|
module.setup.returnedObject();
|
|
},
|
|
returnedObject: function() {
|
|
var
|
|
$firstModules = $allModules.slice(0, elementIndex),
|
|
$lastModules = $allModules.slice(elementIndex + 1)
|
|
;
|
|
// adjust all modules to use correct reference
|
|
$allModules = $firstModules.add($module).add($lastModules);
|
|
}
|
|
},
|
|
|
|
refresh: function() {
|
|
module.refreshSelectors();
|
|
module.refreshData();
|
|
},
|
|
|
|
refreshItems: function() {
|
|
$item = $menu.find(selector.item);
|
|
$divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
|
|
},
|
|
|
|
refreshSelectors: function() {
|
|
module.verbose('Refreshing selector cache');
|
|
$text = $module.find(selector.text);
|
|
$search = $module.find(selector.search);
|
|
$input = $module.find(selector.input);
|
|
$icon = $module.find(selector.icon);
|
|
$combo = ($module.prev().find(selector.text).length > 0)
|
|
? $module.prev().find(selector.text)
|
|
: $module.prev()
|
|
;
|
|
$menu = $module.children(selector.menu);
|
|
$item = $menu.find(selector.item);
|
|
$divider = settings.hideDividers ? $item.parent().children(selector.divider) : $();
|
|
},
|
|
|
|
refreshData: function() {
|
|
module.verbose('Refreshing cached metadata');
|
|
$item
|
|
.removeData(metadata.text)
|
|
.removeData(metadata.value)
|
|
;
|
|
},
|
|
|
|
clearData: function() {
|
|
module.verbose('Clearing metadata');
|
|
$item
|
|
.removeData(metadata.text)
|
|
.removeData(metadata.value)
|
|
;
|
|
$module
|
|
.removeData(metadata.defaultText)
|
|
.removeData(metadata.defaultValue)
|
|
.removeData(metadata.placeholderText)
|
|
;
|
|
},
|
|
|
|
clearItems: function() {
|
|
$menu.empty();
|
|
module.refreshItems();
|
|
},
|
|
|
|
toggle: function() {
|
|
module.verbose('Toggling menu visibility');
|
|
if( !module.is.active() ) {
|
|
module.show();
|
|
}
|
|
else {
|
|
module.hide();
|
|
}
|
|
},
|
|
|
|
show: function(callback, preventFocus) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if ((focused || iconClicked) && module.is.remote() && module.is.noApiCache()) {
|
|
module.clearItems();
|
|
}
|
|
if(!module.can.show() && module.is.remote()) {
|
|
module.debug('No API results retrieved, searching before show');
|
|
module.queryRemote(module.get.query(), module.show, [callback, preventFocus]);
|
|
}
|
|
if( module.can.show() && !module.is.active() ) {
|
|
module.debug('Showing dropdown');
|
|
if(module.has.message() && !(module.has.maxSelections() || module.has.allResultsFiltered()) ) {
|
|
module.remove.message();
|
|
}
|
|
if(module.is.allFiltered()) {
|
|
return true;
|
|
}
|
|
if(settings.onShow.call(element) !== false) {
|
|
module.animate.show(function() {
|
|
if( module.can.click() ) {
|
|
module.bind.intent();
|
|
}
|
|
if(module.has.search() && !preventFocus) {
|
|
module.focusSearch();
|
|
}
|
|
module.set.visible();
|
|
callback.call(element);
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
hide: function(callback, preventBlur) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if( module.is.active() && !module.is.animatingOutward() ) {
|
|
module.debug('Hiding dropdown');
|
|
if(settings.onHide.call(element) !== false) {
|
|
module.animate.hide(function() {
|
|
module.remove.visible();
|
|
// hidding search focus
|
|
if ( module.is.focusedOnSearch() && preventBlur !== true ) {
|
|
$search.blur();
|
|
}
|
|
callback.call(element);
|
|
});
|
|
}
|
|
} else if( module.can.click() ) {
|
|
module.unbind.intent();
|
|
}
|
|
iconClicked = false;
|
|
focused = false;
|
|
},
|
|
|
|
hideOthers: function() {
|
|
module.verbose('Finding other dropdowns to hide');
|
|
$allModules
|
|
.not($module)
|
|
.has(selector.menu + '.' + className.visible)
|
|
.dropdown('hide')
|
|
;
|
|
},
|
|
|
|
hideMenu: function() {
|
|
module.verbose('Hiding menu instantaneously');
|
|
module.remove.active();
|
|
module.remove.visible();
|
|
$menu.transition('hide');
|
|
},
|
|
|
|
hideSubMenus: function() {
|
|
var
|
|
$subMenus = $menu.children(selector.item).find(selector.menu)
|
|
;
|
|
module.verbose('Hiding sub menus', $subMenus);
|
|
$subMenus.transition('hide');
|
|
},
|
|
|
|
bind: {
|
|
events: function() {
|
|
module.bind.keyboardEvents();
|
|
module.bind.inputEvents();
|
|
module.bind.mouseEvents();
|
|
},
|
|
keyboardEvents: function() {
|
|
module.verbose('Binding keyboard events');
|
|
$module
|
|
.on('keydown' + eventNamespace, module.event.keydown)
|
|
;
|
|
if( module.has.search() ) {
|
|
$module
|
|
.on(module.get.inputEvent() + eventNamespace, selector.search, module.event.input)
|
|
;
|
|
}
|
|
if( module.is.multiple() ) {
|
|
$document
|
|
.on('keydown' + elementNamespace, module.event.document.keydown)
|
|
;
|
|
}
|
|
},
|
|
inputEvents: function() {
|
|
module.verbose('Binding input change events');
|
|
$module
|
|
.on('change' + eventNamespace, selector.input, module.event.change)
|
|
;
|
|
},
|
|
mouseEvents: function() {
|
|
module.verbose('Binding mouse events');
|
|
if(module.is.multiple()) {
|
|
$module
|
|
.on(clickEvent + eventNamespace, selector.label, module.event.label.click)
|
|
.on(clickEvent + eventNamespace, selector.remove, module.event.remove.click)
|
|
;
|
|
}
|
|
if( module.is.searchSelection() ) {
|
|
$module
|
|
.on('mousedown' + eventNamespace, module.event.mousedown)
|
|
.on('mouseup' + eventNamespace, module.event.mouseup)
|
|
.on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
|
|
.on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
|
|
.on(clickEvent + eventNamespace, selector.icon, module.event.icon.click)
|
|
.on(clickEvent + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
|
|
.on('focus' + eventNamespace, selector.search, module.event.search.focus)
|
|
.on(clickEvent + eventNamespace, selector.search, module.event.search.focus)
|
|
.on('blur' + eventNamespace, selector.search, module.event.search.blur)
|
|
.on(clickEvent + eventNamespace, selector.text, module.event.text.focus)
|
|
;
|
|
if(module.is.multiple()) {
|
|
$module
|
|
.on(clickEvent + eventNamespace, module.event.click)
|
|
.on(clickEvent + eventNamespace, module.event.search.focus)
|
|
;
|
|
}
|
|
}
|
|
else {
|
|
if(settings.on == 'click') {
|
|
$module
|
|
.on(clickEvent + eventNamespace, selector.icon, module.event.icon.click)
|
|
.on(clickEvent + eventNamespace, module.event.test.toggle)
|
|
;
|
|
}
|
|
else if(settings.on == 'hover') {
|
|
$module
|
|
.on('mouseenter' + eventNamespace, module.delay.show)
|
|
.on('mouseleave' + eventNamespace, module.delay.hide)
|
|
;
|
|
}
|
|
else {
|
|
$module
|
|
.on(settings.on + eventNamespace, module.toggle)
|
|
;
|
|
}
|
|
$module
|
|
.on('mousedown' + eventNamespace, module.event.mousedown)
|
|
.on('mouseup' + eventNamespace, module.event.mouseup)
|
|
.on('focus' + eventNamespace, module.event.focus)
|
|
.on(clickEvent + eventNamespace, selector.clearIcon, module.event.clearIcon.click)
|
|
;
|
|
if(module.has.menuSearch() ) {
|
|
$module
|
|
.on('blur' + eventNamespace, selector.search, module.event.search.blur)
|
|
;
|
|
}
|
|
else {
|
|
$module
|
|
.on('blur' + eventNamespace, module.event.blur)
|
|
;
|
|
}
|
|
}
|
|
$menu
|
|
.on((hasTouch ? 'touchstart' : 'mouseenter') + eventNamespace, selector.item, module.event.item.mouseenter)
|
|
.on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
|
|
.on('click' + eventNamespace, selector.item, module.event.item.click)
|
|
;
|
|
},
|
|
intent: function() {
|
|
module.verbose('Binding hide intent event to document');
|
|
if(hasTouch) {
|
|
$document
|
|
.on('touchstart' + elementNamespace, module.event.test.touch)
|
|
.on('touchmove' + elementNamespace, module.event.test.touch)
|
|
;
|
|
}
|
|
$document
|
|
.on(clickEvent + elementNamespace, module.event.test.hide)
|
|
;
|
|
}
|
|
},
|
|
|
|
unbind: {
|
|
intent: function() {
|
|
module.verbose('Removing hide intent event from document');
|
|
if(hasTouch) {
|
|
$document
|
|
.off('touchstart' + elementNamespace)
|
|
.off('touchmove' + elementNamespace)
|
|
;
|
|
}
|
|
$document
|
|
.off(clickEvent + elementNamespace)
|
|
;
|
|
}
|
|
},
|
|
|
|
filter: function(query) {
|
|
var
|
|
searchTerm = (query !== undefined)
|
|
? query
|
|
: module.get.query(),
|
|
afterFiltered = function() {
|
|
if(module.is.multiple()) {
|
|
module.filterActive();
|
|
}
|
|
if(query || (!query && module.get.activeItem().length == 0)) {
|
|
module.select.firstUnfiltered();
|
|
}
|
|
if( module.has.allResultsFiltered() ) {
|
|
if( settings.onNoResults.call(element, searchTerm) ) {
|
|
if(settings.allowAdditions) {
|
|
if(settings.hideAdditions) {
|
|
module.verbose('User addition with no menu, setting empty style');
|
|
module.set.empty();
|
|
module.hideMenu();
|
|
}
|
|
}
|
|
else {
|
|
module.verbose('All items filtered, showing message', searchTerm);
|
|
module.add.message(message.noResults);
|
|
}
|
|
}
|
|
else {
|
|
module.verbose('All items filtered, hiding dropdown', searchTerm);
|
|
module.hideMenu();
|
|
}
|
|
}
|
|
else {
|
|
module.remove.empty();
|
|
module.remove.message();
|
|
}
|
|
if(settings.allowAdditions) {
|
|
module.add.userSuggestion(module.escape.htmlEntities(query));
|
|
}
|
|
if(module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() ) {
|
|
module.show();
|
|
}
|
|
}
|
|
;
|
|
if(settings.useLabels && module.has.maxSelections()) {
|
|
return;
|
|
}
|
|
if(settings.apiSettings) {
|
|
if( module.can.useAPI() ) {
|
|
module.queryRemote(searchTerm, function() {
|
|
if(settings.filterRemoteData) {
|
|
module.filterItems(searchTerm);
|
|
}
|
|
var preSelected = $input.val();
|
|
if(!Array.isArray(preSelected)) {
|
|
preSelected = preSelected && preSelected!=="" ? preSelected.split(settings.delimiter) : [];
|
|
}
|
|
if (module.is.multiple()) {
|
|
$.each(preSelected,function(index,value){
|
|
$item.filter('[data-value="'+value+'"]')
|
|
.addClass(className.filtered)
|
|
;
|
|
});
|
|
}
|
|
module.focusSearch(true);
|
|
afterFiltered();
|
|
});
|
|
}
|
|
else {
|
|
module.error(error.noAPI);
|
|
}
|
|
}
|
|
else {
|
|
module.filterItems(searchTerm);
|
|
afterFiltered();
|
|
}
|
|
},
|
|
|
|
queryRemote: function(query, callback, callbackParameters) {
|
|
if(!Array.isArray(callbackParameters)){
|
|
callbackParameters = [callbackParameters];
|
|
}
|
|
var
|
|
apiSettings = {
|
|
errorDuration : false,
|
|
cache : 'local',
|
|
throttle : settings.throttle,
|
|
urlData : {
|
|
query: query
|
|
},
|
|
onError: function() {
|
|
module.add.message(message.serverError);
|
|
iconClicked = false;
|
|
focused = false;
|
|
callback.apply(null, callbackParameters);
|
|
},
|
|
onFailure: function() {
|
|
module.add.message(message.serverError);
|
|
iconClicked = false;
|
|
focused = false;
|
|
callback.apply(null, callbackParameters);
|
|
},
|
|
onSuccess : function(response) {
|
|
var
|
|
values = response[fields.remoteValues]
|
|
;
|
|
if (!Array.isArray(values)){
|
|
values = [];
|
|
}
|
|
module.remove.message();
|
|
var menuConfig = {};
|
|
menuConfig[fields.values] = values;
|
|
module.setup.menu(menuConfig);
|
|
|
|
if(values.length===0 && !settings.allowAdditions) {
|
|
module.add.message(message.noResults);
|
|
}
|
|
else {
|
|
var value = module.is.multiple() ? module.get.values() : module.get.value();
|
|
if (value !== '') {
|
|
module.verbose('Value(s) present after click icon, select value(s) in items');
|
|
module.set.selected(value, null, null, true);
|
|
}
|
|
}
|
|
iconClicked = false;
|
|
focused = false;
|
|
callback.apply(null, callbackParameters);
|
|
}
|
|
}
|
|
;
|
|
if( !$module.api('get request') ) {
|
|
module.setup.api();
|
|
}
|
|
apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings);
|
|
$module
|
|
.api('setting', apiSettings)
|
|
.api('query')
|
|
;
|
|
},
|
|
|
|
filterItems: function(query) {
|
|
var
|
|
searchTerm = module.remove.diacritics(query !== undefined
|
|
? query
|
|
: module.get.query()
|
|
),
|
|
results = null,
|
|
escapedTerm = module.escape.string(searchTerm),
|
|
regExpFlags = (settings.ignoreSearchCase ? 'i' : '') + 'gm',
|
|
beginsWithRegExp = new RegExp('^' + escapedTerm, regExpFlags)
|
|
;
|
|
// avoid loop if we're matching nothing
|
|
if( module.has.query() ) {
|
|
results = [];
|
|
|
|
module.verbose('Searching for matching values', searchTerm);
|
|
$item
|
|
.each(function(){
|
|
var
|
|
$choice = $(this),
|
|
text,
|
|
value
|
|
;
|
|
if($choice.hasClass(className.unfilterable)) {
|
|
results.push(this);
|
|
return true;
|
|
}
|
|
if(settings.match === 'both' || settings.match === 'text') {
|
|
text = module.remove.diacritics(String(module.get.choiceText($choice, false)));
|
|
if(text.search(beginsWithRegExp) !== -1) {
|
|
results.push(this);
|
|
return true;
|
|
}
|
|
else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
|
|
results.push(this);
|
|
return true;
|
|
}
|
|
else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
|
|
results.push(this);
|
|
return true;
|
|
}
|
|
}
|
|
if(settings.match === 'both' || settings.match === 'value') {
|
|
value = module.remove.diacritics(String(module.get.choiceValue($choice, text)));
|
|
if(value.search(beginsWithRegExp) !== -1) {
|
|
results.push(this);
|
|
return true;
|
|
}
|
|
else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value)) {
|
|
results.push(this);
|
|
return true;
|
|
}
|
|
else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value)) {
|
|
results.push(this);
|
|
return true;
|
|
}
|
|
}
|
|
})
|
|
;
|
|
}
|
|
module.debug('Showing only matched items', searchTerm);
|
|
module.remove.filteredItem();
|
|
if(results) {
|
|
$item
|
|
.not(results)
|
|
.addClass(className.filtered)
|
|
;
|
|
}
|
|
|
|
if(!module.has.query()) {
|
|
$divider
|
|
.removeClass(className.hidden);
|
|
} else if(settings.hideDividers === true) {
|
|
$divider
|
|
.addClass(className.hidden);
|
|
} else if(settings.hideDividers === 'empty') {
|
|
$divider
|
|
.removeClass(className.hidden)
|
|
.filter(function() {
|
|
// First find the last divider in this divider group
|
|
// Dividers which are direct siblings are considered a group
|
|
var lastDivider = $(this).nextUntil(selector.item);
|
|
|
|
return (lastDivider.length ? lastDivider : $(this))
|
|
// Count all non-filtered items until the next divider (or end of the dropdown)
|
|
.nextUntil(selector.divider)
|
|
.filter(selector.item + ":not(." + className.filtered + ")")
|
|
// Hide divider if no items are found
|
|
.length === 0;
|
|
})
|
|
.addClass(className.hidden);
|
|
}
|
|
},
|
|
|
|
fuzzySearch: function(query, term) {
|
|
var
|
|
termLength = term.length,
|
|
queryLength = query.length
|
|
;
|
|
query = (settings.ignoreSearchCase ? query.toLowerCase() : query);
|
|
term = (settings.ignoreSearchCase ? term.toLowerCase() : term);
|
|
if(queryLength > termLength) {
|
|
return false;
|
|
}
|
|
if(queryLength === termLength) {
|
|
return (query === term);
|
|
}
|
|
search: for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
|
|
var
|
|
queryCharacter = query.charCodeAt(characterIndex)
|
|
;
|
|
while(nextCharacterIndex < termLength) {
|
|
if(term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
|
|
continue search;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
exactSearch: function (query, term) {
|
|
query = (settings.ignoreSearchCase ? query.toLowerCase() : query);
|
|
term = (settings.ignoreSearchCase ? term.toLowerCase() : term);
|
|
return term.indexOf(query) > -1;
|
|
|
|
},
|
|
filterActive: function() {
|
|
if(settings.useLabels) {
|
|
$item.filter('.' + className.active)
|
|
.addClass(className.filtered)
|
|
;
|
|
}
|
|
},
|
|
|
|
focusSearch: function(skipHandler) {
|
|
if( module.has.search() && !module.is.focusedOnSearch() ) {
|
|
if(skipHandler) {
|
|
$module.off('focus' + eventNamespace, selector.search);
|
|
$search.focus();
|
|
$module.on('focus' + eventNamespace, selector.search, module.event.search.focus);
|
|
}
|
|
else {
|
|
$search.focus();
|
|
}
|
|
}
|
|
},
|
|
|
|
blurSearch: function() {
|
|
if( module.has.search() ) {
|
|
$search.blur();
|
|
}
|
|
},
|
|
|
|
forceSelection: function() {
|
|
var
|
|
$currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
|
|
$activeItem = $item.not(className.filtered).filter('.' + className.active).eq(0),
|
|
$selectedItem = ($currentlySelected.length > 0)
|
|
? $currentlySelected
|
|
: $activeItem,
|
|
hasSelected = ($selectedItem.length > 0)
|
|
;
|
|
if(settings.allowAdditions || (hasSelected && !module.is.multiple())) {
|
|
module.debug('Forcing partial selection to selected item', $selectedItem);
|
|
module.event.item.click.call($selectedItem, {}, true);
|
|
}
|
|
else {
|
|
module.remove.searchTerm();
|
|
}
|
|
},
|
|
|
|
change: {
|
|
values: function(values) {
|
|
if(!settings.allowAdditions) {
|
|
module.clear();
|
|
}
|
|
module.debug('Creating dropdown with specified values', values);
|
|
var menuConfig = {};
|
|
menuConfig[fields.values] = values;
|
|
module.setup.menu(menuConfig);
|
|
$.each(values, function(index, item) {
|
|
if(item.selected == true) {
|
|
module.debug('Setting initial selection to', item[fields.value]);
|
|
module.set.selected(item[fields.value]);
|
|
if(!module.is.multiple()) {
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
|
|
if(module.has.selectInput()) {
|
|
module.disconnect.selectObserver();
|
|
$input.html('');
|
|
$input.append('<option disabled selected value></option>');
|
|
$.each(values, function(index, item) {
|
|
var
|
|
value = settings.templates.deQuote(item[fields.value]),
|
|
name = settings.templates.escape(
|
|
item[fields.name] || '',
|
|
settings.preserveHTML
|
|
)
|
|
;
|
|
$input.append('<option value="' + value + '">' + name + '</option>');
|
|
});
|
|
module.observe.select();
|
|
}
|
|
}
|
|
},
|
|
|
|
event: {
|
|
change: function() {
|
|
if(!internalChange) {
|
|
module.debug('Input changed, updating selection');
|
|
module.set.selected();
|
|
}
|
|
},
|
|
focus: function() {
|
|
if(settings.showOnFocus && !activated && module.is.hidden() && !pageLostFocus) {
|
|
focused = true;
|
|
module.show();
|
|
}
|
|
},
|
|
blur: function(event) {
|
|
pageLostFocus = (document.activeElement === this);
|
|
if(!activated && !pageLostFocus) {
|
|
module.remove.activeLabel();
|
|
module.hide();
|
|
}
|
|
},
|
|
mousedown: function() {
|
|
if(module.is.searchSelection()) {
|
|
// prevent menu hiding on immediate re-focus
|
|
willRefocus = true;
|
|
}
|
|
else {
|
|
// prevents focus callback from occurring on mousedown
|
|
activated = true;
|
|
}
|
|
},
|
|
mouseup: function() {
|
|
if(module.is.searchSelection()) {
|
|
// prevent menu hiding on immediate re-focus
|
|
willRefocus = false;
|
|
}
|
|
else {
|
|
activated = false;
|
|
}
|
|
},
|
|
click: function(event) {
|
|
var
|
|
$target = $(event.target)
|
|
;
|
|
// focus search
|
|
if($target.is($module)) {
|
|
if(!module.is.focusedOnSearch()) {
|
|
module.focusSearch();
|
|
}
|
|
else {
|
|
module.show();
|
|
}
|
|
}
|
|
},
|
|
search: {
|
|
focus: function(event) {
|
|
activated = true;
|
|
if(module.is.multiple()) {
|
|
module.remove.activeLabel();
|
|
}
|
|
if(!focused && !module.is.active() && (settings.showOnFocus || (event.type !== 'focus' && event.type !== 'focusin'))) {
|
|
focused = true;
|
|
module.search();
|
|
}
|
|
},
|
|
blur: function(event) {
|
|
pageLostFocus = (document.activeElement === this);
|
|
if(module.is.searchSelection() && !willRefocus) {
|
|
if(!itemActivated && !pageLostFocus) {
|
|
if(settings.forceSelection) {
|
|
module.forceSelection();
|
|
} else if(!settings.allowAdditions){
|
|
module.remove.searchTerm();
|
|
}
|
|
module.hide();
|
|
}
|
|
}
|
|
willRefocus = false;
|
|
}
|
|
},
|
|
clearIcon: {
|
|
click: function(event) {
|
|
module.clear();
|
|
if(module.is.searchSelection()) {
|
|
module.remove.searchTerm();
|
|
}
|
|
module.hide();
|
|
event.stopPropagation();
|
|
}
|
|
},
|
|
icon: {
|
|
click: function(event) {
|
|
iconClicked=true;
|
|
if(module.has.search()) {
|
|
if(!module.is.active()) {
|
|
if(settings.showOnFocus){
|
|
module.focusSearch();
|
|
} else {
|
|
module.toggle();
|
|
}
|
|
} else {
|
|
module.blurSearch();
|
|
}
|
|
} else {
|
|
module.toggle();
|
|
}
|
|
event.stopPropagation();
|
|
}
|
|
},
|
|
text: {
|
|
focus: function(event) {
|
|
activated = true;
|
|
module.focusSearch();
|
|
}
|
|
},
|
|
input: function(event) {
|
|
if(module.is.multiple() || module.is.searchSelection()) {
|
|
module.set.filtered();
|
|
}
|
|
clearTimeout(module.timer);
|
|
module.timer = setTimeout(module.search, settings.delay.search);
|
|
},
|
|
label: {
|
|
click: function(event) {
|
|
var
|
|
$label = $(this),
|
|
$labels = $module.find(selector.label),
|
|
$activeLabels = $labels.filter('.' + className.active),
|
|
$nextActive = $label.nextAll('.' + className.active),
|
|
$prevActive = $label.prevAll('.' + className.active),
|
|
$range = ($nextActive.length > 0)
|
|
? $label.nextUntil($nextActive).add($activeLabels).add($label)
|
|
: $label.prevUntil($prevActive).add($activeLabels).add($label)
|
|
;
|
|
if(event.shiftKey) {
|
|
$activeLabels.removeClass(className.active);
|
|
$range.addClass(className.active);
|
|
}
|
|
else if(event.ctrlKey) {
|
|
$label.toggleClass(className.active);
|
|
}
|
|
else {
|
|
$activeLabels.removeClass(className.active);
|
|
$label.addClass(className.active);
|
|
}
|
|
settings.onLabelSelect.apply(this, $labels.filter('.' + className.active));
|
|
event.stopPropagation();
|
|
}
|
|
},
|
|
remove: {
|
|
click: function(event) {
|
|
var
|
|
$label = $(this).parent()
|
|
;
|
|
if( $label.hasClass(className.active) ) {
|
|
// remove all selected labels
|
|
module.remove.activeLabels();
|
|
}
|
|
else {
|
|
// remove this label only
|
|
module.remove.activeLabels( $label );
|
|
}
|
|
event.stopPropagation();
|
|
}
|
|
},
|
|
test: {
|
|
toggle: function(event) {
|
|
var
|
|
toggleBehavior = (module.is.multiple())
|
|
? module.show
|
|
: module.toggle
|
|
;
|
|
if(module.is.bubbledLabelClick(event) || module.is.bubbledIconClick(event)) {
|
|
return;
|
|
}
|
|
if (!module.is.multiple() || (module.is.multiple() && !module.is.active())) {
|
|
focused = true;
|
|
}
|
|
if( module.determine.eventOnElement(event, toggleBehavior) ) {
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
touch: function(event) {
|
|
module.determine.eventOnElement(event, function() {
|
|
if(event.type == 'touchstart') {
|
|
module.timer = setTimeout(function() {
|
|
module.hide();
|
|
}, settings.delay.touch);
|
|
}
|
|
else if(event.type == 'touchmove') {
|
|
clearTimeout(module.timer);
|
|
}
|
|
});
|
|
event.stopPropagation();
|
|
},
|
|
hide: function(event) {
|
|
if(module.determine.eventInModule(event, module.hide)){
|
|
if(element.id && $(event.target).attr('for') === element.id){
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
class: {
|
|
mutation: function(mutations) {
|
|
mutations.forEach(function(mutation) {
|
|
if(mutation.attributeName === "class") {
|
|
module.check.disabled();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
select: {
|
|
mutation: function(mutations) {
|
|
module.debug('<select> modified, recreating menu');
|
|
if(module.is.selectMutation(mutations)) {
|
|
module.disconnect.selectObserver();
|
|
module.refresh();
|
|
module.setup.select();
|
|
module.set.selected();
|
|
module.observe.select();
|
|
}
|
|
}
|
|
},
|
|
menu: {
|
|
mutation: function(mutations) {
|
|
var
|
|
mutation = mutations[0],
|
|
$addedNode = mutation.addedNodes
|
|
? $(mutation.addedNodes[0])
|
|
: $(false),
|
|
$removedNode = mutation.removedNodes
|
|
? $(mutation.removedNodes[0])
|
|
: $(false),
|
|
$changedNodes = $addedNode.add($removedNode),
|
|
isUserAddition = $changedNodes.is(selector.addition) || $changedNodes.closest(selector.addition).length > 0,
|
|
isMessage = $changedNodes.is(selector.message) || $changedNodes.closest(selector.message).length > 0
|
|
;
|
|
if(isUserAddition || isMessage) {
|
|
module.debug('Updating item selector cache');
|
|
module.refreshItems();
|
|
}
|
|
else {
|
|
module.debug('Menu modified, updating selector cache');
|
|
module.refresh();
|
|
}
|
|
},
|
|
mousedown: function() {
|
|
itemActivated = true;
|
|
},
|
|
mouseup: function() {
|
|
itemActivated = false;
|
|
}
|
|
},
|
|
item: {
|
|
mouseenter: function(event) {
|
|
var
|
|
$target = $(event.target),
|
|
$item = $(this),
|
|
$subMenu = $item.children(selector.menu),
|
|
$otherMenus = $item.siblings(selector.item).children(selector.menu),
|
|
hasSubMenu = ($subMenu.length > 0),
|
|
isBubbledEvent = ($subMenu.find($target).length > 0)
|
|
;
|
|
if( !isBubbledEvent && hasSubMenu ) {
|
|
clearTimeout(module.itemTimer);
|
|
module.itemTimer = setTimeout(function() {
|
|
module.verbose('Showing sub-menu', $subMenu);
|
|
$.each($otherMenus, function() {
|
|
module.animate.hide(false, $(this));
|
|
});
|
|
module.animate.show(false, $subMenu);
|
|
}, settings.delay.show);
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
mouseleave: function(event) {
|
|
var
|
|
$subMenu = $(this).children(selector.menu)
|
|
;
|
|
if($subMenu.length > 0) {
|
|
clearTimeout(module.itemTimer);
|
|
module.itemTimer = setTimeout(function() {
|
|
module.verbose('Hiding sub-menu', $subMenu);
|
|
module.animate.hide(false, $subMenu);
|
|
}, settings.delay.hide);
|
|
}
|
|
},
|
|
click: function (event, skipRefocus) {
|
|
var
|
|
$choice = $(this),
|
|
$target = (event)
|
|
? $(event.target)
|
|
: $(''),
|
|
$subMenu = $choice.find(selector.menu),
|
|
text = module.get.choiceText($choice),
|
|
value = module.get.choiceValue($choice, text),
|
|
hasSubMenu = ($subMenu.length > 0),
|
|
isBubbledEvent = ($subMenu.find($target).length > 0)
|
|
;
|
|
// prevents IE11 bug where menu receives focus even though `tabindex=-1`
|
|
if (document.activeElement.tagName.toLowerCase() !== 'input') {
|
|
$(document.activeElement).blur();
|
|
}
|
|
if(!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
|
|
if(module.is.searchSelection()) {
|
|
if(settings.allowAdditions) {
|
|
module.remove.userAddition();
|
|
}
|
|
module.remove.searchTerm();
|
|
if(!module.is.focusedOnSearch() && !(skipRefocus == true)) {
|
|
module.focusSearch(true);
|
|
}
|
|
}
|
|
if(!settings.useLabels) {
|
|
module.remove.filteredItem();
|
|
module.set.scrollPosition($choice);
|
|
}
|
|
module.determine.selectAction.call(this, text, value);
|
|
}
|
|
}
|
|
},
|
|
|
|
document: {
|
|
// label selection should occur even when element has no focus
|
|
keydown: function(event) {
|
|
var
|
|
pressedKey = event.which,
|
|
isShortcutKey = module.is.inObject(pressedKey, keys)
|
|
;
|
|
if(isShortcutKey) {
|
|
var
|
|
$label = $module.find(selector.label),
|
|
$activeLabel = $label.filter('.' + className.active),
|
|
activeValue = $activeLabel.data(metadata.value),
|
|
labelIndex = $label.index($activeLabel),
|
|
labelCount = $label.length,
|
|
hasActiveLabel = ($activeLabel.length > 0),
|
|
hasMultipleActive = ($activeLabel.length > 1),
|
|
isFirstLabel = (labelIndex === 0),
|
|
isLastLabel = (labelIndex + 1 == labelCount),
|
|
isSearch = module.is.searchSelection(),
|
|
isFocusedOnSearch = module.is.focusedOnSearch(),
|
|
isFocused = module.is.focused(),
|
|
caretAtStart = (isFocusedOnSearch && module.get.caretPosition(false) === 0),
|
|
isSelectedSearch = (caretAtStart && module.get.caretPosition(true) !== 0),
|
|
$nextLabel
|
|
;
|
|
if(isSearch && !hasActiveLabel && !isFocusedOnSearch) {
|
|
return;
|
|
}
|
|
|
|
if(pressedKey == keys.leftArrow) {
|
|
// activate previous label
|
|
if((isFocused || caretAtStart) && !hasActiveLabel) {
|
|
module.verbose('Selecting previous label');
|
|
$label.last().addClass(className.active);
|
|
}
|
|
else if(hasActiveLabel) {
|
|
if(!event.shiftKey) {
|
|
module.verbose('Selecting previous label');
|
|
$label.removeClass(className.active);
|
|
}
|
|
else {
|
|
module.verbose('Adding previous label to selection');
|
|
}
|
|
if(isFirstLabel && !hasMultipleActive) {
|
|
$activeLabel.addClass(className.active);
|
|
}
|
|
else {
|
|
$activeLabel.prev(selector.siblingLabel)
|
|
.addClass(className.active)
|
|
.end()
|
|
;
|
|
}
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
else if(pressedKey == keys.rightArrow) {
|
|
// activate first label
|
|
if(isFocused && !hasActiveLabel) {
|
|
$label.first().addClass(className.active);
|
|
}
|
|
// activate next label
|
|
if(hasActiveLabel) {
|
|
if(!event.shiftKey) {
|
|
module.verbose('Selecting next label');
|
|
$label.removeClass(className.active);
|
|
}
|
|
else {
|
|
module.verbose('Adding next label to selection');
|
|
}
|
|
if(isLastLabel) {
|
|
if(isSearch) {
|
|
if(!isFocusedOnSearch) {
|
|
module.focusSearch();
|
|
}
|
|
else {
|
|
$label.removeClass(className.active);
|
|
}
|
|
}
|
|
else if(hasMultipleActive) {
|
|
$activeLabel.next(selector.siblingLabel).addClass(className.active);
|
|
}
|
|
else {
|
|
$activeLabel.addClass(className.active);
|
|
}
|
|
}
|
|
else {
|
|
$activeLabel.next(selector.siblingLabel).addClass(className.active);
|
|
}
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
else if(pressedKey == keys.deleteKey || pressedKey == keys.backspace) {
|
|
if(hasActiveLabel) {
|
|
module.verbose('Removing active labels');
|
|
if(isLastLabel) {
|
|
if(isSearch && !isFocusedOnSearch) {
|
|
module.focusSearch();
|
|
}
|
|
}
|
|
$activeLabel.last().next(selector.siblingLabel).addClass(className.active);
|
|
module.remove.activeLabels($activeLabel);
|
|
event.preventDefault();
|
|
}
|
|
else if(caretAtStart && !isSelectedSearch && !hasActiveLabel && pressedKey == keys.backspace) {
|
|
module.verbose('Removing last label on input backspace');
|
|
$activeLabel = $label.last().addClass(className.active);
|
|
module.remove.activeLabels($activeLabel);
|
|
}
|
|
}
|
|
else {
|
|
$activeLabel.removeClass(className.active);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
keydown: function(event) {
|
|
var
|
|
pressedKey = event.which,
|
|
isShortcutKey = module.is.inObject(pressedKey, keys)
|
|
;
|
|
if(isShortcutKey) {
|
|
var
|
|
$currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
|
|
$activeItem = $menu.children('.' + className.active).eq(0),
|
|
$selectedItem = ($currentlySelected.length > 0)
|
|
? $currentlySelected
|
|
: $activeItem,
|
|
$visibleItems = ($selectedItem.length > 0)
|
|
? $selectedItem.siblings(':not(.' + className.filtered +')').addBack()
|
|
: $menu.children(':not(.' + className.filtered +')'),
|
|
$subMenu = $selectedItem.children(selector.menu),
|
|
$parentMenu = $selectedItem.closest(selector.menu),
|
|
inVisibleMenu = ($parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0),
|
|
hasSubMenu = ($subMenu.length> 0),
|
|
hasSelectedItem = ($selectedItem.length > 0),
|
|
selectedIsSelectable = ($selectedItem.not(selector.unselectable).length > 0),
|
|
delimiterPressed = (pressedKey == keys.delimiter && settings.allowAdditions && module.is.multiple()),
|
|
isAdditionWithoutMenu = (settings.allowAdditions && settings.hideAdditions && (pressedKey == keys.enter || delimiterPressed) && selectedIsSelectable),
|
|
$nextItem,
|
|
isSubMenuItem,
|
|
newIndex
|
|
;
|
|
// allow selection with menu closed
|
|
if(isAdditionWithoutMenu) {
|
|
module.verbose('Selecting item from keyboard shortcut', $selectedItem);
|
|
module.event.item.click.call($selectedItem, event);
|
|
if(module.is.searchSelection()) {
|
|
module.remove.searchTerm();
|
|
}
|
|
if(module.is.multiple()){
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
|
|
// visible menu keyboard shortcuts
|
|
if( module.is.visible() ) {
|
|
|
|
// enter (select or open sub-menu)
|
|
if(pressedKey == keys.enter || delimiterPressed) {
|
|
if(pressedKey == keys.enter && hasSelectedItem && hasSubMenu && !settings.allowCategorySelection) {
|
|
module.verbose('Pressed enter on unselectable category, opening sub menu');
|
|
pressedKey = keys.rightArrow;
|
|
}
|
|
else if(selectedIsSelectable) {
|
|
module.verbose('Selecting item from keyboard shortcut', $selectedItem);
|
|
module.event.item.click.call($selectedItem, event);
|
|
if(module.is.searchSelection()) {
|
|
module.remove.searchTerm();
|
|
if(module.is.multiple()) {
|
|
$search.focus();
|
|
}
|
|
}
|
|
}
|
|
event.preventDefault();
|
|
}
|
|
|
|
// sub-menu actions
|
|
if(hasSelectedItem) {
|
|
|
|
if(pressedKey == keys.leftArrow) {
|
|
|
|
isSubMenuItem = ($parentMenu[0] !== $menu[0]);
|
|
|
|
if(isSubMenuItem) {
|
|
module.verbose('Left key pressed, closing sub-menu');
|
|
module.animate.hide(false, $parentMenu);
|
|
$selectedItem
|
|
.removeClass(className.selected)
|
|
;
|
|
$parentMenu
|
|
.closest(selector.item)
|
|
.addClass(className.selected)
|
|
;
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
|
|
// right arrow (show sub-menu)
|
|
if(pressedKey == keys.rightArrow) {
|
|
if(hasSubMenu) {
|
|
module.verbose('Right key pressed, opening sub-menu');
|
|
module.animate.show(false, $subMenu);
|
|
$selectedItem
|
|
.removeClass(className.selected)
|
|
;
|
|
$subMenu
|
|
.find(selector.item).eq(0)
|
|
.addClass(className.selected)
|
|
;
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
|
|
// up arrow (traverse menu up)
|
|
if(pressedKey == keys.upArrow) {
|
|
$nextItem = (hasSelectedItem && inVisibleMenu)
|
|
? $selectedItem.prevAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
|
|
: $item.eq(0)
|
|
;
|
|
if($visibleItems.index( $nextItem ) < 0) {
|
|
module.verbose('Up key pressed but reached top of current menu');
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
else {
|
|
module.verbose('Up key pressed, changing active item');
|
|
$selectedItem
|
|
.removeClass(className.selected)
|
|
;
|
|
$nextItem
|
|
.addClass(className.selected)
|
|
;
|
|
module.set.scrollPosition($nextItem);
|
|
if(settings.selectOnKeydown && module.is.single()) {
|
|
module.set.selectedItem($nextItem);
|
|
}
|
|
}
|
|
event.preventDefault();
|
|
}
|
|
|
|
// down arrow (traverse menu down)
|
|
if(pressedKey == keys.downArrow) {
|
|
$nextItem = (hasSelectedItem && inVisibleMenu)
|
|
? $nextItem = $selectedItem.nextAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
|
|
: $item.eq(0)
|
|
;
|
|
if($nextItem.length === 0) {
|
|
module.verbose('Down key pressed but reached bottom of current menu');
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
else {
|
|
module.verbose('Down key pressed, changing active item');
|
|
$item
|
|
.removeClass(className.selected)
|
|
;
|
|
$nextItem
|
|
.addClass(className.selected)
|
|
;
|
|
module.set.scrollPosition($nextItem);
|
|
if(settings.selectOnKeydown && module.is.single()) {
|
|
module.set.selectedItem($nextItem);
|
|
}
|
|
}
|
|
event.preventDefault();
|
|
}
|
|
|
|
// page down (show next page)
|
|
if(pressedKey == keys.pageUp) {
|
|
module.scrollPage('up');
|
|
event.preventDefault();
|
|
}
|
|
if(pressedKey == keys.pageDown) {
|
|
module.scrollPage('down');
|
|
event.preventDefault();
|
|
}
|
|
|
|
// escape (close menu)
|
|
if(pressedKey == keys.escape) {
|
|
module.verbose('Escape key pressed, closing dropdown');
|
|
module.hide();
|
|
}
|
|
|
|
}
|
|
else {
|
|
// delimiter key
|
|
if(delimiterPressed) {
|
|
event.preventDefault();
|
|
}
|
|
// down arrow (open menu)
|
|
if(pressedKey == keys.downArrow && !module.is.visible()) {
|
|
module.verbose('Down key pressed, showing dropdown');
|
|
module.show();
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if( !module.has.search() ) {
|
|
module.set.selectedLetter( String.fromCharCode(pressedKey) );
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
trigger: {
|
|
change: function() {
|
|
var
|
|
inputElement = $input[0]
|
|
;
|
|
if(inputElement) {
|
|
var events = document.createEvent('HTMLEvents');
|
|
module.verbose('Triggering native change event');
|
|
events.initEvent('change', true, false);
|
|
inputElement.dispatchEvent(events);
|
|
}
|
|
}
|
|
},
|
|
|
|
determine: {
|
|
selectAction: function(text, value) {
|
|
selectActionActive = true;
|
|
module.verbose('Determining action', settings.action);
|
|
if( $.isFunction( module.action[settings.action] ) ) {
|
|
module.verbose('Triggering preset action', settings.action, text, value);
|
|
module.action[ settings.action ].call(element, text, value, this);
|
|
}
|
|
else if( $.isFunction(settings.action) ) {
|
|
module.verbose('Triggering user action', settings.action, text, value);
|
|
settings.action.call(element, text, value, this);
|
|
}
|
|
else {
|
|
module.error(error.action, settings.action);
|
|
}
|
|
selectActionActive = false;
|
|
},
|
|
eventInModule: function(event, callback) {
|
|
var
|
|
$target = $(event.target),
|
|
inDocument = ($target.closest(document.documentElement).length > 0),
|
|
inModule = ($target.closest($module).length > 0)
|
|
;
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if(inDocument && !inModule) {
|
|
module.verbose('Triggering event', callback);
|
|
callback();
|
|
return true;
|
|
}
|
|
else {
|
|
module.verbose('Event occurred in dropdown, canceling callback');
|
|
return false;
|
|
}
|
|
},
|
|
eventOnElement: function(event, callback) {
|
|
var
|
|
$target = $(event.target),
|
|
$label = $target.closest(selector.siblingLabel),
|
|
inVisibleDOM = document.body.contains(event.target),
|
|
notOnLabel = ($module.find($label).length === 0 || !(module.is.multiple() && settings.useLabels)),
|
|
notInMenu = ($target.closest($menu).length === 0)
|
|
;
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if(inVisibleDOM && notOnLabel && notInMenu) {
|
|
module.verbose('Triggering event', callback);
|
|
callback();
|
|
return true;
|
|
}
|
|
else {
|
|
module.verbose('Event occurred in dropdown menu, canceling callback');
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
|
|
action: {
|
|
|
|
nothing: function() {},
|
|
|
|
activate: function(text, value, element) {
|
|
value = (value !== undefined)
|
|
? value
|
|
: text
|
|
;
|
|
if( module.can.activate( $(element) ) ) {
|
|
module.set.selected(value, $(element));
|
|
if(!module.is.multiple()) {
|
|
module.hideAndClear();
|
|
}
|
|
}
|
|
},
|
|
|
|
select: function(text, value, element) {
|
|
value = (value !== undefined)
|
|
? value
|
|
: text
|
|
;
|
|
if( module.can.activate( $(element) ) ) {
|
|
module.set.value(value, text, $(element));
|
|
if(!module.is.multiple()) {
|
|
module.hideAndClear();
|
|
}
|
|
}
|
|
},
|
|
|
|
combo: function(text, value, element) {
|
|
value = (value !== undefined)
|
|
? value
|
|
: text
|
|
;
|
|
module.set.selected(value, $(element));
|
|
module.hideAndClear();
|
|
},
|
|
|
|
hide: function(text, value, element) {
|
|
module.set.value(value, text, $(element));
|
|
module.hideAndClear();
|
|
}
|
|
|
|
},
|
|
|
|
get: {
|
|
id: function() {
|
|
return id;
|
|
},
|
|
defaultText: function() {
|
|
return $module.data(metadata.defaultText);
|
|
},
|
|
defaultValue: function() {
|
|
return $module.data(metadata.defaultValue);
|
|
},
|
|
placeholderText: function() {
|
|
if(settings.placeholder != 'auto' && typeof settings.placeholder == 'string') {
|
|
return settings.placeholder;
|
|
}
|
|
return $module.data(metadata.placeholderText) || '';
|
|
},
|
|
text: function() {
|
|
return settings.preserveHTML ? $text.html() : $text.text();
|
|
},
|
|
query: function() {
|
|
return String($search.val()).trim();
|
|
},
|
|
searchWidth: function(value) {
|
|
value = (value !== undefined)
|
|
? value
|
|
: $search.val()
|
|
;
|
|
$sizer.text(value);
|
|
// prevent rounding issues
|
|
return Math.ceil( $sizer.width() + 1);
|
|
},
|
|
selectionCount: function() {
|
|
var
|
|
values = module.get.values(),
|
|
count
|
|
;
|
|
count = ( module.is.multiple() )
|
|
? Array.isArray(values)
|
|
? values.length
|
|
: 0
|
|
: (module.get.value() !== '')
|
|
? 1
|
|
: 0
|
|
;
|
|
return count;
|
|
},
|
|
transition: function($subMenu) {
|
|
return (settings.transition === 'auto')
|
|
? module.is.upward($subMenu)
|
|
? 'slide up'
|
|
: 'slide down'
|
|
: settings.transition
|
|
;
|
|
},
|
|
userValues: function() {
|
|
var
|
|
values = module.get.values()
|
|
;
|
|
if(!values) {
|
|
return false;
|
|
}
|
|
values = Array.isArray(values)
|
|
? values
|
|
: [values]
|
|
;
|
|
return $.grep(values, function(value) {
|
|
return (module.get.item(value) === false);
|
|
});
|
|
},
|
|
uniqueArray: function(array) {
|
|
return $.grep(array, function (value, index) {
|
|
return $.inArray(value, array) === index;
|
|
});
|
|
},
|
|
caretPosition: function(returnEndPos) {
|
|
var
|
|
input = $search.get(0),
|
|
range,
|
|
rangeLength
|
|
;
|
|
if(returnEndPos && 'selectionEnd' in input){
|
|
return input.selectionEnd;
|
|
}
|
|
else if(!returnEndPos && 'selectionStart' in input) {
|
|
return input.selectionStart;
|
|
}
|
|
if (document.selection) {
|
|
input.focus();
|
|
range = document.selection.createRange();
|
|
rangeLength = range.text.length;
|
|
if(returnEndPos) {
|
|
return rangeLength;
|
|
}
|
|
range.moveStart('character', -input.value.length);
|
|
return range.text.length - rangeLength;
|
|
}
|
|
},
|
|
value: function() {
|
|
var
|
|
value = ($input.length > 0)
|
|
? $input.val()
|
|
: $module.data(metadata.value),
|
|
isEmptyMultiselect = (Array.isArray(value) && value.length === 1 && value[0] === '')
|
|
;
|
|
// prevents placeholder element from being selected when multiple
|
|
return (value === undefined || isEmptyMultiselect)
|
|
? ''
|
|
: value
|
|
;
|
|
},
|
|
values: function(raw) {
|
|
var
|
|
value = module.get.value()
|
|
;
|
|
if(value === '') {
|
|
return '';
|
|
}
|
|
return ( !module.has.selectInput() && module.is.multiple() )
|
|
? (typeof value == 'string') // delimited string
|
|
? (raw ? value : module.escape.htmlEntities(value)).split(settings.delimiter)
|
|
: ''
|
|
: value
|
|
;
|
|
},
|
|
remoteValues: function() {
|
|
var
|
|
values = module.get.values(),
|
|
remoteValues = false
|
|
;
|
|
if(values) {
|
|
if(typeof values == 'string') {
|
|
values = [values];
|
|
}
|
|
$.each(values, function(index, value) {
|
|
var
|
|
name = module.read.remoteData(value)
|
|
;
|
|
module.verbose('Restoring value from session data', name, value);
|
|
if(name) {
|
|
if(!remoteValues) {
|
|
remoteValues = {};
|
|
}
|
|
remoteValues[value] = name;
|
|
}
|
|
});
|
|
}
|
|
return remoteValues;
|
|
},
|
|
choiceText: function($choice, preserveHTML) {
|
|
preserveHTML = (preserveHTML !== undefined)
|
|
? preserveHTML
|
|
: settings.preserveHTML
|
|
;
|
|
if($choice) {
|
|
if($choice.find(selector.menu).length > 0) {
|
|
module.verbose('Retrieving text of element with sub-menu');
|
|
$choice = $choice.clone();
|
|
$choice.find(selector.menu).remove();
|
|
$choice.find(selector.menuIcon).remove();
|
|
}
|
|
return ($choice.data(metadata.text) !== undefined)
|
|
? $choice.data(metadata.text)
|
|
: (preserveHTML)
|
|
? $choice.html() && $choice.html().trim()
|
|
: $choice.text() && $choice.text().trim()
|
|
;
|
|
}
|
|
},
|
|
choiceValue: function($choice, choiceText) {
|
|
choiceText = choiceText || module.get.choiceText($choice);
|
|
if(!$choice) {
|
|
return false;
|
|
}
|
|
return ($choice.data(metadata.value) !== undefined)
|
|
? String( $choice.data(metadata.value) )
|
|
: (typeof choiceText === 'string')
|
|
? String(
|
|
settings.ignoreSearchCase
|
|
? choiceText.toLowerCase()
|
|
: choiceText
|
|
).trim()
|
|
: String(choiceText)
|
|
;
|
|
},
|
|
inputEvent: function() {
|
|
var
|
|
input = $search[0]
|
|
;
|
|
if(input) {
|
|
return (input.oninput !== undefined)
|
|
? 'input'
|
|
: (input.onpropertychange !== undefined)
|
|
? 'propertychange'
|
|
: 'keyup'
|
|
;
|
|
}
|
|
return false;
|
|
},
|
|
selectValues: function() {
|
|
var
|
|
select = {},
|
|
oldGroup = [],
|
|
values = []
|
|
;
|
|
$module
|
|
.find('option')
|
|
.each(function() {
|
|
var
|
|
$option = $(this),
|
|
name = $option.html(),
|
|
disabled = $option.attr('disabled'),
|
|
value = ( $option.attr('value') !== undefined )
|
|
? $option.attr('value')
|
|
: name,
|
|
text = ( $option.data(metadata.text) !== undefined )
|
|
? $option.data(metadata.text)
|
|
: name,
|
|
group = $option.parent('optgroup')
|
|
;
|
|
if(settings.placeholder === 'auto' && value === '') {
|
|
select.placeholder = name;
|
|
}
|
|
else {
|
|
if(group.length !== oldGroup.length || group[0] !== oldGroup[0]) {
|
|
values.push({
|
|
type: 'header',
|
|
divider: settings.headerDivider,
|
|
name: group.attr('label') || ''
|
|
});
|
|
oldGroup = group;
|
|
}
|
|
values.push({
|
|
name : name,
|
|
value : value,
|
|
text : text,
|
|
disabled : disabled
|
|
});
|
|
}
|
|
})
|
|
;
|
|
if(settings.placeholder && settings.placeholder !== 'auto') {
|
|
module.debug('Setting placeholder value to', settings.placeholder);
|
|
select.placeholder = settings.placeholder;
|
|
}
|
|
if(settings.sortSelect) {
|
|
if(settings.sortSelect === true) {
|
|
values.sort(function(a, b) {
|
|
return a.name.localeCompare(b.name);
|
|
});
|
|
} else if(settings.sortSelect === 'natural') {
|
|
values.sort(function(a, b) {
|
|
return (a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
|
|
});
|
|
} else if($.isFunction(settings.sortSelect)) {
|
|
values.sort(settings.sortSelect);
|
|
}
|
|
select[fields.values] = values;
|
|
module.debug('Retrieved and sorted values from select', select);
|
|
}
|
|
else {
|
|
select[fields.values] = values;
|
|
module.debug('Retrieved values from select', select);
|
|
}
|
|
return select;
|
|
},
|
|
activeItem: function() {
|
|
return $item.filter('.' + className.active);
|
|
},
|
|
selectedItem: function() {
|
|
var
|
|
$selectedItem = $item.not(selector.unselectable).filter('.' + className.selected)
|
|
;
|
|
return ($selectedItem.length > 0)
|
|
? $selectedItem
|
|
: $item.eq(0)
|
|
;
|
|
},
|
|
itemWithAdditions: function(value) {
|
|
var
|
|
$items = module.get.item(value),
|
|
$userItems = module.create.userChoice(value),
|
|
hasUserItems = ($userItems && $userItems.length > 0)
|
|
;
|
|
if(hasUserItems) {
|
|
$items = ($items.length > 0)
|
|
? $items.add($userItems)
|
|
: $userItems
|
|
;
|
|
}
|
|
return $items;
|
|
},
|
|
item: function(value, strict) {
|
|
var
|
|
$selectedItem = false,
|
|
shouldSearch,
|
|
isMultiple
|
|
;
|
|
value = (value !== undefined)
|
|
? value
|
|
: ( module.get.values() !== undefined)
|
|
? module.get.values()
|
|
: module.get.text()
|
|
;
|
|
isMultiple = (module.is.multiple() && Array.isArray(value));
|
|
shouldSearch = (isMultiple)
|
|
? (value.length > 0)
|
|
: (value !== undefined && value !== null)
|
|
;
|
|
strict = (value === '' || value === false || value === true)
|
|
? true
|
|
: strict || false
|
|
;
|
|
if(shouldSearch) {
|
|
$item
|
|
.each(function() {
|
|
var
|
|
$choice = $(this),
|
|
optionText = module.get.choiceText($choice),
|
|
optionValue = module.get.choiceValue($choice, optionText)
|
|
;
|
|
// safe early exit
|
|
if(optionValue === null || optionValue === undefined) {
|
|
return;
|
|
}
|
|
if(isMultiple) {
|
|
if($.inArray(module.escape.htmlEntities(String(optionValue)), value.map(function(v){return String(v);})) !== -1) {
|
|
$selectedItem = ($selectedItem)
|
|
? $selectedItem.add($choice)
|
|
: $choice
|
|
;
|
|
}
|
|
}
|
|
else if(strict) {
|
|
module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
|
|
if( optionValue === value) {
|
|
$selectedItem = $choice;
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
if(settings.ignoreCase) {
|
|
optionValue = optionValue.toLowerCase();
|
|
value = value.toLowerCase();
|
|
}
|
|
if(module.escape.htmlEntities(String(optionValue)) === module.escape.htmlEntities(String(value))) {
|
|
module.verbose('Found select item by value', optionValue, value);
|
|
$selectedItem = $choice;
|
|
return true;
|
|
}
|
|
}
|
|
})
|
|
;
|
|
}
|
|
return $selectedItem;
|
|
},
|
|
displayType: function() {
|
|
return $module.hasClass('column') ? 'flex' : settings.displayType;
|
|
}
|
|
},
|
|
|
|
check: {
|
|
maxSelections: function(selectionCount) {
|
|
if(settings.maxSelections) {
|
|
selectionCount = (selectionCount !== undefined)
|
|
? selectionCount
|
|
: module.get.selectionCount()
|
|
;
|
|
if(selectionCount >= settings.maxSelections) {
|
|
module.debug('Maximum selection count reached');
|
|
if(settings.useLabels) {
|
|
$item.addClass(className.filtered);
|
|
module.add.message(message.maxSelections);
|
|
}
|
|
return true;
|
|
}
|
|
else {
|
|
module.verbose('No longer at maximum selection count');
|
|
module.remove.message();
|
|
module.remove.filteredItem();
|
|
if(module.is.searchSelection()) {
|
|
module.filterItems();
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
disabled: function(){
|
|
$search.attr('tabindex',module.is.disabled() ? -1 : 0);
|
|
}
|
|
},
|
|
|
|
restore: {
|
|
defaults: function(preventChangeTrigger) {
|
|
module.clear(preventChangeTrigger);
|
|
module.restore.defaultText();
|
|
module.restore.defaultValue();
|
|
},
|
|
defaultText: function() {
|
|
var
|
|
defaultText = module.get.defaultText(),
|
|
placeholderText = module.get.placeholderText
|
|
;
|
|
if(defaultText === placeholderText) {
|
|
module.debug('Restoring default placeholder text', defaultText);
|
|
module.set.placeholderText(defaultText);
|
|
}
|
|
else {
|
|
module.debug('Restoring default text', defaultText);
|
|
module.set.text(defaultText);
|
|
}
|
|
},
|
|
placeholderText: function() {
|
|
module.set.placeholderText();
|
|
},
|
|
defaultValue: function() {
|
|
var
|
|
defaultValue = module.get.defaultValue()
|
|
;
|
|
if(defaultValue !== undefined) {
|
|
module.debug('Restoring default value', defaultValue);
|
|
if(defaultValue !== '') {
|
|
module.set.value(defaultValue);
|
|
module.set.selected();
|
|
}
|
|
else {
|
|
module.remove.activeItem();
|
|
module.remove.selectedItem();
|
|
}
|
|
}
|
|
},
|
|
labels: function() {
|
|
if(settings.allowAdditions) {
|
|
if(!settings.useLabels) {
|
|
module.error(error.labels);
|
|
settings.useLabels = true;
|
|
}
|
|
module.debug('Restoring selected values');
|
|
module.create.userLabels();
|
|
}
|
|
module.check.maxSelections();
|
|
},
|
|
selected: function() {
|
|
module.restore.values();
|
|
if(module.is.multiple()) {
|
|
module.debug('Restoring previously selected values and labels');
|
|
module.restore.labels();
|
|
}
|
|
else {
|
|
module.debug('Restoring previously selected values');
|
|
}
|
|
},
|
|
values: function() {
|
|
// prevents callbacks from occurring on initial load
|
|
module.set.initialLoad();
|
|
if(settings.apiSettings && settings.saveRemoteData && module.get.remoteValues()) {
|
|
module.restore.remoteValues();
|
|
}
|
|
else {
|
|
module.set.selected();
|
|
}
|
|
var value = module.get.value();
|
|
if(value && value !== '' && !(Array.isArray(value) && value.length === 0)) {
|
|
$input.removeClass(className.noselection);
|
|
} else {
|
|
$input.addClass(className.noselection);
|
|
}
|
|
module.remove.initialLoad();
|
|
},
|
|
remoteValues: function() {
|
|
var
|
|
values = module.get.remoteValues()
|
|
;
|
|
module.debug('Recreating selected from session data', values);
|
|
if(values) {
|
|
if( module.is.single() ) {
|
|
$.each(values, function(value, name) {
|
|
module.set.text(name);
|
|
});
|
|
}
|
|
else {
|
|
$.each(values, function(value, name) {
|
|
module.add.label(value, name);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
read: {
|
|
remoteData: function(value) {
|
|
var
|
|
name
|
|
;
|
|
if(window.Storage === undefined) {
|
|
module.error(error.noStorage);
|
|
return;
|
|
}
|
|
name = sessionStorage.getItem(value);
|
|
return (name !== undefined)
|
|
? name
|
|
: false
|
|
;
|
|
}
|
|
},
|
|
|
|
save: {
|
|
defaults: function() {
|
|
module.save.defaultText();
|
|
module.save.placeholderText();
|
|
module.save.defaultValue();
|
|
},
|
|
defaultValue: function() {
|
|
var
|
|
value = module.get.value()
|
|
;
|
|
module.verbose('Saving default value as', value);
|
|
$module.data(metadata.defaultValue, value);
|
|
},
|
|
defaultText: function() {
|
|
var
|
|
text = module.get.text()
|
|
;
|
|
module.verbose('Saving default text as', text);
|
|
$module.data(metadata.defaultText, text);
|
|
},
|
|
placeholderText: function() {
|
|
var
|
|
text
|
|
;
|
|
if(settings.placeholder !== false && $text.hasClass(className.placeholder)) {
|
|
text = module.get.text();
|
|
module.verbose('Saving placeholder text as', text);
|
|
$module.data(metadata.placeholderText, text);
|
|
}
|
|
},
|
|
remoteData: function(name, value) {
|
|
if(window.Storage === undefined) {
|
|
module.error(error.noStorage);
|
|
return;
|
|
}
|
|
module.verbose('Saving remote data to session storage', value, name);
|
|
sessionStorage.setItem(value, name);
|
|
}
|
|
},
|
|
|
|
clear: function(preventChangeTrigger) {
|
|
if(module.is.multiple() && settings.useLabels) {
|
|
module.remove.labels($module.find(selector.label), preventChangeTrigger);
|
|
}
|
|
else {
|
|
module.remove.activeItem();
|
|
module.remove.selectedItem();
|
|
module.remove.filteredItem();
|
|
}
|
|
module.set.placeholderText();
|
|
module.clearValue(preventChangeTrigger);
|
|
},
|
|
|
|
clearValue: function(preventChangeTrigger) {
|
|
module.set.value('', null, null, preventChangeTrigger);
|
|
},
|
|
|
|
scrollPage: function(direction, $selectedItem) {
|
|
var
|
|
$currentItem = $selectedItem || module.get.selectedItem(),
|
|
$menu = $currentItem.closest(selector.menu),
|
|
menuHeight = $menu.outerHeight(),
|
|
currentScroll = $menu.scrollTop(),
|
|
itemHeight = $item.eq(0).outerHeight(),
|
|
itemsPerPage = Math.floor(menuHeight / itemHeight),
|
|
maxScroll = $menu.prop('scrollHeight'),
|
|
newScroll = (direction == 'up')
|
|
? currentScroll - (itemHeight * itemsPerPage)
|
|
: currentScroll + (itemHeight * itemsPerPage),
|
|
$selectableItem = $item.not(selector.unselectable),
|
|
isWithinRange,
|
|
$nextSelectedItem,
|
|
elementIndex
|
|
;
|
|
elementIndex = (direction == 'up')
|
|
? $selectableItem.index($currentItem) - itemsPerPage
|
|
: $selectableItem.index($currentItem) + itemsPerPage
|
|
;
|
|
isWithinRange = (direction == 'up')
|
|
? (elementIndex >= 0)
|
|
: (elementIndex < $selectableItem.length)
|
|
;
|
|
$nextSelectedItem = (isWithinRange)
|
|
? $selectableItem.eq(elementIndex)
|
|
: (direction == 'up')
|
|
? $selectableItem.first()
|
|
: $selectableItem.last()
|
|
;
|
|
if($nextSelectedItem.length > 0) {
|
|
module.debug('Scrolling page', direction, $nextSelectedItem);
|
|
$currentItem
|
|
.removeClass(className.selected)
|
|
;
|
|
$nextSelectedItem
|
|
.addClass(className.selected)
|
|
;
|
|
if(settings.selectOnKeydown && module.is.single()) {
|
|
module.set.selectedItem($nextSelectedItem);
|
|
}
|
|
$menu
|
|
.scrollTop(newScroll)
|
|
;
|
|
}
|
|
},
|
|
|
|
set: {
|
|
filtered: function() {
|
|
var
|
|
isMultiple = module.is.multiple(),
|
|
isSearch = module.is.searchSelection(),
|
|
isSearchMultiple = (isMultiple && isSearch),
|
|
searchValue = (isSearch)
|
|
? module.get.query()
|
|
: '',
|
|
hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0),
|
|
searchWidth = module.get.searchWidth(),
|
|
valueIsSet = searchValue !== ''
|
|
;
|
|
if(isMultiple && hasSearchValue) {
|
|
module.verbose('Adjusting input width', searchWidth, settings.glyphWidth);
|
|
$search.css('width', searchWidth);
|
|
}
|
|
if(hasSearchValue || (isSearchMultiple && valueIsSet)) {
|
|
module.verbose('Hiding placeholder text');
|
|
$text.addClass(className.filtered);
|
|
}
|
|
else if(!isMultiple || (isSearchMultiple && !valueIsSet)) {
|
|
module.verbose('Showing placeholder text');
|
|
$text.removeClass(className.filtered);
|
|
}
|
|
},
|
|
empty: function() {
|
|
$module.addClass(className.empty);
|
|
},
|
|
loading: function() {
|
|
$module.addClass(className.loading);
|
|
},
|
|
placeholderText: function(text) {
|
|
text = text || module.get.placeholderText();
|
|
module.debug('Setting placeholder text', text);
|
|
module.set.text(text);
|
|
$text.addClass(className.placeholder);
|
|
},
|
|
tabbable: function() {
|
|
if( module.is.searchSelection() ) {
|
|
module.debug('Added tabindex to searchable dropdown');
|
|
$search
|
|
.val('')
|
|
;
|
|
module.check.disabled();
|
|
$menu
|
|
.attr('tabindex', -1)
|
|
;
|
|
}
|
|
else {
|
|
module.debug('Added tabindex to dropdown');
|
|
if( $module.attr('tabindex') === undefined) {
|
|
$module
|
|
.attr('tabindex', 0)
|
|
;
|
|
$menu
|
|
.attr('tabindex', -1)
|
|
;
|
|
}
|
|
}
|
|
},
|
|
initialLoad: function() {
|
|
module.verbose('Setting initial load');
|
|
initialLoad = true;
|
|
},
|
|
activeItem: function($item) {
|
|
if( settings.allowAdditions && $item.filter(selector.addition).length > 0 ) {
|
|
$item.addClass(className.filtered);
|
|
}
|
|
else {
|
|
$item.addClass(className.active);
|
|
}
|
|
},
|
|
partialSearch: function(text) {
|
|
var
|
|
length = module.get.query().length
|
|
;
|
|
$search.val( text.substr(0, length));
|
|
},
|
|
scrollPosition: function($item, forceScroll) {
|
|
var
|
|
edgeTolerance = 5,
|
|
$menu,
|
|
hasActive,
|
|
offset,
|
|
itemHeight,
|
|
itemOffset,
|
|
menuOffset,
|
|
menuScroll,
|
|
menuHeight,
|
|
abovePage,
|
|
belowPage
|
|
;
|
|
|
|
$item = $item || module.get.selectedItem();
|
|
$menu = $item.closest(selector.menu);
|
|
hasActive = ($item && $item.length > 0);
|
|
forceScroll = (forceScroll !== undefined)
|
|
? forceScroll
|
|
: false
|
|
;
|
|
if(module.get.activeItem().length === 0){
|
|
forceScroll = false;
|
|
}
|
|
if($item && $menu.length > 0 && hasActive) {
|
|
itemOffset = $item.position().top;
|
|
|
|
$menu.addClass(className.loading);
|
|
menuScroll = $menu.scrollTop();
|
|
menuOffset = $menu.offset().top;
|
|
itemOffset = $item.offset().top;
|
|
offset = menuScroll - menuOffset + itemOffset;
|
|
if(!forceScroll) {
|
|
menuHeight = $menu.height();
|
|
belowPage = menuScroll + menuHeight < (offset + edgeTolerance);
|
|
abovePage = ((offset - edgeTolerance) < menuScroll);
|
|
}
|
|
module.debug('Scrolling to active item', offset);
|
|
if(forceScroll || abovePage || belowPage) {
|
|
$menu.scrollTop(offset);
|
|
}
|
|
$menu.removeClass(className.loading);
|
|
}
|
|
},
|
|
text: function(text) {
|
|
if(settings.action === 'combo') {
|
|
module.debug('Changing combo button text', text, $combo);
|
|
if(settings.preserveHTML) {
|
|
$combo.html(text);
|
|
}
|
|
else {
|
|
$combo.text(text);
|
|
}
|
|
}
|
|
else if(settings.action === 'activate') {
|
|
if(text !== module.get.placeholderText()) {
|
|
$text.removeClass(className.placeholder);
|
|
}
|
|
module.debug('Changing text', text, $text);
|
|
$text
|
|
.removeClass(className.filtered)
|
|
;
|
|
if(settings.preserveHTML) {
|
|
$text.html(text);
|
|
}
|
|
else {
|
|
$text.text(text);
|
|
}
|
|
}
|
|
},
|
|
selectedItem: function($item) {
|
|
var
|
|
value = module.get.choiceValue($item),
|
|
searchText = module.get.choiceText($item, false),
|
|
text = module.get.choiceText($item, true)
|
|
;
|
|
module.debug('Setting user selection to item', $item);
|
|
module.remove.activeItem();
|
|
module.set.partialSearch(searchText);
|
|
module.set.activeItem($item);
|
|
module.set.selected(value, $item);
|
|
module.set.text(text);
|
|
},
|
|
selectedLetter: function(letter) {
|
|
var
|
|
$selectedItem = $item.filter('.' + className.selected),
|
|
alreadySelectedLetter = $selectedItem.length > 0 && module.has.firstLetter($selectedItem, letter),
|
|
$nextValue = false,
|
|
$nextItem
|
|
;
|
|
// check next of same letter
|
|
if(alreadySelectedLetter) {
|
|
$nextItem = $selectedItem.nextAll($item).eq(0);
|
|
if( module.has.firstLetter($nextItem, letter) ) {
|
|
$nextValue = $nextItem;
|
|
}
|
|
}
|
|
// check all values
|
|
if(!$nextValue) {
|
|
$item
|
|
.each(function(){
|
|
if(module.has.firstLetter($(this), letter)) {
|
|
$nextValue = $(this);
|
|
return false;
|
|
}
|
|
})
|
|
;
|
|
}
|
|
// set next value
|
|
if($nextValue) {
|
|
module.verbose('Scrolling to next value with letter', letter);
|
|
module.set.scrollPosition($nextValue);
|
|
$selectedItem.removeClass(className.selected);
|
|
$nextValue.addClass(className.selected);
|
|
if(settings.selectOnKeydown && module.is.single()) {
|
|
module.set.selectedItem($nextValue);
|
|
}
|
|
}
|
|
},
|
|
direction: function($menu) {
|
|
if(settings.direction == 'auto') {
|
|
// reset position, remove upward if it's base menu
|
|
if (!$menu) {
|
|
module.remove.upward();
|
|
} else if (module.is.upward($menu)) {
|
|
//we need make sure when make assertion openDownward for $menu, $menu does not have upward class
|
|
module.remove.upward($menu);
|
|
}
|
|
|
|
if(module.can.openDownward($menu)) {
|
|
module.remove.upward($menu);
|
|
}
|
|
else {
|
|
module.set.upward($menu);
|
|
}
|
|
if(!module.is.leftward($menu) && !module.can.openRightward($menu)) {
|
|
module.set.leftward($menu);
|
|
}
|
|
}
|
|
else if(settings.direction == 'upward') {
|
|
module.set.upward($menu);
|
|
}
|
|
},
|
|
upward: function($currentMenu) {
|
|
var $element = $currentMenu || $module;
|
|
$element.addClass(className.upward);
|
|
},
|
|
leftward: function($currentMenu) {
|
|
var $element = $currentMenu || $menu;
|
|
$element.addClass(className.leftward);
|
|
},
|
|
value: function(value, text, $selected, preventChangeTrigger) {
|
|
if(value !== undefined && value !== '' && !(Array.isArray(value) && value.length === 0)) {
|
|
$input.removeClass(className.noselection);
|
|
} else {
|
|
$input.addClass(className.noselection);
|
|
}
|
|
var
|
|
escapedValue = module.escape.value(value),
|
|
hasInput = ($input.length > 0),
|
|
currentValue = module.get.values(),
|
|
stringValue = (value !== undefined)
|
|
? String(value)
|
|
: value,
|
|
newValue
|
|
;
|
|
if(hasInput) {
|
|
if(!settings.allowReselection && stringValue == currentValue) {
|
|
module.verbose('Skipping value update already same value', value, currentValue);
|
|
if(!module.is.initialLoad()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if( module.is.single() && module.has.selectInput() && module.can.extendSelect() ) {
|
|
module.debug('Adding user option', value);
|
|
module.add.optionValue(value);
|
|
}
|
|
module.debug('Updating input value', escapedValue, currentValue);
|
|
internalChange = true;
|
|
$input
|
|
.val(escapedValue)
|
|
;
|
|
if(settings.fireOnInit === false && module.is.initialLoad()) {
|
|
module.debug('Input native change event ignored on initial load');
|
|
}
|
|
else if(preventChangeTrigger !== true) {
|
|
module.trigger.change();
|
|
}
|
|
internalChange = false;
|
|
}
|
|
else {
|
|
module.verbose('Storing value in metadata', escapedValue, $input);
|
|
if(escapedValue !== currentValue) {
|
|
$module.data(metadata.value, stringValue);
|
|
}
|
|
}
|
|
if(settings.fireOnInit === false && module.is.initialLoad()) {
|
|
module.verbose('No callback on initial load', settings.onChange);
|
|
}
|
|
else if(preventChangeTrigger !== true) {
|
|
settings.onChange.call(element, value, text, $selected);
|
|
}
|
|
},
|
|
active: function() {
|
|
$module
|
|
.addClass(className.active)
|
|
;
|
|
},
|
|
multiple: function() {
|
|
$module.addClass(className.multiple);
|
|
},
|
|
visible: function() {
|
|
$module.addClass(className.visible);
|
|
},
|
|
exactly: function(value, $selectedItem) {
|
|
module.debug('Setting selected to exact values');
|
|
module.clear();
|
|
module.set.selected(value, $selectedItem);
|
|
},
|
|
selected: function(value, $selectedItem, preventChangeTrigger, keepSearchTerm) {
|
|
var
|
|
isMultiple = module.is.multiple()
|
|
;
|
|
$selectedItem = (settings.allowAdditions)
|
|
? $selectedItem || module.get.itemWithAdditions(value)
|
|
: $selectedItem || module.get.item(value)
|
|
;
|
|
if(!$selectedItem) {
|
|
return;
|
|
}
|
|
module.debug('Setting selected menu item to', $selectedItem);
|
|
if(module.is.multiple()) {
|
|
module.remove.searchWidth();
|
|
}
|
|
if(module.is.single()) {
|
|
module.remove.activeItem();
|
|
module.remove.selectedItem();
|
|
}
|
|
else if(settings.useLabels) {
|
|
module.remove.selectedItem();
|
|
}
|
|
// select each item
|
|
$selectedItem
|
|
.each(function() {
|
|
var
|
|
$selected = $(this),
|
|
selectedText = module.get.choiceText($selected),
|
|
selectedValue = module.get.choiceValue($selected, selectedText),
|
|
|
|
isFiltered = $selected.hasClass(className.filtered),
|
|
isActive = $selected.hasClass(className.active),
|
|
isUserValue = $selected.hasClass(className.addition),
|
|
shouldAnimate = (isMultiple && $selectedItem.length == 1)
|
|
;
|
|
if(isMultiple) {
|
|
if(!isActive || isUserValue) {
|
|
if(settings.apiSettings && settings.saveRemoteData) {
|
|
module.save.remoteData(selectedText, selectedValue);
|
|
}
|
|
if(settings.useLabels) {
|
|
module.add.label(selectedValue, selectedText, shouldAnimate);
|
|
module.add.value(selectedValue, selectedText, $selected);
|
|
module.set.activeItem($selected);
|
|
module.filterActive();
|
|
module.select.nextAvailable($selectedItem);
|
|
}
|
|
else {
|
|
module.add.value(selectedValue, selectedText, $selected);
|
|
module.set.text(module.add.variables(message.count));
|
|
module.set.activeItem($selected);
|
|
}
|
|
}
|
|
else if(!isFiltered && (settings.useLabels || selectActionActive)) {
|
|
module.debug('Selected active value, removing label');
|
|
module.remove.selected(selectedValue);
|
|
}
|
|
}
|
|
else {
|
|
if(settings.apiSettings && settings.saveRemoteData) {
|
|
module.save.remoteData(selectedText, selectedValue);
|
|
}
|
|
if (!keepSearchTerm) {
|
|
module.set.text(selectedText);
|
|
}
|
|
module.set.value(selectedValue, selectedText, $selected, preventChangeTrigger);
|
|
$selected
|
|
.addClass(className.active)
|
|
.addClass(className.selected)
|
|
;
|
|
}
|
|
})
|
|
;
|
|
if (!keepSearchTerm) {
|
|
module.remove.searchTerm();
|
|
}
|
|
}
|
|
},
|
|
|
|
add: {
|
|
label: function(value, text, shouldAnimate) {
|
|
var
|
|
$next = module.is.searchSelection()
|
|
? $search
|
|
: $text,
|
|
escapedValue = module.escape.value(value),
|
|
$label
|
|
;
|
|
if(settings.ignoreCase) {
|
|
escapedValue = escapedValue.toLowerCase();
|
|
}
|
|
$label = $('<a />')
|
|
.addClass(className.label)
|
|
.attr('data-' + metadata.value, escapedValue)
|
|
.html(templates.label(escapedValue, text, settings.preserveHTML, settings.className))
|
|
;
|
|
$label = settings.onLabelCreate.call($label, escapedValue, text);
|
|
|
|
if(module.has.label(value)) {
|
|
module.debug('User selection already exists, skipping', escapedValue);
|
|
return;
|
|
}
|
|
if(settings.label.variation) {
|
|
$label.addClass(settings.label.variation);
|
|
}
|
|
if(shouldAnimate === true) {
|
|
module.debug('Animating in label', $label);
|
|
$label
|
|
.addClass(className.hidden)
|
|
.insertBefore($next)
|
|
.transition({
|
|
animation : settings.label.transition,
|
|
debug : settings.debug,
|
|
verbose : settings.verbose,
|
|
duration : settings.label.duration
|
|
})
|
|
;
|
|
}
|
|
else {
|
|
module.debug('Adding selection label', $label);
|
|
$label
|
|
.insertBefore($next)
|
|
;
|
|
}
|
|
},
|
|
message: function(message) {
|
|
var
|
|
$message = $menu.children(selector.message),
|
|
html = settings.templates.message(module.add.variables(message))
|
|
;
|
|
if($message.length > 0) {
|
|
$message
|
|
.html(html)
|
|
;
|
|
}
|
|
else {
|
|
$message = $('<div/>')
|
|
.html(html)
|
|
.addClass(className.message)
|
|
.appendTo($menu)
|
|
;
|
|
}
|
|
},
|
|
optionValue: function(value) {
|
|
var
|
|
escapedValue = module.escape.value(value),
|
|
$option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
|
|
hasOption = ($option.length > 0)
|
|
;
|
|
if(hasOption) {
|
|
return;
|
|
}
|
|
// temporarily disconnect observer
|
|
module.disconnect.selectObserver();
|
|
if( module.is.single() ) {
|
|
module.verbose('Removing previous user addition');
|
|
$input.find('option.' + className.addition).remove();
|
|
}
|
|
$('<option/>')
|
|
.prop('value', escapedValue)
|
|
.addClass(className.addition)
|
|
.html(value)
|
|
.appendTo($input)
|
|
;
|
|
module.verbose('Adding user addition as an <option>', value);
|
|
module.observe.select();
|
|
},
|
|
userSuggestion: function(value) {
|
|
var
|
|
$addition = $menu.children(selector.addition),
|
|
$existingItem = module.get.item(value),
|
|
alreadyHasValue = $existingItem && $existingItem.not(selector.addition).length,
|
|
hasUserSuggestion = $addition.length > 0,
|
|
html
|
|
;
|
|
if(settings.useLabels && module.has.maxSelections()) {
|
|
return;
|
|
}
|
|
if(value === '' || alreadyHasValue) {
|
|
$addition.remove();
|
|
return;
|
|
}
|
|
if(hasUserSuggestion) {
|
|
$addition
|
|
.data(metadata.value, value)
|
|
.data(metadata.text, value)
|
|
.attr('data-' + metadata.value, value)
|
|
.attr('data-' + metadata.text, value)
|
|
.removeClass(className.filtered)
|
|
;
|
|
if(!settings.hideAdditions) {
|
|
html = settings.templates.addition( module.add.variables(message.addResult, value) );
|
|
$addition
|
|
.html(html)
|
|
;
|
|
}
|
|
module.verbose('Replacing user suggestion with new value', $addition);
|
|
}
|
|
else {
|
|
$addition = module.create.userChoice(value);
|
|
$addition
|
|
.prependTo($menu)
|
|
;
|
|
module.verbose('Adding item choice to menu corresponding with user choice addition', $addition);
|
|
}
|
|
if(!settings.hideAdditions || module.is.allFiltered()) {
|
|
$addition
|
|
.addClass(className.selected)
|
|
.siblings()
|
|
.removeClass(className.selected)
|
|
;
|
|
}
|
|
module.refreshItems();
|
|
},
|
|
variables: function(message, term) {
|
|
var
|
|
hasCount = (message.search('{count}') !== -1),
|
|
hasMaxCount = (message.search('{maxCount}') !== -1),
|
|
hasTerm = (message.search('{term}') !== -1),
|
|
count,
|
|
query
|
|
;
|
|
module.verbose('Adding templated variables to message', message);
|
|
if(hasCount) {
|
|
count = module.get.selectionCount();
|
|
message = message.replace('{count}', count);
|
|
}
|
|
if(hasMaxCount) {
|
|
count = module.get.selectionCount();
|
|
message = message.replace('{maxCount}', settings.maxSelections);
|
|
}
|
|
if(hasTerm) {
|
|
query = term || module.get.query();
|
|
message = message.replace('{term}', query);
|
|
}
|
|
return message;
|
|
},
|
|
value: function(addedValue, addedText, $selectedItem) {
|
|
var
|
|
currentValue = module.get.values(true),
|
|
newValue
|
|
;
|
|
if(module.has.value(addedValue)) {
|
|
module.debug('Value already selected');
|
|
return;
|
|
}
|
|
if(addedValue === '') {
|
|
module.debug('Cannot select blank values from multiselect');
|
|
return;
|
|
}
|
|
// extend current array
|
|
if(Array.isArray(currentValue)) {
|
|
newValue = currentValue.concat([addedValue]);
|
|
newValue = module.get.uniqueArray(newValue);
|
|
}
|
|
else {
|
|
newValue = [addedValue];
|
|
}
|
|
// add values
|
|
if( module.has.selectInput() ) {
|
|
if(module.can.extendSelect()) {
|
|
module.debug('Adding value to select', addedValue, newValue, $input);
|
|
module.add.optionValue(addedValue);
|
|
}
|
|
}
|
|
else {
|
|
newValue = newValue.join(settings.delimiter);
|
|
module.debug('Setting hidden input to delimited value', newValue, $input);
|
|
}
|
|
|
|
if(settings.fireOnInit === false && module.is.initialLoad()) {
|
|
module.verbose('Skipping onadd callback on initial load', settings.onAdd);
|
|
}
|
|
else {
|
|
settings.onAdd.call(element, addedValue, addedText, $selectedItem);
|
|
}
|
|
module.set.value(newValue, addedText, $selectedItem);
|
|
module.check.maxSelections();
|
|
},
|
|
},
|
|
|
|
remove: {
|
|
active: function() {
|
|
$module.removeClass(className.active);
|
|
},
|
|
activeLabel: function() {
|
|
$module.find(selector.label).removeClass(className.active);
|
|
},
|
|
empty: function() {
|
|
$module.removeClass(className.empty);
|
|
},
|
|
loading: function() {
|
|
$module.removeClass(className.loading);
|
|
},
|
|
initialLoad: function() {
|
|
initialLoad = false;
|
|
},
|
|
upward: function($currentMenu) {
|
|
var $element = $currentMenu || $module;
|
|
$element.removeClass(className.upward);
|
|
},
|
|
leftward: function($currentMenu) {
|
|
var $element = $currentMenu || $menu;
|
|
$element.removeClass(className.leftward);
|
|
},
|
|
visible: function() {
|
|
$module.removeClass(className.visible);
|
|
},
|
|
activeItem: function() {
|
|
$item.removeClass(className.active);
|
|
},
|
|
filteredItem: function() {
|
|
if(settings.useLabels && module.has.maxSelections() ) {
|
|
return;
|
|
}
|
|
if(settings.useLabels && module.is.multiple()) {
|
|
$item.not('.' + className.active).removeClass(className.filtered);
|
|
}
|
|
else {
|
|
$item.removeClass(className.filtered);
|
|
}
|
|
if(settings.hideDividers) {
|
|
$divider.removeClass(className.hidden);
|
|
}
|
|
module.remove.empty();
|
|
},
|
|
optionValue: function(value) {
|
|
var
|
|
escapedValue = module.escape.value(value),
|
|
$option = $input.find('option[value="' + module.escape.string(escapedValue) + '"]'),
|
|
hasOption = ($option.length > 0)
|
|
;
|
|
if(!hasOption || !$option.hasClass(className.addition)) {
|
|
return;
|
|
}
|
|
// temporarily disconnect observer
|
|
if(selectObserver) {
|
|
selectObserver.disconnect();
|
|
module.verbose('Temporarily disconnecting mutation observer');
|
|
}
|
|
$option.remove();
|
|
module.verbose('Removing user addition as an <option>', escapedValue);
|
|
if(selectObserver) {
|
|
selectObserver.observe($input[0], {
|
|
childList : true,
|
|
subtree : true
|
|
});
|
|
}
|
|
},
|
|
message: function() {
|
|
$menu.children(selector.message).remove();
|
|
},
|
|
searchWidth: function() {
|
|
$search.css('width', '');
|
|
},
|
|
searchTerm: function() {
|
|
module.verbose('Cleared search term');
|
|
$search.val('');
|
|
module.set.filtered();
|
|
},
|
|
userAddition: function() {
|
|
$item.filter(selector.addition).remove();
|
|
},
|
|
selected: function(value, $selectedItem, preventChangeTrigger) {
|
|
$selectedItem = (settings.allowAdditions)
|
|
? $selectedItem || module.get.itemWithAdditions(value)
|
|
: $selectedItem || module.get.item(value)
|
|
;
|
|
|
|
if(!$selectedItem) {
|
|
return false;
|
|
}
|
|
|
|
$selectedItem
|
|
.each(function() {
|
|
var
|
|
$selected = $(this),
|
|
selectedText = module.get.choiceText($selected),
|
|
selectedValue = module.get.choiceValue($selected, selectedText)
|
|
;
|
|
if(module.is.multiple()) {
|
|
if(settings.useLabels) {
|
|
module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
|
|
module.remove.label(selectedValue);
|
|
}
|
|
else {
|
|
module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
|
|
if(module.get.selectionCount() === 0) {
|
|
module.set.placeholderText();
|
|
}
|
|
else {
|
|
module.set.text(module.add.variables(message.count));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
module.remove.value(selectedValue, selectedText, $selected, preventChangeTrigger);
|
|
}
|
|
$selected
|
|
.removeClass(className.filtered)
|
|
.removeClass(className.active)
|
|
;
|
|
if(settings.useLabels) {
|
|
$selected.removeClass(className.selected);
|
|
}
|
|
})
|
|
;
|
|
},
|
|
selectedItem: function() {
|
|
$item.removeClass(className.selected);
|
|
},
|
|
value: function(removedValue, removedText, $removedItem, preventChangeTrigger) {
|
|
var
|
|
values = module.get.values(),
|
|
newValue
|
|
;
|
|
removedValue = module.escape.htmlEntities(removedValue);
|
|
if( module.has.selectInput() ) {
|
|
module.verbose('Input is <select> removing selected option', removedValue);
|
|
newValue = module.remove.arrayValue(removedValue, values);
|
|
module.remove.optionValue(removedValue);
|
|
}
|
|
else {
|
|
module.verbose('Removing from delimited values', removedValue);
|
|
newValue = module.remove.arrayValue(removedValue, values);
|
|
newValue = newValue.join(settings.delimiter);
|
|
}
|
|
if(settings.fireOnInit === false && module.is.initialLoad()) {
|
|
module.verbose('No callback on initial load', settings.onRemove);
|
|
}
|
|
else {
|
|
settings.onRemove.call(element, removedValue, removedText, $removedItem);
|
|
}
|
|
module.set.value(newValue, removedText, $removedItem, preventChangeTrigger);
|
|
module.check.maxSelections();
|
|
},
|
|
arrayValue: function(removedValue, values) {
|
|
if( !Array.isArray(values) ) {
|
|
values = [values];
|
|
}
|
|
values = $.grep(values, function(value){
|
|
return (removedValue != value);
|
|
});
|
|
module.verbose('Removed value from delimited string', removedValue, values);
|
|
return values;
|
|
},
|
|
label: function(value, shouldAnimate) {
|
|
var
|
|
escapedValue = module.escape.value(value),
|
|
$labels = $module.find(selector.label),
|
|
$removedLabel = $labels.filter('[data-' + metadata.value + '="' + module.escape.string(settings.ignoreCase ? escapedValue.toLowerCase() : escapedValue) +'"]')
|
|
;
|
|
module.verbose('Removing label', $removedLabel);
|
|
$removedLabel.remove();
|
|
},
|
|
activeLabels: function($activeLabels) {
|
|
$activeLabels = $activeLabels || $module.find(selector.label).filter('.' + className.active);
|
|
module.verbose('Removing active label selections', $activeLabels);
|
|
module.remove.labels($activeLabels);
|
|
},
|
|
labels: function($labels, preventChangeTrigger) {
|
|
$labels = $labels || $module.find(selector.label);
|
|
module.verbose('Removing labels', $labels);
|
|
$labels
|
|
.each(function(){
|
|
var
|
|
$label = $(this),
|
|
value = $label.data(metadata.value),
|
|
stringValue = (value !== undefined)
|
|
? String(value)
|
|
: value,
|
|
isUserValue = module.is.userValue(stringValue)
|
|
;
|
|
if(settings.onLabelRemove.call($label, value) === false) {
|
|
module.debug('Label remove callback cancelled removal');
|
|
return;
|
|
}
|
|
module.remove.message();
|
|
if(isUserValue) {
|
|
module.remove.value(stringValue, stringValue, module.get.item(stringValue), preventChangeTrigger);
|
|
module.remove.label(stringValue);
|
|
}
|
|
else {
|
|
// selected will also remove label
|
|
module.remove.selected(stringValue, false, preventChangeTrigger);
|
|
}
|
|
})
|
|
;
|
|
},
|
|
tabbable: function() {
|
|
if( module.is.searchSelection() ) {
|
|
module.debug('Searchable dropdown initialized');
|
|
$search
|
|
.removeAttr('tabindex')
|
|
;
|
|
$menu
|
|
.removeAttr('tabindex')
|
|
;
|
|
}
|
|
else {
|
|
module.debug('Simple selection dropdown initialized');
|
|
$module
|
|
.removeAttr('tabindex')
|
|
;
|
|
$menu
|
|
.removeAttr('tabindex')
|
|
;
|
|
}
|
|
},
|
|
diacritics: function(text) {
|
|
return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036f]/g, '') : text;
|
|
}
|
|
},
|
|
|
|
has: {
|
|
menuSearch: function() {
|
|
return (module.has.search() && $search.closest($menu).length > 0);
|
|
},
|
|
clearItem: function() {
|
|
return ($clear.length > 0);
|
|
},
|
|
search: function() {
|
|
return ($search.length > 0);
|
|
},
|
|
sizer: function() {
|
|
return ($sizer.length > 0);
|
|
},
|
|
selectInput: function() {
|
|
return ( $input.is('select') );
|
|
},
|
|
minCharacters: function(searchTerm) {
|
|
if(settings.minCharacters && !iconClicked) {
|
|
searchTerm = (searchTerm !== undefined)
|
|
? String(searchTerm)
|
|
: String(module.get.query())
|
|
;
|
|
return (searchTerm.length >= settings.minCharacters);
|
|
}
|
|
iconClicked=false;
|
|
return true;
|
|
},
|
|
firstLetter: function($item, letter) {
|
|
var
|
|
text,
|
|
firstLetter
|
|
;
|
|
if(!$item || $item.length === 0 || typeof letter !== 'string') {
|
|
return false;
|
|
}
|
|
text = module.get.choiceText($item, false);
|
|
letter = letter.toLowerCase();
|
|
firstLetter = String(text).charAt(0).toLowerCase();
|
|
return (letter == firstLetter);
|
|
},
|
|
input: function() {
|
|
return ($input.length > 0);
|
|
},
|
|
items: function() {
|
|
return ($item.length > 0);
|
|
},
|
|
menu: function() {
|
|
return ($menu.length > 0);
|
|
},
|
|
subMenu: function($currentMenu) {
|
|
return ($currentMenu || $menu).find(selector.menu).length > 0;
|
|
},
|
|
message: function() {
|
|
return ($menu.children(selector.message).length !== 0);
|
|
},
|
|
label: function(value) {
|
|
var
|
|
escapedValue = module.escape.value(value),
|
|
$labels = $module.find(selector.label)
|
|
;
|
|
if(settings.ignoreCase) {
|
|
escapedValue = escapedValue.toLowerCase();
|
|
}
|
|
return ($labels.filter('[data-' + metadata.value + '="' + module.escape.string(escapedValue) +'"]').length > 0);
|
|
},
|
|
maxSelections: function() {
|
|
return (settings.maxSelections && module.get.selectionCount() >= settings.maxSelections);
|
|
},
|
|
allResultsFiltered: function() {
|
|
var
|
|
$normalResults = $item.not(selector.addition)
|
|
;
|
|
return ($normalResults.filter(selector.unselectable).length === $normalResults.length);
|
|
},
|
|
userSuggestion: function() {
|
|
return ($menu.children(selector.addition).length > 0);
|
|
},
|
|
query: function() {
|
|
return (module.get.query() !== '');
|
|
},
|
|
value: function(value) {
|
|
return (settings.ignoreCase)
|
|
? module.has.valueIgnoringCase(value)
|
|
: module.has.valueMatchingCase(value)
|
|
;
|
|
},
|
|
valueMatchingCase: function(value) {
|
|
var
|
|
values = module.get.values(true),
|
|
hasValue = Array.isArray(values)
|
|
? values && ($.inArray(value, values) !== -1)
|
|
: (values == value)
|
|
;
|
|
return (hasValue)
|
|
? true
|
|
: false
|
|
;
|
|
},
|
|
valueIgnoringCase: function(value) {
|
|
var
|
|
values = module.get.values(true),
|
|
hasValue = false
|
|
;
|
|
if(!Array.isArray(values)) {
|
|
values = [values];
|
|
}
|
|
$.each(values, function(index, existingValue) {
|
|
if(String(value).toLowerCase() == String(existingValue).toLowerCase()) {
|
|
hasValue = true;
|
|
return false;
|
|
}
|
|
});
|
|
return hasValue;
|
|
}
|
|
},
|
|
|
|
is: {
|
|
active: function() {
|
|
return $module.hasClass(className.active);
|
|
},
|
|
animatingInward: function() {
|
|
return $menu.transition('is inward');
|
|
},
|
|
animatingOutward: function() {
|
|
return $menu.transition('is outward');
|
|
},
|
|
bubbledLabelClick: function(event) {
|
|
return $(event.target).is('select, input') && $module.closest('label').length > 0;
|
|
},
|
|
bubbledIconClick: function(event) {
|
|
return $(event.target).closest($icon).length > 0;
|
|
},
|
|
chrome: function() {
|
|
return !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
|
|
},
|
|
alreadySetup: function() {
|
|
return ($module.is('select') && $module.parent(selector.dropdown).data(moduleNamespace) !== undefined && $module.prev().length === 0);
|
|
},
|
|
animating: function($subMenu) {
|
|
return ($subMenu)
|
|
? $subMenu.transition && $subMenu.transition('is animating')
|
|
: $menu.transition && $menu.transition('is animating')
|
|
;
|
|
},
|
|
leftward: function($subMenu) {
|
|
var $selectedMenu = $subMenu || $menu;
|
|
return $selectedMenu.hasClass(className.leftward);
|
|
},
|
|
clearable: function() {
|
|
return ($module.hasClass(className.clearable) || settings.clearable);
|
|
},
|
|
disabled: function() {
|
|
return $module.hasClass(className.disabled);
|
|
},
|
|
focused: function() {
|
|
return (document.activeElement === $module[0]);
|
|
},
|
|
focusedOnSearch: function() {
|
|
return (document.activeElement === $search[0]);
|
|
},
|
|
allFiltered: function() {
|
|
return( (module.is.multiple() || module.has.search()) && !(settings.hideAdditions == false && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered() );
|
|
},
|
|
hidden: function($subMenu) {
|
|
return !module.is.visible($subMenu);
|
|
},
|
|
initialLoad: function() {
|
|
return initialLoad;
|
|
},
|
|
inObject: function(needle, object) {
|
|
var
|
|
found = false
|
|
;
|
|
$.each(object, function(index, property) {
|
|
if(property == needle) {
|
|
found = true;
|
|
return true;
|
|
}
|
|
});
|
|
return found;
|
|
},
|
|
multiple: function() {
|
|
return $module.hasClass(className.multiple);
|
|
},
|
|
remote: function() {
|
|
return settings.apiSettings && module.can.useAPI();
|
|
},
|
|
noApiCache: function() {
|
|
return settings.apiSettings && !settings.apiSettings.cache
|
|
},
|
|
single: function() {
|
|
return !module.is.multiple();
|
|
},
|
|
selectMutation: function(mutations) {
|
|
var
|
|
selectChanged = false
|
|
;
|
|
$.each(mutations, function(index, mutation) {
|
|
if($(mutation.target).is('select') || $(mutation.addedNodes).is('select')) {
|
|
selectChanged = true;
|
|
return false;
|
|
}
|
|
});
|
|
return selectChanged;
|
|
},
|
|
search: function() {
|
|
return $module.hasClass(className.search);
|
|
},
|
|
searchSelection: function() {
|
|
return ( module.has.search() && $search.parent(selector.dropdown).length === 1 );
|
|
},
|
|
selection: function() {
|
|
return $module.hasClass(className.selection);
|
|
},
|
|
userValue: function(value) {
|
|
return ($.inArray(value, module.get.userValues()) !== -1);
|
|
},
|
|
upward: function($menu) {
|
|
var $element = $menu || $module;
|
|
return $element.hasClass(className.upward);
|
|
},
|
|
visible: function($subMenu) {
|
|
return ($subMenu)
|
|
? $subMenu.hasClass(className.visible)
|
|
: $menu.hasClass(className.visible)
|
|
;
|
|
},
|
|
verticallyScrollableContext: function() {
|
|
var
|
|
overflowY = ($context.get(0) !== window)
|
|
? $context.css('overflow-y')
|
|
: false
|
|
;
|
|
return (overflowY == 'auto' || overflowY == 'scroll');
|
|
},
|
|
horizontallyScrollableContext: function() {
|
|
var
|
|
overflowX = ($context.get(0) !== window)
|
|
? $context.css('overflow-X')
|
|
: false
|
|
;
|
|
return (overflowX == 'auto' || overflowX == 'scroll');
|
|
}
|
|
},
|
|
|
|
can: {
|
|
activate: function($item) {
|
|
if(settings.useLabels) {
|
|
return true;
|
|
}
|
|
if(!module.has.maxSelections()) {
|
|
return true;
|
|
}
|
|
if(module.has.maxSelections() && $item.hasClass(className.active)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
openDownward: function($subMenu) {
|
|
var
|
|
$currentMenu = $subMenu || $menu,
|
|
canOpenDownward = true,
|
|
onScreen = {},
|
|
calculations
|
|
;
|
|
$currentMenu
|
|
.addClass(className.loading)
|
|
;
|
|
calculations = {
|
|
context: {
|
|
offset : ($context.get(0) === window)
|
|
? { top: 0, left: 0}
|
|
: $context.offset(),
|
|
scrollTop : $context.scrollTop(),
|
|
height : $context.outerHeight()
|
|
},
|
|
menu : {
|
|
offset: $currentMenu.offset(),
|
|
height: $currentMenu.outerHeight()
|
|
}
|
|
};
|
|
if(module.is.verticallyScrollableContext()) {
|
|
calculations.menu.offset.top += calculations.context.scrollTop;
|
|
}
|
|
if(module.has.subMenu($currentMenu)) {
|
|
calculations.menu.height += $currentMenu.find(selector.menu).first().outerHeight();
|
|
}
|
|
onScreen = {
|
|
above : (calculations.context.scrollTop) <= calculations.menu.offset.top - calculations.context.offset.top - calculations.menu.height,
|
|
below : (calculations.context.scrollTop + calculations.context.height) >= calculations.menu.offset.top - calculations.context.offset.top + calculations.menu.height
|
|
};
|
|
if(onScreen.below) {
|
|
module.verbose('Dropdown can fit in context downward', onScreen);
|
|
canOpenDownward = true;
|
|
}
|
|
else if(!onScreen.below && !onScreen.above) {
|
|
module.verbose('Dropdown cannot fit in either direction, favoring downward', onScreen);
|
|
canOpenDownward = true;
|
|
}
|
|
else {
|
|
module.verbose('Dropdown cannot fit below, opening upward', onScreen);
|
|
canOpenDownward = false;
|
|
}
|
|
$currentMenu.removeClass(className.loading);
|
|
return canOpenDownward;
|
|
},
|
|
openRightward: function($subMenu) {
|
|
var
|
|
$currentMenu = $subMenu || $menu,
|
|
canOpenRightward = true,
|
|
isOffscreenRight = false,
|
|
calculations
|
|
;
|
|
$currentMenu
|
|
.addClass(className.loading)
|
|
;
|
|
calculations = {
|
|
context: {
|
|
offset : ($context.get(0) === window)
|
|
? { top: 0, left: 0}
|
|
: $context.offset(),
|
|
scrollLeft : $context.scrollLeft(),
|
|
width : $context.outerWidth()
|
|
},
|
|
menu: {
|
|
offset : $currentMenu.offset(),
|
|
width : $currentMenu.outerWidth()
|
|
}
|
|
};
|
|
if(module.is.horizontallyScrollableContext()) {
|
|
calculations.menu.offset.left += calculations.context.scrollLeft;
|
|
}
|
|
isOffscreenRight = (calculations.menu.offset.left - calculations.context.offset.left + calculations.menu.width >= calculations.context.scrollLeft + calculations.context.width);
|
|
if(isOffscreenRight) {
|
|
module.verbose('Dropdown cannot fit in context rightward', isOffscreenRight);
|
|
canOpenRightward = false;
|
|
}
|
|
$currentMenu.removeClass(className.loading);
|
|
return canOpenRightward;
|
|
},
|
|
click: function() {
|
|
return (hasTouch || settings.on == 'click');
|
|
},
|
|
extendSelect: function() {
|
|
return settings.allowAdditions || settings.apiSettings;
|
|
},
|
|
show: function() {
|
|
return !module.is.disabled() && (module.has.items() || module.has.message());
|
|
},
|
|
useAPI: function() {
|
|
return $.fn.api !== undefined;
|
|
}
|
|
},
|
|
|
|
animate: {
|
|
show: function(callback, $subMenu) {
|
|
var
|
|
$currentMenu = $subMenu || $menu,
|
|
start = ($subMenu)
|
|
? function() {}
|
|
: function() {
|
|
module.hideSubMenus();
|
|
module.hideOthers();
|
|
module.set.active();
|
|
},
|
|
transition
|
|
;
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
module.verbose('Doing menu show animation', $currentMenu);
|
|
module.set.direction($subMenu);
|
|
transition = settings.transition.showMethod || module.get.transition($subMenu);
|
|
if( module.is.selection() ) {
|
|
module.set.scrollPosition(module.get.selectedItem(), true);
|
|
}
|
|
if( module.is.hidden($currentMenu) || module.is.animating($currentMenu) ) {
|
|
if(transition === 'none') {
|
|
start();
|
|
$currentMenu.transition({
|
|
displayType: module.get.displayType()
|
|
}).transition('show');
|
|
callback.call(element);
|
|
}
|
|
else if($.fn.transition !== undefined && $module.transition('is supported')) {
|
|
$currentMenu
|
|
.transition({
|
|
animation : transition + ' in',
|
|
debug : settings.debug,
|
|
verbose : settings.verbose,
|
|
duration : settings.transition.showDuration || settings.duration,
|
|
queue : true,
|
|
onStart : start,
|
|
displayType: module.get.displayType(),
|
|
onComplete : function() {
|
|
callback.call(element);
|
|
}
|
|
})
|
|
;
|
|
}
|
|
else {
|
|
module.error(error.noTransition, transition);
|
|
}
|
|
}
|
|
},
|
|
hide: function(callback, $subMenu) {
|
|
var
|
|
$currentMenu = $subMenu || $menu,
|
|
start = ($subMenu)
|
|
? function() {}
|
|
: function() {
|
|
if( module.can.click() ) {
|
|
module.unbind.intent();
|
|
}
|
|
module.remove.active();
|
|
},
|
|
transition = settings.transition.hideMethod || module.get.transition($subMenu)
|
|
;
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if( module.is.visible($currentMenu) || module.is.animating($currentMenu) ) {
|
|
module.verbose('Doing menu hide animation', $currentMenu);
|
|
|
|
if(transition === 'none') {
|
|
start();
|
|
$currentMenu.transition({
|
|
displayType: module.get.displayType()
|
|
}).transition('hide');
|
|
callback.call(element);
|
|
}
|
|
else if($.fn.transition !== undefined && $module.transition('is supported')) {
|
|
$currentMenu
|
|
.transition({
|
|
animation : transition + ' out',
|
|
duration : settings.transition.hideDuration || settings.duration,
|
|
debug : settings.debug,
|
|
verbose : settings.verbose,
|
|
queue : false,
|
|
onStart : start,
|
|
displayType: module.get.displayType(),
|
|
onComplete : function() {
|
|
callback.call(element);
|
|
}
|
|
})
|
|
;
|
|
}
|
|
else {
|
|
module.error(error.transition);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
hideAndClear: function() {
|
|
module.remove.searchTerm();
|
|
if( module.has.maxSelections() ) {
|
|
return;
|
|
}
|
|
if(module.has.search()) {
|
|
module.hide(function() {
|
|
module.remove.filteredItem();
|
|
});
|
|
}
|
|
else {
|
|
module.hide();
|
|
}
|
|
},
|
|
|
|
delay: {
|
|
show: function() {
|
|
module.verbose('Delaying show event to ensure user intent');
|
|
clearTimeout(module.timer);
|
|
module.timer = setTimeout(module.show, settings.delay.show);
|
|
},
|
|
hide: function() {
|
|
module.verbose('Delaying hide event to ensure user intent');
|
|
clearTimeout(module.timer);
|
|
module.timer = setTimeout(module.hide, settings.delay.hide);
|
|
}
|
|
},
|
|
|
|
escape: {
|
|
value: function(value) {
|
|
var
|
|
multipleValues = Array.isArray(value),
|
|
stringValue = (typeof value === 'string'),
|
|
isUnparsable = (!stringValue && !multipleValues),
|
|
hasQuotes = (stringValue && value.search(regExp.quote) !== -1),
|
|
values = []
|
|
;
|
|
if(isUnparsable || !hasQuotes) {
|
|
return value;
|
|
}
|
|
module.debug('Encoding quote values for use in select', value);
|
|
if(multipleValues) {
|
|
$.each(value, function(index, value){
|
|
values.push(value.replace(regExp.quote, '"'));
|
|
});
|
|
return values;
|
|
}
|
|
return value.replace(regExp.quote, '"');
|
|
},
|
|
string: function(text) {
|
|
text = String(text);
|
|
return text.replace(regExp.escape, '\\$&');
|
|
},
|
|
htmlEntities: function(string) {
|
|
var
|
|
badChars = /[<>"'`]/g,
|
|
shouldEscape = /[&<>"'`]/,
|
|
escape = {
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
"`": "`"
|
|
},
|
|
escapedChar = function(chr) {
|
|
return escape[chr];
|
|
}
|
|
;
|
|
if(shouldEscape.test(string)) {
|
|
string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&");
|
|
return string.replace(badChars, escapedChar);
|
|
}
|
|
return string;
|
|
}
|
|
},
|
|
|
|
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 = setTimeout(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) && performance.length > 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 = query.length - 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 {
|
|
module.error(error.method, query);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
if ( $.isFunction( found ) ) {
|
|
response = found.apply(context, passedArguments);
|
|
}
|
|
else if(found !== undefined) {
|
|
response = found;
|
|
}
|
|
if(Array.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
|
|
: $allModules
|
|
;
|
|
};
|
|
|
|
$.fn.dropdown.settings = {
|
|
|
|
silent : false,
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
on : 'click', // what event should show menu action on item selection
|
|
action : 'activate', // action on item selection (nothing, activate, select, combo, hide, function(){})
|
|
|
|
values : false, // specify values to use for dropdown
|
|
|
|
clearable : false, // whether the value of the dropdown can be cleared
|
|
|
|
apiSettings : false,
|
|
selectOnKeydown : true, // Whether selection should occur automatically when keyboard shortcuts used
|
|
minCharacters : 0, // Minimum characters required to trigger API call
|
|
|
|
filterRemoteData : false, // Whether API results should be filtered after being returned for query term
|
|
saveRemoteData : true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
|
|
|
|
throttle : 200, // How long to wait after last user input to search remotely
|
|
|
|
context : window, // Context to use when determining if on screen
|
|
direction : 'auto', // Whether dropdown should always open in one direction
|
|
keepOnScreen : true, // Whether dropdown should check whether it is on screen before showing
|
|
|
|
match : 'both', // what to match against with search selection (both, text, or label)
|
|
fullTextSearch : false, // search anywhere in value (set to 'exact' to require exact matches)
|
|
ignoreDiacritics : false, // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
|
|
hideDividers : false, // Whether to hide any divider elements (specified in selector.divider) that are sibling to any items when searched (set to true will hide all dividers, set to 'empty' will hide them when they are not followed by a visible item)
|
|
|
|
placeholder : 'auto', // whether to convert blank <select> values to placeholder text
|
|
preserveHTML : true, // preserve html when selecting value
|
|
sortSelect : false, // sort selection on init
|
|
|
|
forceSelection : true, // force a choice on blur with search selection
|
|
|
|
allowAdditions : false, // whether multiple select should allow user added values
|
|
ignoreCase : false, // whether to consider case sensitivity when creating labels
|
|
ignoreSearchCase : true, // whether to consider case sensitivity when filtering items
|
|
hideAdditions : true, // whether or not to hide special message prompting a user they can enter a value
|
|
|
|
maxSelections : false, // When set to a number limits the number of selections to this count
|
|
useLabels : true, // whether multiple select should filter currently active selections from choices
|
|
delimiter : ',', // when multiselect uses normal <input> the values will be delimited with this character
|
|
|
|
showOnFocus : true, // show menu on focus
|
|
allowReselection : false, // whether current value should trigger callbacks when reselected
|
|
allowTab : true, // add tabindex to element
|
|
allowCategorySelection : false, // allow elements with sub-menus to be selected
|
|
|
|
fireOnInit : false, // Whether callbacks should fire when initializing dropdown values
|
|
|
|
transition : 'auto', // auto transition will slide down or up based on direction
|
|
duration : 200, // duration of transition
|
|
displayType : false, // displayType of transition
|
|
|
|
glyphWidth : 1.037, // widest glyph width in em (W is 1.037 em) used to calculate multiselect input width
|
|
|
|
headerDivider : true, // whether option headers should have an additional divider line underneath when converted from <select> <optgroup>
|
|
|
|
// label settings on multi-select
|
|
label: {
|
|
transition : 'scale',
|
|
duration : 200,
|
|
variation : false
|
|
},
|
|
|
|
// delay before event
|
|
delay : {
|
|
hide : 300,
|
|
show : 200,
|
|
search : 20,
|
|
touch : 50
|
|
},
|
|
|
|
/* Callbacks */
|
|
onChange : function(value, text, $selected){},
|
|
onAdd : function(value, text, $selected){},
|
|
onRemove : function(value, text, $selected){},
|
|
onSearch : function(searchTerm){},
|
|
|
|
onLabelSelect : function($selectedLabels){},
|
|
onLabelCreate : function(value, text) { return $(this); },
|
|
onLabelRemove : function(value) { return true; },
|
|
onNoResults : function(searchTerm) { return true; },
|
|
onShow : function(){},
|
|
onHide : function(){},
|
|
|
|
/* Component */
|
|
name : 'Dropdown',
|
|
namespace : 'dropdown',
|
|
|
|
message: {
|
|
addResult : 'Add <b>{term}</b>',
|
|
count : '{count} selected',
|
|
maxSelections : 'Max {maxCount} selections',
|
|
noResults : 'No results found.',
|
|
serverError : 'There was an error contacting the server'
|
|
},
|
|
|
|
error : {
|
|
action : 'You called a dropdown action that was not defined',
|
|
alreadySetup : 'Once a select has been initialized behaviors must be called on the created ui dropdown',
|
|
labels : 'Allowing user additions currently requires the use of labels.',
|
|
missingMultiple : '<select> requires multiple property to be set to correctly preserve multiple values',
|
|
method : 'The method you called is not defined.',
|
|
noAPI : 'The API module is required to load resources remotely',
|
|
noStorage : 'Saving remote data requires session storage',
|
|
noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>',
|
|
noNormalize : '"ignoreDiacritics" setting will be ignored. Browser does not support String().normalize(). You may consider including <https://cdn.jsdelivr.net/npm/unorm@1.4.1/lib/unorm.min.js> as a polyfill.'
|
|
},
|
|
|
|
regExp : {
|
|
escape : /[-[\]{}()*+?.,\\^$|#\s:=@]/g,
|
|
quote : /"/g
|
|
},
|
|
|
|
metadata : {
|
|
defaultText : 'defaultText',
|
|
defaultValue : 'defaultValue',
|
|
placeholderText : 'placeholder',
|
|
text : 'text',
|
|
value : 'value'
|
|
},
|
|
|
|
// property names for remote query
|
|
fields: {
|
|
remoteValues : 'results', // grouping for api results
|
|
values : 'values', // grouping for all dropdown values
|
|
disabled : 'disabled', // whether value should be disabled
|
|
name : 'name', // displayed dropdown text
|
|
description : 'description', // displayed dropdown description
|
|
descriptionVertical : 'descriptionVertical', // whether description should be vertical
|
|
value : 'value', // actual dropdown value
|
|
text : 'text', // displayed text when selected
|
|
type : 'type', // type of dropdown element
|
|
image : 'image', // optional image path
|
|
imageClass : 'imageClass', // optional individual class for image
|
|
icon : 'icon', // optional icon name
|
|
iconClass : 'iconClass', // optional individual class for icon (for example to use flag instead)
|
|
class : 'class', // optional individual class for item/header
|
|
divider : 'divider' // optional divider append for group headers
|
|
},
|
|
|
|
keys : {
|
|
backspace : 8,
|
|
delimiter : 188, // comma
|
|
deleteKey : 46,
|
|
enter : 13,
|
|
escape : 27,
|
|
pageUp : 33,
|
|
pageDown : 34,
|
|
leftArrow : 37,
|
|
upArrow : 38,
|
|
rightArrow : 39,
|
|
downArrow : 40
|
|
},
|
|
|
|
selector : {
|
|
addition : '.addition',
|
|
divider : '.divider, .header',
|
|
dropdown : '.ui.dropdown',
|
|
hidden : '.hidden',
|
|
icon : '> .dropdown.icon',
|
|
input : '> input[type="hidden"], > select',
|
|
item : '.item',
|
|
label : '> .label',
|
|
remove : '> .label > .delete.icon',
|
|
siblingLabel : '.label',
|
|
menu : '.menu',
|
|
message : '.message',
|
|
menuIcon : '.dropdown.icon',
|
|
search : 'input.search, .menu > .search > input, .menu input.search',
|
|
sizer : '> span.sizer',
|
|
text : '> .text:not(.icon)',
|
|
unselectable : '.disabled, .filtered',
|
|
clearIcon : '> .remove.icon'
|
|
},
|
|
|
|
className : {
|
|
active : 'active',
|
|
addition : 'addition',
|
|
animating : 'animating',
|
|
description : 'description',
|
|
descriptionVertical : 'vertical',
|
|
disabled : 'disabled',
|
|
empty : 'empty',
|
|
dropdown : 'ui dropdown',
|
|
filtered : 'filtered',
|
|
hidden : 'hidden transition',
|
|
icon : 'icon',
|
|
image : 'image',
|
|
item : 'item',
|
|
label : 'ui label',
|
|
loading : 'loading',
|
|
menu : 'menu',
|
|
message : 'message',
|
|
multiple : 'multiple',
|
|
placeholder : 'default',
|
|
sizer : 'sizer',
|
|
search : 'search',
|
|
selected : 'selected',
|
|
selection : 'selection',
|
|
text : 'text',
|
|
upward : 'upward',
|
|
leftward : 'left',
|
|
visible : 'visible',
|
|
clearable : 'clearable',
|
|
noselection : 'noselection',
|
|
delete : 'delete',
|
|
header : 'header',
|
|
divider : 'divider',
|
|
groupIcon : '',
|
|
unfilterable : 'unfilterable'
|
|
}
|
|
|
|
};
|
|
|
|
/* Templates */
|
|
$.fn.dropdown.settings.templates = {
|
|
deQuote: function(string, encode) {
|
|
return String(string).replace(/"/g,encode ? """ : "");
|
|
},
|
|
escape: function(string, preserveHTML) {
|
|
if (preserveHTML){
|
|
return string;
|
|
}
|
|
var
|
|
badChars = /[<>"'`]/g,
|
|
shouldEscape = /[&<>"'`]/,
|
|
escape = {
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
"`": "`"
|
|
},
|
|
escapedChar = function(chr) {
|
|
return escape[chr];
|
|
}
|
|
;
|
|
if(shouldEscape.test(string)) {
|
|
string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&");
|
|
return string.replace(badChars, escapedChar);
|
|
}
|
|
return string;
|
|
},
|
|
// generates dropdown from select values
|
|
dropdown: function(select, fields, preserveHTML, className) {
|
|
var
|
|
placeholder = select.placeholder || false,
|
|
html = '',
|
|
escape = $.fn.dropdown.settings.templates.escape
|
|
;
|
|
html += '<i class="dropdown icon"></i>';
|
|
if(placeholder) {
|
|
html += '<div class="default text">' + escape(placeholder,preserveHTML) + '</div>';
|
|
}
|
|
else {
|
|
html += '<div class="text"></div>';
|
|
}
|
|
html += '<div class="'+className.menu+'">';
|
|
html += $.fn.dropdown.settings.templates.menu(select, fields, preserveHTML,className);
|
|
html += '</div>';
|
|
return html;
|
|
},
|
|
|
|
// generates just menu from select
|
|
menu: function(response, fields, preserveHTML, className) {
|
|
var
|
|
values = response[fields.values] || [],
|
|
html = '',
|
|
escape = $.fn.dropdown.settings.templates.escape,
|
|
deQuote = $.fn.dropdown.settings.templates.deQuote
|
|
;
|
|
$.each(values, function(index, option) {
|
|
var
|
|
itemType = (option[fields.type])
|
|
? option[fields.type]
|
|
: 'item',
|
|
isMenu = itemType.indexOf('menu') !== -1
|
|
;
|
|
|
|
if( itemType === 'item' || isMenu) {
|
|
var
|
|
maybeText = (option[fields.text])
|
|
? ' data-text="' + deQuote(option[fields.text],true) + '"'
|
|
: '',
|
|
maybeDisabled = (option[fields.disabled])
|
|
? className.disabled+' '
|
|
: '',
|
|
maybeDescriptionVertical = (option[fields.descriptionVertical])
|
|
? className.descriptionVertical+' '
|
|
: '',
|
|
hasDescription = (escape(option[fields.description] || '', preserveHTML) != '')
|
|
;
|
|
html += '<div class="'+ maybeDisabled + maybeDescriptionVertical + (option[fields.class] ? deQuote(option[fields.class]) : className.item)+'" data-value="' + deQuote(option[fields.value],true) + '"' + maybeText + '>';
|
|
if (isMenu) {
|
|
html += '<i class="'+ (itemType.indexOf('left') !== -1 ? 'left' : '') + ' dropdown icon"></i>';
|
|
}
|
|
if(option[fields.image]) {
|
|
html += '<img class="'+(option[fields.imageClass] ? deQuote(option[fields.imageClass]) : className.image)+'" src="' + deQuote(option[fields.image]) + '">';
|
|
}
|
|
if(option[fields.icon]) {
|
|
html += '<i class="'+deQuote(option[fields.icon])+' '+(option[fields.iconClass] ? deQuote(option[fields.iconClass]) : className.icon)+'"></i>';
|
|
}
|
|
if(hasDescription){
|
|
html += '<span class="'+ className.description +'">'+ escape(option[fields.description] || '', preserveHTML) + '</span>';
|
|
html += (!isMenu) ? '<span class="'+ className.text + '">' : '';
|
|
}
|
|
if (isMenu) {
|
|
html += '<span class="' + className.text + '">';
|
|
}
|
|
html += escape(option[fields.name] || '', preserveHTML);
|
|
if (isMenu) {
|
|
html += '</span>';
|
|
html += '<div class="' + itemType + '">';
|
|
html += $.fn.dropdown.settings.templates.menu(option, fields, preserveHTML, className);
|
|
html += '</div>';
|
|
} else if(hasDescription){
|
|
html += '</span>';
|
|
}
|
|
html += '</div>';
|
|
} else if (itemType === 'header') {
|
|
var groupName = escape(option[fields.name] || '', preserveHTML),
|
|
groupIcon = option[fields.icon] ? deQuote(option[fields.icon]) : className.groupIcon
|
|
;
|
|
if(groupName !== '' || groupIcon !== '') {
|
|
html += '<div class="' + (option[fields.class] ? deQuote(option[fields.class]) : className.header) + '">';
|
|
if (groupIcon !== '') {
|
|
html += '<i class="' + groupIcon + ' ' + (option[fields.iconClass] ? deQuote(option[fields.iconClass]) : className.icon) + '"></i>';
|
|
}
|
|
html += groupName;
|
|
html += '</div>';
|
|
}
|
|
if(option[fields.divider]){
|
|
html += '<div class="'+className.divider+'"></div>';
|
|
}
|
|
}
|
|
});
|
|
return html;
|
|
},
|
|
|
|
// generates label for multiselect
|
|
label: function(value, text, preserveHTML, className) {
|
|
var
|
|
escape = $.fn.dropdown.settings.templates.escape;
|
|
return escape(text,preserveHTML) + '<i class="'+className.delete+' icon"></i>';
|
|
},
|
|
|
|
|
|
// generates messages like "No results"
|
|
message: function(message) {
|
|
return message;
|
|
},
|
|
|
|
// generates user addition to selection menu
|
|
addition: function(choice) {
|
|
return choice;
|
|
}
|
|
|
|
};
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Modal
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
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) { setTimeout(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,
|
|
fields = settings.fields,
|
|
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.hasClass('modal') ? $module.data(moduleNamespace) : undefined,
|
|
|
|
ignoreRepeatedEvents = false,
|
|
|
|
initialMouseDownInModal,
|
|
initialMouseDownInScrollbar,
|
|
initialBodyMargin = '',
|
|
tempBodyMargin = '',
|
|
|
|
elementEventNamespace,
|
|
id,
|
|
observer,
|
|
module
|
|
;
|
|
module = {
|
|
|
|
initialize: function() {
|
|
if(!$module.hasClass('modal')) {
|
|
module.create.modal();
|
|
if(!$.isFunction(settings.onHidden)) {
|
|
settings.onHidden = function () {
|
|
module.destroy();
|
|
$module.remove();
|
|
};
|
|
}
|
|
}
|
|
$module.addClass(settings.class);
|
|
if (settings.title !== '') {
|
|
$module.find(selector.title).html(module.helpers.escape(settings.title, settings.preserveHTML)).addClass(settings.classTitle);
|
|
}
|
|
if (settings.content !== '') {
|
|
$module.find(selector.content).html(module.helpers.escape(settings.content, settings.preserveHTML)).addClass(settings.classContent);
|
|
}
|
|
if(module.has.configActions()){
|
|
var $actions = $module.find(selector.actions).addClass(settings.classActions);
|
|
if ($actions.length === 0) {
|
|
$actions = $('<div/>', {class: className.actions + ' ' + (settings.classActions || '')}).appendTo($module);
|
|
} else {
|
|
$actions.empty();
|
|
}
|
|
settings.actions.forEach(function (el) {
|
|
var icon = el[fields.icon] ? '<i class="' + module.helpers.deQuote(el[fields.icon]) + ' icon"></i>' : '',
|
|
text = module.helpers.escape(el[fields.text] || '', settings.preserveHTML),
|
|
cls = module.helpers.deQuote(el[fields.class] || ''),
|
|
click = el[fields.click] && $.isFunction(el[fields.click]) ? el[fields.click] : function () {};
|
|
$actions.append($('<button/>', {
|
|
html: icon + text,
|
|
class: className.button + ' ' + cls,
|
|
click: function () {
|
|
if (click.call(element, $module) === false) {
|
|
return;
|
|
}
|
|
module.hide();
|
|
}
|
|
}));
|
|
});
|
|
}
|
|
module.cache = {};
|
|
module.verbose('Initializing dimmer', $context);
|
|
|
|
module.create.id();
|
|
module.create.dimmer();
|
|
|
|
if ( settings.allowMultiple ) {
|
|
module.create.innerDimmer();
|
|
}
|
|
if (!settings.centered){
|
|
$module.addClass('top aligned');
|
|
}
|
|
module.refreshModals();
|
|
|
|
module.bind.events();
|
|
if(settings.observeChanges) {
|
|
module.observeChanges();
|
|
}
|
|
module.instantiate();
|
|
if(settings.autoShow){
|
|
module.show();
|
|
}
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of modal');
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, instance)
|
|
;
|
|
},
|
|
|
|
create: {
|
|
modal: function() {
|
|
$module = $('<div/>', {class: className.modal});
|
|
if (settings.closeIcon) {
|
|
$close = $('<i/>', {class: className.close})
|
|
$module.append($close);
|
|
}
|
|
if (settings.title !== '') {
|
|
$('<div/>', {class: className.title}).appendTo($module);
|
|
}
|
|
if (settings.content !== '') {
|
|
$('<div/>', {class: className.content}).appendTo($module);
|
|
}
|
|
if (module.has.configActions()) {
|
|
$('<div/>', {class: className.actions}).appendTo($module);
|
|
}
|
|
$context.append($module);
|
|
},
|
|
dimmer: function() {
|
|
var
|
|
defaultSettings = {
|
|
debug : settings.debug,
|
|
dimmerName : 'modals'
|
|
},
|
|
dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
|
|
;
|
|
if($.fn.dimmer === undefined) {
|
|
module.error(error.dimmer);
|
|
return;
|
|
}
|
|
module.debug('Creating dimmer');
|
|
$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();
|
|
}
|
|
$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);
|
|
},
|
|
innerDimmer: function() {
|
|
if ( $module.find(selector.dimmer).length == 0 ) {
|
|
$module.prepend('<div class="ui inverted dimmer"></div>');
|
|
}
|
|
}
|
|
},
|
|
|
|
destroy: function() {
|
|
if (observer) {
|
|
observer.disconnect();
|
|
}
|
|
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');
|
|
module.refresh();
|
|
});
|
|
observer.observe(element, {
|
|
childList : true,
|
|
subtree : true
|
|
});
|
|
module.debug('Setting up mutation observer', observer);
|
|
}
|
|
},
|
|
|
|
refresh: function() {
|
|
module.remove.scrolling();
|
|
module.cacheSizes();
|
|
if(!module.can.useFlex()) {
|
|
module.set.modalOffset();
|
|
}
|
|
module.set.screenHeight();
|
|
module.set.type();
|
|
},
|
|
|
|
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($toggle.length > 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)
|
|
;
|
|
},
|
|
scrollLock: function() {
|
|
// touch events default to passive, due to changes in chrome to optimize mobile perf
|
|
$dimmable.get(0).addEventListener('touchmove', module.event.preventScroll, { passive: false });
|
|
}
|
|
},
|
|
|
|
unbind: {
|
|
scrollLock: function() {
|
|
$dimmable.get(0).removeEventListener('touchmove', module.event.preventScroll, { passive: false });
|
|
}
|
|
},
|
|
|
|
get: {
|
|
id: function() {
|
|
return (Math.random().toString(16) + '000000000').substr(2, 8);
|
|
},
|
|
element: function() {
|
|
return $module;
|
|
},
|
|
settings: function() {
|
|
return settings;
|
|
}
|
|
},
|
|
|
|
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;
|
|
});
|
|
},
|
|
preventScroll: function(event) {
|
|
if(event.target.className.indexOf('dimmer') !== -1) {
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
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();
|
|
},
|
|
mousedown: function(event) {
|
|
var
|
|
$target = $(event.target),
|
|
isRtl = module.is.rtl();
|
|
;
|
|
initialMouseDownInModal = ($target.closest(selector.modal).length > 0);
|
|
if(initialMouseDownInModal) {
|
|
module.verbose('Mouse down event registered inside the modal');
|
|
}
|
|
initialMouseDownInScrollbar = module.is.scrolling() && ((!isRtl && $(window).outerWidth() - settings.scrollbarWidth <= event.clientX) || (isRtl && settings.scrollbarWidth >= event.clientX));
|
|
if(initialMouseDownInScrollbar) {
|
|
module.verbose('Mouse down event registered inside the scrollbar');
|
|
}
|
|
},
|
|
mouseup: function(event) {
|
|
if(!settings.closable) {
|
|
module.verbose('Dimmer clicked but closable setting is disabled');
|
|
return;
|
|
}
|
|
if(initialMouseDownInModal) {
|
|
module.debug('Dimmer clicked but mouse down was initially registered inside the modal');
|
|
return;
|
|
}
|
|
if(initialMouseDownInScrollbar){
|
|
module.debug('Dimmer clicked but mouse down was initially registered inside the scrollbar');
|
|
return;
|
|
}
|
|
var
|
|
$target = $(event.target),
|
|
isInModal = ($target.closest(selector.modal).length > 0),
|
|
isInDOM = $.contains(document.documentElement, event.target)
|
|
;
|
|
if(!isInModal && isInDOM && module.is.active() && $module.hasClass(className.front) ) {
|
|
module.debug('Dimmer clicked, hiding all modals');
|
|
if(settings.allowMultiple) {
|
|
if(!module.hideAll()) {
|
|
return;
|
|
}
|
|
}
|
|
else if(!module.hide()){
|
|
return;
|
|
}
|
|
module.remove.clickaway();
|
|
}
|
|
},
|
|
debounce: function(method, delay) {
|
|
clearTimeout(module.timer);
|
|
module.timer = setTimeout(method, delay);
|
|
},
|
|
keyboard: function(event) {
|
|
var
|
|
keyCode = event.which,
|
|
escapeKey = 27
|
|
;
|
|
if(keyCode == escapeKey) {
|
|
if(settings.closable) {
|
|
module.debug('Escape key pressed hiding modal');
|
|
if ( $module.hasClass(className.front) ) {
|
|
module.hide();
|
|
}
|
|
}
|
|
else {
|
|
module.debug('Escape key pressed, but closable is set to false');
|
|
}
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
resize: function() {
|
|
if( $dimmable.dimmer('is active') && ( module.is.animating() || module.is.active() ) ) {
|
|
requestAnimationFrame(module.refresh);
|
|
}
|
|
}
|
|
},
|
|
|
|
toggle: function() {
|
|
if( module.is.active() || module.is.animating() ) {
|
|
module.hide();
|
|
}
|
|
else {
|
|
module.show();
|
|
}
|
|
},
|
|
|
|
show: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
module.refreshModals();
|
|
module.set.dimmerSettings();
|
|
module.set.dimmerStyles();
|
|
|
|
module.showModal(callback);
|
|
},
|
|
|
|
hide: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
module.refreshModals();
|
|
return module.hideModal(callback);
|
|
},
|
|
|
|
showModal: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if( module.is.animating() || !module.is.active() ) {
|
|
module.showDimmer();
|
|
module.cacheSizes();
|
|
module.set.bodyMargin();
|
|
if(module.can.useFlex()) {
|
|
module.remove.legacy();
|
|
}
|
|
else {
|
|
module.set.legacy();
|
|
module.set.modalOffset();
|
|
module.debug('Using non-flex legacy modal positioning.');
|
|
}
|
|
module.set.screenHeight();
|
|
module.set.type();
|
|
module.set.clickaway();
|
|
|
|
if( !settings.allowMultiple && module.others.active() ) {
|
|
module.hideOthers(module.showModal);
|
|
}
|
|
else {
|
|
ignoreRepeatedEvents = false;
|
|
if( settings.allowMultiple ) {
|
|
if ( module.others.active() ) {
|
|
$otherModals.filter('.' + className.active).find(selector.dimmer).addClass('active');
|
|
}
|
|
|
|
if ( settings.detachable ) {
|
|
$module.detach().appendTo($dimmer);
|
|
}
|
|
}
|
|
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.showMethod || settings.transition) + ' in',
|
|
queue : settings.queue,
|
|
duration : settings.transition.showDuration || 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, hideOthersToo) {
|
|
var
|
|
$previousModal = $otherModals.filter('.' + className.active).last()
|
|
;
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
module.debug('Hiding modal');
|
|
if(settings.onHide.call(element, $(this)) === false) {
|
|
module.verbose('Hide callback returned false cancelling hide');
|
|
ignoreRepeatedEvents = false;
|
|
return false;
|
|
}
|
|
|
|
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.hideMethod || settings.transition) + ' out',
|
|
queue : settings.queue,
|
|
duration : settings.transition.hideDuration || settings.duration,
|
|
useFailSafe : true,
|
|
onStart : function() {
|
|
if(!module.others.active() && !module.others.animating() && !keepDimmed) {
|
|
module.hideDimmer();
|
|
}
|
|
if( settings.keyboardShortcuts && !module.others.active() ) {
|
|
module.remove.keyboardShortcuts();
|
|
}
|
|
},
|
|
onComplete : function() {
|
|
module.unbind.scrollLock();
|
|
if ( settings.allowMultiple ) {
|
|
$previousModal.addClass(className.front);
|
|
$module.removeClass(className.front);
|
|
|
|
if ( hideOthersToo ) {
|
|
$allModals.find(selector.dimmer).removeClass('active');
|
|
}
|
|
else {
|
|
$previousModal.find(selector.dimmer).removeClass('active');
|
|
}
|
|
}
|
|
if($.isFunction(settings.onHidden)) {
|
|
settings.onHidden.call(element);
|
|
}
|
|
module.remove.dimmerStyles();
|
|
module.restore.focus();
|
|
callback();
|
|
}
|
|
})
|
|
;
|
|
}
|
|
else {
|
|
module.error(error.noTransition);
|
|
}
|
|
}
|
|
},
|
|
|
|
showDimmer: function() {
|
|
if($dimmable.dimmer('is animating') || !$dimmable.dimmer('is active') ) {
|
|
module.save.bodyMargin();
|
|
module.debug('Showing dimmer');
|
|
$dimmable.dimmer('show');
|
|
}
|
|
else {
|
|
module.debug('Dimmer already visible');
|
|
}
|
|
},
|
|
|
|
hideDimmer: function() {
|
|
if( $dimmable.dimmer('is animating') || ($dimmable.dimmer('is active')) ) {
|
|
module.unbind.scrollLock();
|
|
$dimmable.dimmer('hide', function() {
|
|
module.restore.bodyMargin();
|
|
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( $visibleModals.length > 0 ) {
|
|
module.debug('Hiding all visible modals');
|
|
var hideOk = true;
|
|
//check in reverse order trying to hide most top displayed modal first
|
|
$($visibleModals.get().reverse()).each(function(index,element){
|
|
if(hideOk){
|
|
hideOk = $(element).modal('hide modal', callback, false, true);
|
|
}
|
|
});
|
|
if(hideOk) {
|
|
module.hideDimmer();
|
|
}
|
|
return hideOk;
|
|
}
|
|
},
|
|
|
|
hideOthers: function(callback) {
|
|
var
|
|
$visibleModals = $otherModals.filter('.' + className.active + ', .' + className.animating)
|
|
;
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if( $visibleModals.length > 0 ) {
|
|
module.debug('Hiding other modals', $otherModals);
|
|
$visibleModals
|
|
.modal('hide modal', callback, true)
|
|
;
|
|
}
|
|
},
|
|
|
|
others: {
|
|
active: function() {
|
|
return ($otherModals.filter('.' + className.active).length > 0);
|
|
},
|
|
animating: function() {
|
|
return ($otherModals.filter('.' + className.animating).length > 0);
|
|
}
|
|
},
|
|
|
|
|
|
add: {
|
|
keyboardShortcuts: function() {
|
|
module.verbose('Adding keyboard shortcuts');
|
|
$document
|
|
.on('keyup' + eventNamespace, module.event.keyboard)
|
|
;
|
|
}
|
|
},
|
|
|
|
save: {
|
|
focus: function() {
|
|
var
|
|
$activeElement = $(document.activeElement),
|
|
inCurrentModal = $activeElement.closest($module).length > 0
|
|
;
|
|
if(!inCurrentModal) {
|
|
$focusedElement = $(document.activeElement).blur();
|
|
}
|
|
},
|
|
bodyMargin: function() {
|
|
initialBodyMargin = $body.css('margin-'+(module.can.leftBodyScrollbar() ? 'left':'right'));
|
|
var bodyMarginRightPixel = parseInt(initialBodyMargin.replace(/[^\d.]/g, '')),
|
|
bodyScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
tempBodyMargin = bodyMarginRightPixel + bodyScrollbarWidth;
|
|
}
|
|
},
|
|
|
|
restore: {
|
|
focus: function() {
|
|
if($focusedElement && $focusedElement.length > 0 && settings.restoreFocus) {
|
|
$focusedElement.focus();
|
|
}
|
|
},
|
|
bodyMargin: function() {
|
|
var position = module.can.leftBodyScrollbar() ? 'left':'right';
|
|
$body.css('margin-'+position, initialBodyMargin);
|
|
$body.find(selector.bodyFixed.replace('right',position)).each(function(){
|
|
var el = $(this),
|
|
attribute = el.css('position') === 'fixed' ? 'padding-'+position : position
|
|
;
|
|
el.css(attribute, '');
|
|
});
|
|
}
|
|
},
|
|
|
|
remove: {
|
|
active: function() {
|
|
$module.removeClass(className.active);
|
|
},
|
|
legacy: function() {
|
|
$module.removeClass(className.legacy);
|
|
},
|
|
clickaway: function() {
|
|
if (!settings.detachable) {
|
|
$module
|
|
.off('mousedown' + elementEventNamespace)
|
|
;
|
|
}
|
|
$dimmer
|
|
.off('mousedown' + elementEventNamespace)
|
|
;
|
|
$dimmer
|
|
.off('mouseup' + elementEventNamespace)
|
|
;
|
|
},
|
|
dimmerStyles: function() {
|
|
$dimmer.removeClass(className.inverted);
|
|
$dimmable.removeClass(className.blurring);
|
|
},
|
|
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() {
|
|
$module.addClass(className.loading);
|
|
var
|
|
scrollHeight = $module.prop('scrollHeight'),
|
|
modalWidth = $module.outerWidth(),
|
|
modalHeight = $module.outerHeight()
|
|
;
|
|
if(module.cache.pageHeight === undefined || modalHeight !== 0) {
|
|
$.extend(module.cache, {
|
|
pageHeight : $(document).outerHeight(),
|
|
width : modalWidth,
|
|
height : modalHeight + settings.offset,
|
|
scrollHeight : scrollHeight + settings.offset,
|
|
contextHeight : (settings.context == 'body')
|
|
? $(window).height()
|
|
: $dimmable.height(),
|
|
});
|
|
module.cache.topOffset = -(module.cache.height / 2);
|
|
}
|
|
$module.removeClass(className.loading);
|
|
module.debug('Caching modal and container sizes', module.cache);
|
|
},
|
|
helpers: {
|
|
deQuote: function(string) {
|
|
return String(string).replace(/"/g,"");
|
|
},
|
|
escape: function(string, preserveHTML) {
|
|
if (preserveHTML){
|
|
return string;
|
|
}
|
|
var
|
|
badChars = /[<>"'`]/g,
|
|
shouldEscape = /[&<>"'`]/,
|
|
escape = {
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
"`": "`"
|
|
},
|
|
escapedChar = function(chr) {
|
|
return escape[chr];
|
|
}
|
|
;
|
|
if(shouldEscape.test(string)) {
|
|
string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&");
|
|
return string.replace(badChars, escapedChar);
|
|
}
|
|
return string;
|
|
}
|
|
},
|
|
can: {
|
|
leftBodyScrollbar: function(){
|
|
if(module.cache.leftBodyScrollbar === undefined) {
|
|
module.cache.leftBodyScrollbar = module.is.rtl() && ((module.is.iframe && !module.is.firefox()) || module.is.safari() || module.is.edge() || module.is.ie());
|
|
}
|
|
return module.cache.leftBodyScrollbar;
|
|
},
|
|
useFlex: function() {
|
|
if (settings.useFlex === 'auto') {
|
|
return settings.detachable && !module.is.ie();
|
|
}
|
|
if(settings.useFlex && module.is.ie()) {
|
|
module.debug('useFlex true is not supported in IE');
|
|
} else if(settings.useFlex && !settings.detachable) {
|
|
module.debug('useFlex true in combination with detachable false is not supported');
|
|
}
|
|
return settings.useFlex;
|
|
},
|
|
fit: function() {
|
|
var
|
|
contextHeight = module.cache.contextHeight,
|
|
verticalCenter = module.cache.contextHeight / 2,
|
|
topOffset = module.cache.topOffset,
|
|
scrollHeight = module.cache.scrollHeight,
|
|
height = module.cache.height,
|
|
paddingHeight = settings.padding,
|
|
startPosition = (verticalCenter + topOffset)
|
|
;
|
|
return (scrollHeight > height)
|
|
? (startPosition + scrollHeight + paddingHeight < contextHeight)
|
|
: (height + (paddingHeight * 2) < contextHeight)
|
|
;
|
|
}
|
|
},
|
|
has: {
|
|
configActions: function () {
|
|
return Array.isArray(settings.actions) && settings.actions.length > 0;
|
|
}
|
|
},
|
|
is: {
|
|
active: function() {
|
|
return $module.hasClass(className.active);
|
|
},
|
|
ie: function() {
|
|
if(module.cache.isIE === undefined) {
|
|
var
|
|
isIE11 = (!(window.ActiveXObject) && 'ActiveXObject' in window),
|
|
isIE = ('ActiveXObject' in window)
|
|
;
|
|
module.cache.isIE = (isIE11 || isIE);
|
|
}
|
|
return module.cache.isIE;
|
|
},
|
|
animating: function() {
|
|
return $module.transition('is supported')
|
|
? $module.transition('is animating')
|
|
: $module.is(':visible')
|
|
;
|
|
},
|
|
scrolling: function() {
|
|
return $dimmable.hasClass(className.scrolling);
|
|
},
|
|
modernBrowser: function() {
|
|
// appName for IE11 reports 'Netscape' can no longer use
|
|
return !(window.ActiveXObject || 'ActiveXObject' in window);
|
|
},
|
|
rtl: function() {
|
|
if(module.cache.isRTL === undefined) {
|
|
module.cache.isRTL = $body.attr('dir') === 'rtl' || $body.css('direction') === 'rtl';
|
|
}
|
|
return module.cache.isRTL;
|
|
},
|
|
safari: function() {
|
|
if(module.cache.isSafari === undefined) {
|
|
module.cache.isSafari = /constructor/i.test(window.HTMLElement) || !!window.ApplePaySession;
|
|
}
|
|
return module.cache.isSafari;
|
|
},
|
|
edge: function(){
|
|
if(module.cache.isEdge === undefined) {
|
|
module.cache.isEdge = !!window.setImmediate && !module.is.ie();
|
|
}
|
|
return module.cache.isEdge;
|
|
},
|
|
firefox: function(){
|
|
if(module.cache.isFirefox === undefined) {
|
|
module.cache.isFirefox = !!window.InstallTrigger;
|
|
}
|
|
return module.cache.isFirefox;
|
|
},
|
|
iframe: function() {
|
|
return !(self === top);
|
|
}
|
|
},
|
|
|
|
set: {
|
|
autofocus: function() {
|
|
var
|
|
$inputs = $module.find('[tabindex], :input').filter(':visible').filter(function() {
|
|
return $(this).closest('.disabled').length === 0;
|
|
}),
|
|
$autofocus = $inputs.filter('[autofocus]'),
|
|
$input = ($autofocus.length > 0)
|
|
? $autofocus.first()
|
|
: $inputs.first()
|
|
;
|
|
if($input.length > 0) {
|
|
$input.focus();
|
|
}
|
|
},
|
|
bodyMargin: function() {
|
|
var position = module.can.leftBodyScrollbar() ? 'left':'right';
|
|
if(settings.detachable || module.can.fit()) {
|
|
$body.css('margin-'+position, tempBodyMargin + 'px');
|
|
}
|
|
$body.find(selector.bodyFixed.replace('right',position)).each(function(){
|
|
var el = $(this),
|
|
attribute = el.css('position') === 'fixed' ? 'padding-'+position : position
|
|
;
|
|
el.css(attribute, 'calc(' + el.css(attribute) + ' + ' + tempBodyMargin + 'px)');
|
|
});
|
|
},
|
|
clickaway: function() {
|
|
if (!settings.detachable) {
|
|
$module
|
|
.on('mousedown' + elementEventNamespace, module.event.mousedown)
|
|
;
|
|
}
|
|
$dimmer
|
|
.on('mousedown' + elementEventNamespace, module.event.mousedown)
|
|
;
|
|
$dimmer
|
|
.on('mouseup' + elementEventNamespace, module.event.mouseup)
|
|
;
|
|
},
|
|
dimmerSettings: function() {
|
|
if($.fn.dimmer === undefined) {
|
|
module.error(error.dimmer);
|
|
return;
|
|
}
|
|
var
|
|
defaultSettings = {
|
|
debug : settings.debug,
|
|
dimmerName : 'modals',
|
|
closable : 'auto',
|
|
useFlex : module.can.useFlex(),
|
|
duration : {
|
|
show : settings.transition.showDuration || settings.duration,
|
|
hide : settings.transition.hideDuration || settings.duration
|
|
}
|
|
},
|
|
dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
|
|
;
|
|
if(settings.inverted) {
|
|
dimmerSettings.variation = (dimmerSettings.variation !== undefined)
|
|
? dimmerSettings.variation + ' inverted'
|
|
: 'inverted'
|
|
;
|
|
}
|
|
$context.dimmer('setting', dimmerSettings);
|
|
},
|
|
dimmerStyles: function() {
|
|
if(settings.inverted) {
|
|
$dimmer.addClass(className.inverted);
|
|
}
|
|
else {
|
|
$dimmer.removeClass(className.inverted);
|
|
}
|
|
if(settings.blurring) {
|
|
$dimmable.addClass(className.blurring);
|
|
}
|
|
else {
|
|
$dimmable.removeClass(className.blurring);
|
|
}
|
|
},
|
|
modalOffset: function() {
|
|
if (!settings.detachable) {
|
|
var canFit = module.can.fit();
|
|
$module
|
|
.css({
|
|
top: (!$module.hasClass('aligned') && canFit)
|
|
? $(document).scrollTop() + (module.cache.contextHeight - module.cache.height) / 2
|
|
: !canFit || $module.hasClass('top')
|
|
? $(document).scrollTop() + settings.padding
|
|
: $(document).scrollTop() + (module.cache.contextHeight - module.cache.height - settings.padding),
|
|
marginLeft: -(module.cache.width / 2)
|
|
})
|
|
;
|
|
} else {
|
|
$module
|
|
.css({
|
|
marginTop: (!$module.hasClass('aligned') && module.can.fit())
|
|
? -(module.cache.height / 2)
|
|
: settings.padding / 2,
|
|
marginLeft: -(module.cache.width / 2)
|
|
})
|
|
;
|
|
}
|
|
module.verbose('Setting modal offset for legacy mode');
|
|
},
|
|
screenHeight: function() {
|
|
if( module.can.fit() ) {
|
|
$body.css('height', '');
|
|
}
|
|
else if(!$module.hasClass('bottom')) {
|
|
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 + ' ' + className.front);
|
|
$otherModals.filter('.' + className.active).removeClass(className.front);
|
|
},
|
|
scrolling: function() {
|
|
$dimmable.addClass(className.scrolling);
|
|
$module.addClass(className.scrolling);
|
|
module.unbind.scrollLock();
|
|
},
|
|
legacy: function() {
|
|
$module.addClass(className.legacy);
|
|
},
|
|
type: function() {
|
|
if(module.can.fit()) {
|
|
module.verbose('Modal fits on screen');
|
|
if(!module.others.active() && !module.others.animating()) {
|
|
module.remove.scrolling();
|
|
module.bind.scrollLock();
|
|
}
|
|
}
|
|
else if (!$module.hasClass('bottom')){
|
|
module.verbose('Modal cannot fit on screen setting to scrolling');
|
|
module.set.scrolling();
|
|
} else {
|
|
module.verbose('Bottom aligned modal not fitting on screen is unsupported for scrolling');
|
|
}
|
|
},
|
|
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 = setTimeout(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) && performance.length > 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 = query.length - 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(Array.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) {
|
|
if ($.isFunction(settings.templates[query])) {
|
|
settings.autoShow = true;
|
|
settings.className.modal = settings.className.template;
|
|
settings = $.extend(true, {}, settings, settings.templates[query].apply(module ,queryArguments));
|
|
|
|
// reassign shortcuts
|
|
className = settings.className;
|
|
namespace = settings.namespace;
|
|
fields = settings.fields;
|
|
error = settings.error;
|
|
}
|
|
module.initialize();
|
|
}
|
|
if (!$.isFunction(settings.templates[query])) {
|
|
module.invoke(query);
|
|
}
|
|
}
|
|
else {
|
|
if(instance !== undefined) {
|
|
instance.invoke('destroy');
|
|
}
|
|
module.initialize();
|
|
returnedValue = $module;
|
|
}
|
|
})
|
|
;
|
|
|
|
return (returnedValue !== undefined)
|
|
? returnedValue
|
|
: this
|
|
;
|
|
};
|
|
|
|
$.fn.modal.settings = {
|
|
|
|
name : 'Modal',
|
|
namespace : 'modal',
|
|
|
|
useFlex : 'auto',
|
|
offset : 0,
|
|
|
|
silent : false,
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
observeChanges : false,
|
|
|
|
allowMultiple : false,
|
|
detachable : true,
|
|
closable : true,
|
|
autofocus : true,
|
|
restoreFocus : true,
|
|
autoShow : false,
|
|
|
|
inverted : false,
|
|
blurring : false,
|
|
|
|
centered : true,
|
|
|
|
dimmerSettings : {
|
|
closable : false,
|
|
useCSS : true
|
|
},
|
|
|
|
// whether to use keyboard shortcuts
|
|
keyboardShortcuts: true,
|
|
|
|
context : 'body',
|
|
|
|
queue : false,
|
|
duration : 500,
|
|
transition : 'scale',
|
|
|
|
// padding with edge of page
|
|
padding : 50,
|
|
scrollbarWidth: 10,
|
|
|
|
//dynamic content
|
|
title : '',
|
|
content : '',
|
|
class : '',
|
|
classTitle : '',
|
|
classContent : '',
|
|
classActions : '',
|
|
closeIcon : false,
|
|
actions : false,
|
|
preserveHTML : true,
|
|
|
|
fields : {
|
|
class : 'class',
|
|
text : 'text',
|
|
icon : 'icon',
|
|
click : 'click'
|
|
},
|
|
|
|
// called before show animation
|
|
onShow : function(){},
|
|
|
|
// called after show animation
|
|
onVisible : function(){},
|
|
|
|
// called before hide animation
|
|
onHide : function(){ return true; },
|
|
|
|
// called after hide animation
|
|
onHidden : false,
|
|
|
|
// called after approve selector match
|
|
onApprove : function(){ return true; },
|
|
|
|
// called after deny selector match
|
|
onDeny : function(){ return true; },
|
|
|
|
selector : {
|
|
title : '> .header',
|
|
content : '> .content',
|
|
actions : '> .actions',
|
|
close : '> .close',
|
|
approve : '.actions .positive, .actions .approve, .actions .ok',
|
|
deny : '.actions .negative, .actions .deny, .actions .cancel',
|
|
modal : '.ui.modal',
|
|
dimmer : '> .ui.dimmer',
|
|
bodyFixed: '> .ui.fixed.menu, > .ui.right.toast-container, > .ui.right.sidebar, > .ui.fixed.nag, > .ui.fixed.nag > .close',
|
|
prompt : '.ui.input > input'
|
|
},
|
|
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',
|
|
inverted : 'inverted',
|
|
legacy : 'legacy',
|
|
loading : 'loading',
|
|
scrolling : 'scrolling',
|
|
undetached : 'undetached',
|
|
front : 'front',
|
|
close : 'close icon',
|
|
button : 'ui button',
|
|
modal : 'ui modal',
|
|
title : 'header',
|
|
content : 'content',
|
|
actions : 'actions',
|
|
template : 'ui tiny modal',
|
|
ok : 'positive',
|
|
cancel : 'negative',
|
|
prompt : 'ui fluid input'
|
|
},
|
|
text: {
|
|
ok : 'Ok',
|
|
cancel: 'Cancel'
|
|
}
|
|
};
|
|
|
|
$.fn.modal.settings.templates = {
|
|
getArguments: function(args) {
|
|
var queryArguments = [].slice.call(args);
|
|
if($.isPlainObject(queryArguments[0])){
|
|
return $.extend({
|
|
handler:function(){},
|
|
content:'',
|
|
title: ''
|
|
}, queryArguments[0]);
|
|
} else {
|
|
if(!$.isFunction(queryArguments[queryArguments.length-1])) {
|
|
queryArguments.push(function() {});
|
|
}
|
|
return {
|
|
handler: queryArguments.pop(),
|
|
content: queryArguments.pop() || '',
|
|
title: queryArguments.pop() || ''
|
|
};
|
|
}
|
|
},
|
|
alert: function () {
|
|
var settings = this.get.settings(),
|
|
args = settings.templates.getArguments(arguments)
|
|
;
|
|
return {
|
|
title : args.title,
|
|
content: args.content,
|
|
actions: [{
|
|
text : settings.text.ok,
|
|
class: settings.className.ok,
|
|
click: args.handler
|
|
}]
|
|
}
|
|
},
|
|
confirm: function () {
|
|
var settings = this.get.settings(),
|
|
args = settings.templates.getArguments(arguments)
|
|
;
|
|
return {
|
|
title : args.title,
|
|
content: args.content,
|
|
actions: [{
|
|
text : settings.text.ok,
|
|
class: settings.className.ok,
|
|
click: function(){args.handler(true)}
|
|
},{
|
|
text: settings.text.cancel,
|
|
class: settings.className.cancel,
|
|
click: function(){args.handler(false)}
|
|
}]
|
|
}
|
|
},
|
|
prompt: function () {
|
|
var $this = this,
|
|
settings = this.get.settings(),
|
|
args = settings.templates.getArguments(arguments),
|
|
input = $($.parseHTML(args.content)).filter('.ui.input')
|
|
;
|
|
if (input.length === 0) {
|
|
args.content += '<p><div class="'+settings.className.prompt+'"><input placeholder="'+this.helpers.deQuote(args.placeholder || '')+'" type="text" value="'+this.helpers.deQuote(args.defaultValue || '')+'"></div></p>';
|
|
}
|
|
return {
|
|
title : args.title,
|
|
content: args.content,
|
|
actions: [{
|
|
text: settings.text.ok,
|
|
class: settings.className.ok,
|
|
click: function(){
|
|
var settings = $this.get.settings(),
|
|
inputField = $this.get.element().find(settings.selector.prompt)[0]
|
|
;
|
|
args.handler($(inputField).val());
|
|
}
|
|
},{
|
|
text: settings.text.cancel,
|
|
class: settings.className.cancel,
|
|
click: function(){args.handler(null)}
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Progress
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
window = (typeof window != 'undefined' && window.Math == Math)
|
|
? window
|
|
: (typeof self != 'undefined' && self.Math == Math)
|
|
? self
|
|
: Function('return this')()
|
|
;
|
|
|
|
$.fn.progress = function(parameters) {
|
|
var
|
|
$allModules = $(this),
|
|
|
|
moduleSelector = $allModules.selector || '',
|
|
|
|
time = new Date().getTime(),
|
|
performance = [],
|
|
|
|
query = arguments[0],
|
|
methodInvoked = (typeof query == 'string'),
|
|
queryArguments = [].slice.call(arguments, 1),
|
|
|
|
returnedValue
|
|
;
|
|
|
|
$allModules
|
|
.each(function() {
|
|
var
|
|
settings = ( $.isPlainObject(parameters) )
|
|
? $.extend(true, {}, $.fn.progress.settings, parameters)
|
|
: $.extend({}, $.fn.progress.settings),
|
|
|
|
className = settings.className,
|
|
metadata = settings.metadata,
|
|
namespace = settings.namespace,
|
|
selector = settings.selector,
|
|
error = settings.error,
|
|
|
|
eventNamespace = '.' + namespace,
|
|
moduleNamespace = 'module-' + namespace,
|
|
|
|
$module = $(this),
|
|
$bars = $(this).find(selector.bar),
|
|
$progresses = $(this).find(selector.progress),
|
|
$label = $(this).find(selector.label),
|
|
|
|
element = this,
|
|
instance = $module.data(moduleNamespace),
|
|
|
|
animating = false,
|
|
transitionEnd,
|
|
module
|
|
;
|
|
module = {
|
|
helper: {
|
|
sum: function (nums) {
|
|
return Array.isArray(nums) ? nums.reduce(function (left, right) {
|
|
return left + Number(right);
|
|
}, 0) : 0;
|
|
},
|
|
/**
|
|
* Derive precision for multiple progress with total and values.
|
|
*
|
|
* This helper dervices a precision that is sufficiently large to show minimum value of multiple progress.
|
|
*
|
|
* Example1
|
|
* - total: 1122
|
|
* - values: [325, 111, 74, 612]
|
|
* - min ratio: 74/1122 = 0.0659...
|
|
* - required precision: 100
|
|
*
|
|
* Example2
|
|
* - total: 10541
|
|
* - values: [3235, 1111, 74, 6121]
|
|
* - min ratio: 74/10541 = 0.0070...
|
|
* - required precision: 1000
|
|
*
|
|
* @param min A minimum value within multiple values
|
|
* @param total A total amount of multiple values
|
|
* @returns {number} A precison. Could be 1, 10, 100, ... 1e+10.
|
|
*/
|
|
derivePrecision: function(min, total) {
|
|
var precisionPower = 0
|
|
var precision = 1;
|
|
var ratio = min / total;
|
|
while (precisionPower < 10) {
|
|
ratio = ratio * precision;
|
|
if (ratio > 1) {
|
|
break;
|
|
}
|
|
precision = Math.pow(10, precisionPower++);
|
|
}
|
|
return precision;
|
|
},
|
|
forceArray: function (element) {
|
|
return Array.isArray(element)
|
|
? element
|
|
: !isNaN(element)
|
|
? [element]
|
|
: typeof element == 'string'
|
|
? element.split(',')
|
|
: []
|
|
;
|
|
}
|
|
},
|
|
|
|
initialize: function() {
|
|
module.set.duration();
|
|
module.set.transitionEvent();
|
|
module.debug(element);
|
|
|
|
module.read.metadata();
|
|
module.read.settings();
|
|
|
|
module.instantiate();
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of progress', module);
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, module)
|
|
;
|
|
},
|
|
destroy: function() {
|
|
module.verbose('Destroying previous progress for', $module);
|
|
clearInterval(instance.interval);
|
|
module.remove.state();
|
|
$module.removeData(moduleNamespace);
|
|
instance = undefined;
|
|
},
|
|
|
|
reset: function() {
|
|
module.remove.nextValue();
|
|
module.update.progress(0);
|
|
},
|
|
|
|
complete: function(keepState) {
|
|
if(module.percent === undefined || module.percent < 100) {
|
|
module.remove.progressPoll();
|
|
if(keepState !== true){
|
|
module.set.percent(100);
|
|
}
|
|
}
|
|
},
|
|
|
|
read: {
|
|
metadata: function() {
|
|
var
|
|
data = {
|
|
percent : module.helper.forceArray($module.data(metadata.percent)),
|
|
total : $module.data(metadata.total),
|
|
value : module.helper.forceArray($module.data(metadata.value))
|
|
}
|
|
;
|
|
if(data.total !== undefined) {
|
|
module.debug('Total value set from metadata', data.total);
|
|
module.set.total(data.total);
|
|
}
|
|
if(data.value.length > 0) {
|
|
module.debug('Current value set from metadata', data.value);
|
|
module.set.value(data.value);
|
|
module.set.progress(data.value);
|
|
}
|
|
if(data.percent.length > 0) {
|
|
module.debug('Current percent value set from metadata', data.percent);
|
|
module.set.percent(data.percent);
|
|
}
|
|
},
|
|
settings: function() {
|
|
if(settings.total !== false) {
|
|
module.debug('Current total set in settings', settings.total);
|
|
module.set.total(settings.total);
|
|
}
|
|
if(settings.value !== false) {
|
|
module.debug('Current value set in settings', settings.value);
|
|
module.set.value(settings.value);
|
|
module.set.progress(module.value);
|
|
}
|
|
if(settings.percent !== false) {
|
|
module.debug('Current percent set in settings', settings.percent);
|
|
module.set.percent(settings.percent);
|
|
}
|
|
}
|
|
},
|
|
|
|
bind: {
|
|
transitionEnd: function(callback) {
|
|
var
|
|
transitionEnd = module.get.transitionEnd()
|
|
;
|
|
$bars
|
|
.one(transitionEnd + eventNamespace, function(event) {
|
|
clearTimeout(module.failSafeTimer);
|
|
callback.call(this, event);
|
|
})
|
|
;
|
|
module.failSafeTimer = setTimeout(function() {
|
|
$bars.triggerHandler(transitionEnd);
|
|
}, settings.duration + settings.failSafeDelay);
|
|
module.verbose('Adding fail safe timer', module.timer);
|
|
}
|
|
},
|
|
|
|
increment: function(incrementValue) {
|
|
var
|
|
startValue,
|
|
newValue
|
|
;
|
|
if( module.has.total() ) {
|
|
startValue = module.get.value();
|
|
incrementValue = incrementValue || 1;
|
|
}
|
|
else {
|
|
startValue = module.get.percent();
|
|
incrementValue = incrementValue || module.get.randomValue();
|
|
}
|
|
newValue = startValue + incrementValue;
|
|
module.debug('Incrementing percentage by', startValue, newValue, incrementValue);
|
|
newValue = module.get.normalizedValue(newValue);
|
|
module.set.progress(newValue);
|
|
},
|
|
decrement: function(decrementValue) {
|
|
var
|
|
total = module.get.total(),
|
|
startValue,
|
|
newValue
|
|
;
|
|
if(total) {
|
|
startValue = module.get.value();
|
|
decrementValue = decrementValue || 1;
|
|
newValue = startValue - decrementValue;
|
|
module.debug('Decrementing value by', decrementValue, startValue);
|
|
}
|
|
else {
|
|
startValue = module.get.percent();
|
|
decrementValue = decrementValue || module.get.randomValue();
|
|
newValue = startValue - decrementValue;
|
|
module.debug('Decrementing percentage by', decrementValue, startValue);
|
|
}
|
|
newValue = module.get.normalizedValue(newValue);
|
|
module.set.progress(newValue);
|
|
},
|
|
|
|
has: {
|
|
progressPoll: function() {
|
|
return module.progressPoll;
|
|
},
|
|
total: function() {
|
|
return (module.get.total() !== false);
|
|
}
|
|
},
|
|
|
|
get: {
|
|
text: function(templateText, index) {
|
|
var
|
|
index_ = index || 0,
|
|
value = module.get.value(index_),
|
|
total = module.get.total(),
|
|
percent = (animating)
|
|
? module.get.displayPercent(index_)
|
|
: module.get.percent(index_),
|
|
left = (total !== false)
|
|
? Math.max(0,total - value)
|
|
: (100 - percent)
|
|
;
|
|
templateText = templateText || '';
|
|
templateText = templateText
|
|
.replace('{value}', value)
|
|
.replace('{total}', total || 0)
|
|
.replace('{left}', left)
|
|
.replace('{percent}', percent)
|
|
.replace('{bar}', settings.text.bars[index_] || '')
|
|
;
|
|
module.verbose('Adding variables to progress bar text', templateText);
|
|
return templateText;
|
|
},
|
|
|
|
normalizedValue: function(value) {
|
|
if(value < 0) {
|
|
module.debug('Value cannot decrement below 0');
|
|
return 0;
|
|
}
|
|
if(module.has.total()) {
|
|
if(value > module.total) {
|
|
module.debug('Value cannot increment above total', module.total);
|
|
return module.total;
|
|
}
|
|
}
|
|
else if(value > 100 ) {
|
|
module.debug('Value cannot increment above 100 percent');
|
|
return 100;
|
|
}
|
|
return value;
|
|
},
|
|
|
|
updateInterval: function() {
|
|
if(settings.updateInterval == 'auto') {
|
|
return settings.duration;
|
|
}
|
|
return settings.updateInterval;
|
|
},
|
|
|
|
randomValue: function() {
|
|
module.debug('Generating random increment percentage');
|
|
return Math.floor((Math.random() * settings.random.max) + settings.random.min);
|
|
},
|
|
|
|
numericValue: function(value) {
|
|
return (typeof value === 'string')
|
|
? (value.replace(/[^\d.]/g, '') !== '')
|
|
? +(value.replace(/[^\d.]/g, ''))
|
|
: false
|
|
: value
|
|
;
|
|
},
|
|
|
|
transitionEnd: function() {
|
|
var
|
|
element = document.createElement('element'),
|
|
transitions = {
|
|
'transition' :'transitionend',
|
|
'OTransition' :'oTransitionEnd',
|
|
'MozTransition' :'transitionend',
|
|
'WebkitTransition' :'webkitTransitionEnd'
|
|
},
|
|
transition
|
|
;
|
|
for(transition in transitions){
|
|
if( element.style[transition] !== undefined ){
|
|
return transitions[transition];
|
|
}
|
|
}
|
|
},
|
|
|
|
// gets current displayed percentage (if animating values this is the intermediary value)
|
|
displayPercent: function(index) {
|
|
var
|
|
$bar = $($bars[index]),
|
|
barWidth = $bar.width(),
|
|
totalWidth = $module.width(),
|
|
minDisplay = parseInt($bar.css('min-width'), 10),
|
|
displayPercent = (barWidth > minDisplay)
|
|
? (barWidth / totalWidth * 100)
|
|
: module.percent
|
|
;
|
|
return (settings.precision > 0)
|
|
? Math.round(displayPercent * (10 * settings.precision)) / (10 * settings.precision)
|
|
: Math.round(displayPercent)
|
|
;
|
|
},
|
|
|
|
percent: function(index) {
|
|
return module.percent && module.percent[index || 0] || 0;
|
|
},
|
|
value: function(index) {
|
|
return module.nextValue || module.value && module.value[index || 0] || 0;
|
|
},
|
|
total: function() {
|
|
return module.total !== undefined ? module.total : false;
|
|
}
|
|
},
|
|
|
|
create: {
|
|
progressPoll: function() {
|
|
module.progressPoll = setTimeout(function() {
|
|
module.update.toNextValue();
|
|
module.remove.progressPoll();
|
|
}, module.get.updateInterval());
|
|
},
|
|
},
|
|
|
|
is: {
|
|
complete: function() {
|
|
return module.is.success() || module.is.warning() || module.is.error();
|
|
},
|
|
success: function() {
|
|
return $module.hasClass(className.success);
|
|
},
|
|
warning: function() {
|
|
return $module.hasClass(className.warning);
|
|
},
|
|
error: function() {
|
|
return $module.hasClass(className.error);
|
|
},
|
|
active: function() {
|
|
return $module.hasClass(className.active);
|
|
},
|
|
visible: function() {
|
|
return $module.is(':visible');
|
|
}
|
|
},
|
|
|
|
remove: {
|
|
progressPoll: function() {
|
|
module.verbose('Removing progress poll timer');
|
|
if(module.progressPoll) {
|
|
clearTimeout(module.progressPoll);
|
|
delete module.progressPoll;
|
|
}
|
|
},
|
|
nextValue: function() {
|
|
module.verbose('Removing progress value stored for next update');
|
|
delete module.nextValue;
|
|
},
|
|
state: function() {
|
|
module.verbose('Removing stored state');
|
|
delete module.total;
|
|
delete module.percent;
|
|
delete module.value;
|
|
},
|
|
active: function() {
|
|
module.verbose('Removing active state');
|
|
$module.removeClass(className.active);
|
|
},
|
|
success: function() {
|
|
module.verbose('Removing success state');
|
|
$module.removeClass(className.success);
|
|
},
|
|
warning: function() {
|
|
module.verbose('Removing warning state');
|
|
$module.removeClass(className.warning);
|
|
},
|
|
error: function() {
|
|
module.verbose('Removing error state');
|
|
$module.removeClass(className.error);
|
|
}
|
|
},
|
|
|
|
set: {
|
|
barWidth: function(values) {
|
|
module.debug("set bar width with ", values);
|
|
values = module.helper.forceArray(values);
|
|
var firstNonZeroIndex = -1;
|
|
var lastNonZeroIndex = -1;
|
|
var valuesSum = module.helper.sum(values);
|
|
var barCounts = $bars.length;
|
|
var isMultiple = barCounts > 1;
|
|
var percents = values.map(function(value, index) {
|
|
var allZero = (index === barCounts - 1 && valuesSum === 0);
|
|
var $bar = $($bars[index]);
|
|
if (value === 0 && isMultiple && !allZero) {
|
|
$bar.css('display', 'none');
|
|
} else {
|
|
if (isMultiple && allZero) {
|
|
$bar.css('background', 'transparent');
|
|
}
|
|
if (firstNonZeroIndex == -1) {
|
|
firstNonZeroIndex = index;
|
|
}
|
|
lastNonZeroIndex = index;
|
|
$bar.css({
|
|
display: 'block',
|
|
width: value + '%'
|
|
});
|
|
}
|
|
return parseFloat(value);
|
|
});
|
|
values.forEach(function(_, index) {
|
|
var $bar = $($bars[index]);
|
|
$bar.css({
|
|
borderTopLeftRadius: index == firstNonZeroIndex ? '' : 0,
|
|
borderBottomLeftRadius: index == firstNonZeroIndex ? '' : 0,
|
|
borderTopRightRadius: index == lastNonZeroIndex ? '' : 0,
|
|
borderBottomRightRadius: index == lastNonZeroIndex ? '' : 0
|
|
});
|
|
});
|
|
$module
|
|
.attr('data-percent', percents)
|
|
;
|
|
},
|
|
duration: function(duration) {
|
|
duration = duration || settings.duration;
|
|
duration = (typeof duration == 'number')
|
|
? duration + 'ms'
|
|
: duration
|
|
;
|
|
module.verbose('Setting progress bar transition duration', duration);
|
|
$bars
|
|
.css({
|
|
'transition-duration': duration
|
|
})
|
|
;
|
|
},
|
|
percent: function(percents) {
|
|
percents = module.helper.forceArray(percents).map(function(percent) {
|
|
percent = (typeof percent == 'string')
|
|
? +(percent.replace('%', ''))
|
|
: percent
|
|
;
|
|
return (settings.limitValues)
|
|
? Math.max(0, Math.min(100, percent))
|
|
: percent
|
|
;
|
|
});
|
|
var hasTotal = module.has.total();
|
|
var totalPercent = module.helper.sum(percents);
|
|
var isMultipleValues = percents.length > 1 && hasTotal;
|
|
var sumTotal = module.helper.sum(module.helper.forceArray(module.value));
|
|
if (isMultipleValues && sumTotal > module.total) {
|
|
// Sum values instead of pecents to avoid precision issues when summing floats
|
|
module.error(error.sumExceedsTotal, sumTotal, module.total);
|
|
} else if (!isMultipleValues && totalPercent > 100) {
|
|
// Sum before rounding since sum of rounded may have error though sum of actual is fine
|
|
module.error(error.tooHigh, totalPercent);
|
|
} else if (totalPercent < 0) {
|
|
module.error(error.tooLow, totalPercent);
|
|
} else {
|
|
var autoPrecision = settings.precision > 0
|
|
? settings.precision
|
|
: isMultipleValues
|
|
? module.helper.derivePrecision(Math.min.apply(null, module.value), module.total)
|
|
: 0;
|
|
|
|
// round display percentage
|
|
var roundedPercents = percents.map(function (percent) {
|
|
return (autoPrecision > 0)
|
|
? Math.round(percent * (10 * autoPrecision)) / (10 * autoPrecision)
|
|
: Math.round(percent)
|
|
;
|
|
});
|
|
module.percent = roundedPercents;
|
|
if (hasTotal) {
|
|
module.value = percents.map(function (percent) {
|
|
return (autoPrecision > 0)
|
|
? Math.round((percent / 100) * module.total * (10 * autoPrecision)) / (10 * autoPrecision)
|
|
: Math.round((percent / 100) * module.total * 10) / 10
|
|
;
|
|
});
|
|
}
|
|
module.set.barWidth(percents);
|
|
module.set.labelInterval();
|
|
}
|
|
settings.onChange.call(element, percents, module.value, module.total);
|
|
},
|
|
labelInterval: function() {
|
|
var
|
|
animationCallback = function() {
|
|
module.verbose('Bar finished animating, removing continuous label updates');
|
|
clearInterval(module.interval);
|
|
animating = false;
|
|
module.set.labels();
|
|
}
|
|
;
|
|
clearInterval(module.interval);
|
|
module.bind.transitionEnd(animationCallback);
|
|
animating = true;
|
|
module.interval = setInterval(function() {
|
|
var
|
|
isInDOM = $.contains(document.documentElement, element)
|
|
;
|
|
if(!isInDOM) {
|
|
clearInterval(module.interval);
|
|
animating = false;
|
|
}
|
|
module.set.labels();
|
|
}, settings.framerate);
|
|
},
|
|
labels: function() {
|
|
module.verbose('Setting both bar progress and outer label text');
|
|
module.set.barLabel();
|
|
module.set.state();
|
|
},
|
|
label: function(text) {
|
|
text = text || '';
|
|
if(text) {
|
|
text = module.get.text(text);
|
|
module.verbose('Setting label to text', text);
|
|
$label.text(text);
|
|
}
|
|
},
|
|
state: function(percent) {
|
|
percent = (percent !== undefined)
|
|
? percent
|
|
: module.helper.sum(module.percent)
|
|
;
|
|
if(percent === 100) {
|
|
if(settings.autoSuccess && $bars.length === 1 && !(module.is.warning() || module.is.error() || module.is.success())) {
|
|
module.set.success();
|
|
module.debug('Automatically triggering success at 100%');
|
|
}
|
|
else {
|
|
module.verbose('Reached 100% removing active state');
|
|
module.remove.active();
|
|
module.remove.progressPoll();
|
|
}
|
|
}
|
|
else if(percent > 0) {
|
|
module.verbose('Adjusting active progress bar label', percent);
|
|
module.set.active();
|
|
}
|
|
else {
|
|
module.remove.active();
|
|
module.set.label(settings.text.active);
|
|
}
|
|
},
|
|
barLabel: function(text) {
|
|
$progresses.map(function(index, element){
|
|
var $progress = $(element);
|
|
if (text !== undefined) {
|
|
$progress.text( module.get.text(text, index) );
|
|
}
|
|
else if (settings.label == 'ratio' && module.has.total()) {
|
|
module.verbose('Adding ratio to bar label');
|
|
$progress.text( module.get.text(settings.text.ratio, index) );
|
|
}
|
|
else if (settings.label == 'percent') {
|
|
module.verbose('Adding percentage to bar label');
|
|
$progress.text( module.get.text(settings.text.percent, index) );
|
|
}
|
|
});
|
|
},
|
|
active: function(text) {
|
|
text = text || settings.text.active;
|
|
module.debug('Setting active state');
|
|
if(settings.showActivity && !module.is.active() ) {
|
|
$module.addClass(className.active);
|
|
}
|
|
module.remove.warning();
|
|
module.remove.error();
|
|
module.remove.success();
|
|
text = settings.onLabelUpdate('active', text, module.value, module.total);
|
|
if(text) {
|
|
module.set.label(text);
|
|
}
|
|
module.bind.transitionEnd(function() {
|
|
settings.onActive.call(element, module.value, module.total);
|
|
});
|
|
},
|
|
success : function(text, keepState) {
|
|
text = text || settings.text.success || settings.text.active;
|
|
module.debug('Setting success state');
|
|
$module.addClass(className.success);
|
|
module.remove.active();
|
|
module.remove.warning();
|
|
module.remove.error();
|
|
module.complete(keepState);
|
|
if(settings.text.success) {
|
|
text = settings.onLabelUpdate('success', text, module.value, module.total);
|
|
module.set.label(text);
|
|
}
|
|
else {
|
|
text = settings.onLabelUpdate('active', text, module.value, module.total);
|
|
module.set.label(text);
|
|
}
|
|
module.bind.transitionEnd(function() {
|
|
settings.onSuccess.call(element, module.total);
|
|
});
|
|
},
|
|
warning : function(text, keepState) {
|
|
text = text || settings.text.warning;
|
|
module.debug('Setting warning state');
|
|
$module.addClass(className.warning);
|
|
module.remove.active();
|
|
module.remove.success();
|
|
module.remove.error();
|
|
module.complete(keepState);
|
|
text = settings.onLabelUpdate('warning', text, module.value, module.total);
|
|
if(text) {
|
|
module.set.label(text);
|
|
}
|
|
module.bind.transitionEnd(function() {
|
|
settings.onWarning.call(element, module.value, module.total);
|
|
});
|
|
},
|
|
error : function(text, keepState) {
|
|
text = text || settings.text.error;
|
|
module.debug('Setting error state');
|
|
$module.addClass(className.error);
|
|
module.remove.active();
|
|
module.remove.success();
|
|
module.remove.warning();
|
|
module.complete(keepState);
|
|
text = settings.onLabelUpdate('error', text, module.value, module.total);
|
|
if(text) {
|
|
module.set.label(text);
|
|
}
|
|
module.bind.transitionEnd(function() {
|
|
settings.onError.call(element, module.value, module.total);
|
|
});
|
|
},
|
|
transitionEvent: function() {
|
|
transitionEnd = module.get.transitionEnd();
|
|
},
|
|
total: function(totalValue) {
|
|
module.total = totalValue;
|
|
},
|
|
value: function(value) {
|
|
module.value = module.helper.forceArray(value);
|
|
},
|
|
progress: function(value) {
|
|
if(!module.has.progressPoll()) {
|
|
module.debug('First update in progress update interval, immediately updating', value);
|
|
module.update.progress(value);
|
|
module.create.progressPoll();
|
|
}
|
|
else {
|
|
module.debug('Updated within interval, setting next update to use new value', value);
|
|
module.set.nextValue(value);
|
|
}
|
|
},
|
|
nextValue: function(value) {
|
|
module.nextValue = value;
|
|
}
|
|
},
|
|
|
|
update: {
|
|
toNextValue: function() {
|
|
var
|
|
nextValue = module.nextValue
|
|
;
|
|
if(nextValue) {
|
|
module.debug('Update interval complete using last updated value', nextValue);
|
|
module.update.progress(nextValue);
|
|
module.remove.nextValue();
|
|
}
|
|
},
|
|
progress: function(values) {
|
|
var hasTotal = module.has.total();
|
|
if (hasTotal) {
|
|
module.set.value(values);
|
|
}
|
|
var percentCompletes = module.helper.forceArray(values).map(function(value) {
|
|
var
|
|
percentComplete
|
|
;
|
|
value = module.get.numericValue(value);
|
|
if (value === false) {
|
|
module.error(error.nonNumeric, value);
|
|
}
|
|
value = module.get.normalizedValue(value);
|
|
if (hasTotal) {
|
|
percentComplete = module.total > 0 ? (value / module.total) * 100 : 100;
|
|
module.debug('Calculating percent complete from total', percentComplete);
|
|
}
|
|
else {
|
|
percentComplete = value;
|
|
module.debug('Setting value to exact percentage value', percentComplete);
|
|
}
|
|
return percentComplete;
|
|
});
|
|
module.set.percent( percentCompletes );
|
|
}
|
|
},
|
|
|
|
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 = setTimeout(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) && performance.length > 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 = query.length - 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 {
|
|
module.error(error.method, query);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
if ( $.isFunction( found ) ) {
|
|
response = found.apply(context, passedArguments);
|
|
}
|
|
else if(found !== undefined) {
|
|
response = found;
|
|
}
|
|
if(Array.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.progress.settings = {
|
|
|
|
name : 'Progress',
|
|
namespace : 'progress',
|
|
|
|
silent : false,
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
random : {
|
|
min : 2,
|
|
max : 5
|
|
},
|
|
|
|
duration : 300,
|
|
|
|
updateInterval : 'auto',
|
|
|
|
autoSuccess : true,
|
|
showActivity : true,
|
|
limitValues : true,
|
|
|
|
label : 'percent',
|
|
precision : 0,
|
|
framerate : (1000 / 30), /// 30 fps
|
|
|
|
percent : false,
|
|
total : false,
|
|
value : false,
|
|
|
|
// delay in ms for fail safe animation callback
|
|
failSafeDelay : 100,
|
|
|
|
onLabelUpdate : function(state, text, value, total){
|
|
return text;
|
|
},
|
|
onChange : function(percent, value, total){},
|
|
onSuccess : function(total){},
|
|
onActive : function(value, total){},
|
|
onError : function(value, total){},
|
|
onWarning : function(value, total){},
|
|
|
|
error : {
|
|
method : 'The method you called is not defined.',
|
|
nonNumeric : 'Progress value is non numeric',
|
|
tooHigh : 'Value specified is above 100%',
|
|
tooLow : 'Value specified is below 0%',
|
|
sumExceedsTotal : 'Sum of multple values exceed total',
|
|
},
|
|
|
|
regExp: {
|
|
variable: /\{\$*[A-z0-9]+\}/g
|
|
},
|
|
|
|
metadata: {
|
|
percent : 'percent',
|
|
total : 'total',
|
|
value : 'value'
|
|
},
|
|
|
|
selector : {
|
|
bar : '> .bar',
|
|
label : '> .label',
|
|
progress : '.bar > .progress'
|
|
},
|
|
|
|
text : {
|
|
active : false,
|
|
error : false,
|
|
success : false,
|
|
warning : false,
|
|
percent : '{percent}%',
|
|
ratio : '{value} of {total}',
|
|
bars : ['']
|
|
},
|
|
|
|
className : {
|
|
active : 'active',
|
|
error : 'error',
|
|
success : 'success',
|
|
warning : 'warning'
|
|
}
|
|
|
|
};
|
|
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Sidebar
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
window = (typeof window != 'undefined' && window.Math == Math)
|
|
? window
|
|
: (typeof self != 'undefined' && self.Math == Math)
|
|
? self
|
|
: Function('return this')()
|
|
;
|
|
|
|
$.fn.sidebar = function(parameters) {
|
|
var
|
|
$allModules = $(this),
|
|
$window = $(window),
|
|
$document = $(document),
|
|
$html = $('html'),
|
|
$head = $('head'),
|
|
|
|
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) { setTimeout(callback, 0); },
|
|
|
|
returnedValue
|
|
;
|
|
|
|
$allModules
|
|
.each(function() {
|
|
var
|
|
settings = ( $.isPlainObject(parameters) )
|
|
? $.extend(true, {}, $.fn.sidebar.settings, parameters)
|
|
: $.extend({}, $.fn.sidebar.settings),
|
|
|
|
selector = settings.selector,
|
|
className = settings.className,
|
|
namespace = settings.namespace,
|
|
regExp = settings.regExp,
|
|
error = settings.error,
|
|
|
|
eventNamespace = '.' + namespace,
|
|
moduleNamespace = 'module-' + namespace,
|
|
|
|
$module = $(this),
|
|
$context = $(settings.context),
|
|
|
|
$sidebars = $module.children(selector.sidebar),
|
|
$fixed = $context.children(selector.fixed),
|
|
$pusher = $context.children(selector.pusher),
|
|
$style,
|
|
|
|
element = this,
|
|
instance = $module.data(moduleNamespace),
|
|
|
|
elementNamespace,
|
|
id,
|
|
currentScroll,
|
|
transitionEvent,
|
|
|
|
module
|
|
;
|
|
|
|
module = {
|
|
|
|
initialize: function() {
|
|
module.debug('Initializing sidebar', parameters);
|
|
|
|
module.create.id();
|
|
|
|
transitionEvent = module.get.transitionEvent();
|
|
|
|
// avoids locking rendering if initialized in onReady
|
|
if(settings.delaySetup) {
|
|
requestAnimationFrame(module.setup.layout);
|
|
}
|
|
else {
|
|
module.setup.layout();
|
|
}
|
|
|
|
requestAnimationFrame(function() {
|
|
module.setup.cache();
|
|
});
|
|
|
|
module.instantiate();
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of module', module);
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, module)
|
|
;
|
|
},
|
|
|
|
create: {
|
|
id: function() {
|
|
id = (Math.random().toString(16) + '000000000').substr(2,8);
|
|
elementNamespace = '.' + id;
|
|
module.verbose('Creating unique id for element', id);
|
|
}
|
|
},
|
|
|
|
destroy: function() {
|
|
module.verbose('Destroying previous module for', $module);
|
|
$module
|
|
.off(eventNamespace)
|
|
.removeData(moduleNamespace)
|
|
;
|
|
if(module.is.ios()) {
|
|
module.remove.ios();
|
|
}
|
|
// bound by uuid
|
|
$context.off(elementNamespace);
|
|
$window.off(elementNamespace);
|
|
$document.off(elementNamespace);
|
|
},
|
|
|
|
event: {
|
|
clickaway: function(event) {
|
|
if(settings.closable){
|
|
var
|
|
clickedInPusher = ($pusher.find(event.target).length > 0 || $pusher.is(event.target)),
|
|
clickedContext = ($context.is(event.target))
|
|
;
|
|
if(clickedInPusher) {
|
|
module.verbose('User clicked on dimmed page');
|
|
module.hide();
|
|
}
|
|
if(clickedContext) {
|
|
module.verbose('User clicked on dimmable context (scaled out page)');
|
|
module.hide();
|
|
}
|
|
}
|
|
},
|
|
touch: function(event) {
|
|
//event.stopPropagation();
|
|
},
|
|
containScroll: function(event) {
|
|
if(element.scrollTop <= 0) {
|
|
element.scrollTop = 1;
|
|
}
|
|
if((element.scrollTop + element.offsetHeight) >= element.scrollHeight) {
|
|
element.scrollTop = element.scrollHeight - element.offsetHeight - 1;
|
|
}
|
|
},
|
|
scroll: function(event) {
|
|
if( $(event.target).closest(selector.sidebar).length === 0 ) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
},
|
|
|
|
bind: {
|
|
clickaway: function() {
|
|
module.verbose('Adding clickaway events to context', $context);
|
|
$context
|
|
.on('click' + elementNamespace, module.event.clickaway)
|
|
.on('touchend' + elementNamespace, module.event.clickaway)
|
|
;
|
|
},
|
|
scrollLock: function() {
|
|
if(settings.scrollLock) {
|
|
module.debug('Disabling page scroll');
|
|
$window
|
|
.on('DOMMouseScroll' + elementNamespace, module.event.scroll)
|
|
;
|
|
}
|
|
module.verbose('Adding events to contain sidebar scroll');
|
|
$document
|
|
.on('touchmove' + elementNamespace, module.event.touch)
|
|
;
|
|
$module
|
|
.on('scroll' + eventNamespace, module.event.containScroll)
|
|
;
|
|
}
|
|
},
|
|
unbind: {
|
|
clickaway: function() {
|
|
module.verbose('Removing clickaway events from context', $context);
|
|
$context.off(elementNamespace);
|
|
},
|
|
scrollLock: function() {
|
|
module.verbose('Removing scroll lock from page');
|
|
$document.off(elementNamespace);
|
|
$window.off(elementNamespace);
|
|
$module.off('scroll' + eventNamespace);
|
|
}
|
|
},
|
|
|
|
add: {
|
|
inlineCSS: function() {
|
|
var
|
|
width = module.cache.width || $module.outerWidth(),
|
|
height = module.cache.height || $module.outerHeight(),
|
|
isRTL = module.is.rtl(),
|
|
direction = module.get.direction(),
|
|
distance = {
|
|
left : width,
|
|
right : -width,
|
|
top : height,
|
|
bottom : -height
|
|
},
|
|
style
|
|
;
|
|
|
|
if(isRTL){
|
|
module.verbose('RTL detected, flipping widths');
|
|
distance.left = -width;
|
|
distance.right = width;
|
|
}
|
|
|
|
style = '<style>';
|
|
|
|
if(direction === 'left' || direction === 'right') {
|
|
module.debug('Adding CSS rules for animation distance', width);
|
|
style += ''
|
|
+ ' .ui.visible.' + direction + '.sidebar ~ .fixed,'
|
|
+ ' .ui.visible.' + direction + '.sidebar ~ .pusher {'
|
|
+ ' -webkit-transform: translate3d('+ distance[direction] + 'px, 0, 0);'
|
|
+ ' transform: translate3d('+ distance[direction] + 'px, 0, 0);'
|
|
+ ' }'
|
|
;
|
|
}
|
|
else if(direction === 'top' || direction == 'bottom') {
|
|
style += ''
|
|
+ ' .ui.visible.' + direction + '.sidebar ~ .fixed,'
|
|
+ ' .ui.visible.' + direction + '.sidebar ~ .pusher {'
|
|
+ ' -webkit-transform: translate3d(0, ' + distance[direction] + 'px, 0);'
|
|
+ ' transform: translate3d(0, ' + distance[direction] + 'px, 0);'
|
|
+ ' }'
|
|
;
|
|
}
|
|
|
|
/* IE is only browser not to create context with transforms */
|
|
/* https://www.w3.org/Bugs/Public/show_bug.cgi?id=16328 */
|
|
if( module.is.ie() ) {
|
|
if(direction === 'left' || direction === 'right') {
|
|
module.debug('Adding CSS rules for animation distance', width);
|
|
style += ''
|
|
+ ' body.pushable > .ui.visible.' + direction + '.sidebar ~ .pusher:after {'
|
|
+ ' -webkit-transform: translate3d('+ distance[direction] + 'px, 0, 0);'
|
|
+ ' transform: translate3d('+ distance[direction] + 'px, 0, 0);'
|
|
+ ' }'
|
|
;
|
|
}
|
|
else if(direction === 'top' || direction == 'bottom') {
|
|
style += ''
|
|
+ ' body.pushable > .ui.visible.' + direction + '.sidebar ~ .pusher:after {'
|
|
+ ' -webkit-transform: translate3d(0, ' + distance[direction] + 'px, 0);'
|
|
+ ' transform: translate3d(0, ' + distance[direction] + 'px, 0);'
|
|
+ ' }'
|
|
;
|
|
}
|
|
/* opposite sides visible forces content overlay */
|
|
style += ''
|
|
+ ' body.pushable > .ui.visible.left.sidebar ~ .ui.visible.right.sidebar ~ .pusher:after,'
|
|
+ ' body.pushable > .ui.visible.right.sidebar ~ .ui.visible.left.sidebar ~ .pusher:after {'
|
|
+ ' -webkit-transform: translate3d(0, 0, 0);'
|
|
+ ' transform: translate3d(0, 0, 0);'
|
|
+ ' }'
|
|
;
|
|
}
|
|
style += '</style>';
|
|
$style = $(style)
|
|
.appendTo($head)
|
|
;
|
|
module.debug('Adding sizing css to head', $style);
|
|
}
|
|
},
|
|
|
|
refresh: function() {
|
|
module.verbose('Refreshing selector cache');
|
|
$context = $(settings.context);
|
|
$sidebars = $context.children(selector.sidebar);
|
|
$pusher = $context.children(selector.pusher);
|
|
$fixed = $context.children(selector.fixed);
|
|
module.clear.cache();
|
|
},
|
|
|
|
refreshSidebars: function() {
|
|
module.verbose('Refreshing other sidebars');
|
|
$sidebars = $context.children(selector.sidebar);
|
|
},
|
|
|
|
repaint: function() {
|
|
module.verbose('Forcing repaint event');
|
|
element.style.display = 'none';
|
|
var ignored = element.offsetHeight;
|
|
element.scrollTop = element.scrollTop;
|
|
element.style.display = '';
|
|
},
|
|
|
|
setup: {
|
|
cache: function() {
|
|
module.cache = {
|
|
width : $module.outerWidth(),
|
|
height : $module.outerHeight()
|
|
};
|
|
},
|
|
layout: function() {
|
|
if( $context.children(selector.pusher).length === 0 ) {
|
|
module.debug('Adding wrapper element for sidebar');
|
|
module.error(error.pusher);
|
|
$pusher = $('<div class="pusher" />');
|
|
$context
|
|
.children()
|
|
.not(selector.omitted)
|
|
.not($sidebars)
|
|
.wrapAll($pusher)
|
|
;
|
|
module.refresh();
|
|
}
|
|
if($module.nextAll(selector.pusher).length === 0 || $module.nextAll(selector.pusher)[0] !== $pusher[0]) {
|
|
module.debug('Moved sidebar to correct parent element');
|
|
module.error(error.movedSidebar, element);
|
|
$module.detach().prependTo($context);
|
|
module.refresh();
|
|
}
|
|
module.clear.cache();
|
|
module.set.pushable();
|
|
module.set.direction();
|
|
}
|
|
},
|
|
|
|
attachEvents: function(selector, event) {
|
|
var
|
|
$toggle = $(selector)
|
|
;
|
|
event = $.isFunction(module[event])
|
|
? module[event]
|
|
: module.toggle
|
|
;
|
|
if($toggle.length > 0) {
|
|
module.debug('Attaching sidebar events to element', selector, event);
|
|
$toggle
|
|
.on('click' + eventNamespace, event)
|
|
;
|
|
}
|
|
else {
|
|
module.error(error.notFound, selector);
|
|
}
|
|
},
|
|
|
|
show: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if(module.is.hidden()) {
|
|
module.refreshSidebars();
|
|
if(settings.overlay) {
|
|
module.error(error.overlay);
|
|
settings.transition = 'overlay';
|
|
}
|
|
module.refresh();
|
|
if(module.othersActive()) {
|
|
module.debug('Other sidebars currently visible');
|
|
if(settings.exclusive) {
|
|
// if not overlay queue animation after hide
|
|
if(settings.transition != 'overlay') {
|
|
module.hideOthers(module.show);
|
|
return;
|
|
}
|
|
else {
|
|
module.hideOthers();
|
|
}
|
|
}
|
|
else {
|
|
settings.transition = 'overlay';
|
|
}
|
|
}
|
|
module.pushPage(function() {
|
|
callback.call(element);
|
|
settings.onShow.call(element);
|
|
});
|
|
settings.onChange.call(element);
|
|
settings.onVisible.call(element);
|
|
}
|
|
else {
|
|
module.debug('Sidebar is already visible');
|
|
}
|
|
},
|
|
|
|
hide: function(callback) {
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if(module.is.visible() || module.is.animating()) {
|
|
module.debug('Hiding sidebar', callback);
|
|
module.refreshSidebars();
|
|
module.pullPage(function() {
|
|
callback.call(element);
|
|
settings.onHidden.call(element);
|
|
});
|
|
settings.onChange.call(element);
|
|
settings.onHide.call(element);
|
|
}
|
|
},
|
|
|
|
othersAnimating: function() {
|
|
return ($sidebars.not($module).filter('.' + className.animating).length > 0);
|
|
},
|
|
othersVisible: function() {
|
|
return ($sidebars.not($module).filter('.' + className.visible).length > 0);
|
|
},
|
|
othersActive: function() {
|
|
return(module.othersVisible() || module.othersAnimating());
|
|
},
|
|
|
|
hideOthers: function(callback) {
|
|
var
|
|
$otherSidebars = $sidebars.not($module).filter('.' + className.visible),
|
|
sidebarCount = $otherSidebars.length,
|
|
callbackCount = 0
|
|
;
|
|
callback = callback || function(){};
|
|
$otherSidebars
|
|
.sidebar('hide', function() {
|
|
callbackCount++;
|
|
if(callbackCount == sidebarCount) {
|
|
callback();
|
|
}
|
|
})
|
|
;
|
|
},
|
|
|
|
toggle: function() {
|
|
module.verbose('Determining toggled direction');
|
|
if(module.is.hidden()) {
|
|
module.show();
|
|
}
|
|
else {
|
|
module.hide();
|
|
}
|
|
},
|
|
|
|
pushPage: function(callback) {
|
|
var
|
|
transition = module.get.transition(),
|
|
$transition = (transition === 'overlay' || module.othersActive())
|
|
? $module
|
|
: $pusher,
|
|
animate,
|
|
dim,
|
|
transitionEnd
|
|
;
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
if(settings.transition == 'scale down') {
|
|
module.scrollToTop();
|
|
}
|
|
module.set.transition(transition);
|
|
module.repaint();
|
|
animate = function() {
|
|
module.bind.clickaway();
|
|
module.add.inlineCSS();
|
|
module.set.animating();
|
|
module.set.visible();
|
|
};
|
|
dim = function() {
|
|
module.set.dimmed();
|
|
};
|
|
transitionEnd = function(event) {
|
|
if( event.target == $transition[0] ) {
|
|
$transition.off(transitionEvent + elementNamespace, transitionEnd);
|
|
module.remove.animating();
|
|
module.bind.scrollLock();
|
|
callback.call(element);
|
|
}
|
|
};
|
|
$transition.off(transitionEvent + elementNamespace);
|
|
$transition.on(transitionEvent + elementNamespace, transitionEnd);
|
|
requestAnimationFrame(animate);
|
|
if(settings.dimPage && !module.othersVisible()) {
|
|
requestAnimationFrame(dim);
|
|
}
|
|
},
|
|
|
|
pullPage: function(callback) {
|
|
var
|
|
transition = module.get.transition(),
|
|
$transition = (transition == 'overlay' || module.othersActive())
|
|
? $module
|
|
: $pusher,
|
|
animate,
|
|
transitionEnd
|
|
;
|
|
callback = $.isFunction(callback)
|
|
? callback
|
|
: function(){}
|
|
;
|
|
module.verbose('Removing context push state', module.get.direction());
|
|
|
|
module.unbind.clickaway();
|
|
module.unbind.scrollLock();
|
|
|
|
animate = function() {
|
|
module.set.transition(transition);
|
|
module.set.animating();
|
|
module.remove.visible();
|
|
if(settings.dimPage && !module.othersVisible()) {
|
|
$pusher.removeClass(className.dimmed);
|
|
}
|
|
};
|
|
transitionEnd = function(event) {
|
|
if( event.target == $transition[0] ) {
|
|
$transition.off(transitionEvent + elementNamespace, transitionEnd);
|
|
module.remove.animating();
|
|
module.remove.transition();
|
|
module.remove.inlineCSS();
|
|
if(transition == 'scale down' || (settings.returnScroll && module.is.mobile()) ) {
|
|
module.scrollBack();
|
|
}
|
|
callback.call(element);
|
|
}
|
|
};
|
|
$transition.off(transitionEvent + elementNamespace);
|
|
$transition.on(transitionEvent + elementNamespace, transitionEnd);
|
|
requestAnimationFrame(animate);
|
|
},
|
|
|
|
scrollToTop: function() {
|
|
module.verbose('Scrolling to top of page to avoid animation issues');
|
|
currentScroll = $(window).scrollTop();
|
|
$module.scrollTop(0);
|
|
window.scrollTo(0, 0);
|
|
},
|
|
|
|
scrollBack: function() {
|
|
module.verbose('Scrolling back to original page position');
|
|
window.scrollTo(0, currentScroll);
|
|
},
|
|
|
|
clear: {
|
|
cache: function() {
|
|
module.verbose('Clearing cached dimensions');
|
|
module.cache = {};
|
|
}
|
|
},
|
|
|
|
set: {
|
|
|
|
// ios only (scroll on html not document). This prevent auto-resize canvas/scroll in ios
|
|
// (This is no longer necessary in latest iOS)
|
|
ios: function() {
|
|
$html.addClass(className.ios);
|
|
},
|
|
|
|
// container
|
|
pushed: function() {
|
|
$context.addClass(className.pushed);
|
|
},
|
|
pushable: function() {
|
|
$context.addClass(className.pushable);
|
|
},
|
|
|
|
// pusher
|
|
dimmed: function() {
|
|
$pusher.addClass(className.dimmed);
|
|
},
|
|
|
|
// sidebar
|
|
active: function() {
|
|
$module.addClass(className.active);
|
|
},
|
|
animating: function() {
|
|
$module.addClass(className.animating);
|
|
},
|
|
transition: function(transition) {
|
|
transition = transition || module.get.transition();
|
|
$module.addClass(transition);
|
|
},
|
|
direction: function(direction) {
|
|
direction = direction || module.get.direction();
|
|
$module.addClass(className[direction]);
|
|
},
|
|
visible: function() {
|
|
$module.addClass(className.visible);
|
|
},
|
|
overlay: function() {
|
|
$module.addClass(className.overlay);
|
|
}
|
|
},
|
|
remove: {
|
|
|
|
inlineCSS: function() {
|
|
module.debug('Removing inline css styles', $style);
|
|
if($style && $style.length > 0) {
|
|
$style.remove();
|
|
}
|
|
},
|
|
|
|
// ios scroll on html not document
|
|
ios: function() {
|
|
$html.removeClass(className.ios);
|
|
},
|
|
|
|
// context
|
|
pushed: function() {
|
|
$context.removeClass(className.pushed);
|
|
},
|
|
pushable: function() {
|
|
$context.removeClass(className.pushable);
|
|
},
|
|
|
|
// sidebar
|
|
active: function() {
|
|
$module.removeClass(className.active);
|
|
},
|
|
animating: function() {
|
|
$module.removeClass(className.animating);
|
|
},
|
|
transition: function(transition) {
|
|
transition = transition || module.get.transition();
|
|
$module.removeClass(transition);
|
|
},
|
|
direction: function(direction) {
|
|
direction = direction || module.get.direction();
|
|
$module.removeClass(className[direction]);
|
|
},
|
|
visible: function() {
|
|
$module.removeClass(className.visible);
|
|
},
|
|
overlay: function() {
|
|
$module.removeClass(className.overlay);
|
|
}
|
|
},
|
|
|
|
get: {
|
|
direction: function() {
|
|
if($module.hasClass(className.top)) {
|
|
return className.top;
|
|
}
|
|
else if($module.hasClass(className.right)) {
|
|
return className.right;
|
|
}
|
|
else if($module.hasClass(className.bottom)) {
|
|
return className.bottom;
|
|
}
|
|
return className.left;
|
|
},
|
|
transition: function() {
|
|
var
|
|
direction = module.get.direction(),
|
|
transition
|
|
;
|
|
transition = ( module.is.mobile() )
|
|
? (settings.mobileTransition == 'auto')
|
|
? settings.defaultTransition.mobile[direction]
|
|
: settings.mobileTransition
|
|
: (settings.transition == 'auto')
|
|
? settings.defaultTransition.computer[direction]
|
|
: settings.transition
|
|
;
|
|
module.verbose('Determined transition', transition);
|
|
return transition;
|
|
},
|
|
transitionEvent: function() {
|
|
var
|
|
element = document.createElement('element'),
|
|
transitions = {
|
|
'transition' :'transitionend',
|
|
'OTransition' :'oTransitionEnd',
|
|
'MozTransition' :'transitionend',
|
|
'WebkitTransition' :'webkitTransitionEnd'
|
|
},
|
|
transition
|
|
;
|
|
for(transition in transitions){
|
|
if( element.style[transition] !== undefined ){
|
|
return transitions[transition];
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
is: {
|
|
|
|
ie: function() {
|
|
var
|
|
isIE11 = (!(window.ActiveXObject) && 'ActiveXObject' in window),
|
|
isIE = ('ActiveXObject' in window)
|
|
;
|
|
return (isIE11 || isIE);
|
|
},
|
|
|
|
ios: function() {
|
|
var
|
|
userAgent = navigator.userAgent,
|
|
isIOS = userAgent.match(regExp.ios),
|
|
isMobileChrome = userAgent.match(regExp.mobileChrome)
|
|
;
|
|
if(isIOS && !isMobileChrome) {
|
|
module.verbose('Browser was found to be iOS', userAgent);
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
},
|
|
mobile: function() {
|
|
var
|
|
userAgent = navigator.userAgent,
|
|
isMobile = userAgent.match(regExp.mobile)
|
|
;
|
|
if(isMobile) {
|
|
module.verbose('Browser was found to be mobile', userAgent);
|
|
return true;
|
|
}
|
|
else {
|
|
module.verbose('Browser is not mobile, using regular transition', userAgent);
|
|
return false;
|
|
}
|
|
},
|
|
hidden: function() {
|
|
return !module.is.visible();
|
|
},
|
|
visible: function() {
|
|
return $module.hasClass(className.visible);
|
|
},
|
|
// alias
|
|
open: function() {
|
|
return module.is.visible();
|
|
},
|
|
closed: function() {
|
|
return module.is.hidden();
|
|
},
|
|
vertical: function() {
|
|
return $module.hasClass(className.top);
|
|
},
|
|
animating: function() {
|
|
return $context.hasClass(className.animating);
|
|
},
|
|
rtl: function () {
|
|
if(module.cache.rtl === undefined) {
|
|
module.cache.rtl = $module.attr('dir') === 'rtl' || $module.css('direction') === 'rtl';
|
|
}
|
|
return module.cache.rtl;
|
|
}
|
|
},
|
|
|
|
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 = setTimeout(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) && performance.length > 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 = query.length - 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 {
|
|
module.error(error.method, query);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
if ( $.isFunction( found ) ) {
|
|
response = found.apply(context, passedArguments);
|
|
}
|
|
else if(found !== undefined) {
|
|
response = found;
|
|
}
|
|
if(Array.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) {
|
|
module.invoke('destroy');
|
|
}
|
|
module.initialize();
|
|
}
|
|
});
|
|
|
|
return (returnedValue !== undefined)
|
|
? returnedValue
|
|
: this
|
|
;
|
|
};
|
|
|
|
$.fn.sidebar.settings = {
|
|
|
|
name : 'Sidebar',
|
|
namespace : 'sidebar',
|
|
|
|
silent : false,
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
transition : 'auto',
|
|
mobileTransition : 'auto',
|
|
|
|
defaultTransition : {
|
|
computer: {
|
|
left : 'uncover',
|
|
right : 'uncover',
|
|
top : 'overlay',
|
|
bottom : 'overlay'
|
|
},
|
|
mobile: {
|
|
left : 'uncover',
|
|
right : 'uncover',
|
|
top : 'overlay',
|
|
bottom : 'overlay'
|
|
}
|
|
},
|
|
|
|
context : 'body',
|
|
exclusive : false,
|
|
closable : true,
|
|
dimPage : true,
|
|
scrollLock : false,
|
|
returnScroll : false,
|
|
delaySetup : false,
|
|
|
|
duration : 500,
|
|
|
|
onChange : function(){},
|
|
onShow : function(){},
|
|
onHide : function(){},
|
|
|
|
onHidden : function(){},
|
|
onVisible : function(){},
|
|
|
|
className : {
|
|
active : 'active',
|
|
animating : 'animating',
|
|
dimmed : 'dimmed',
|
|
ios : 'ios',
|
|
pushable : 'pushable',
|
|
pushed : 'pushed',
|
|
right : 'right',
|
|
top : 'top',
|
|
left : 'left',
|
|
bottom : 'bottom',
|
|
visible : 'visible'
|
|
},
|
|
|
|
selector: {
|
|
fixed : '.fixed',
|
|
omitted : 'script, link, style, .ui.modal, .ui.dimmer, .ui.nag, .ui.fixed',
|
|
pusher : '.pusher',
|
|
sidebar : '.ui.sidebar'
|
|
},
|
|
|
|
regExp: {
|
|
ios : /(iPad|iPhone|iPod)/g,
|
|
mobileChrome : /(CriOS)/g,
|
|
mobile : /Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune/g
|
|
},
|
|
|
|
error : {
|
|
method : 'The method you called is not defined.',
|
|
pusher : 'Had to add pusher element. For optimal performance make sure body content is inside a pusher element',
|
|
movedSidebar : 'Had to move sidebar. For optimal performance make sure sidebar and pusher are direct children of your body tag',
|
|
overlay : 'The overlay setting is no longer supported, use animation: overlay',
|
|
notFound : 'There were no elements that matched the specified selector'
|
|
}
|
|
|
|
};
|
|
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Toast
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
window = (typeof window != 'undefined' && window.Math == Math)
|
|
? window
|
|
: (typeof self != 'undefined' && self.Math == Math)
|
|
? self
|
|
: Function('return this')()
|
|
;
|
|
|
|
$.fn.toast = function(parameters) {
|
|
var
|
|
$allModules = $(this),
|
|
moduleSelector = $allModules.selector || '',
|
|
|
|
time = new Date().getTime(),
|
|
performance = [],
|
|
|
|
query = arguments[0],
|
|
methodInvoked = (typeof query == 'string'),
|
|
queryArguments = [].slice.call(arguments, 1),
|
|
returnedValue
|
|
;
|
|
$allModules
|
|
.each(function() {
|
|
var
|
|
settings = ( $.isPlainObject(parameters) )
|
|
? $.extend(true, {}, $.fn.toast.settings, parameters)
|
|
: $.extend({}, $.fn.toast.settings),
|
|
|
|
className = settings.className,
|
|
selector = settings.selector,
|
|
error = settings.error,
|
|
namespace = settings.namespace,
|
|
fields = settings.fields,
|
|
|
|
eventNamespace = '.' + namespace,
|
|
moduleNamespace = namespace + '-module',
|
|
|
|
$module = $(this),
|
|
$toastBox,
|
|
$toast,
|
|
$actions,
|
|
$progress,
|
|
$progressBar,
|
|
$animationObject,
|
|
$close,
|
|
$context = (settings.context)
|
|
? $(settings.context)
|
|
: $('body'),
|
|
|
|
isToastComponent = $module.hasClass('toast') || $module.hasClass('message') || $module.hasClass('card'),
|
|
|
|
element = this,
|
|
instance = isToastComponent ? $module.data(moduleNamespace) : undefined,
|
|
|
|
module
|
|
;
|
|
module = {
|
|
|
|
initialize: function() {
|
|
module.verbose('Initializing element');
|
|
if (!module.has.container()) {
|
|
module.create.container();
|
|
}
|
|
if(isToastComponent || settings.message !== '' || settings.title !== '' || module.get.iconClass() !== '' || settings.showImage || module.has.configActions()) {
|
|
if(typeof settings.showProgress !== 'string' || [className.top,className.bottom].indexOf(settings.showProgress) === -1 ) {
|
|
settings.showProgress = false;
|
|
}
|
|
module.create.toast();
|
|
if(settings.closeOnClick && (settings.closeIcon || $($toast).find(selector.input).length > 0 || module.has.configActions())){
|
|
settings.closeOnClick = false;
|
|
}
|
|
if(!settings.closeOnClick) {
|
|
$toastBox.addClass(className.unclickable);
|
|
}
|
|
module.bind.events();
|
|
}
|
|
module.instantiate();
|
|
if($toastBox) {
|
|
module.show();
|
|
}
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of toast');
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, instance)
|
|
;
|
|
},
|
|
|
|
destroy: function() {
|
|
if($toastBox) {
|
|
module.debug('Removing toast', $toastBox);
|
|
module.unbind.events();
|
|
$toastBox.remove();
|
|
$toastBox = undefined;
|
|
$toast = undefined;
|
|
$animationObject = undefined;
|
|
settings.onRemove.call($toastBox, element);
|
|
$progress = undefined;
|
|
$progressBar = undefined;
|
|
$close = undefined;
|
|
}
|
|
$module
|
|
.removeData(moduleNamespace)
|
|
;
|
|
},
|
|
|
|
show: function(callback) {
|
|
callback = callback || function(){};
|
|
module.debug('Showing toast');
|
|
if(settings.onShow.call($toastBox, element) === false) {
|
|
module.debug('onShow callback returned false, cancelling toast animation');
|
|
return;
|
|
}
|
|
module.animate.show(callback);
|
|
},
|
|
|
|
close: function(callback) {
|
|
callback = callback || function(){};
|
|
module.remove.visible();
|
|
module.unbind.events();
|
|
module.animate.close(callback);
|
|
|
|
},
|
|
|
|
create: {
|
|
container: function() {
|
|
module.verbose('Creating container');
|
|
$context.append($('<div/>',{class: settings.position + ' ' + className.container + ' ' +(settings.horizontal ? className.horizontal : '')}));
|
|
},
|
|
toast: function() {
|
|
$toastBox = $('<div/>', {class: className.box});
|
|
var iconClass = module.get.iconClass();
|
|
if (!isToastComponent) {
|
|
module.verbose('Creating toast');
|
|
$toast = $('<div/>');
|
|
var $content = $('<div/>', {class: className.content});
|
|
if (iconClass !== '') {
|
|
$toast.append($('<i/>', {class: iconClass + ' ' + className.icon}));
|
|
}
|
|
|
|
if (settings.showImage) {
|
|
$toast.append($('<img>', {
|
|
class: className.image + ' ' + settings.classImage,
|
|
src: settings.showImage
|
|
}));
|
|
}
|
|
if (settings.title !== '') {
|
|
$content.append($('<div/>', {
|
|
class: className.title,
|
|
text: settings.title
|
|
}));
|
|
}
|
|
|
|
$content.append($('<div/>', {class: className.message, html: module.helpers.escape(settings.message, settings.preserveHTML)}));
|
|
|
|
$toast
|
|
.addClass(settings.class + ' ' + className.toast)
|
|
.append($content)
|
|
;
|
|
$toast.css('opacity', settings.opacity);
|
|
if (settings.closeIcon) {
|
|
$close = $('<i/>', {class: className.close + ' ' + (typeof settings.closeIcon === 'string' ? settings.closeIcon : '')});
|
|
if($close.hasClass(className.left)) {
|
|
$toast.prepend($close);
|
|
} else {
|
|
$toast.append($close);
|
|
}
|
|
}
|
|
} else {
|
|
$toast = settings.cloneModule ? $module.clone().removeAttr('id') : $module;
|
|
$close = $toast.find('> i'+module.helpers.toClass(className.close));
|
|
settings.closeIcon = ($close.length > 0);
|
|
if (iconClass !== '') {
|
|
$toast.find(selector.icon).attr('class',iconClass + ' ' + className.icon);
|
|
}
|
|
if (settings.showImage) {
|
|
$toast.find(selector.image).attr('src',settings.showImage);
|
|
}
|
|
if (settings.title !== '') {
|
|
$toast.find(selector.title).html(module.helpers.escape(settings.title, settings.preserveHTML));
|
|
}
|
|
if (settings.message !== '') {
|
|
$toast.find(selector.message).html(module.helpers.escape(settings.message, settings.preserveHTML));
|
|
}
|
|
}
|
|
if ($toast.hasClass(className.compact)) {
|
|
settings.compact = true;
|
|
}
|
|
if ($toast.hasClass('card')) {
|
|
settings.compact = false;
|
|
}
|
|
$actions = $toast.find('.actions');
|
|
if (module.has.configActions()) {
|
|
if ($actions.length === 0) {
|
|
$actions = $('<div/>', {class: className.actions + ' ' + (settings.classActions || '')}).appendTo($toast);
|
|
}
|
|
if($toast.hasClass('card') && !$actions.hasClass(className.attached)) {
|
|
$actions.addClass(className.extraContent);
|
|
if($actions.hasClass(className.vertical)) {
|
|
$actions.removeClass(className.vertical);
|
|
module.error(error.verticalCard);
|
|
}
|
|
}
|
|
settings.actions.forEach(function (el) {
|
|
var icon = el[fields.icon] ? '<i class="' + module.helpers.deQuote(el[fields.icon]) + ' icon"></i>' : '',
|
|
text = module.helpers.escape(el[fields.text] || '', settings.preserveHTML),
|
|
cls = module.helpers.deQuote(el[fields.class] || ''),
|
|
click = el[fields.click] && $.isFunction(el[fields.click]) ? el[fields.click] : function () {};
|
|
$actions.append($('<button/>', {
|
|
html: icon + text,
|
|
class: className.button + ' ' + cls,
|
|
click: function () {
|
|
if (click.call(element, $module) === false) {
|
|
return;
|
|
}
|
|
module.close();
|
|
}
|
|
}));
|
|
});
|
|
}
|
|
if ($actions && $actions.hasClass(className.vertical)) {
|
|
$toast.addClass(className.vertical);
|
|
}
|
|
if($actions.length > 0 && !$actions.hasClass(className.attached)) {
|
|
if ($actions && (!$actions.hasClass(className.basic) || $actions.hasClass(className.left))) {
|
|
$toast.addClass(className.actions);
|
|
}
|
|
}
|
|
if(settings.displayTime === 'auto'){
|
|
settings.displayTime = Math.max(settings.minDisplayTime, $toast.text().split(" ").length / settings.wordsPerMinute * 60000);
|
|
}
|
|
$toastBox.append($toast);
|
|
|
|
if($actions.length > 0 && $actions.hasClass(className.attached)) {
|
|
$actions.addClass(className.buttons);
|
|
$actions.detach();
|
|
$toast.addClass(className.attached);
|
|
if (!$actions.hasClass(className.vertical)) {
|
|
if ($actions.hasClass(className.top)) {
|
|
$toastBox.prepend($actions);
|
|
$toast.addClass(className.bottom);
|
|
} else {
|
|
$toastBox.append($actions);
|
|
$toast.addClass(className.top);
|
|
}
|
|
} else {
|
|
$toast.wrap(
|
|
$('<div/>',{
|
|
class:className.vertical + ' ' +
|
|
className.attached + ' ' +
|
|
(settings.compact ? className.compact : '')
|
|
})
|
|
);
|
|
if($actions.hasClass(className.left)) {
|
|
$toast.addClass(className.left).parent().addClass(className.left).prepend($actions);
|
|
} else {
|
|
$toast.parent().append($actions);
|
|
}
|
|
}
|
|
}
|
|
if($module !== $toast) {
|
|
$module = $toast;
|
|
element = $toast[0];
|
|
}
|
|
if(settings.displayTime > 0) {
|
|
var progressingClass = className.progressing+' '+(settings.pauseOnHover ? className.pausable:'');
|
|
if (!!settings.showProgress) {
|
|
$progress = $('<div/>', {
|
|
class: className.progress + ' ' + (settings.classProgress || settings.class),
|
|
'data-percent': ''
|
|
});
|
|
if(!settings.classProgress) {
|
|
if ($toast.hasClass('toast') && !$toast.hasClass(className.inverted)) {
|
|
$progress.addClass(className.inverted);
|
|
} else {
|
|
$progress.removeClass(className.inverted);
|
|
}
|
|
}
|
|
$progressBar = $('<div/>', {class: 'bar '+(settings.progressUp ? 'up ' : 'down ')+progressingClass});
|
|
$progress
|
|
.addClass(settings.showProgress)
|
|
.append($progressBar);
|
|
if ($progress.hasClass(className.top)) {
|
|
$toastBox.prepend($progress);
|
|
} else {
|
|
$toastBox.append($progress);
|
|
}
|
|
$progressBar.css('animation-duration', settings.displayTime / 1000 + 's');
|
|
}
|
|
$animationObject = $('<span/>',{class:'wait '+progressingClass});
|
|
$animationObject.css('animation-duration', settings.displayTime / 1000 + 's');
|
|
$animationObject.appendTo($toast);
|
|
}
|
|
if (settings.compact) {
|
|
$toastBox.addClass(className.compact);
|
|
$toast.addClass(className.compact);
|
|
if($progress) {
|
|
$progress.addClass(className.compact);
|
|
}
|
|
}
|
|
if (settings.newestOnTop) {
|
|
$toastBox.prependTo(module.get.container());
|
|
}
|
|
else {
|
|
$toastBox.appendTo(module.get.container());
|
|
}
|
|
}
|
|
},
|
|
|
|
bind: {
|
|
events: function() {
|
|
module.debug('Binding events to toast');
|
|
if(settings.closeOnClick || settings.closeIcon) {
|
|
(settings.closeIcon ? $close : $toast)
|
|
.on('click' + eventNamespace, module.event.click)
|
|
;
|
|
}
|
|
if($animationObject) {
|
|
$animationObject.on('animationend' + eventNamespace, module.close);
|
|
}
|
|
$toastBox
|
|
.on('click' + eventNamespace, selector.approve, module.event.approve)
|
|
.on('click' + eventNamespace, selector.deny, module.event.deny)
|
|
;
|
|
}
|
|
},
|
|
|
|
unbind: {
|
|
events: function() {
|
|
module.debug('Unbinding events to toast');
|
|
if(settings.closeOnClick || settings.closeIcon) {
|
|
(settings.closeIcon ? $close : $toast)
|
|
.off('click' + eventNamespace)
|
|
;
|
|
}
|
|
if($animationObject) {
|
|
$animationObject.off('animationend' + eventNamespace);
|
|
}
|
|
$toastBox
|
|
.off('click' + eventNamespace)
|
|
;
|
|
}
|
|
},
|
|
|
|
animate: {
|
|
show: function(callback) {
|
|
callback = $.isFunction(callback) ? callback : function(){};
|
|
if(settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
|
|
module.set.visible();
|
|
$toastBox
|
|
.transition({
|
|
animation : settings.transition.showMethod + ' in',
|
|
queue : false,
|
|
debug : settings.debug,
|
|
verbose : settings.verbose,
|
|
duration : settings.transition.showDuration,
|
|
onComplete : function() {
|
|
callback.call($toastBox, element);
|
|
settings.onVisible.call($toastBox, element);
|
|
}
|
|
})
|
|
;
|
|
}
|
|
},
|
|
close: function(callback) {
|
|
callback = $.isFunction(callback) ? callback : function(){};
|
|
module.debug('Closing toast');
|
|
if(settings.onHide.call($toastBox, element) === false) {
|
|
module.debug('onHide callback returned false, cancelling toast animation');
|
|
return;
|
|
}
|
|
if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
|
|
$toastBox
|
|
.transition({
|
|
animation : settings.transition.hideMethod + ' out',
|
|
queue : false,
|
|
duration : settings.transition.hideDuration,
|
|
debug : settings.debug,
|
|
verbose : settings.verbose,
|
|
interval : 50,
|
|
|
|
onBeforeHide: function(callback){
|
|
callback = $.isFunction(callback)?callback : function(){};
|
|
if(settings.transition.closeEasing !== ''){
|
|
if($toastBox) {
|
|
$toastBox.css('opacity', 0);
|
|
$toastBox.wrap('<div/>').parent().hide(settings.transition.closeDuration, settings.transition.closeEasing, function () {
|
|
if ($toastBox) {
|
|
$toastBox.parent().remove();
|
|
callback.call($toastBox);
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
callback.call($toastBox);
|
|
}
|
|
},
|
|
onComplete : function() {
|
|
callback.call($toastBox, element);
|
|
settings.onHidden.call($toastBox, element);
|
|
module.destroy();
|
|
}
|
|
})
|
|
;
|
|
}
|
|
else {
|
|
module.error(error.noTransition);
|
|
}
|
|
},
|
|
pause: function() {
|
|
$animationObject.css('animationPlayState','paused');
|
|
if($progressBar) {
|
|
$progressBar.css('animationPlayState', 'paused');
|
|
}
|
|
},
|
|
continue: function() {
|
|
$animationObject.css('animationPlayState','running');
|
|
if($progressBar) {
|
|
$progressBar.css('animationPlayState', 'running');
|
|
}
|
|
}
|
|
},
|
|
|
|
has: {
|
|
container: function() {
|
|
module.verbose('Determining if there is already a container');
|
|
return ($context.find(module.helpers.toClass(settings.position) + selector.container + (settings.horizontal ? module.helpers.toClass(className.horizontal) : '')).length > 0);
|
|
},
|
|
toast: function(){
|
|
return !!module.get.toast();
|
|
},
|
|
toasts: function(){
|
|
return module.get.toasts().length > 0;
|
|
},
|
|
configActions: function () {
|
|
return Array.isArray(settings.actions) && settings.actions.length > 0;
|
|
}
|
|
},
|
|
|
|
get: {
|
|
container: function() {
|
|
return ($context.find(module.helpers.toClass(settings.position) + selector.container)[0]);
|
|
},
|
|
toastBox: function() {
|
|
return $toastBox || null;
|
|
},
|
|
toast: function() {
|
|
return $toast || null;
|
|
},
|
|
toasts: function() {
|
|
return $(module.get.container()).find(selector.box);
|
|
},
|
|
iconClass: function() {
|
|
return typeof settings.showIcon === 'string' ? settings.showIcon : settings.showIcon && settings.icons[settings.class] ? settings.icons[settings.class] : '';
|
|
},
|
|
remainingTime: function() {
|
|
return $animationObject ? $animationObject.css('opacity') * settings.displayTime : 0;
|
|
}
|
|
},
|
|
|
|
set: {
|
|
visible: function() {
|
|
$toast.addClass(className.visible);
|
|
}
|
|
},
|
|
|
|
remove: {
|
|
visible: function() {
|
|
$toast.removeClass(className.visible);
|
|
}
|
|
},
|
|
|
|
event: {
|
|
click: function(event) {
|
|
if($(event.target).closest('a').length === 0) {
|
|
settings.onClick.call($toastBox, element);
|
|
module.close();
|
|
}
|
|
},
|
|
approve: function() {
|
|
if(settings.onApprove.call(element, $module) === false) {
|
|
module.verbose('Approve callback returned false cancelling close');
|
|
return;
|
|
}
|
|
module.close();
|
|
},
|
|
deny: function() {
|
|
if(settings.onDeny.call(element, $module) === false) {
|
|
module.verbose('Deny callback returned false cancelling close');
|
|
return;
|
|
}
|
|
module.close();
|
|
}
|
|
},
|
|
|
|
helpers: {
|
|
toClass: function(selector) {
|
|
var
|
|
classes = selector.split(' '),
|
|
result = ''
|
|
;
|
|
|
|
classes.forEach(function (element) {
|
|
result += '.' + element;
|
|
});
|
|
|
|
return result;
|
|
},
|
|
deQuote: function(string) {
|
|
return String(string).replace(/"/g,"");
|
|
},
|
|
escape: function(string, preserveHTML) {
|
|
if (preserveHTML){
|
|
return string;
|
|
}
|
|
var
|
|
badChars = /[<>"'`]/g,
|
|
shouldEscape = /[&<>"'`]/,
|
|
escape = {
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
"`": "`"
|
|
},
|
|
escapedChar = function(chr) {
|
|
return escape[chr];
|
|
}
|
|
;
|
|
if(shouldEscape.test(string)) {
|
|
string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&");
|
|
return string.replace(badChars, escapedChar);
|
|
}
|
|
return string;
|
|
}
|
|
},
|
|
|
|
can: {
|
|
useElement: function(element){
|
|
if ($.fn[element] !== undefined) {
|
|
return true;
|
|
}
|
|
module.error(error.noElement.replace('{element}',element));
|
|
return false;
|
|
}
|
|
},
|
|
|
|
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 = setTimeout(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) && performance.length > 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 = query.length - 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 {
|
|
module.error(error.method, query);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
if ( $.isFunction( found ) ) {
|
|
response = found.apply(context, passedArguments);
|
|
}
|
|
else if(found !== undefined) {
|
|
response = found;
|
|
}
|
|
if(Array.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();
|
|
returnedValue = $module;
|
|
}
|
|
})
|
|
;
|
|
|
|
return (returnedValue !== undefined)
|
|
? returnedValue
|
|
: this
|
|
;
|
|
};
|
|
|
|
$.fn.toast.settings = {
|
|
|
|
name : 'Toast',
|
|
namespace : 'toast',
|
|
|
|
silent : false,
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
context : 'body',
|
|
|
|
position : 'top right',
|
|
horizontal : false,
|
|
class : 'neutral',
|
|
classProgress : false,
|
|
classActions : false,
|
|
classImage : 'mini',
|
|
|
|
title : '',
|
|
message : '',
|
|
displayTime : 3000, // set to zero to require manually dismissal, otherwise hides on its own
|
|
minDisplayTime : 1000, // minimum displaytime in case displayTime is set to 'auto'
|
|
wordsPerMinute : 120,
|
|
showIcon : false,
|
|
newestOnTop : false,
|
|
showProgress : false,
|
|
pauseOnHover : true,
|
|
progressUp : false, //if true, the bar will start at 0% and increase to 100%
|
|
opacity : 1,
|
|
compact : true,
|
|
closeIcon : false,
|
|
closeOnClick : true,
|
|
cloneModule : true,
|
|
actions : false,
|
|
preserveHTML : true,
|
|
showImage : false,
|
|
|
|
// transition settings
|
|
transition : {
|
|
showMethod : 'scale',
|
|
showDuration : 500,
|
|
hideMethod : 'scale',
|
|
hideDuration : 500,
|
|
closeEasing : 'easeOutCubic', //Set to empty string to stack the closed toast area immediately (old behaviour)
|
|
closeDuration: 500
|
|
},
|
|
|
|
error: {
|
|
method : 'The method you called is not defined.',
|
|
noElement : 'This module requires ui {element}',
|
|
verticalCard : 'Vertical but not attached actions are not supported for card layout'
|
|
},
|
|
|
|
className : {
|
|
container : 'ui toast-container',
|
|
box : 'floating toast-box',
|
|
progress : 'ui attached active progress',
|
|
toast : 'ui toast',
|
|
icon : 'centered icon',
|
|
visible : 'visible',
|
|
content : 'content',
|
|
title : 'ui header',
|
|
message : 'message',
|
|
actions : 'actions',
|
|
extraContent : 'extra content',
|
|
button : 'ui button',
|
|
buttons : 'ui buttons',
|
|
close : 'close icon',
|
|
image : 'ui image',
|
|
vertical : 'vertical',
|
|
horizontal : 'horizontal',
|
|
attached : 'attached',
|
|
inverted : 'inverted',
|
|
compact : 'compact',
|
|
pausable : 'pausable',
|
|
progressing : 'progressing',
|
|
top : 'top',
|
|
bottom : 'bottom',
|
|
left : 'left',
|
|
basic : 'basic',
|
|
unclickable : 'unclickable'
|
|
},
|
|
|
|
icons : {
|
|
info : 'info',
|
|
success : 'checkmark',
|
|
warning : 'warning',
|
|
error : 'times'
|
|
},
|
|
|
|
selector : {
|
|
container : '.ui.toast-container',
|
|
box : '.toast-box',
|
|
toast : '.ui.toast',
|
|
title : '.header',
|
|
message : '.message:not(.ui)',
|
|
image : '> img.image, > .image > img',
|
|
icon : '> i.icon',
|
|
input : 'input:not([type="hidden"]), textarea, select, button, .ui.button, ui.dropdown',
|
|
approve : '.actions .positive, .actions .approve, .actions .ok',
|
|
deny : '.actions .negative, .actions .deny, .actions .cancel'
|
|
},
|
|
|
|
fields : {
|
|
class : 'class',
|
|
text : 'text',
|
|
icon : 'icon',
|
|
click : 'click'
|
|
},
|
|
|
|
// callbacks
|
|
onShow : function(){},
|
|
onVisible : function(){},
|
|
onClick : function(){},
|
|
onHide : function(){},
|
|
onHidden : function(){},
|
|
onRemove : function(){},
|
|
onApprove : function(){},
|
|
onDeny : function(){}
|
|
};
|
|
|
|
$.extend( $.easing, {
|
|
easeOutBounce: function (x, t, b, c, d) {
|
|
if ((t/=d) < (1/2.75)) {
|
|
return c*(7.5625*t*t) + b;
|
|
} else if (t < (2/2.75)) {
|
|
return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
|
|
} else if (t < (2.5/2.75)) {
|
|
return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
|
|
} else {
|
|
return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
|
|
}
|
|
},
|
|
easeOutCubic: function (t) {
|
|
return (--t)*t*t+1;
|
|
}
|
|
});
|
|
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Form Validation
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
window = (typeof window != 'undefined' && window.Math == Math)
|
|
? window
|
|
: (typeof self != 'undefined' && self.Math == Math)
|
|
? self
|
|
: Function('return this')()
|
|
;
|
|
|
|
$.fn.form = function(parameters) {
|
|
var
|
|
$allModules = $(this),
|
|
moduleSelector = $allModules.selector || '',
|
|
|
|
time = new Date().getTime(),
|
|
performance = [],
|
|
|
|
query = arguments[0],
|
|
legacyParameters = arguments[1],
|
|
methodInvoked = (typeof query == 'string'),
|
|
queryArguments = [].slice.call(arguments, 1),
|
|
returnedValue
|
|
;
|
|
$allModules
|
|
.each(function() {
|
|
var
|
|
$module = $(this),
|
|
element = this,
|
|
|
|
formErrors = [],
|
|
keyHeldDown = false,
|
|
|
|
// set at run-time
|
|
$field,
|
|
$group,
|
|
$message,
|
|
$prompt,
|
|
$submit,
|
|
$clear,
|
|
$reset,
|
|
|
|
settings,
|
|
validation,
|
|
|
|
metadata,
|
|
selector,
|
|
className,
|
|
regExp,
|
|
error,
|
|
|
|
namespace,
|
|
moduleNamespace,
|
|
eventNamespace,
|
|
|
|
submitting = false,
|
|
dirty = false,
|
|
history = ['clean', 'clean'],
|
|
|
|
instance,
|
|
module
|
|
;
|
|
|
|
module = {
|
|
|
|
initialize: function() {
|
|
|
|
// settings grabbed at run time
|
|
module.get.settings();
|
|
if(methodInvoked) {
|
|
if(instance === undefined) {
|
|
module.instantiate();
|
|
}
|
|
module.invoke(query);
|
|
}
|
|
else {
|
|
if(instance !== undefined) {
|
|
instance.invoke('destroy');
|
|
module.refresh();
|
|
}
|
|
module.verbose('Initializing form validation', $module, settings);
|
|
module.bindEvents();
|
|
module.set.defaults();
|
|
if (settings.autoCheckRequired) {
|
|
module.set.autoCheck();
|
|
}
|
|
module.instantiate();
|
|
}
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of module', module);
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, module)
|
|
;
|
|
},
|
|
|
|
destroy: function() {
|
|
module.verbose('Destroying previous module', instance);
|
|
module.removeEvents();
|
|
$module
|
|
.removeData(moduleNamespace)
|
|
;
|
|
},
|
|
|
|
refresh: function() {
|
|
module.verbose('Refreshing selector cache');
|
|
$field = $module.find(selector.field);
|
|
$group = $module.find(selector.group);
|
|
$message = $module.find(selector.message);
|
|
$prompt = $module.find(selector.prompt);
|
|
|
|
$submit = $module.find(selector.submit);
|
|
$clear = $module.find(selector.clear);
|
|
$reset = $module.find(selector.reset);
|
|
},
|
|
|
|
submit: function() {
|
|
module.verbose('Submitting form', $module);
|
|
submitting = true;
|
|
$module.submit();
|
|
},
|
|
|
|
attachEvents: function(selector, action) {
|
|
action = action || 'submit';
|
|
$(selector).on('click' + eventNamespace, function(event) {
|
|
module[action]();
|
|
event.preventDefault();
|
|
});
|
|
},
|
|
|
|
bindEvents: function() {
|
|
module.verbose('Attaching form events');
|
|
$module
|
|
.on('submit' + eventNamespace, module.validate.form)
|
|
.on('blur' + eventNamespace, selector.field, module.event.field.blur)
|
|
.on('click' + eventNamespace, selector.submit, module.submit)
|
|
.on('click' + eventNamespace, selector.reset, module.reset)
|
|
.on('click' + eventNamespace, selector.clear, module.clear)
|
|
;
|
|
if(settings.keyboardShortcuts) {
|
|
$module.on('keydown' + eventNamespace, selector.field, module.event.field.keydown);
|
|
}
|
|
$field.each(function(index, el) {
|
|
var
|
|
$input = $(el),
|
|
type = $input.prop('type'),
|
|
inputEvent = module.get.changeEvent(type, $input)
|
|
;
|
|
$input.on(inputEvent + eventNamespace, module.event.field.change);
|
|
});
|
|
|
|
// Dirty events
|
|
if (settings.preventLeaving) {
|
|
$(window).on('beforeunload' + eventNamespace, module.event.beforeUnload);
|
|
}
|
|
|
|
$field.on('change click keyup keydown blur', function(e) {
|
|
module.determine.isDirty();
|
|
});
|
|
|
|
$module.on('dirty' + eventNamespace, function(e) {
|
|
settings.onDirty.call();
|
|
});
|
|
|
|
$module.on('clean' + eventNamespace, function(e) {
|
|
settings.onClean.call();
|
|
})
|
|
},
|
|
|
|
clear: function() {
|
|
$field.each(function (index, el) {
|
|
var
|
|
$field = $(el),
|
|
$element = $field.parent(),
|
|
$fieldGroup = $field.closest($group),
|
|
$prompt = $fieldGroup.find(selector.prompt),
|
|
$calendar = $field.closest(selector.uiCalendar),
|
|
defaultValue = $field.data(metadata.defaultValue) || '',
|
|
isCheckbox = $element.is(selector.uiCheckbox),
|
|
isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
|
|
isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
|
|
isErrored = $fieldGroup.hasClass(className.error)
|
|
;
|
|
if(isErrored) {
|
|
module.verbose('Resetting error on field', $fieldGroup);
|
|
$fieldGroup.removeClass(className.error);
|
|
$prompt.remove();
|
|
}
|
|
if(isDropdown) {
|
|
module.verbose('Resetting dropdown value', $element, defaultValue);
|
|
$element.dropdown('clear', true);
|
|
}
|
|
else if(isCheckbox) {
|
|
$field.prop('checked', false);
|
|
}
|
|
else if (isCalendar) {
|
|
$calendar.calendar('clear');
|
|
}
|
|
else {
|
|
module.verbose('Resetting field value', $field, defaultValue);
|
|
$field.val('');
|
|
}
|
|
});
|
|
module.remove.states();
|
|
},
|
|
|
|
reset: function() {
|
|
$field.each(function (index, el) {
|
|
var
|
|
$field = $(el),
|
|
$element = $field.parent(),
|
|
$fieldGroup = $field.closest($group),
|
|
$calendar = $field.closest(selector.uiCalendar),
|
|
$prompt = $fieldGroup.find(selector.prompt),
|
|
defaultValue = $field.data(metadata.defaultValue),
|
|
isCheckbox = $element.is(selector.uiCheckbox),
|
|
isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
|
|
isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
|
|
isErrored = $fieldGroup.hasClass(className.error)
|
|
;
|
|
if(defaultValue === undefined) {
|
|
return;
|
|
}
|
|
if(isErrored) {
|
|
module.verbose('Resetting error on field', $fieldGroup);
|
|
$fieldGroup.removeClass(className.error);
|
|
$prompt.remove();
|
|
}
|
|
if(isDropdown) {
|
|
module.verbose('Resetting dropdown value', $element, defaultValue);
|
|
$element.dropdown('restore defaults', true);
|
|
}
|
|
else if(isCheckbox) {
|
|
module.verbose('Resetting checkbox value', $element, defaultValue);
|
|
$field.prop('checked', defaultValue);
|
|
}
|
|
else if (isCalendar) {
|
|
$calendar.calendar('set date', defaultValue);
|
|
}
|
|
else {
|
|
module.verbose('Resetting field value', $field, defaultValue);
|
|
$field.val(defaultValue);
|
|
}
|
|
});
|
|
module.remove.states();
|
|
},
|
|
|
|
determine: {
|
|
isValid: function() {
|
|
var
|
|
allValid = true
|
|
;
|
|
$.each(validation, function(fieldName, field) {
|
|
if( !( module.validate.field(field, fieldName, true) ) ) {
|
|
allValid = false;
|
|
}
|
|
});
|
|
return allValid;
|
|
},
|
|
isDirty: function(e) {
|
|
var formIsDirty = false;
|
|
|
|
$field.each(function(index, el) {
|
|
var
|
|
$el = $(el),
|
|
isCheckbox = ($el.filter(selector.checkbox).length > 0),
|
|
isDirty
|
|
;
|
|
|
|
if (isCheckbox) {
|
|
isDirty = module.is.checkboxDirty($el);
|
|
} else {
|
|
isDirty = module.is.fieldDirty($el);
|
|
}
|
|
|
|
$el.data(settings.metadata.isDirty, isDirty);
|
|
|
|
formIsDirty |= isDirty;
|
|
});
|
|
|
|
if (formIsDirty) {
|
|
module.set.dirty();
|
|
} else {
|
|
module.set.clean();
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
is: {
|
|
bracketedRule: function(rule) {
|
|
return (rule.type && rule.type.match(settings.regExp.bracket));
|
|
},
|
|
// duck type rule test
|
|
shorthandRules: function(rules) {
|
|
return (typeof rules == 'string' || Array.isArray(rules));
|
|
},
|
|
empty: function($field) {
|
|
if(!$field || $field.length === 0) {
|
|
return true;
|
|
}
|
|
else if($field.is(selector.checkbox)) {
|
|
return !$field.is(':checked');
|
|
}
|
|
else {
|
|
return module.is.blank($field);
|
|
}
|
|
},
|
|
blank: function($field) {
|
|
return String($field.val()).trim() === '';
|
|
},
|
|
valid: function(field, showErrors) {
|
|
var
|
|
allValid = true
|
|
;
|
|
if(field) {
|
|
module.verbose('Checking if field is valid', field);
|
|
return module.validate.field(validation[field], field, !!showErrors);
|
|
}
|
|
else {
|
|
module.verbose('Checking if form is valid');
|
|
$.each(validation, function(fieldName, field) {
|
|
if( !module.is.valid(fieldName, showErrors) ) {
|
|
allValid = false;
|
|
}
|
|
});
|
|
return allValid;
|
|
}
|
|
},
|
|
dirty: function() {
|
|
return dirty;
|
|
},
|
|
clean: function() {
|
|
return !dirty;
|
|
},
|
|
fieldDirty: function($el) {
|
|
var initialValue = $el.data(metadata.defaultValue);
|
|
// Explicitly check for null/undefined here as value may be `false`, so ($el.data(dataInitialValue) || '') would not work
|
|
if (initialValue == null) { initialValue = ''; }
|
|
else if(Array.isArray(initialValue)) {
|
|
initialValue = initialValue.toString();
|
|
}
|
|
var currentValue = $el.val();
|
|
if (currentValue == null) { currentValue = ''; }
|
|
// multiple select values are returned as arrays which are never equal, so do string conversion first
|
|
else if(Array.isArray(currentValue)) {
|
|
currentValue = currentValue.toString();
|
|
}
|
|
// Boolean values can be encoded as "true/false" or "True/False" depending on underlying frameworks so we need a case insensitive comparison
|
|
var boolRegex = /^(true|false)$/i;
|
|
var isBoolValue = boolRegex.test(initialValue) && boolRegex.test(currentValue);
|
|
if (isBoolValue) {
|
|
var regex = new RegExp("^" + initialValue + "$", "i");
|
|
return !regex.test(currentValue);
|
|
}
|
|
|
|
return currentValue !== initialValue;
|
|
},
|
|
checkboxDirty: function($el) {
|
|
var initialValue = $el.data(metadata.defaultValue);
|
|
var currentValue = $el.is(":checked");
|
|
|
|
return initialValue !== currentValue;
|
|
},
|
|
justDirty: function() {
|
|
return (history[0] === 'dirty');
|
|
},
|
|
justClean: function() {
|
|
return (history[0] === 'clean');
|
|
}
|
|
},
|
|
|
|
removeEvents: function() {
|
|
$module.off(eventNamespace);
|
|
$field.off(eventNamespace);
|
|
$submit.off(eventNamespace);
|
|
$field.off(eventNamespace);
|
|
},
|
|
|
|
event: {
|
|
field: {
|
|
keydown: function(event) {
|
|
var
|
|
$field = $(this),
|
|
key = event.which,
|
|
isInput = $field.is(selector.input),
|
|
isCheckbox = $field.is(selector.checkbox),
|
|
isInDropdown = ($field.closest(selector.uiDropdown).length > 0),
|
|
keyCode = {
|
|
enter : 13,
|
|
escape : 27
|
|
}
|
|
;
|
|
if( key == keyCode.escape) {
|
|
module.verbose('Escape key pressed blurring field');
|
|
$field[0]
|
|
.blur()
|
|
;
|
|
}
|
|
if(!event.ctrlKey && key == keyCode.enter && isInput && !isInDropdown && !isCheckbox) {
|
|
if(!keyHeldDown) {
|
|
$field.one('keyup' + eventNamespace, module.event.field.keyup);
|
|
module.submit();
|
|
module.debug('Enter pressed on input submitting form');
|
|
}
|
|
keyHeldDown = true;
|
|
}
|
|
},
|
|
keyup: function() {
|
|
keyHeldDown = false;
|
|
},
|
|
blur: function(event) {
|
|
var
|
|
$field = $(this),
|
|
$fieldGroup = $field.closest($group),
|
|
validationRules = module.get.validation($field)
|
|
;
|
|
if(validationRules && (settings.on == 'blur' || ( $fieldGroup.hasClass(className.error) && settings.revalidate) )) {
|
|
module.debug('Revalidating field', $field, validationRules);
|
|
module.validate.field( validationRules );
|
|
if(!settings.inline) {
|
|
module.validate.form(false,true);
|
|
}
|
|
}
|
|
},
|
|
change: function(event) {
|
|
var
|
|
$field = $(this),
|
|
$fieldGroup = $field.closest($group),
|
|
validationRules = module.get.validation($field)
|
|
;
|
|
if(validationRules && (settings.on == 'change' || ( $fieldGroup.hasClass(className.error) && settings.revalidate) )) {
|
|
clearTimeout(module.timer);
|
|
module.timer = setTimeout(function() {
|
|
module.debug('Revalidating field', $field, validationRules);
|
|
module.validate.field( validationRules );
|
|
if(!settings.inline) {
|
|
module.validate.form(false,true);
|
|
}
|
|
}, settings.delay);
|
|
}
|
|
}
|
|
},
|
|
beforeUnload: function(event) {
|
|
if (module.is.dirty() && !submitting) {
|
|
var event = event || window.event;
|
|
|
|
// For modern browsers
|
|
if (event) {
|
|
event.returnValue = settings.text.leavingMessage;
|
|
}
|
|
|
|
// For olders...
|
|
return settings.text.leavingMessage;
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
get: {
|
|
ancillaryValue: function(rule) {
|
|
if(!rule.type || (!rule.value && !module.is.bracketedRule(rule))) {
|
|
return false;
|
|
}
|
|
return (rule.value !== undefined)
|
|
? rule.value
|
|
: rule.type.match(settings.regExp.bracket)[1] + ''
|
|
;
|
|
},
|
|
ruleName: function(rule) {
|
|
if( module.is.bracketedRule(rule) ) {
|
|
return rule.type.replace(rule.type.match(settings.regExp.bracket)[0], '');
|
|
}
|
|
return rule.type;
|
|
},
|
|
changeEvent: function(type, $input) {
|
|
if(type == 'checkbox' || type == 'radio' || type == 'hidden' || $input.is('select')) {
|
|
return 'change';
|
|
}
|
|
else {
|
|
return module.get.inputEvent();
|
|
}
|
|
},
|
|
inputEvent: function() {
|
|
return (document.createElement('input').oninput !== undefined)
|
|
? 'input'
|
|
: (document.createElement('input').onpropertychange !== undefined)
|
|
? 'propertychange'
|
|
: 'keyup'
|
|
;
|
|
},
|
|
fieldsFromShorthand: function(fields) {
|
|
var
|
|
fullFields = {}
|
|
;
|
|
$.each(fields, function(name, rules) {
|
|
if (!Array.isArray(rules) && typeof rules === 'object') {
|
|
fullFields[name] = rules;
|
|
} else {
|
|
if (typeof rules == 'string') {
|
|
rules = [rules];
|
|
}
|
|
fullFields[name] = {
|
|
rules: []
|
|
};
|
|
$.each(rules, function (index, rule) {
|
|
fullFields[name].rules.push({type: rule});
|
|
});
|
|
}
|
|
});
|
|
return fullFields;
|
|
},
|
|
prompt: function(rule, field) {
|
|
var
|
|
ruleName = module.get.ruleName(rule),
|
|
ancillary = module.get.ancillaryValue(rule),
|
|
$field = module.get.field(field.identifier),
|
|
value = $field.val(),
|
|
prompt = $.isFunction(rule.prompt)
|
|
? rule.prompt(value)
|
|
: rule.prompt || settings.prompt[ruleName] || settings.text.unspecifiedRule,
|
|
requiresValue = (prompt.search('{value}') !== -1),
|
|
requiresName = (prompt.search('{name}') !== -1),
|
|
$label,
|
|
name,
|
|
parts,
|
|
suffixPrompt
|
|
;
|
|
if(ancillary && ancillary.indexOf('..') >= 0) {
|
|
parts = ancillary.split('..', 2);
|
|
if(!rule.prompt) {
|
|
suffixPrompt = (
|
|
parts[0] === '' ? settings.prompt.maxValue.replace(/\{ruleValue\}/g,'{max}') :
|
|
parts[1] === '' ? settings.prompt.minValue.replace(/\{ruleValue\}/g,'{min}') :
|
|
settings.prompt.range
|
|
);
|
|
prompt += suffixPrompt.replace(/\{name\}/g, ' ' + settings.text.and);
|
|
}
|
|
prompt = prompt.replace(/\{min\}/g, parts[0]);
|
|
prompt = prompt.replace(/\{max\}/g, parts[1]);
|
|
}
|
|
if(requiresValue) {
|
|
prompt = prompt.replace(/\{value\}/g, $field.val());
|
|
}
|
|
if(requiresName) {
|
|
$label = $field.closest(selector.group).find('label').eq(0);
|
|
name = ($label.length == 1)
|
|
? $label.text()
|
|
: $field.prop('placeholder') || settings.text.unspecifiedField
|
|
;
|
|
prompt = prompt.replace(/\{name\}/g, name);
|
|
}
|
|
prompt = prompt.replace(/\{identifier\}/g, field.identifier);
|
|
prompt = prompt.replace(/\{ruleValue\}/g, ancillary);
|
|
if(!rule.prompt) {
|
|
module.verbose('Using default validation prompt for type', prompt, ruleName);
|
|
}
|
|
return prompt;
|
|
},
|
|
settings: function() {
|
|
if($.isPlainObject(parameters)) {
|
|
var
|
|
keys = Object.keys(parameters),
|
|
isLegacySettings = (keys.length > 0)
|
|
? (parameters[keys[0]].identifier !== undefined && parameters[keys[0]].rules !== undefined)
|
|
: false
|
|
;
|
|
if(isLegacySettings) {
|
|
// 1.x (ducktyped)
|
|
settings = $.extend(true, {}, $.fn.form.settings, legacyParameters);
|
|
validation = $.extend({}, $.fn.form.settings.defaults, parameters);
|
|
module.error(settings.error.oldSyntax, element);
|
|
module.verbose('Extending settings from legacy parameters', validation, settings);
|
|
}
|
|
else {
|
|
// 2.x
|
|
if(parameters.fields) {
|
|
parameters.fields = module.get.fieldsFromShorthand(parameters.fields);
|
|
}
|
|
settings = $.extend(true, {}, $.fn.form.settings, parameters);
|
|
validation = $.extend({}, $.fn.form.settings.defaults, settings.fields);
|
|
module.verbose('Extending settings', validation, settings);
|
|
}
|
|
}
|
|
else {
|
|
settings = $.fn.form.settings;
|
|
validation = $.fn.form.settings.defaults;
|
|
module.verbose('Using default form validation', validation, settings);
|
|
}
|
|
|
|
// shorthand
|
|
namespace = settings.namespace;
|
|
metadata = settings.metadata;
|
|
selector = settings.selector;
|
|
className = settings.className;
|
|
regExp = settings.regExp;
|
|
error = settings.error;
|
|
moduleNamespace = 'module-' + namespace;
|
|
eventNamespace = '.' + namespace;
|
|
|
|
// grab instance
|
|
instance = $module.data(moduleNamespace);
|
|
|
|
// refresh selector cache
|
|
(instance || module).refresh();
|
|
},
|
|
field: function(identifier) {
|
|
module.verbose('Finding field with identifier', identifier);
|
|
identifier = module.escape.string(identifier);
|
|
var t;
|
|
if((t=$field.filter('#' + identifier)).length > 0 ) {
|
|
return t;
|
|
}
|
|
if((t=$field.filter('[name="' + identifier +'"]')).length > 0 ) {
|
|
return t;
|
|
}
|
|
if((t=$field.filter('[name="' + identifier +'[]"]')).length > 0 ) {
|
|
return t;
|
|
}
|
|
if((t=$field.filter('[data-' + metadata.validate + '="'+ identifier +'"]')).length > 0 ) {
|
|
return t;
|
|
}
|
|
return $('<input/>');
|
|
},
|
|
fields: function(fields) {
|
|
var
|
|
$fields = $()
|
|
;
|
|
$.each(fields, function(index, name) {
|
|
$fields = $fields.add( module.get.field(name) );
|
|
});
|
|
return $fields;
|
|
},
|
|
validation: function($field) {
|
|
var
|
|
fieldValidation,
|
|
identifier
|
|
;
|
|
if(!validation) {
|
|
return false;
|
|
}
|
|
$.each(validation, function(fieldName, field) {
|
|
identifier = field.identifier || fieldName;
|
|
$.each(module.get.field(identifier), function(index, groupField) {
|
|
if(groupField == $field[0]) {
|
|
field.identifier = identifier;
|
|
fieldValidation = field;
|
|
return false;
|
|
}
|
|
});
|
|
});
|
|
return fieldValidation || false;
|
|
},
|
|
value: function (field) {
|
|
var
|
|
fields = [],
|
|
results
|
|
;
|
|
fields.push(field);
|
|
results = module.get.values.call(element, fields);
|
|
return results[field];
|
|
},
|
|
values: function (fields) {
|
|
var
|
|
$fields = Array.isArray(fields)
|
|
? module.get.fields(fields)
|
|
: $field,
|
|
values = {}
|
|
;
|
|
$fields.each(function(index, field) {
|
|
var
|
|
$field = $(field),
|
|
$calendar = $field.closest(selector.uiCalendar),
|
|
name = $field.prop('name'),
|
|
value = $field.val(),
|
|
isCheckbox = $field.is(selector.checkbox),
|
|
isRadio = $field.is(selector.radio),
|
|
isMultiple = (name.indexOf('[]') !== -1),
|
|
isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
|
|
isChecked = (isCheckbox)
|
|
? $field.is(':checked')
|
|
: false
|
|
;
|
|
if(name) {
|
|
if(isMultiple) {
|
|
name = name.replace('[]', '');
|
|
if(!values[name]) {
|
|
values[name] = [];
|
|
}
|
|
if(isCheckbox) {
|
|
if(isChecked) {
|
|
values[name].push(value || true);
|
|
}
|
|
else {
|
|
values[name].push(false);
|
|
}
|
|
}
|
|
else {
|
|
values[name].push(value);
|
|
}
|
|
}
|
|
else {
|
|
if(isRadio) {
|
|
if(values[name] === undefined || values[name] === false) {
|
|
values[name] = (isChecked)
|
|
? value || true
|
|
: false
|
|
;
|
|
}
|
|
}
|
|
else if(isCheckbox) {
|
|
if(isChecked) {
|
|
values[name] = value || true;
|
|
}
|
|
else {
|
|
values[name] = false;
|
|
}
|
|
}
|
|
else if(isCalendar) {
|
|
var date = $calendar.calendar('get date');
|
|
|
|
if (date !== null) {
|
|
if (settings.dateHandling == 'date') {
|
|
values[name] = date;
|
|
} else if(settings.dateHandling == 'input') {
|
|
values[name] = $calendar.calendar('get input date')
|
|
} else if (settings.dateHandling == 'formatter') {
|
|
var type = $calendar.calendar('setting', 'type');
|
|
|
|
switch(type) {
|
|
case 'date':
|
|
values[name] = settings.formatter.date(date);
|
|
break;
|
|
|
|
case 'datetime':
|
|
values[name] = settings.formatter.datetime(date);
|
|
break;
|
|
|
|
case 'time':
|
|
values[name] = settings.formatter.time(date);
|
|
break;
|
|
|
|
case 'month':
|
|
values[name] = settings.formatter.month(date);
|
|
break;
|
|
|
|
case 'year':
|
|
values[name] = settings.formatter.year(date);
|
|
break;
|
|
|
|
default:
|
|
module.debug('Wrong calendar mode', $calendar, type);
|
|
values[name] = '';
|
|
}
|
|
}
|
|
} else {
|
|
values[name] = '';
|
|
}
|
|
} else {
|
|
values[name] = value;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return values;
|
|
},
|
|
dirtyFields: function() {
|
|
return $field.filter(function(index, e) {
|
|
return $(e).data(metadata.isDirty);
|
|
});
|
|
}
|
|
},
|
|
|
|
has: {
|
|
|
|
field: function(identifier) {
|
|
module.verbose('Checking for existence of a field with identifier', identifier);
|
|
identifier = module.escape.string(identifier);
|
|
if(typeof identifier !== 'string') {
|
|
module.error(error.identifier, identifier);
|
|
}
|
|
if($field.filter('#' + identifier).length > 0 ) {
|
|
return true;
|
|
}
|
|
else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
|
|
return true;
|
|
}
|
|
else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
},
|
|
|
|
can: {
|
|
useElement: function(element){
|
|
if ($.fn[element] !== undefined) {
|
|
return true;
|
|
}
|
|
module.error(error.noElement.replace('{element}',element));
|
|
return false;
|
|
}
|
|
},
|
|
|
|
escape: {
|
|
string: function(text) {
|
|
text = String(text);
|
|
return text.replace(regExp.escape, '\\$&');
|
|
}
|
|
},
|
|
|
|
add: {
|
|
// alias
|
|
rule: function(name, rules) {
|
|
module.add.field(name, rules);
|
|
},
|
|
field: function(name, rules) {
|
|
// Validation should have at least a standard format
|
|
if(validation[name] === undefined || validation[name].rules === undefined) {
|
|
validation[name] = {
|
|
rules: []
|
|
};
|
|
}
|
|
var
|
|
newValidation = {
|
|
rules: []
|
|
}
|
|
;
|
|
if(module.is.shorthandRules(rules)) {
|
|
rules = Array.isArray(rules)
|
|
? rules
|
|
: [rules]
|
|
;
|
|
$.each(rules, function(_index, rule) {
|
|
newValidation.rules.push({ type: rule });
|
|
});
|
|
}
|
|
else {
|
|
newValidation.rules = rules.rules;
|
|
}
|
|
// For each new rule, check if there's not already one with the same type
|
|
$.each(newValidation.rules, function (_index, rule) {
|
|
if ($.grep(validation[name].rules, function(item){ return item.type == rule.type; }).length == 0) {
|
|
validation[name].rules.push(rule);
|
|
}
|
|
});
|
|
module.debug('Adding rules', newValidation.rules, validation);
|
|
},
|
|
fields: function(fields) {
|
|
validation = $.extend({}, validation, module.get.fieldsFromShorthand(fields));
|
|
},
|
|
prompt: function(identifier, errors, internal) {
|
|
var
|
|
$field = module.get.field(identifier),
|
|
$fieldGroup = $field.closest($group),
|
|
$prompt = $fieldGroup.children(selector.prompt),
|
|
promptExists = ($prompt.length !== 0)
|
|
;
|
|
errors = (typeof errors == 'string')
|
|
? [errors]
|
|
: errors
|
|
;
|
|
module.verbose('Adding field error state', identifier);
|
|
if(!internal) {
|
|
$fieldGroup
|
|
.addClass(className.error)
|
|
;
|
|
}
|
|
if(settings.inline) {
|
|
if(!promptExists) {
|
|
$prompt = settings.templates.prompt(errors, className.label);
|
|
$prompt
|
|
.appendTo($fieldGroup)
|
|
;
|
|
}
|
|
$prompt
|
|
.html(errors[0])
|
|
;
|
|
if(!promptExists) {
|
|
if(settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
|
|
module.verbose('Displaying error with css transition', settings.transition);
|
|
$prompt.transition(settings.transition + ' in', settings.duration);
|
|
}
|
|
else {
|
|
module.verbose('Displaying error with fallback javascript animation');
|
|
$prompt
|
|
.fadeIn(settings.duration)
|
|
;
|
|
}
|
|
}
|
|
else {
|
|
module.verbose('Inline errors are disabled, no inline error added', identifier);
|
|
}
|
|
}
|
|
},
|
|
errors: function(errors) {
|
|
module.debug('Adding form error messages', errors);
|
|
module.set.error();
|
|
$message
|
|
.html( settings.templates.error(errors) )
|
|
;
|
|
}
|
|
},
|
|
|
|
remove: {
|
|
errors: function() {
|
|
module.debug('Removing form error messages');
|
|
$message.empty();
|
|
},
|
|
states: function() {
|
|
$module.removeClass(className.error).removeClass(className.success);
|
|
if(!settings.inline) {
|
|
module.remove.errors();
|
|
}
|
|
module.determine.isDirty();
|
|
},
|
|
rule: function(field, rule) {
|
|
var
|
|
rules = Array.isArray(rule)
|
|
? rule
|
|
: [rule]
|
|
;
|
|
if(validation[field] === undefined || !Array.isArray(validation[field].rules)) {
|
|
return;
|
|
}
|
|
if(rule === undefined) {
|
|
module.debug('Removed all rules');
|
|
validation[field].rules = [];
|
|
return;
|
|
}
|
|
$.each(validation[field].rules, function(index, rule) {
|
|
if(rule && rules.indexOf(rule.type) !== -1) {
|
|
module.debug('Removed rule', rule.type);
|
|
validation[field].rules.splice(index, 1);
|
|
}
|
|
});
|
|
},
|
|
field: function(field) {
|
|
var
|
|
fields = Array.isArray(field)
|
|
? field
|
|
: [field]
|
|
;
|
|
$.each(fields, function(index, field) {
|
|
module.remove.rule(field);
|
|
});
|
|
},
|
|
// alias
|
|
rules: function(field, rules) {
|
|
if(Array.isArray(field)) {
|
|
$.each(field, function(index, field) {
|
|
module.remove.rule(field, rules);
|
|
});
|
|
}
|
|
else {
|
|
module.remove.rule(field, rules);
|
|
}
|
|
},
|
|
fields: function(fields) {
|
|
module.remove.field(fields);
|
|
},
|
|
prompt: function(identifier) {
|
|
var
|
|
$field = module.get.field(identifier),
|
|
$fieldGroup = $field.closest($group),
|
|
$prompt = $fieldGroup.children(selector.prompt)
|
|
;
|
|
$fieldGroup
|
|
.removeClass(className.error)
|
|
;
|
|
if(settings.inline && $prompt.is(':visible')) {
|
|
module.verbose('Removing prompt for field', identifier);
|
|
if(settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
|
|
$prompt.transition(settings.transition + ' out', settings.duration, function() {
|
|
$prompt.remove();
|
|
});
|
|
}
|
|
else {
|
|
$prompt
|
|
.fadeOut(settings.duration, function(){
|
|
$prompt.remove();
|
|
})
|
|
;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
set: {
|
|
success: function() {
|
|
$module
|
|
.removeClass(className.error)
|
|
.addClass(className.success)
|
|
;
|
|
},
|
|
defaults: function () {
|
|
$field.each(function (index, el) {
|
|
var
|
|
$el = $(el),
|
|
$parent = $el.parent(),
|
|
isCheckbox = ($el.filter(selector.checkbox).length > 0),
|
|
isDropdown = $parent.is(selector.uiDropdown) && module.can.useElement('dropdown'),
|
|
$calendar = $el.closest(selector.uiCalendar),
|
|
isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
|
|
value = (isCheckbox)
|
|
? $el.is(':checked')
|
|
: $el.val()
|
|
;
|
|
if (isDropdown) {
|
|
$parent.dropdown('save defaults');
|
|
}
|
|
else if (isCalendar) {
|
|
$calendar.calendar('refresh');
|
|
}
|
|
$el.data(metadata.defaultValue, value);
|
|
$el.data(metadata.isDirty, false);
|
|
});
|
|
},
|
|
error: function() {
|
|
$module
|
|
.removeClass(className.success)
|
|
.addClass(className.error)
|
|
;
|
|
},
|
|
value: function (field, value) {
|
|
var
|
|
fields = {}
|
|
;
|
|
fields[field] = value;
|
|
return module.set.values.call(element, fields);
|
|
},
|
|
values: function (fields) {
|
|
if($.isEmptyObject(fields)) {
|
|
return;
|
|
}
|
|
$.each(fields, function(key, value) {
|
|
var
|
|
$field = module.get.field(key),
|
|
$element = $field.parent(),
|
|
$calendar = $field.closest(selector.uiCalendar),
|
|
isMultiple = Array.isArray(value),
|
|
isCheckbox = $element.is(selector.uiCheckbox) && module.can.useElement('checkbox'),
|
|
isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
|
|
isRadio = ($field.is(selector.radio) && isCheckbox),
|
|
isCalendar = ($calendar.length > 0 && module.can.useElement('calendar')),
|
|
fieldExists = ($field.length > 0),
|
|
$multipleField
|
|
;
|
|
if(fieldExists) {
|
|
if(isMultiple && isCheckbox) {
|
|
module.verbose('Selecting multiple', value, $field);
|
|
$element.checkbox('uncheck');
|
|
$.each(value, function(index, value) {
|
|
$multipleField = $field.filter('[value="' + value + '"]');
|
|
$element = $multipleField.parent();
|
|
if($multipleField.length > 0) {
|
|
$element.checkbox('check');
|
|
}
|
|
});
|
|
}
|
|
else if(isRadio) {
|
|
module.verbose('Selecting radio value', value, $field);
|
|
$field.filter('[value="' + value + '"]')
|
|
.parent(selector.uiCheckbox)
|
|
.checkbox('check')
|
|
;
|
|
}
|
|
else if(isCheckbox) {
|
|
module.verbose('Setting checkbox value', value, $element);
|
|
if(value === true || value === 1) {
|
|
$element.checkbox('check');
|
|
}
|
|
else {
|
|
$element.checkbox('uncheck');
|
|
}
|
|
}
|
|
else if(isDropdown) {
|
|
module.verbose('Setting dropdown value', value, $element);
|
|
$element.dropdown('set selected', value);
|
|
}
|
|
else if (isCalendar) {
|
|
$calendar.calendar('set date',value);
|
|
}
|
|
else {
|
|
module.verbose('Setting field value', value, $field);
|
|
$field.val(value);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
dirty: function() {
|
|
module.verbose('Setting state dirty');
|
|
dirty = true;
|
|
history[0] = history[1];
|
|
history[1] = 'dirty';
|
|
|
|
if (module.is.justClean()) {
|
|
$module.trigger('dirty');
|
|
}
|
|
},
|
|
clean: function() {
|
|
module.verbose('Setting state clean');
|
|
dirty = false;
|
|
history[0] = history[1];
|
|
history[1] = 'clean';
|
|
|
|
if (module.is.justDirty()) {
|
|
$module.trigger('clean');
|
|
}
|
|
},
|
|
asClean: function() {
|
|
module.set.defaults();
|
|
module.set.clean();
|
|
},
|
|
asDirty: function() {
|
|
module.set.defaults();
|
|
module.set.dirty();
|
|
},
|
|
autoCheck: function() {
|
|
module.debug('Enabling auto check on required fields');
|
|
$field.each(function (_index, el) {
|
|
var
|
|
$el = $(el),
|
|
$elGroup = $(el).closest($group),
|
|
isCheckbox = ($el.filter(selector.checkbox).length > 0),
|
|
isRequired = $el.prop('required') || $elGroup.hasClass(className.required) || $elGroup.parent().hasClass(className.required),
|
|
isDisabled = $el.is(':disabled') || $elGroup.hasClass(className.disabled) || $elGroup.parent().hasClass(className.disabled),
|
|
validation = module.get.validation($el),
|
|
hasEmptyRule = validation
|
|
? $.grep(validation.rules, function(rule) { return rule.type == "empty" }) !== 0
|
|
: false,
|
|
identifier = validation.identifier || $el.attr('id') || $el.attr('name') || $el.data(metadata.validate)
|
|
;
|
|
if (isRequired && !isDisabled && !hasEmptyRule && identifier !== undefined) {
|
|
if (isCheckbox) {
|
|
module.verbose("Adding 'checked' rule on field", identifier);
|
|
module.add.rule(identifier, "checked");
|
|
} else {
|
|
module.verbose("Adding 'empty' rule on field", identifier);
|
|
module.add.rule(identifier, "empty");
|
|
}
|
|
}
|
|
});
|
|
},
|
|
optional: function(identifier, bool) {
|
|
bool = (bool !== false);
|
|
$.each(validation, function(fieldName, field) {
|
|
if (identifier == fieldName || identifier == field.identifier) {
|
|
field.optional = bool;
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
validate: {
|
|
|
|
form: function(event, ignoreCallbacks) {
|
|
var values = module.get.values();
|
|
|
|
// input keydown event will fire submit repeatedly by browser default
|
|
if(keyHeldDown) {
|
|
return false;
|
|
}
|
|
|
|
// reset errors
|
|
formErrors = [];
|
|
if( module.determine.isValid() ) {
|
|
module.debug('Form has no validation errors, submitting');
|
|
module.set.success();
|
|
if(!settings.inline) {
|
|
module.remove.errors();
|
|
}
|
|
if(ignoreCallbacks !== true) {
|
|
return settings.onSuccess.call(element, event, values);
|
|
}
|
|
}
|
|
else {
|
|
module.debug('Form has errors');
|
|
submitting = false;
|
|
module.set.error();
|
|
if(!settings.inline) {
|
|
module.add.errors(formErrors);
|
|
}
|
|
// prevent ajax submit
|
|
if(event && $module.data('moduleApi') !== undefined) {
|
|
event.stopImmediatePropagation();
|
|
}
|
|
if(settings.errorFocus) {
|
|
var focusElement, hasTabIndex = true;
|
|
if (typeof settings.errorFocus === 'string') {
|
|
focusElement = $(settings.errorFocus);
|
|
hasTabIndex = focusElement.is('[tabindex]');
|
|
// to be able to focus/scroll into non input elements we need a tabindex
|
|
if (!hasTabIndex) {
|
|
focusElement.attr('tabindex',-1);
|
|
}
|
|
} else {
|
|
focusElement = $group.filter('.' + className.error).first().find(selector.field);
|
|
}
|
|
focusElement.focus();
|
|
// only remove tabindex if it was dynamically created above
|
|
if (!hasTabIndex){
|
|
focusElement.removeAttr('tabindex');
|
|
}
|
|
}
|
|
if(ignoreCallbacks !== true) {
|
|
return settings.onFailure.call(element, formErrors, values);
|
|
}
|
|
}
|
|
},
|
|
|
|
// takes a validation object and returns whether field passes validation
|
|
field: function(field, fieldName, showErrors) {
|
|
showErrors = (showErrors !== undefined)
|
|
? showErrors
|
|
: true
|
|
;
|
|
if(typeof field == 'string') {
|
|
module.verbose('Validating field', field);
|
|
fieldName = field;
|
|
field = validation[field];
|
|
}
|
|
var
|
|
identifier = field.identifier || fieldName,
|
|
$field = module.get.field(identifier),
|
|
$dependsField = (field.depends)
|
|
? module.get.field(field.depends)
|
|
: false,
|
|
fieldValid = true,
|
|
fieldErrors = []
|
|
;
|
|
if(!field.identifier) {
|
|
module.debug('Using field name as identifier', identifier);
|
|
field.identifier = identifier;
|
|
}
|
|
var isDisabled = !$field.filter(':not(:disabled)').length;
|
|
if(isDisabled) {
|
|
module.debug('Field is disabled. Skipping', identifier);
|
|
}
|
|
else if(field.optional && module.is.blank($field)){
|
|
module.debug('Field is optional and blank. Skipping', identifier);
|
|
}
|
|
else if(field.depends && module.is.empty($dependsField)) {
|
|
module.debug('Field depends on another value that is not present or empty. Skipping', $dependsField);
|
|
}
|
|
else if(field.rules !== undefined) {
|
|
if(showErrors) {
|
|
$field.closest($group).removeClass(className.error);
|
|
}
|
|
$.each(field.rules, function(index, rule) {
|
|
if( module.has.field(identifier)) {
|
|
var invalidFields = module.validate.rule(field, rule,true) || [];
|
|
if (invalidFields.length>0){
|
|
module.debug('Field is invalid', identifier, rule.type);
|
|
fieldErrors.push(module.get.prompt(rule, field));
|
|
fieldValid = false;
|
|
if(showErrors){
|
|
$(invalidFields).closest($group).addClass(className.error);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if(fieldValid) {
|
|
if(showErrors) {
|
|
module.remove.prompt(identifier, fieldErrors);
|
|
settings.onValid.call($field);
|
|
}
|
|
}
|
|
else {
|
|
if(showErrors) {
|
|
formErrors = formErrors.concat(fieldErrors);
|
|
module.add.prompt(identifier, fieldErrors, true);
|
|
settings.onInvalid.call($field, fieldErrors);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
// takes validation rule and returns whether field passes rule
|
|
rule: function(field, rule, internal) {
|
|
var
|
|
$field = module.get.field(field.identifier),
|
|
ancillary = module.get.ancillaryValue(rule),
|
|
ruleName = module.get.ruleName(rule),
|
|
ruleFunction = settings.rules[ruleName],
|
|
invalidFields = [],
|
|
isCheckbox = $field.is(selector.checkbox),
|
|
isValid = function(field){
|
|
var value = (isCheckbox ? $(field).filter(':checked').val() : $(field).val());
|
|
// cast to string avoiding encoding special values
|
|
value = (value === undefined || value === '' || value === null)
|
|
? ''
|
|
: (settings.shouldTrim && rule.shouldTrim !== false) || rule.shouldTrim ? String(value + '').trim() : String(value + '')
|
|
;
|
|
return ruleFunction.call(field, value, ancillary, $module);
|
|
}
|
|
;
|
|
if( !$.isFunction(ruleFunction) ) {
|
|
module.error(error.noRule, ruleName);
|
|
return;
|
|
}
|
|
if(isCheckbox) {
|
|
if (!isValid($field)) {
|
|
invalidFields = $field;
|
|
}
|
|
} else {
|
|
$.each($field, function (index, field) {
|
|
if (!isValid(field)) {
|
|
invalidFields.push(field);
|
|
}
|
|
});
|
|
}
|
|
return internal ? invalidFields : !(invalidFields.length>0);
|
|
}
|
|
},
|
|
|
|
setting: function(name, value) {
|
|
if( $.isPlainObject(name) ) {
|
|
$.extend(true, settings, name);
|
|
}
|
|
else if(value !== undefined) {
|
|
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 = setTimeout(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($allModules.length > 1) {
|
|
title += ' ' + '(' + $allModules.length + ')';
|
|
}
|
|
if( (console.group !== undefined || console.table !== undefined) && performance.length > 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 = query.length - 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(Array.isArray(returnedValue)) {
|
|
returnedValue.push(response);
|
|
}
|
|
else if(returnedValue !== undefined) {
|
|
returnedValue = [returnedValue, response];
|
|
}
|
|
else if(response !== undefined) {
|
|
returnedValue = response;
|
|
}
|
|
return found;
|
|
}
|
|
};
|
|
module.initialize();
|
|
})
|
|
;
|
|
|
|
return (returnedValue !== undefined)
|
|
? returnedValue
|
|
: this
|
|
;
|
|
};
|
|
|
|
$.fn.form.settings = {
|
|
|
|
name : 'Form',
|
|
namespace : 'form',
|
|
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
fields : false,
|
|
|
|
keyboardShortcuts : true,
|
|
on : 'submit',
|
|
inline : false,
|
|
|
|
delay : 200,
|
|
revalidate : true,
|
|
shouldTrim : true,
|
|
|
|
transition : 'scale',
|
|
duration : 200,
|
|
|
|
autoCheckRequired : false,
|
|
preventLeaving : false,
|
|
errorFocus : false,
|
|
dateHandling : 'date', // 'date', 'input', 'formatter'
|
|
|
|
onValid : function() {},
|
|
onInvalid : function() {},
|
|
onSuccess : function() { return true; },
|
|
onFailure : function() { return false; },
|
|
onDirty : function() {},
|
|
onClean : function() {},
|
|
|
|
metadata : {
|
|
defaultValue : 'default',
|
|
validate : 'validate',
|
|
isDirty : 'isDirty'
|
|
},
|
|
|
|
regExp: {
|
|
htmlID : /^[a-zA-Z][\w:.-]*$/g,
|
|
bracket : /\[(.*)\]/i,
|
|
decimal : /^\d+\.?\d*$/,
|
|
email : /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,
|
|
escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|:,=@]/g,
|
|
flags : /^\/(.*)\/(.*)?/,
|
|
integer : /^\-?\d+$/,
|
|
number : /^\-?\d*(\.\d+)?$/,
|
|
url : /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/i
|
|
},
|
|
|
|
text: {
|
|
and : 'and',
|
|
unspecifiedRule : 'Please enter a valid value',
|
|
unspecifiedField : 'This field',
|
|
leavingMessage : 'There are unsaved changes on this page which will be discarded if you continue.'
|
|
},
|
|
|
|
prompt: {
|
|
range : '{name} must be in a range from {min} to {max}',
|
|
maxValue : '{name} must have a maximum value of {ruleValue}',
|
|
minValue : '{name} must have a minimum value of {ruleValue}',
|
|
empty : '{name} must have a value',
|
|
checked : '{name} must be checked',
|
|
email : '{name} must be a valid e-mail',
|
|
url : '{name} must be a valid url',
|
|
regExp : '{name} is not formatted correctly',
|
|
integer : '{name} must be an integer',
|
|
decimal : '{name} must be a decimal number',
|
|
number : '{name} must be set to a number',
|
|
is : '{name} must be "{ruleValue}"',
|
|
isExactly : '{name} must be exactly "{ruleValue}"',
|
|
not : '{name} cannot be set to "{ruleValue}"',
|
|
notExactly : '{name} cannot be set to exactly "{ruleValue}"',
|
|
contain : '{name} must contain "{ruleValue}"',
|
|
containExactly : '{name} must contain exactly "{ruleValue}"',
|
|
doesntContain : '{name} cannot contain "{ruleValue}"',
|
|
doesntContainExactly : '{name} cannot contain exactly "{ruleValue}"',
|
|
minLength : '{name} must be at least {ruleValue} characters',
|
|
length : '{name} must be at least {ruleValue} characters',
|
|
exactLength : '{name} must be exactly {ruleValue} characters',
|
|
maxLength : '{name} cannot be longer than {ruleValue} characters',
|
|
match : '{name} must match {ruleValue} field',
|
|
different : '{name} must have a different value than {ruleValue} field',
|
|
creditCard : '{name} must be a valid credit card number',
|
|
minCount : '{name} must have at least {ruleValue} choices',
|
|
exactCount : '{name} must have exactly {ruleValue} choices',
|
|
maxCount : '{name} must have {ruleValue} or less choices'
|
|
},
|
|
|
|
selector : {
|
|
checkbox : 'input[type="checkbox"], input[type="radio"]',
|
|
clear : '.clear',
|
|
field : 'input:not(.search):not([type="file"]), textarea, select',
|
|
group : '.field',
|
|
input : 'input:not([type="file"])',
|
|
message : '.error.message',
|
|
prompt : '.prompt.label',
|
|
radio : 'input[type="radio"]',
|
|
reset : '.reset:not([type="reset"])',
|
|
submit : '.submit:not([type="submit"])',
|
|
uiCheckbox : '.ui.checkbox',
|
|
uiDropdown : '.ui.dropdown',
|
|
uiCalendar : '.ui.calendar'
|
|
},
|
|
|
|
className : {
|
|
error : 'error',
|
|
label : 'ui basic red pointing prompt label',
|
|
pressed : 'down',
|
|
success : 'success',
|
|
required : 'required',
|
|
disabled : 'disabled'
|
|
},
|
|
|
|
error: {
|
|
identifier : 'You must specify a string identifier for each field',
|
|
method : 'The method you called is not defined.',
|
|
noRule : 'There is no rule matching the one you specified',
|
|
oldSyntax : 'Starting in 2.0 forms now only take a single settings object. Validation settings converted to new syntax automatically.',
|
|
noElement : 'This module requires ui {element}'
|
|
},
|
|
|
|
templates: {
|
|
|
|
// template that produces error message
|
|
error: function(errors) {
|
|
var
|
|
html = '<ul class="list">'
|
|
;
|
|
$.each(errors, function(index, value) {
|
|
html += '<li>' + value + '</li>';
|
|
});
|
|
html += '</ul>';
|
|
return $(html);
|
|
},
|
|
|
|
// template that produces label
|
|
prompt: function(errors, labelClasses) {
|
|
return $('<div/>')
|
|
.addClass(labelClasses)
|
|
.html(errors[0])
|
|
;
|
|
}
|
|
},
|
|
|
|
formatter: {
|
|
date: function(date) {
|
|
return Intl.DateTimeFormat('en-GB').format(date);
|
|
},
|
|
datetime: function(date) {
|
|
return Intl.DateTimeFormat('en-GB', {
|
|
year: "numeric",
|
|
month: "2-digit",
|
|
day: "2-digit",
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit'
|
|
}).format(date);
|
|
},
|
|
time: function(date) {
|
|
return Intl.DateTimeFormat('en-GB', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit'
|
|
}).format(date);
|
|
},
|
|
month: function(date) {
|
|
return Intl.DateTimeFormat('en-GB', {
|
|
month: '2-digit',
|
|
year: 'numeric'
|
|
}).format(date);
|
|
},
|
|
year: function(date) {
|
|
return Intl.DateTimeFormat('en-GB', {
|
|
year: 'numeric'
|
|
}).format(date);
|
|
}
|
|
},
|
|
|
|
rules: {
|
|
|
|
// is not empty or blank string
|
|
empty: function(value) {
|
|
return !(value === undefined || '' === value || Array.isArray(value) && value.length === 0);
|
|
},
|
|
|
|
// checkbox checked
|
|
checked: function() {
|
|
return ($(this).filter(':checked').length > 0);
|
|
},
|
|
|
|
// is most likely an email
|
|
email: function(value){
|
|
return $.fn.form.settings.regExp.email.test(value);
|
|
},
|
|
|
|
// value is most likely url
|
|
url: function(value) {
|
|
return $.fn.form.settings.regExp.url.test(value);
|
|
},
|
|
|
|
// matches specified regExp
|
|
regExp: function(value, regExp) {
|
|
if(regExp instanceof RegExp) {
|
|
return value.match(regExp);
|
|
}
|
|
var
|
|
regExpParts = regExp.match($.fn.form.settings.regExp.flags),
|
|
flags
|
|
;
|
|
// regular expression specified as /baz/gi (flags)
|
|
if(regExpParts) {
|
|
regExp = (regExpParts.length >= 2)
|
|
? regExpParts[1]
|
|
: regExp
|
|
;
|
|
flags = (regExpParts.length >= 3)
|
|
? regExpParts[2]
|
|
: ''
|
|
;
|
|
}
|
|
return value.match( new RegExp(regExp, flags) );
|
|
},
|
|
minValue: function(value, range) {
|
|
return $.fn.form.settings.rules.range(value, range+'..', 'number');
|
|
},
|
|
maxValue: function(value, range) {
|
|
return $.fn.form.settings.rules.range(value, '..'+range, 'number');
|
|
},
|
|
// is valid integer or matches range
|
|
integer: function(value, range) {
|
|
return $.fn.form.settings.rules.range(value, range, 'integer');
|
|
},
|
|
range: function(value, range, regExp) {
|
|
if(typeof regExp == "string") {
|
|
regExp = $.fn.form.settings.regExp[regExp];
|
|
}
|
|
if(!(regExp instanceof RegExp)) {
|
|
regExp = $.fn.form.settings.regExp.integer;
|
|
}
|
|
var
|
|
min,
|
|
max,
|
|
parts
|
|
;
|
|
if( !range || ['', '..'].indexOf(range) !== -1) {
|
|
// do nothing
|
|
}
|
|
else if(range.indexOf('..') == -1) {
|
|
if(regExp.test(range)) {
|
|
min = max = range - 0;
|
|
}
|
|
}
|
|
else {
|
|
parts = range.split('..', 2);
|
|
if(regExp.test(parts[0])) {
|
|
min = parts[0] - 0;
|
|
}
|
|
if(regExp.test(parts[1])) {
|
|
max = parts[1] - 0;
|
|
}
|
|
}
|
|
return (
|
|
regExp.test(value) &&
|
|
(min === undefined || value >= min) &&
|
|
(max === undefined || value <= max)
|
|
);
|
|
},
|
|
|
|
// is valid number (with decimal)
|
|
decimal: function(value, range) {
|
|
return $.fn.form.settings.rules.range(value, range, 'decimal');
|
|
},
|
|
|
|
// is valid number
|
|
number: function(value, range) {
|
|
return $.fn.form.settings.rules.range(value, range, 'number');
|
|
},
|
|
|
|
// is value (case insensitive)
|
|
is: function(value, text) {
|
|
text = (typeof text == 'string')
|
|
? text.toLowerCase()
|
|
: text
|
|
;
|
|
value = (typeof value == 'string')
|
|
? value.toLowerCase()
|
|
: value
|
|
;
|
|
return (value == text);
|
|
},
|
|
|
|
// is value
|
|
isExactly: function(value, text) {
|
|
return (value == text);
|
|
},
|
|
|
|
// value is not another value (case insensitive)
|
|
not: function(value, notValue) {
|
|
value = (typeof value == 'string')
|
|
? value.toLowerCase()
|
|
: value
|
|
;
|
|
notValue = (typeof notValue == 'string')
|
|
? notValue.toLowerCase()
|
|
: notValue
|
|
;
|
|
return (value != notValue);
|
|
},
|
|
|
|
// value is not another value (case sensitive)
|
|
notExactly: function(value, notValue) {
|
|
return (value != notValue);
|
|
},
|
|
|
|
// value contains text (insensitive)
|
|
contains: function(value, text) {
|
|
// escape regex characters
|
|
text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
|
|
return (value.search( new RegExp(text, 'i') ) !== -1);
|
|
},
|
|
|
|
// value contains text (case sensitive)
|
|
containsExactly: function(value, text) {
|
|
// escape regex characters
|
|
text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
|
|
return (value.search( new RegExp(text) ) !== -1);
|
|
},
|
|
|
|
// value contains text (insensitive)
|
|
doesntContain: function(value, text) {
|
|
// escape regex characters
|
|
text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
|
|
return (value.search( new RegExp(text, 'i') ) === -1);
|
|
},
|
|
|
|
// value contains text (case sensitive)
|
|
doesntContainExactly: function(value, text) {
|
|
// escape regex characters
|
|
text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
|
|
return (value.search( new RegExp(text) ) === -1);
|
|
},
|
|
|
|
// is at least string length
|
|
minLength: function(value, requiredLength) {
|
|
return (value !== undefined)
|
|
? (value.length >= requiredLength)
|
|
: false
|
|
;
|
|
},
|
|
|
|
// see rls notes for 2.0.6 (this is a duplicate of minLength)
|
|
length: function(value, requiredLength) {
|
|
return (value !== undefined)
|
|
? (value.length >= requiredLength)
|
|
: false
|
|
;
|
|
},
|
|
|
|
// is exactly length
|
|
exactLength: function(value, requiredLength) {
|
|
return (value !== undefined)
|
|
? (value.length == requiredLength)
|
|
: false
|
|
;
|
|
},
|
|
|
|
// is less than length
|
|
maxLength: function(value, maxLength) {
|
|
return (value !== undefined)
|
|
? (value.length <= maxLength)
|
|
: false
|
|
;
|
|
},
|
|
|
|
// matches another field
|
|
match: function(value, identifier, $module) {
|
|
var
|
|
matchingValue,
|
|
matchingElement
|
|
;
|
|
if((matchingElement = $module.find('[data-validate="'+ identifier +'"]')).length > 0 ) {
|
|
matchingValue = matchingElement.val();
|
|
}
|
|
else if((matchingElement = $module.find('#' + identifier)).length > 0) {
|
|
matchingValue = matchingElement.val();
|
|
}
|
|
else if((matchingElement = $module.find('[name="' + identifier +'"]')).length > 0) {
|
|
matchingValue = matchingElement.val();
|
|
}
|
|
else if((matchingElement = $module.find('[name="' + identifier +'[]"]')).length > 0 ) {
|
|
matchingValue = matchingElement;
|
|
}
|
|
return (matchingValue !== undefined)
|
|
? ( value.toString() == matchingValue.toString() )
|
|
: false
|
|
;
|
|
},
|
|
|
|
// different than another field
|
|
different: function(value, identifier, $module) {
|
|
// use either id or name of field
|
|
var
|
|
matchingValue,
|
|
matchingElement
|
|
;
|
|
if((matchingElement = $module.find('[data-validate="'+ identifier +'"]')).length > 0 ) {
|
|
matchingValue = matchingElement.val();
|
|
}
|
|
else if((matchingElement = $module.find('#' + identifier)).length > 0) {
|
|
matchingValue = matchingElement.val();
|
|
}
|
|
else if((matchingElement = $module.find('[name="' + identifier +'"]')).length > 0) {
|
|
matchingValue = matchingElement.val();
|
|
}
|
|
else if((matchingElement = $module.find('[name="' + identifier +'[]"]')).length > 0 ) {
|
|
matchingValue = matchingElement;
|
|
}
|
|
return (matchingValue !== undefined)
|
|
? ( value.toString() !== matchingValue.toString() )
|
|
: false
|
|
;
|
|
},
|
|
|
|
creditCard: function(cardNumber, cardTypes) {
|
|
var
|
|
cards = {
|
|
visa: {
|
|
pattern : /^4/,
|
|
length : [16]
|
|
},
|
|
amex: {
|
|
pattern : /^3[47]/,
|
|
length : [15]
|
|
},
|
|
mastercard: {
|
|
pattern : /^5[1-5]/,
|
|
length : [16]
|
|
},
|
|
discover: {
|
|
pattern : /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/,
|
|
length : [16]
|
|
},
|
|
unionPay: {
|
|
pattern : /^(62|88)/,
|
|
length : [16, 17, 18, 19]
|
|
},
|
|
jcb: {
|
|
pattern : /^35(2[89]|[3-8][0-9])/,
|
|
length : [16]
|
|
},
|
|
maestro: {
|
|
pattern : /^(5018|5020|5038|6304|6759|676[1-3])/,
|
|
length : [12, 13, 14, 15, 16, 17, 18, 19]
|
|
},
|
|
dinersClub: {
|
|
pattern : /^(30[0-5]|^36)/,
|
|
length : [14]
|
|
},
|
|
laser: {
|
|
pattern : /^(6304|670[69]|6771)/,
|
|
length : [16, 17, 18, 19]
|
|
},
|
|
visaElectron: {
|
|
pattern : /^(4026|417500|4508|4844|491(3|7))/,
|
|
length : [16]
|
|
}
|
|
},
|
|
valid = {},
|
|
validCard = false,
|
|
requiredTypes = (typeof cardTypes == 'string')
|
|
? cardTypes.split(',')
|
|
: false,
|
|
unionPay,
|
|
validation
|
|
;
|
|
|
|
if(typeof cardNumber !== 'string' || cardNumber.length === 0) {
|
|
return;
|
|
}
|
|
|
|
// allow dashes and spaces in card
|
|
cardNumber = cardNumber.replace(/[\s\-]/g, '');
|
|
|
|
// verify card types
|
|
if(requiredTypes) {
|
|
$.each(requiredTypes, function(index, type){
|
|
// verify each card type
|
|
validation = cards[type];
|
|
if(validation) {
|
|
valid = {
|
|
length : ($.inArray(cardNumber.length, validation.length) !== -1),
|
|
pattern : (cardNumber.search(validation.pattern) !== -1)
|
|
};
|
|
if(valid.length && valid.pattern) {
|
|
validCard = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
if(!validCard) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// skip luhn for UnionPay
|
|
unionPay = {
|
|
number : ($.inArray(cardNumber.length, cards.unionPay.length) !== -1),
|
|
pattern : (cardNumber.search(cards.unionPay.pattern) !== -1)
|
|
};
|
|
if(unionPay.number && unionPay.pattern) {
|
|
return true;
|
|
}
|
|
|
|
// verify luhn, adapted from <https://gist.github.com/2134376>
|
|
var
|
|
length = cardNumber.length,
|
|
multiple = 0,
|
|
producedValue = [
|
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
[0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
|
|
],
|
|
sum = 0
|
|
;
|
|
while (length--) {
|
|
sum += producedValue[multiple][parseInt(cardNumber.charAt(length), 10)];
|
|
multiple ^= 1;
|
|
}
|
|
return (sum % 10 === 0 && sum > 0);
|
|
},
|
|
|
|
minCount: function(value, minCount) {
|
|
if(minCount == 0) {
|
|
return true;
|
|
}
|
|
if(minCount == 1) {
|
|
return (value !== '');
|
|
}
|
|
return (value.split(',').length >= minCount);
|
|
},
|
|
|
|
exactCount: function(value, exactCount) {
|
|
if(exactCount == 0) {
|
|
return (value === '');
|
|
}
|
|
if(exactCount == 1) {
|
|
return (value !== '' && value.search(',') === -1);
|
|
}
|
|
return (value.split(',').length == exactCount);
|
|
},
|
|
|
|
maxCount: function(value, maxCount) {
|
|
if(maxCount == 0) {
|
|
return false;
|
|
}
|
|
if(maxCount == 1) {
|
|
return (value.search(',') === -1);
|
|
}
|
|
return (value.split(',').length <= maxCount);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - API
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isWindow = $.isWindow || function(obj) {
|
|
return obj != null && obj === obj.window;
|
|
};
|
|
|
|
window = (typeof window != 'undefined' && window.Math == Math)
|
|
? window
|
|
: (typeof self != 'undefined' && self.Math == Math)
|
|
? self
|
|
: Function('return this')()
|
|
;
|
|
|
|
$.api = $.fn.api = function(parameters) {
|
|
|
|
var
|
|
// use window context if none specified
|
|
$allModules = $.isFunction(this)
|
|
? $(window)
|
|
: $(this),
|
|
moduleSelector = $allModules.selector || '',
|
|
time = new Date().getTime(),
|
|
performance = [],
|
|
|
|
query = arguments[0],
|
|
methodInvoked = (typeof query == 'string'),
|
|
queryArguments = [].slice.call(arguments, 1),
|
|
|
|
returnedValue
|
|
;
|
|
|
|
$allModules
|
|
.each(function() {
|
|
var
|
|
settings = ( $.isPlainObject(parameters) )
|
|
? $.extend(true, {}, $.fn.api.settings, parameters)
|
|
: $.extend({}, $.fn.api.settings),
|
|
|
|
// internal aliases
|
|
namespace = settings.namespace,
|
|
metadata = settings.metadata,
|
|
selector = settings.selector,
|
|
error = settings.error,
|
|
className = settings.className,
|
|
|
|
// define namespaces for modules
|
|
eventNamespace = '.' + namespace,
|
|
moduleNamespace = 'module-' + namespace,
|
|
|
|
// element that creates request
|
|
$module = $(this),
|
|
$form = $module.closest(selector.form),
|
|
|
|
// context used for state
|
|
$context = (settings.stateContext)
|
|
? $(settings.stateContext)
|
|
: $module,
|
|
|
|
// request details
|
|
ajaxSettings,
|
|
requestSettings,
|
|
url,
|
|
data,
|
|
requestStartTime,
|
|
|
|
// standard module
|
|
element = this,
|
|
context = $context[0],
|
|
instance = $module.data(moduleNamespace),
|
|
module
|
|
;
|
|
|
|
module = {
|
|
|
|
initialize: function() {
|
|
if(!methodInvoked) {
|
|
module.bind.events();
|
|
}
|
|
module.instantiate();
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of module', module);
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, instance)
|
|
;
|
|
},
|
|
|
|
destroy: function() {
|
|
module.verbose('Destroying previous module for', element);
|
|
$module
|
|
.removeData(moduleNamespace)
|
|
.off(eventNamespace)
|
|
;
|
|
},
|
|
|
|
bind: {
|
|
events: function() {
|
|
var
|
|
triggerEvent = module.get.event()
|
|
;
|
|
if( triggerEvent ) {
|
|
module.verbose('Attaching API events to element', triggerEvent);
|
|
$module
|
|
.on(triggerEvent + eventNamespace, module.event.trigger)
|
|
;
|
|
}
|
|
else if(settings.on == 'now') {
|
|
module.debug('Querying API endpoint immediately');
|
|
module.query();
|
|
}
|
|
}
|
|
},
|
|
|
|
decode: {
|
|
json: function(response) {
|
|
if(response !== undefined && typeof response == 'string') {
|
|
try {
|
|
response = JSON.parse(response);
|
|
}
|
|
catch(e) {
|
|
// isnt json string
|
|
}
|
|
}
|
|
return response;
|
|
}
|
|
},
|
|
|
|
read: {
|
|
cachedResponse: function(url) {
|
|
var
|
|
response
|
|
;
|
|
if(window.Storage === undefined) {
|
|
module.error(error.noStorage);
|
|
return;
|
|
}
|
|
response = sessionStorage.getItem(url);
|
|
module.debug('Using cached response', url, response);
|
|
response = module.decode.json(response);
|
|
return response;
|
|
}
|
|
},
|
|
write: {
|
|
cachedResponse: function(url, response) {
|
|
if(response && response === '') {
|
|
module.debug('Response empty, not caching', response);
|
|
return;
|
|
}
|
|
if(window.Storage === undefined) {
|
|
module.error(error.noStorage);
|
|
return;
|
|
}
|
|
if( $.isPlainObject(response) ) {
|
|
response = JSON.stringify(response);
|
|
}
|
|
sessionStorage.setItem(url, response);
|
|
module.verbose('Storing cached response for url', url, response);
|
|
}
|
|
},
|
|
|
|
query: function() {
|
|
|
|
if(module.is.disabled()) {
|
|
module.debug('Element is disabled API request aborted');
|
|
return;
|
|
}
|
|
|
|
if(module.is.loading()) {
|
|
if(settings.interruptRequests) {
|
|
module.debug('Interrupting previous request');
|
|
module.abort();
|
|
}
|
|
else {
|
|
module.debug('Cancelling request, previous request is still pending');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// pass element metadata to url (value, text)
|
|
if(settings.defaultData) {
|
|
$.extend(true, settings.urlData, module.get.defaultData());
|
|
}
|
|
|
|
// Add form content
|
|
if(settings.serializeForm) {
|
|
settings.data = module.add.formData(settings.data);
|
|
}
|
|
|
|
// call beforesend and get any settings changes
|
|
requestSettings = module.get.settings();
|
|
|
|
// check if before send cancelled request
|
|
if(requestSettings === false) {
|
|
module.cancelled = true;
|
|
module.error(error.beforeSend);
|
|
return;
|
|
}
|
|
else {
|
|
module.cancelled = false;
|
|
}
|
|
|
|
// get url
|
|
url = module.get.templatedURL();
|
|
|
|
if(!url && !module.is.mocked()) {
|
|
module.error(error.missingURL);
|
|
return;
|
|
}
|
|
|
|
// replace variables
|
|
url = module.add.urlData( url );
|
|
// missing url parameters
|
|
if( !url && !module.is.mocked()) {
|
|
return;
|
|
}
|
|
|
|
requestSettings.url = settings.base + url;
|
|
|
|
// look for jQuery ajax parameters in settings
|
|
ajaxSettings = $.extend(true, {}, settings, {
|
|
type : settings.method || settings.type,
|
|
data : data,
|
|
url : settings.base + url,
|
|
beforeSend : settings.beforeXHR,
|
|
success : function() {},
|
|
failure : function() {},
|
|
complete : function() {}
|
|
});
|
|
|
|
module.debug('Querying URL', ajaxSettings.url);
|
|
module.verbose('Using AJAX settings', ajaxSettings);
|
|
if(settings.cache === 'local' && module.read.cachedResponse(url)) {
|
|
module.debug('Response returned from local cache');
|
|
module.request = module.create.request();
|
|
module.request.resolveWith(context, [ module.read.cachedResponse(url) ]);
|
|
return;
|
|
}
|
|
|
|
if( !settings.throttle ) {
|
|
module.debug('Sending request', data, ajaxSettings.method);
|
|
module.send.request();
|
|
}
|
|
else {
|
|
if(!settings.throttleFirstRequest && !module.timer) {
|
|
module.debug('Sending request', data, ajaxSettings.method);
|
|
module.send.request();
|
|
module.timer = setTimeout(function(){}, settings.throttle);
|
|
}
|
|
else {
|
|
module.debug('Throttling request', settings.throttle);
|
|
clearTimeout(module.timer);
|
|
module.timer = setTimeout(function() {
|
|
if(module.timer) {
|
|
delete module.timer;
|
|
}
|
|
module.debug('Sending throttled request', data, ajaxSettings.method);
|
|
module.send.request();
|
|
}, settings.throttle);
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
should: {
|
|
removeError: function() {
|
|
return ( settings.hideError === true || (settings.hideError === 'auto' && !module.is.form()) );
|
|
}
|
|
},
|
|
|
|
is: {
|
|
disabled: function() {
|
|
return ($module.filter(selector.disabled).length > 0);
|
|
},
|
|
expectingJSON: function() {
|
|
return settings.dataType === 'json' || settings.dataType === 'jsonp';
|
|
},
|
|
form: function() {
|
|
return $module.is('form') || $context.is('form');
|
|
},
|
|
mocked: function() {
|
|
return (settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync);
|
|
},
|
|
input: function() {
|
|
return $module.is('input');
|
|
},
|
|
loading: function() {
|
|
return (module.request)
|
|
? (module.request.state() == 'pending')
|
|
: false
|
|
;
|
|
},
|
|
abortedRequest: function(xhr) {
|
|
if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) {
|
|
module.verbose('XHR request determined to be aborted');
|
|
return true;
|
|
}
|
|
else {
|
|
module.verbose('XHR request was not aborted');
|
|
return false;
|
|
}
|
|
},
|
|
validResponse: function(response) {
|
|
if( (!module.is.expectingJSON()) || !$.isFunction(settings.successTest) ) {
|
|
module.verbose('Response is not JSON, skipping validation', settings.successTest, response);
|
|
return true;
|
|
}
|
|
module.debug('Checking JSON returned success', settings.successTest, response);
|
|
if( settings.successTest(response) ) {
|
|
module.debug('Response passed success test', response);
|
|
return true;
|
|
}
|
|
else {
|
|
module.debug('Response failed success test', response);
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
|
|
was: {
|
|
cancelled: function() {
|
|
return (module.cancelled || false);
|
|
},
|
|
succesful: function() {
|
|
module.verbose('This behavior will be deleted due to typo. Use "was successful" instead.');
|
|
return module.was.successful();
|
|
},
|
|
successful: function() {
|
|
return (module.request && module.request.state() == 'resolved');
|
|
},
|
|
failure: function() {
|
|
return (module.request && module.request.state() == 'rejected');
|
|
},
|
|
complete: function() {
|
|
return (module.request && (module.request.state() == 'resolved' || module.request.state() == 'rejected') );
|
|
}
|
|
},
|
|
|
|
add: {
|
|
urlData: function(url, urlData) {
|
|
var
|
|
requiredVariables,
|
|
optionalVariables
|
|
;
|
|
if(url) {
|
|
requiredVariables = url.match(settings.regExp.required);
|
|
optionalVariables = url.match(settings.regExp.optional);
|
|
urlData = urlData || settings.urlData;
|
|
if(requiredVariables) {
|
|
module.debug('Looking for required URL variables', requiredVariables);
|
|
$.each(requiredVariables, function(index, templatedString) {
|
|
var
|
|
// allow legacy {$var} style
|
|
variable = (templatedString.indexOf('$') !== -1)
|
|
? templatedString.substr(2, templatedString.length - 3)
|
|
: templatedString.substr(1, templatedString.length - 2),
|
|
value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
|
|
? urlData[variable]
|
|
: ($module.data(variable) !== undefined)
|
|
? $module.data(variable)
|
|
: ($context.data(variable) !== undefined)
|
|
? $context.data(variable)
|
|
: urlData[variable]
|
|
;
|
|
// remove value
|
|
if(value === undefined) {
|
|
module.error(error.requiredParameter, variable, url);
|
|
url = false;
|
|
return false;
|
|
}
|
|
else {
|
|
module.verbose('Found required variable', variable, value);
|
|
value = (settings.encodeParameters)
|
|
? module.get.urlEncodedValue(value)
|
|
: value
|
|
;
|
|
url = url.replace(templatedString, value);
|
|
}
|
|
});
|
|
}
|
|
if(optionalVariables) {
|
|
module.debug('Looking for optional URL variables', requiredVariables);
|
|
$.each(optionalVariables, function(index, templatedString) {
|
|
var
|
|
// allow legacy {/$var} style
|
|
variable = (templatedString.indexOf('$') !== -1)
|
|
? templatedString.substr(3, templatedString.length - 4)
|
|
: templatedString.substr(2, templatedString.length - 3),
|
|
value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
|
|
? urlData[variable]
|
|
: ($module.data(variable) !== undefined)
|
|
? $module.data(variable)
|
|
: ($context.data(variable) !== undefined)
|
|
? $context.data(variable)
|
|
: urlData[variable]
|
|
;
|
|
// optional replacement
|
|
if(value !== undefined) {
|
|
module.verbose('Optional variable Found', variable, value);
|
|
url = url.replace(templatedString, value);
|
|
}
|
|
else {
|
|
module.verbose('Optional variable not found', variable);
|
|
// remove preceding slash if set
|
|
if(url.indexOf('/' + templatedString) !== -1) {
|
|
url = url.replace('/' + templatedString, '');
|
|
}
|
|
else {
|
|
url = url.replace(templatedString, '');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
return url;
|
|
},
|
|
formData: function(data) {
|
|
var
|
|
canSerialize = ($.fn.serializeObject !== undefined),
|
|
formData = (canSerialize)
|
|
? $form.serializeObject()
|
|
: $form.serialize(),
|
|
hasOtherData
|
|
;
|
|
data = data || settings.data;
|
|
hasOtherData = $.isPlainObject(data);
|
|
|
|
if(hasOtherData) {
|
|
if(canSerialize) {
|
|
module.debug('Extending existing data with form data', data, formData);
|
|
data = $.extend(true, {}, data, formData);
|
|
}
|
|
else {
|
|
module.error(error.missingSerialize);
|
|
module.debug('Cant extend data. Replacing data with form data', data, formData);
|
|
data = formData;
|
|
}
|
|
}
|
|
else {
|
|
module.debug('Adding form data', formData);
|
|
data = formData;
|
|
}
|
|
return data;
|
|
}
|
|
},
|
|
|
|
send: {
|
|
request: function() {
|
|
module.set.loading();
|
|
module.request = module.create.request();
|
|
if( module.is.mocked() ) {
|
|
module.mockedXHR = module.create.mockedXHR();
|
|
}
|
|
else {
|
|
module.xhr = module.create.xhr();
|
|
}
|
|
settings.onRequest.call(context, module.request, module.xhr);
|
|
}
|
|
},
|
|
|
|
event: {
|
|
trigger: function(event) {
|
|
module.query();
|
|
if(event.type == 'submit' || event.type == 'click') {
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
xhr: {
|
|
always: function() {
|
|
// nothing special
|
|
},
|
|
done: function(response, textStatus, xhr) {
|
|
var
|
|
context = this,
|
|
elapsedTime = (new Date().getTime() - requestStartTime),
|
|
timeLeft = (settings.loadingDuration - elapsedTime),
|
|
translatedResponse = ( $.isFunction(settings.onResponse) )
|
|
? module.is.expectingJSON() && !settings.rawResponse
|
|
? settings.onResponse.call(context, $.extend(true, {}, response))
|
|
: settings.onResponse.call(context, response)
|
|
: false
|
|
;
|
|
timeLeft = (timeLeft > 0)
|
|
? timeLeft
|
|
: 0
|
|
;
|
|
if(translatedResponse) {
|
|
module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response);
|
|
response = translatedResponse;
|
|
}
|
|
if(timeLeft > 0) {
|
|
module.debug('Response completed early delaying state change by', timeLeft);
|
|
}
|
|
setTimeout(function() {
|
|
if( module.is.validResponse(response) ) {
|
|
module.request.resolveWith(context, [response, xhr]);
|
|
}
|
|
else {
|
|
module.request.rejectWith(context, [xhr, 'invalid']);
|
|
}
|
|
}, timeLeft);
|
|
},
|
|
fail: function(xhr, status, httpMessage) {
|
|
var
|
|
context = this,
|
|
elapsedTime = (new Date().getTime() - requestStartTime),
|
|
timeLeft = (settings.loadingDuration - elapsedTime)
|
|
;
|
|
timeLeft = (timeLeft > 0)
|
|
? timeLeft
|
|
: 0
|
|
;
|
|
if(timeLeft > 0) {
|
|
module.debug('Response completed early delaying state change by', timeLeft);
|
|
}
|
|
setTimeout(function() {
|
|
if( module.is.abortedRequest(xhr) ) {
|
|
module.request.rejectWith(context, [xhr, 'aborted', httpMessage]);
|
|
}
|
|
else {
|
|
module.request.rejectWith(context, [xhr, 'error', status, httpMessage]);
|
|
}
|
|
}, timeLeft);
|
|
}
|
|
},
|
|
request: {
|
|
done: function(response, xhr) {
|
|
module.debug('Successful API Response', response);
|
|
if(settings.cache === 'local' && url) {
|
|
module.write.cachedResponse(url, response);
|
|
module.debug('Saving server response locally', module.cache);
|
|
}
|
|
settings.onSuccess.call(context, response, $module, xhr);
|
|
},
|
|
complete: function(firstParameter, secondParameter) {
|
|
var
|
|
xhr,
|
|
response
|
|
;
|
|
// have to guess callback parameters based on request success
|
|
if( module.was.successful() ) {
|
|
response = firstParameter;
|
|
xhr = secondParameter;
|
|
}
|
|
else {
|
|
xhr = firstParameter;
|
|
response = module.get.responseFromXHR(xhr);
|
|
}
|
|
module.remove.loading();
|
|
settings.onComplete.call(context, response, $module, xhr);
|
|
},
|
|
fail: function(xhr, status, httpMessage) {
|
|
var
|
|
// pull response from xhr if available
|
|
response = module.get.responseFromXHR(xhr),
|
|
errorMessage = module.get.errorFromRequest(response, status, httpMessage)
|
|
;
|
|
if(status == 'aborted') {
|
|
module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage);
|
|
settings.onAbort.call(context, status, $module, xhr);
|
|
return true;
|
|
}
|
|
else if(status == 'invalid') {
|
|
module.debug('JSON did not pass success test. A server-side error has most likely occurred', response);
|
|
}
|
|
else if(status == 'error') {
|
|
if(xhr !== undefined) {
|
|
module.debug('XHR produced a server error', status, httpMessage);
|
|
// make sure we have an error to display to console
|
|
if( (xhr.status < 200 || xhr.status >= 300) && httpMessage !== undefined && httpMessage !== '') {
|
|
module.error(error.statusMessage + httpMessage, ajaxSettings.url);
|
|
}
|
|
settings.onError.call(context, errorMessage, $module, xhr);
|
|
}
|
|
}
|
|
|
|
if(settings.errorDuration && status !== 'aborted') {
|
|
module.debug('Adding error state');
|
|
module.set.error();
|
|
if( module.should.removeError() ) {
|
|
setTimeout(module.remove.error, settings.errorDuration);
|
|
}
|
|
}
|
|
module.debug('API Request failed', errorMessage, xhr);
|
|
settings.onFailure.call(context, response, $module, xhr);
|
|
}
|
|
}
|
|
},
|
|
|
|
create: {
|
|
|
|
request: function() {
|
|
// api request promise
|
|
return $.Deferred()
|
|
.always(module.event.request.complete)
|
|
.done(module.event.request.done)
|
|
.fail(module.event.request.fail)
|
|
;
|
|
},
|
|
|
|
mockedXHR: function () {
|
|
var
|
|
// xhr does not simulate these properties of xhr but must return them
|
|
textStatus = false,
|
|
status = false,
|
|
httpMessage = false,
|
|
responder = settings.mockResponse || settings.response,
|
|
asyncResponder = settings.mockResponseAsync || settings.responseAsync,
|
|
asyncCallback,
|
|
response,
|
|
mockedXHR
|
|
;
|
|
|
|
mockedXHR = $.Deferred()
|
|
.always(module.event.xhr.complete)
|
|
.done(module.event.xhr.done)
|
|
.fail(module.event.xhr.fail)
|
|
;
|
|
|
|
if(responder) {
|
|
if( $.isFunction(responder) ) {
|
|
module.debug('Using specified synchronous callback', responder);
|
|
response = responder.call(context, requestSettings);
|
|
}
|
|
else {
|
|
module.debug('Using settings specified response', responder);
|
|
response = responder;
|
|
}
|
|
// simulating response
|
|
mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
|
|
}
|
|
else if( $.isFunction(asyncResponder) ) {
|
|
asyncCallback = function(response) {
|
|
module.debug('Async callback returned response', response);
|
|
|
|
if(response) {
|
|
mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
|
|
}
|
|
else {
|
|
mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]);
|
|
}
|
|
};
|
|
module.debug('Using specified async response callback', asyncResponder);
|
|
asyncResponder.call(context, requestSettings, asyncCallback);
|
|
}
|
|
return mockedXHR;
|
|
},
|
|
|
|
xhr: function() {
|
|
var
|
|
xhr
|
|
;
|
|
// ajax request promise
|
|
xhr = $.ajax(ajaxSettings)
|
|
.always(module.event.xhr.always)
|
|
.done(module.event.xhr.done)
|
|
.fail(module.event.xhr.fail)
|
|
;
|
|
module.verbose('Created server request', xhr, ajaxSettings);
|
|
return xhr;
|
|
}
|
|
},
|
|
|
|
set: {
|
|
error: function() {
|
|
module.verbose('Adding error state to element', $context);
|
|
$context.addClass(className.error);
|
|
},
|
|
loading: function() {
|
|
module.verbose('Adding loading state to element', $context);
|
|
$context.addClass(className.loading);
|
|
requestStartTime = new Date().getTime();
|
|
}
|
|
},
|
|
|
|
remove: {
|
|
error: function() {
|
|
module.verbose('Removing error state from element', $context);
|
|
$context.removeClass(className.error);
|
|
},
|
|
loading: function() {
|
|
module.verbose('Removing loading state from element', $context);
|
|
$context.removeClass(className.loading);
|
|
}
|
|
},
|
|
|
|
get: {
|
|
responseFromXHR: function(xhr) {
|
|
return $.isPlainObject(xhr)
|
|
? (module.is.expectingJSON())
|
|
? module.decode.json(xhr.responseText)
|
|
: xhr.responseText
|
|
: false
|
|
;
|
|
},
|
|
errorFromRequest: function(response, status, httpMessage) {
|
|
return ($.isPlainObject(response) && response.error !== undefined)
|
|
? response.error // use json error message
|
|
: (settings.error[status] !== undefined) // use server error message
|
|
? settings.error[status]
|
|
: httpMessage
|
|
;
|
|
},
|
|
request: function() {
|
|
return module.request || false;
|
|
},
|
|
xhr: function() {
|
|
return module.xhr || false;
|
|
},
|
|
settings: function() {
|
|
var
|
|
runSettings
|
|
;
|
|
runSettings = settings.beforeSend.call($module, settings);
|
|
if(runSettings) {
|
|
if(runSettings.success !== undefined) {
|
|
module.debug('Legacy success callback detected', runSettings);
|
|
module.error(error.legacyParameters, runSettings.success);
|
|
runSettings.onSuccess = runSettings.success;
|
|
}
|
|
if(runSettings.failure !== undefined) {
|
|
module.debug('Legacy failure callback detected', runSettings);
|
|
module.error(error.legacyParameters, runSettings.failure);
|
|
runSettings.onFailure = runSettings.failure;
|
|
}
|
|
if(runSettings.complete !== undefined) {
|
|
module.debug('Legacy complete callback detected', runSettings);
|
|
module.error(error.legacyParameters, runSettings.complete);
|
|
runSettings.onComplete = runSettings.complete;
|
|
}
|
|
}
|
|
if(runSettings === undefined) {
|
|
module.error(error.noReturnedValue);
|
|
}
|
|
if(runSettings === false) {
|
|
return runSettings;
|
|
}
|
|
return (runSettings !== undefined)
|
|
? $.extend(true, {}, runSettings)
|
|
: $.extend(true, {}, settings)
|
|
;
|
|
},
|
|
urlEncodedValue: function(value) {
|
|
var
|
|
decodedValue = window.decodeURIComponent(value),
|
|
encodedValue = window.encodeURIComponent(value),
|
|
alreadyEncoded = (decodedValue !== value)
|
|
;
|
|
if(alreadyEncoded) {
|
|
module.debug('URL value is already encoded, avoiding double encoding', value);
|
|
return value;
|
|
}
|
|
module.verbose('Encoding value using encodeURIComponent', value, encodedValue);
|
|
return encodedValue;
|
|
},
|
|
defaultData: function() {
|
|
var
|
|
data = {}
|
|
;
|
|
if( !$.isWindow(element) ) {
|
|
if( module.is.input() ) {
|
|
data.value = $module.val();
|
|
}
|
|
else if( module.is.form() ) {
|
|
|
|
}
|
|
else {
|
|
data.text = $module.text();
|
|
}
|
|
}
|
|
return data;
|
|
},
|
|
event: function() {
|
|
if( $.isWindow(element) || settings.on == 'now' ) {
|
|
module.debug('API called without element, no events attached');
|
|
return false;
|
|
}
|
|
else if(settings.on == 'auto') {
|
|
if( $module.is('input') ) {
|
|
return (element.oninput !== undefined)
|
|
? 'input'
|
|
: (element.onpropertychange !== undefined)
|
|
? 'propertychange'
|
|
: 'keyup'
|
|
;
|
|
}
|
|
else if( $module.is('form') ) {
|
|
return 'submit';
|
|
}
|
|
else {
|
|
return 'click';
|
|
}
|
|
}
|
|
else {
|
|
return settings.on;
|
|
}
|
|
},
|
|
templatedURL: function(action) {
|
|
action = action || $module.data(metadata.action) || settings.action || false;
|
|
url = $module.data(metadata.url) || settings.url || false;
|
|
if(url) {
|
|
module.debug('Using specified url', url);
|
|
return url;
|
|
}
|
|
if(action) {
|
|
module.debug('Looking up url for action', action, settings.api);
|
|
if(settings.api[action] === undefined && !module.is.mocked()) {
|
|
module.error(error.missingAction, settings.action, settings.api);
|
|
return;
|
|
}
|
|
url = settings.api[action];
|
|
}
|
|
else if( module.is.form() ) {
|
|
url = $module.attr('action') || $context.attr('action') || false;
|
|
module.debug('No url or action specified, defaulting to form action', url);
|
|
}
|
|
return url;
|
|
}
|
|
},
|
|
|
|
abort: function() {
|
|
var
|
|
xhr = module.get.xhr()
|
|
;
|
|
if( xhr && xhr.state() !== 'resolved') {
|
|
module.debug('Cancelling API request');
|
|
xhr.abort();
|
|
}
|
|
},
|
|
|
|
// reset state
|
|
reset: function() {
|
|
module.remove.error();
|
|
module.remove.loading();
|
|
},
|
|
|
|
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 = setTimeout(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) && performance.length > 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 = query.length - 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 {
|
|
module.error(error.method, query);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
if ( $.isFunction( found ) ) {
|
|
response = found.apply(context, passedArguments);
|
|
}
|
|
else if(found !== undefined) {
|
|
response = found;
|
|
}
|
|
if(Array.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
|
|
;
|
|
};
|
|
|
|
$.api.settings = {
|
|
|
|
name : 'API',
|
|
namespace : 'api',
|
|
|
|
debug : false,
|
|
verbose : false,
|
|
performance : true,
|
|
|
|
// object containing all templates endpoints
|
|
api : {},
|
|
|
|
// whether to cache responses
|
|
cache : true,
|
|
|
|
// whether new requests should abort previous requests
|
|
interruptRequests : true,
|
|
|
|
// event binding
|
|
on : 'auto',
|
|
|
|
// context for applying state classes
|
|
stateContext : false,
|
|
|
|
// duration for loading state
|
|
loadingDuration : 0,
|
|
|
|
// whether to hide errors after a period of time
|
|
hideError : 'auto',
|
|
|
|
// duration for error state
|
|
errorDuration : 2000,
|
|
|
|
// whether parameters should be encoded with encodeURIComponent
|
|
encodeParameters : true,
|
|
|
|
// API action to use
|
|
action : false,
|
|
|
|
// templated URL to use
|
|
url : false,
|
|
|
|
// base URL to apply to all endpoints
|
|
base : '',
|
|
|
|
// data that will
|
|
urlData : {},
|
|
|
|
// whether to add default data to url data
|
|
defaultData : true,
|
|
|
|
// whether to serialize closest form
|
|
serializeForm : false,
|
|
|
|
// how long to wait before request should occur
|
|
throttle : 0,
|
|
|
|
// whether to throttle first request or only repeated
|
|
throttleFirstRequest : true,
|
|
|
|
// standard ajax settings
|
|
method : 'get',
|
|
data : {},
|
|
dataType : 'json',
|
|
|
|
// mock response
|
|
mockResponse : false,
|
|
mockResponseAsync : false,
|
|
|
|
// aliases for mock
|
|
response : false,
|
|
responseAsync : false,
|
|
|
|
// whether onResponse should work with response value without force converting into an object
|
|
rawResponse : false,
|
|
|
|
// callbacks before request
|
|
beforeSend : function(settings) { return settings; },
|
|
beforeXHR : function(xhr) {},
|
|
onRequest : function(promise, xhr) {},
|
|
|
|
// after request
|
|
onResponse : false, // function(response) { },
|
|
|
|
// response was successful, if JSON passed validation
|
|
onSuccess : function(response, $module) {},
|
|
|
|
// request finished without aborting
|
|
onComplete : function(response, $module) {},
|
|
|
|
// failed JSON success test
|
|
onFailure : function(response, $module) {},
|
|
|
|
// server error
|
|
onError : function(errorMessage, $module) {},
|
|
|
|
// request aborted
|
|
onAbort : function(errorMessage, $module) {},
|
|
|
|
successTest : false,
|
|
|
|
// errors
|
|
error : {
|
|
beforeSend : 'The before send function has aborted the request',
|
|
error : 'There was an error with your request',
|
|
exitConditions : 'API Request Aborted. Exit conditions met',
|
|
JSONParse : 'JSON could not be parsed during error handling',
|
|
legacyParameters : 'You are using legacy API success callback names',
|
|
method : 'The method you called is not defined',
|
|
missingAction : 'API action used but no url was defined',
|
|
missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object',
|
|
missingURL : 'No URL specified for api event',
|
|
noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.',
|
|
noStorage : 'Caching responses locally requires session storage',
|
|
parseError : 'There was an error parsing your request',
|
|
requiredParameter : 'Missing a required URL parameter: ',
|
|
statusMessage : 'Server gave an error: ',
|
|
timeout : 'Your request timed out'
|
|
},
|
|
|
|
regExp : {
|
|
required : /\{\$*[A-z0-9]+\}/g,
|
|
optional : /\{\/\$*[A-z0-9]+\}/g,
|
|
},
|
|
|
|
className: {
|
|
loading : 'loading',
|
|
error : 'error'
|
|
},
|
|
|
|
selector: {
|
|
disabled : '.disabled',
|
|
form : 'form'
|
|
},
|
|
|
|
metadata: {
|
|
action : 'action',
|
|
url : 'url'
|
|
}
|
|
};
|
|
|
|
|
|
|
|
})( jQuery, window, document );
|
|
|
|
/*!
|
|
* # Fomantic-UI 2.8.8 - Transition
|
|
* http://github.com/fomantic/Fomantic-UI/
|
|
*
|
|
*
|
|
* Released under the MIT license
|
|
* http://opensource.org/licenses/MIT
|
|
*
|
|
*/
|
|
|
|
;(function ($, window, document, undefined) {
|
|
|
|
'use strict';
|
|
|
|
$.isFunction = $.isFunction || function(obj) {
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
window = (typeof window != 'undefined' && window.Math == Math)
|
|
? window
|
|
: (typeof self != 'undefined' && self.Math == Math)
|
|
? self
|
|
: Function('return this')()
|
|
;
|
|
|
|
$.fn.transition = function() {
|
|
var
|
|
$allModules = $(this),
|
|
moduleSelector = $allModules.selector || '',
|
|
|
|
time = new Date().getTime(),
|
|
performance = [],
|
|
|
|
moduleArguments = arguments,
|
|
query = moduleArguments[0],
|
|
queryArguments = [].slice.call(arguments, 1),
|
|
methodInvoked = (typeof query === 'string'),
|
|
|
|
returnedValue
|
|
;
|
|
$allModules
|
|
.each(function(index) {
|
|
var
|
|
$module = $(this),
|
|
element = this,
|
|
|
|
// set at run time
|
|
settings,
|
|
instance,
|
|
|
|
error,
|
|
className,
|
|
metadata,
|
|
animationEnd,
|
|
|
|
moduleNamespace,
|
|
eventNamespace,
|
|
module
|
|
;
|
|
|
|
module = {
|
|
|
|
initialize: function() {
|
|
|
|
// get full settings
|
|
settings = module.get.settings.apply(element, moduleArguments);
|
|
|
|
// shorthand
|
|
className = settings.className;
|
|
error = settings.error;
|
|
metadata = settings.metadata;
|
|
|
|
// define namespace
|
|
eventNamespace = '.' + settings.namespace;
|
|
moduleNamespace = 'module-' + settings.namespace;
|
|
instance = $module.data(moduleNamespace) || module;
|
|
|
|
// get vendor specific events
|
|
animationEnd = module.get.animationEndEvent();
|
|
|
|
if(methodInvoked) {
|
|
methodInvoked = module.invoke(query);
|
|
}
|
|
|
|
// method not invoked, lets run an animation
|
|
if(methodInvoked === false) {
|
|
module.verbose('Converted arguments into settings object', settings);
|
|
if(settings.interval) {
|
|
module.delay(settings.animate);
|
|
}
|
|
else {
|
|
module.animate();
|
|
}
|
|
module.instantiate();
|
|
}
|
|
},
|
|
|
|
instantiate: function() {
|
|
module.verbose('Storing instance of module', module);
|
|
instance = module;
|
|
$module
|
|
.data(moduleNamespace, instance)
|
|
;
|
|
},
|
|
|
|
destroy: function() {
|
|
module.verbose('Destroying previous module for', element);
|
|
$module
|
|
.removeData(moduleNamespace)
|
|
;
|
|
},
|
|
|
|
refresh: function() {
|
|
module.verbose('Refreshing display type on next animation');
|
|
delete module.displayType;
|
|
},
|
|
|
|
forceRepaint: function() {
|
|
module.verbose('Forcing element repaint');
|
|
var
|
|
$parentElement = $module.parent(),
|
|
$nextElement = $module.next()
|
|
;
|
|
if($nextElement.length === 0) {
|
|
$module.detach().appendTo($parentElement);
|
|
}
|
|
else {
|
|
$module.detach().insertBefore($nextElement);
|
|
}
|
|
},
|
|
|
|
repaint: function() {
|
|
module.verbose('Repainting element');
|
|
var
|
|
fakeAssignment = element.offsetWidth
|
|
;
|
|
},
|
|
|
|
delay: function(interval) {
|
|
var
|
|
direction = module.get.animationDirection(),
|
|
shouldReverse,
|
|
delay
|
|
;
|
|
if(!direction) {
|
|
direction = module.can.transition()
|
|
? module.get.direction()
|
|
: 'static'
|
|
;
|
|
}
|
|
interval = (interval !== undefined)
|
|
? interval
|
|
: settings.interval
|
|
;
|
|
shouldReverse = (settings.reverse == 'auto' && direction == className.outward);
|
|
delay = (shouldReverse || settings.reverse == true)
|
|
? ($allModules.length - index) * settings.interval
|
|
: index * settings.interval
|
|
;
|
|
module.debug('Delaying animation by', delay);
|
|
setTimeout(module.animate, delay);
|
|
},
|
|
|
|
animate: function(overrideSettings) {
|
|
settings = overrideSettings || settings;
|
|
if(!module.is.supported()) {
|
|
module.error(error.support);
|
|
return false;
|
|
}
|
|
module.debug('Preparing animation', settings.animation);
|
|
if(module.is.animating()) {
|
|
if(settings.queue) {
|
|
if(!settings.allowRepeats && module.has.direction() && module.is.occurring() && module.queuing !== true) {
|
|
module.debug('Animation is currently occurring, preventing queueing same animation', settings.animation);
|
|
}
|
|
else {
|
|
module.queue(settings.animation);
|
|
}
|
|
return false;
|
|
}
|
|
else if(!settings.allowRepeats && module.is.occurring()) {
|
|
module.debug('Animation is already occurring, will not execute repeated animation', settings.animation);
|
|
return false;
|
|
}
|
|
else {
|
|
module.debug('New animation started, completing previous early', settings.animation);
|
|
instance.complete();
|
|
}
|
|
}
|
|
if( module.can.animate() ) {
|
|
module.set.animating(settings.animation);
|
|
}
|
|
else {
|
|
module.error(error.noAnimation, settings.animation, element);
|
|
}
|
|
},
|
|
|
|
reset: function() {
|
|
module.debug('Resetting animation to beginning conditions');
|
|
module.remove.animationCallbacks();
|
|
module.restore.conditions();
|
|
module.remove.animating();
|
|
},
|
|
|
|
queue: function(animation) {
|
|
module.debug('Queueing animation of', animation);
|
|
module.queuing = true;
|
|
$module
|
|
.one(animationEnd + '.queue' + eventNamespace, function() {
|
|
module.queuing = false;
|
|
module.repaint();
|
|
module.animate.apply(this, settings);
|
|
})
|
|
;
|
|
},
|
|
|
|
complete: function (event) {
|
|
if(event && event.target === element) {
|
|
event.stopPropagation();
|
|
}
|
|
module.debug('Animation complete', settings.animation);
|
|
module.remove.completeCallback();
|
|
module.remove.failSafe();
|
|
if(!module.is.looping()) {
|
|
if( module.is.outward() ) {
|
|
module.verbose('Animation is outward, hiding element');
|
|
module.restore.conditions();
|
|
module.hide();
|
|
}
|
|
else if( module.is.inward() ) {
|
|
module.verbose('Animation is outward, showing element');
|
|
module.restore.conditions();
|
|
module.show();
|
|
}
|
|
else {
|
|
module.verbose('Static animation completed');
|
|
module.restore.conditions();
|
|
settings.onComplete.call(element);
|
|
}
|
|
}
|
|
},
|
|
|
|
force: {
|
|
visible: function() {
|
|
var
|
|
style = $module.attr('style'),
|
|
userStyle = module.get.userStyle(style),
|
|
displayType = module.get.displayType(),
|
|
overrideStyle = userStyle + 'display: ' + displayType + ' !important;',
|
|
inlineDisplay = $module[0].style.display,
|
|
mustStayHidden = !displayType || (inlineDisplay === 'none' && settings.skipInlineHidden) || $module[0].tagName.match(/(script|link|style)/i)
|
|
;
|
|
if (mustStayHidden){
|
|
module.remove.transition();
|
|
return false;
|
|
}
|
|
module.verbose('Overriding default display to show element', displayType);
|
|
$module
|
|
.attr('style', overrideStyle)
|
|
;
|
|
return true;
|
|
},
|
|
hidden: function() {
|
|
var
|
|
style = $module.attr('style'),
|
|
currentDisplay = $module.css('display'),
|
|
emptyStyle = (style === undefined || style === '')
|
|
;
|
|
if(currentDisplay !== 'none' && !module.is.hidden()) {
|
|
module.verbose('Overriding default display to hide element');
|
|
$module
|
|
.css('display', 'none')
|
|
;
|
|
}
|
|
else if(emptyStyle) {
|
|
$module
|
|
.removeAttr('style')
|
|
;
|
|
}
|
|
}
|
|
},
|
|
|
|
has: {
|
|
direction: function(animation) {
|
|
var
|
|
hasDirection = false
|
|
;
|
|
animation = animation || settings.animation;
|
|
if(typeof animation === 'string') {
|
|
animation = animation.split(' ');
|
|
$.each(animation, function(index, word){
|
|
if(word === className.inward || word === className.outward) {
|
|
hasDirection = true;
|
|
}
|
|
});
|
|
}
|
|
return hasDirection;
|
|
},
|
|
inlineDisplay: function() {
|
|
var
|
|
style = $module.attr('style') || ''
|
|
;
|
|
return Array.isArray(style.match(/display.*?;/, ''));
|
|
}
|
|
},
|
|
|
|
set: {
|
|
animating: function(animation) {
|
|
// remove previous callbacks
|
|
module.remove.completeCallback();
|
|
|
|
// determine exact animation
|
|
animation = animation || settings.animation;
|
|
var animationClass = module.get.animationClass(animation);
|
|
|
|
// save animation class in cache to restore class names
|
|
module.save.animation(animationClass);
|
|
|
|
if(module.force.visible()) {
|
|
module.remove.hidden();
|
|
module.remove.direction();
|
|
|
|
module.start.animation(animationClass);
|
|
}
|
|
},
|
|
duration: function(animationName, duration) {
|
|
duration = duration || settings.duration;
|
|
duration = (typeof duration == 'number')
|
|
? duration + 'ms'
|
|
: duration
|
|
;
|
|
if(duration || duration === 0) {
|
|
module.verbose('Setting animation duration', duration);
|
|
$module
|
|
.css({
|
|
'animation-duration': duration
|
|
})
|
|
;
|
|
}
|
|
},
|
|
direction: function(direction) {
|
|
direction = direction || module.get.direction();
|
|
if(direction == className.inward) {
|
|
module.set.inward();
|
|
}
|
|
else {
|
|
module.set.outward();
|
|
}
|
|
},
|
|
looping: function() {
|
|
module.debug('Transition set to loop');
|
|
$module
|
|
.addClass(className.looping)
|
|
;
|
|
},
|
|
hidden: function() {
|
|
$module
|
|
.addClass(className.transition)
|
|
.addClass(className.hidden)
|
|
;
|
|
},
|
|
inward: function() {
|
|
module.debug('Setting direction to inward');
|
|
$module
|
|
.removeClass(className.outward)
|
|
.addClass(className.inward)
|
|
;
|
|
},
|
|
outward: function() {
|
|
module.debug('Setting direction to outward');
|
|
$module
|
|
.removeClass(className.inward)
|
|
.addClass(className.outward)
|
|
;
|
|
},
|
|
visible: function() {
|
|
$module
|
|
.addClass(className.transition)
|
|
.addClass(className.visible)
|
|
;
|
|
}
|
|
},
|
|
|
|
start: {
|
|
animation: function(animationClass) {
|
|
animationClass = animationClass || module.get.animationClass();
|
|
module.debug('Starting tween', animationClass);
|
|
$module
|
|
.addClass(animationClass)
|
|
.one(animationEnd + '.complete' + eventNamespace, module.complete)
|
|
;
|
|
if(settings.useFailSafe) {
|
|
module.add.failSafe();
|
|
}
|
|
module.set.duration(settings.duration);
|
|
settings.onStart.call(element);
|
|
}
|
|
},
|
|
|
|
save: {
|
|
animation: function(animation) {
|
|
if(!module.cache) {
|
|
module.cache = {};
|
|
}
|
|
module.cache.animation = animation;
|
|
},
|
|
displayType: function(displayType) {
|
|
if(displayType !== 'none') {
|
|
$module.data(metadata.displayType, displayType);
|
|
}
|
|
},
|
|
transitionExists: function(animation, exists) {
|
|
$.fn.transition.exists[animation] = exists;
|
|
module.verbose('Saving existence of transition', animation, exists);
|
|
}
|
|
},
|
|
|
|
restore: {
|
|
conditions: function() {
|
|
var
|
|
animation = module.get.currentAnimation()
|
|
;
|
|
if(animation) {
|
|
$module
|
|
.removeClass(animation)
|
|
;
|
|
module.verbose('Removing animation class', module.cache);
|
|
}
|
|
module.remove.duration();
|
|
}
|
|
},
|
|
|
|
add: {
|
|
failSafe: function() {
|
|
var
|
|
duration = module.get.duration()
|
|
;
|
|
module.timer = setTimeout(function() {
|
|
$module.triggerHandler(animationEnd);
|
|
}, duration + settings.failSafeDelay);
|
|
module.verbose('Adding fail safe timer', module.timer);
|
|
}
|
|
},
|
|
|
|
remove: {
|
|
animating: function() {
|
|
$module.removeClass(className.animating);
|
|
},
|
|
animationCallbacks: function() {
|
|
module.remove.queueCallback();
|
|
module.remove.completeCallback();
|
|
},
|
|
queueCallback: function() {
|
|
$module.off('.queue' + eventNamespace);
|
|
},
|
|
completeCallback: function() {
|
|
$module.off('.complete' + eventNamespace);
|
|
},
|
|
display: function() {
|
|
$module.css('display', '');
|
|
},
|
|
direction: function() {
|
|
$module
|
|
.removeClass(className.inward)
|
|
.removeClass(className.outward)
|
|
;
|
|
},
|
|
duration: function() {
|
|
$module
|
|
.css('animation-duration', '')
|
|
;
|
|
},
|
|
failSafe: function() {
|
|
module.verbose('Removing fail safe timer', module.timer);
|
|
if(module.timer) {
|
|
clearTimeout(module.timer);
|
|
}
|
|
},
|
|
hidden: function() {
|
|
$module.removeClass(className.hidden);
|
|
},
|
|
visible: function() {
|
|
$module.removeClass(className.visible);
|
|
},
|
|
looping: function() {
|
|
module.debug('Transitions are no longer looping');
|
|
if( module.is.looping() ) {
|
|
module.reset();
|
|
$module
|
|
.removeClass(className.looping)
|
|
;
|
|
}
|
|
},
|
|
transition: function() {
|
|
$module
|
|
.removeClass(className.transition)
|
|
.removeClass(className.visible)
|
|
.removeClass(className.hidden)
|
|
;
|
|
}
|
|
},
|
|
get: {
|
|
settings: function(animation, duration, onComplete) {
|
|
// single settings object
|
|
if(typeof animation == 'object') {
|
|
return $.extend(true, {}, $.fn.transition.settings, animation);
|
|
}
|
|
// all arguments provided
|
|
else if(typeof onComplete == 'function') {
|
|
return $.extend({}, $.fn.transition.settings, {
|
|
animation : animation,
|
|
onComplete : onComplete,
|
|
duration : duration
|
|
});
|
|
}
|
|
// only duration provided
|
|
else if(typeof duration == 'string' || typeof duration == 'number') {
|
|
return $.extend({}, $.fn.transition.settings, {
|
|
animation : animation,
|
|
duration : duration
|
|
});
|
|
}
|
|
// duration is actually settings object
|
|
else if(typeof duration == 'object') {
|
|
return $.extend({}, $.fn.transition.settings, duration, {
|
|
animation : animation
|
|
});
|
|
}
|
|
// duration is actually callback
|
|
else if(typeof duration == 'function') {
|
|
return $.extend({}, $.fn.transition.settings, {
|
|
animation : animation,
|
|
onComplete : duration
|
|
});
|
|
}
|
|
// only animation provided
|
|
else {
|
|
return $.extend({}, $.fn.transition.settings, {
|
|
animation : animation
|
|
});
|
|
}
|
|
},
|
|
animationClass: function(animation) {
|
|
var
|
|
animationClass = animation || settings.animation,
|
|
directionClass = (module.can.transition() && !module.has.direction())
|
|
? module.get.direction() + ' '
|
|
: ''
|
|
;
|
|
return className.animating + ' '
|
|
+ className.transition + ' '
|
|
+ directionClass
|
|
+ animationClass
|
|
;
|
|
},
|
|
currentAnimation: function() {
|
|
return (module.cache && module.cache.animation !== undefined)
|
|
? module.cache.animation
|
|
: false
|
|
;
|
|
},
|
|
currentDirection: function() {
|
|
return module.is.inward()
|
|
? className.inward
|
|
: className.outward
|
|
;
|
|
},
|
|
direction: function() {
|
|
return module.is.hidden() || !module.is.visible()
|
|
? className.inward
|
|
: className.outward
|
|
;
|
|
},
|
|
animationDirection: function(animation) {
|
|
var
|
|
direction
|
|
;
|
|
animation = animation || settings.animation;
|
|
if(typeof animation === 'string') {
|
|
animation = animation.split(' ');
|
|
// search animation name for out/in class
|
|
$.each(animation, function(index, word){
|
|
if(word === className.inward) {
|
|
direction = className.inward;
|
|
}
|
|
else if(word === className.outward) {
|
|
direction = className.outward;
|
|
}
|
|
});
|
|
}
|
|
// return found direction
|
|
if(direction) {
|
|
return direction;
|
|
}
|
|
return false;
|
|
},
|
|
duration: function(duration) {
|
|
duration = duration || settings.duration;
|
|
if(duration === false) {
|
|
duration = $module.css('animation-duration') || 0;
|
|
}
|
|
return (typeof duration === 'string')
|
|
? (duration.indexOf('ms') > -1)
|
|
? parseFloat(duration)
|
|
: parseFloat(duration) * 1000
|
|
: duration
|
|
;
|
|
},
|
|
displayType: function(shouldDetermine) {
|
|
shouldDetermine = (shouldDetermine !== undefined)
|
|
? shouldDetermine
|
|
: true
|
|
;
|
|
if(settings.displayType) {
|
|
return settings.displayType;
|
|
}
|
|
if(shouldDetermine && $module.data(metadata.displayType) === undefined) {
|
|
var currentDisplay = $module.css('display');
|
|
if(currentDisplay === '' || currentDisplay === 'none'){
|
|
// create fake element to determine display state
|
|
module.can.transition(true);
|
|
} else {
|
|
module.save.displayType(currentDisplay);
|
|
}
|
|
}
|
|
return $module.data(metadata.displayType);
|
|
},
|
|
userStyle: function(style) {
|
|
style = style || $module.attr('style') || '';
|
|
return style.replace(/display.*?;/, '');
|
|
},
|
|
transitionExists: function(animation) {
|
|
return $.fn.transition.exists[animation];
|
|
},
|
|
animationStartEvent: function() {
|
|
var
|
|
element = document.createElement('div'),
|
|
animations = {
|
|
'animation' :'animationstart',
|
|
'OAnimation' :'oAnimationStart',
|
|
'MozAnimation' :'mozAnimationStart',
|
|
'WebkitAnimation' :'webkitAnimationStart'
|
|
},
|
|
animation
|
|
;
|
|
for(animation in animations){
|
|
if( element.style[animation] !== undefined ){
|
|
return animations[animation];
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
animationEndEvent: function() {
|
|
var
|
|
element = document.createElement('div'),
|
|
animations = {
|
|
'animation' :'animationend',
|
|
'OAnimation' :'oAnimationEnd',
|
|
'MozAnimation' :'mozAnimationEnd',
|
|
'WebkitAnimation' :'webkitAnimationEnd'
|
|
},
|
|
animation
|
|
;
|
|
for(animation in animations){
|
|
if( element.style[animation] !== undefined ){
|
|
return animations[animation];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
},
|
|
|
|
can: {
|
|
transition: function(forced) {
|
|
var
|
|
animation = settings.animation,
|
|
transitionExists = module.get.transitionExists(animation),
|
|
displayType = module.get.displayType(false),
|
|
elementClass,
|
|
tagName,
|
|
$clone,
|
|
currentAnimation,
|
|
inAnimation,
|
|
directionExists
|
|
;
|
|
if( transitionExists === undefined || forced) {
|
|
module.verbose('Determining whether animation exists');
|
|
elementClass = $module.attr('class');
|
|
tagName = $module.prop('tagName');
|
|
|
|
$clone = $('<' + tagName + ' />').addClass( elementClass ).insertAfter($module);
|
|
currentAnimation = $clone
|
|
.addClass(animation)
|
|
.removeClass(className.inward)
|
|
.removeClass(className.outward)
|
|
.addClass(className.animating)
|
|
.addClass(className.transition)
|
|
.css('animationName')
|
|
;
|
|
inAnimation = $clone
|
|
.addClass(className.inward)
|
|
.css('animationName')
|
|
;
|
|
if(!displayType) {
|
|
displayType = $clone
|
|
.attr('class', elementClass)
|
|
.removeAttr('style')
|
|
.removeClass(className.hidden)
|
|
.removeClass(className.visible)
|
|
.show()
|
|
.css('display')
|
|
;
|
|
module.verbose('Determining final display state', displayType);
|
|
module.save.displayType(displayType);
|
|
}
|
|
|
|
$clone.remove();
|
|
if(currentAnimation != inAnimation) {
|
|
module.debug('Direction exists for animation', animation);
|
|
directionExists = true;
|
|
}
|
|
else if(currentAnimation == 'none' || !currentAnimation) {
|
|
module.debug('No animation defined in css', animation);
|
|
return;
|
|
}
|
|
else {
|
|
module.debug('Static animation found', animation, displayType);
|
|
directionExists = false;
|
|
}
|
|
module.save.transitionExists(animation, directionExists);
|
|
}
|
|
return (transitionExists !== undefined)
|
|
? transitionExists
|
|
: directionExists
|
|
;
|
|
},
|
|
animate: function() {
|
|
// can transition does not return a value if animation does not exist
|
|
return (module.can.transition() !== undefined);
|
|
}
|
|
},
|
|
|
|
is: {
|
|
animating: function() {
|
|
return $module.hasClass(className.animating);
|
|
},
|
|
inward: function() {
|
|
return $module.hasClass(className.inward);
|
|
},
|
|
outward: function() {
|
|
return $module.hasClass(className.outward);
|
|
},
|
|
looping: function() {
|
|
return $module.hasClass(className.looping);
|
|
},
|
|
occurring: function(animation) {
|
|
animation = animation || settings.animation;
|
|
animation = '.' + animation.replace(' ', '.');
|
|
return ( $module.filter(animation).length > 0 );
|
|
},
|
|
visible: function() {
|
|
return $module.is(':visible');
|
|
},
|
|
hidden: function() {
|
|
return $module.css('visibility') === 'hidden';
|
|
},
|
|
supported: function() {
|
|
return(animationEnd !== false);
|
|
}
|
|
},
|
|
|
|
hide: function() {
|
|
module.verbose('Hiding element');
|
|
if( module.is.animating() ) {
|
|
module.reset();
|
|
}
|
|
element.blur(); // IE will trigger focus change if element is not blurred before hiding
|
|
module.remove.display();
|
|
module.remove.visible();
|
|
if($.isFunction(settings.onBeforeHide)){
|
|
settings.onBeforeHide.call(element,function(){
|
|
module.hideNow();
|
|
});
|
|
} else {
|
|
module.hideNow();
|
|
}
|
|
|
|
},
|
|
|
|
hideNow: function() {
|
|
module.set.hidden();
|
|
module.force.hidden();
|
|
settings.onHide.call(element);
|
|
settings.onComplete.call(element);
|
|
// module.repaint();
|
|
},
|
|
|
|
show: function(display) {
|
|
module.verbose('Showing element', display);
|
|
if(module.force.visible()) {
|
|
module.remove.hidden();
|
|
module.set.visible();
|
|
settings.onShow.call(element);
|
|
settings.onComplete.call(element);
|
|
// module.repaint();
|
|
}
|
|
},
|
|
|
|
toggle: function() {
|
|
if( module.is.visible() ) {
|
|
module.hide();
|
|
}
|
|
else {
|
|
module.show();
|
|
}
|
|
},
|
|
|
|
stop: function() {
|
|
module.debug('Stopping current animation');
|
|
$module.triggerHandler(animationEnd);
|
|
},
|
|
|
|
stopAll: function() {
|
|
module.debug('Stopping all animation');
|
|
module.remove.queueCallback();
|
|
$module.triggerHandler(animationEnd);
|
|
},
|
|
|
|
clear: {
|
|
queue: function() {
|
|
module.debug('Clearing animation queue');
|
|
module.remove.queueCallback();
|
|
}
|
|
},
|
|
|
|
enable: function() {
|
|
module.verbose('Starting animation');
|
|
$module.removeClass(className.disabled);
|
|
},
|
|
|
|
disable: function() {
|
|
module.debug('Stopping animation');
|
|
$module.addClass(className.disabled);
|
|
},
|
|
|
|
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 = setTimeout(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($allModules.length > 1) {
|
|
title += ' ' + '(' + $allModules.length + ')';
|
|
}
|
|
if( (console.group !== undefined || console.table !== undefined) && performance.length > 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 = [];
|
|
}
|
|
},
|
|
// modified for transition to return invoke success
|
|
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 = query.length - 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(Array.isArray(returnedValue)) {
|
|
returnedValue.push(response);
|
|
}
|
|
else if(returnedValue !== undefined) {
|
|
returnedValue = [returnedValue, response];
|
|
}
|
|
else if(response !== undefined) {
|
|
returnedValue = response;
|
|
}
|
|
return (found !== undefined)
|
|
? found
|
|
: false
|
|
;
|
|
}
|
|
};
|
|
module.initialize();
|
|
})
|
|
;
|
|
return (returnedValue !== undefined)
|
|
? returnedValue
|
|
: this
|
|
;
|
|
};
|
|
|
|
// Records if CSS transition is available
|
|
$.fn.transition.exists = {};
|
|
|
|
$.fn.transition.settings = {
|
|
|
|
// module info
|
|
name : 'Transition',
|
|
|
|
// hide all output from this component regardless of other settings
|
|
silent : false,
|
|
|
|
// debug content outputted to console
|
|
debug : false,
|
|
|
|
// verbose debug output
|
|
verbose : false,
|
|
|
|
// performance data output
|
|
performance : true,
|
|
|
|
// event namespace
|
|
namespace : 'transition',
|
|
|
|
// delay between animations in group
|
|
interval : 0,
|
|
|
|
// whether group animations should be reversed
|
|
reverse : 'auto',
|
|
|
|
// animation callback event
|
|
onStart : function() {},
|
|
onComplete : function() {},
|
|
onShow : function() {},
|
|
onHide : function() {},
|
|
|
|
// whether timeout should be used to ensure callback fires in cases animationend does not
|
|
useFailSafe : true,
|
|
|
|
// delay in ms for fail safe
|
|
failSafeDelay : 100,
|
|
|
|
// whether EXACT animation can occur twice in a row
|
|
allowRepeats : false,
|
|
|
|
// Override final display type on visible
|
|
displayType : false,
|
|
|
|
// animation duration
|
|
animation : 'fade',
|
|
duration : false,
|
|
|
|
// new animations will occur after previous ones
|
|
queue : true,
|
|
|
|
// whether initially inline hidden objects should be skipped for transition
|
|
skipInlineHidden: false,
|
|
|
|
metadata : {
|
|
displayType: 'display'
|
|
},
|
|
|
|
className : {
|
|
animating : 'animating',
|
|
disabled : 'disabled',
|
|
hidden : 'hidden',
|
|
inward : 'in',
|
|
loading : 'loading',
|
|
looping : 'looping',
|
|
outward : 'out',
|
|
transition : 'transition',
|
|
visible : 'visible'
|
|
},
|
|
|
|
// possible errors
|
|
error: {
|
|
noAnimation : 'Element is no longer attached to DOM. Unable to animate. Use silent setting to surpress this warning in production.',
|
|
repeated : 'That animation is already occurring, cancelling repeated animation',
|
|
method : 'The method you called is not defined',
|
|
support : 'This browser does not support CSS animations'
|
|
}
|
|
|
|
};
|
|
|
|
|
|
})( jQuery, window, document );
|