You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
708 lines
20 KiB
708 lines
20 KiB
/*! |
|
* # Semantic UI 2.2.9 - State |
|
* http://github.com/semantic-org/semantic-ui/ |
|
* |
|
* |
|
* Released under the MIT license |
|
* http://opensource.org/licenses/MIT |
|
* |
|
*/ |
|
|
|
;(function ($, window, document, undefined) { |
|
|
|
"use strict"; |
|
|
|
window = (typeof window != 'undefined' && window.Math == Math) |
|
? window |
|
: (typeof self != 'undefined' && self.Math == Math) |
|
? self |
|
: Function('return this')() |
|
; |
|
|
|
$.fn.state = function(parameters) { |
|
var |
|
$allModules = $(this), |
|
|
|
moduleSelector = $allModules.selector || '', |
|
|
|
hasTouch = ('ontouchstart' in document.documentElement), |
|
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.state.settings, parameters) |
|
: $.extend({}, $.fn.state.settings), |
|
|
|
error = settings.error, |
|
metadata = settings.metadata, |
|
className = settings.className, |
|
namespace = settings.namespace, |
|
states = settings.states, |
|
text = settings.text, |
|
|
|
eventNamespace = '.' + namespace, |
|
moduleNamespace = namespace + '-module', |
|
|
|
$module = $(this), |
|
|
|
element = this, |
|
instance = $module.data(moduleNamespace), |
|
|
|
module |
|
; |
|
module = { |
|
|
|
initialize: function() { |
|
module.verbose('Initializing module'); |
|
|
|
// allow module to guess desired state based on element |
|
if(settings.automatic) { |
|
module.add.defaults(); |
|
} |
|
|
|
// bind events with delegated events |
|
if(settings.context && moduleSelector !== '') { |
|
$(settings.context) |
|
.on(moduleSelector, 'mouseenter' + eventNamespace, module.change.text) |
|
.on(moduleSelector, 'mouseleave' + eventNamespace, module.reset.text) |
|
.on(moduleSelector, 'click' + eventNamespace, module.toggle.state) |
|
; |
|
} |
|
else { |
|
$module |
|
.on('mouseenter' + eventNamespace, module.change.text) |
|
.on('mouseleave' + eventNamespace, module.reset.text) |
|
.on('click' + eventNamespace, module.toggle.state) |
|
; |
|
} |
|
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 |
|
.off(eventNamespace) |
|
.removeData(moduleNamespace) |
|
; |
|
}, |
|
|
|
refresh: function() { |
|
module.verbose('Refreshing selector cache'); |
|
$module = $(element); |
|
}, |
|
|
|
add: { |
|
defaults: function() { |
|
var |
|
userStates = parameters && $.isPlainObject(parameters.states) |
|
? parameters.states |
|
: {} |
|
; |
|
$.each(settings.defaults, function(type, typeStates) { |
|
if( module.is[type] !== undefined && module.is[type]() ) { |
|
module.verbose('Adding default states', type, element); |
|
$.extend(settings.states, typeStates, userStates); |
|
} |
|
}); |
|
} |
|
}, |
|
|
|
is: { |
|
|
|
active: function() { |
|
return $module.hasClass(className.active); |
|
}, |
|
loading: function() { |
|
return $module.hasClass(className.loading); |
|
}, |
|
inactive: function() { |
|
return !( $module.hasClass(className.active) ); |
|
}, |
|
state: function(state) { |
|
if(className[state] === undefined) { |
|
return false; |
|
} |
|
return $module.hasClass( className[state] ); |
|
}, |
|
|
|
enabled: function() { |
|
return !( $module.is(settings.filter.active) ); |
|
}, |
|
disabled: function() { |
|
return ( $module.is(settings.filter.active) ); |
|
}, |
|
textEnabled: function() { |
|
return !( $module.is(settings.filter.text) ); |
|
}, |
|
|
|
// definitions for automatic type detection |
|
button: function() { |
|
return $module.is('.button:not(a, .submit)'); |
|
}, |
|
input: function() { |
|
return $module.is('input'); |
|
}, |
|
progress: function() { |
|
return $module.is('.ui.progress'); |
|
} |
|
}, |
|
|
|
allow: function(state) { |
|
module.debug('Now allowing state', state); |
|
states[state] = true; |
|
}, |
|
disallow: function(state) { |
|
module.debug('No longer allowing', state); |
|
states[state] = false; |
|
}, |
|
|
|
allows: function(state) { |
|
return states[state] || false; |
|
}, |
|
|
|
enable: function() { |
|
$module.removeClass(className.disabled); |
|
}, |
|
|
|
disable: function() { |
|
$module.addClass(className.disabled); |
|
}, |
|
|
|
setState: function(state) { |
|
if(module.allows(state)) { |
|
$module.addClass( className[state] ); |
|
} |
|
}, |
|
|
|
removeState: function(state) { |
|
if(module.allows(state)) { |
|
$module.removeClass( className[state] ); |
|
} |
|
}, |
|
|
|
toggle: { |
|
state: function() { |
|
var |
|
apiRequest, |
|
requestCancelled |
|
; |
|
if( module.allows('active') && module.is.enabled() ) { |
|
module.refresh(); |
|
if($.fn.api !== undefined) { |
|
apiRequest = $module.api('get request'); |
|
requestCancelled = $module.api('was cancelled'); |
|
if( requestCancelled ) { |
|
module.debug('API Request cancelled by beforesend'); |
|
settings.activateTest = function(){ return false; }; |
|
settings.deactivateTest = function(){ return false; }; |
|
} |
|
else if(apiRequest) { |
|
module.listenTo(apiRequest); |
|
return; |
|
} |
|
} |
|
module.change.state(); |
|
} |
|
} |
|
}, |
|
|
|
listenTo: function(apiRequest) { |
|
module.debug('API request detected, waiting for state signal', apiRequest); |
|
if(apiRequest) { |
|
if(text.loading) { |
|
module.update.text(text.loading); |
|
} |
|
$.when(apiRequest) |
|
.then(function() { |
|
if(apiRequest.state() == 'resolved') { |
|
module.debug('API request succeeded'); |
|
settings.activateTest = function(){ return true; }; |
|
settings.deactivateTest = function(){ return true; }; |
|
} |
|
else { |
|
module.debug('API request failed'); |
|
settings.activateTest = function(){ return false; }; |
|
settings.deactivateTest = function(){ return false; }; |
|
} |
|
module.change.state(); |
|
}) |
|
; |
|
} |
|
}, |
|
|
|
// checks whether active/inactive state can be given |
|
change: { |
|
|
|
state: function() { |
|
module.debug('Determining state change direction'); |
|
// inactive to active change |
|
if( module.is.inactive() ) { |
|
module.activate(); |
|
} |
|
else { |
|
module.deactivate(); |
|
} |
|
if(settings.sync) { |
|
module.sync(); |
|
} |
|
settings.onChange.call(element); |
|
}, |
|
|
|
text: function() { |
|
if( module.is.textEnabled() ) { |
|
if(module.is.disabled() ) { |
|
module.verbose('Changing text to disabled text', text.hover); |
|
module.update.text(text.disabled); |
|
} |
|
else if( module.is.active() ) { |
|
if(text.hover) { |
|
module.verbose('Changing text to hover text', text.hover); |
|
module.update.text(text.hover); |
|
} |
|
else if(text.deactivate) { |
|
module.verbose('Changing text to deactivating text', text.deactivate); |
|
module.update.text(text.deactivate); |
|
} |
|
} |
|
else { |
|
if(text.hover) { |
|
module.verbose('Changing text to hover text', text.hover); |
|
module.update.text(text.hover); |
|
} |
|
else if(text.activate){ |
|
module.verbose('Changing text to activating text', text.activate); |
|
module.update.text(text.activate); |
|
} |
|
} |
|
} |
|
} |
|
|
|
}, |
|
|
|
activate: function() { |
|
if( settings.activateTest.call(element) ) { |
|
module.debug('Setting state to active'); |
|
$module |
|
.addClass(className.active) |
|
; |
|
module.update.text(text.active); |
|
settings.onActivate.call(element); |
|
} |
|
}, |
|
|
|
deactivate: function() { |
|
if( settings.deactivateTest.call(element) ) { |
|
module.debug('Setting state to inactive'); |
|
$module |
|
.removeClass(className.active) |
|
; |
|
module.update.text(text.inactive); |
|
settings.onDeactivate.call(element); |
|
} |
|
}, |
|
|
|
sync: function() { |
|
module.verbose('Syncing other buttons to current state'); |
|
if( module.is.active() ) { |
|
$allModules |
|
.not($module) |
|
.state('activate'); |
|
} |
|
else { |
|
$allModules |
|
.not($module) |
|
.state('deactivate') |
|
; |
|
} |
|
}, |
|
|
|
get: { |
|
text: function() { |
|
return (settings.selector.text) |
|
? $module.find(settings.selector.text).text() |
|
: $module.html() |
|
; |
|
}, |
|
textFor: function(state) { |
|
return text[state] || false; |
|
} |
|
}, |
|
|
|
flash: { |
|
text: function(text, duration, callback) { |
|
var |
|
previousText = module.get.text() |
|
; |
|
module.debug('Flashing text message', text, duration); |
|
text = text || settings.text.flash; |
|
duration = duration || settings.flashDuration; |
|
callback = callback || function() {}; |
|
module.update.text(text); |
|
setTimeout(function(){ |
|
module.update.text(previousText); |
|
callback.call(element); |
|
}, duration); |
|
} |
|
}, |
|
|
|
reset: { |
|
// on mouseout sets text to previous value |
|
text: function() { |
|
var |
|
activeText = text.active || $module.data(metadata.storedText), |
|
inactiveText = text.inactive || $module.data(metadata.storedText) |
|
; |
|
if( module.is.textEnabled() ) { |
|
if( module.is.active() && activeText) { |
|
module.verbose('Resetting active text', activeText); |
|
module.update.text(activeText); |
|
} |
|
else if(inactiveText) { |
|
module.verbose('Resetting inactive text', activeText); |
|
module.update.text(inactiveText); |
|
} |
|
} |
|
} |
|
}, |
|
|
|
update: { |
|
text: function(text) { |
|
var |
|
currentText = module.get.text() |
|
; |
|
if(text && text !== currentText) { |
|
module.debug('Updating text', text); |
|
if(settings.selector.text) { |
|
$module |
|
.data(metadata.storedText, text) |
|
.find(settings.selector.text) |
|
.text(text) |
|
; |
|
} |
|
else { |
|
$module |
|
.data(metadata.storedText, text) |
|
.html(text) |
|
; |
|
} |
|
} |
|
else { |
|
module.debug('Text is already set, ignoring update', text); |
|
} |
|
} |
|
}, |
|
|
|
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($.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.state.settings = { |
|
|
|
// module info |
|
name : 'State', |
|
|
|
// debug output |
|
debug : false, |
|
|
|
// verbose debug output |
|
verbose : false, |
|
|
|
// namespace for events |
|
namespace : 'state', |
|
|
|
// debug data includes performance |
|
performance : true, |
|
|
|
// callback occurs on state change |
|
onActivate : function() {}, |
|
onDeactivate : function() {}, |
|
onChange : function() {}, |
|
|
|
// state test functions |
|
activateTest : function() { return true; }, |
|
deactivateTest : function() { return true; }, |
|
|
|
// whether to automatically map default states |
|
automatic : true, |
|
|
|
// activate / deactivate changes all elements instantiated at same time |
|
sync : false, |
|
|
|
// default flash text duration, used for temporarily changing text of an element |
|
flashDuration : 1000, |
|
|
|
// selector filter |
|
filter : { |
|
text : '.loading, .disabled', |
|
active : '.disabled' |
|
}, |
|
|
|
context : false, |
|
|
|
// error |
|
error: { |
|
beforeSend : 'The before send function has cancelled state change', |
|
method : 'The method you called is not defined.' |
|
}, |
|
|
|
// metadata |
|
metadata: { |
|
promise : 'promise', |
|
storedText : 'stored-text' |
|
}, |
|
|
|
// change class on state |
|
className: { |
|
active : 'active', |
|
disabled : 'disabled', |
|
error : 'error', |
|
loading : 'loading', |
|
success : 'success', |
|
warning : 'warning' |
|
}, |
|
|
|
selector: { |
|
// selector for text node |
|
text: false |
|
}, |
|
|
|
defaults : { |
|
input: { |
|
disabled : true, |
|
loading : true, |
|
active : true |
|
}, |
|
button: { |
|
disabled : true, |
|
loading : true, |
|
active : true, |
|
}, |
|
progress: { |
|
active : true, |
|
success : true, |
|
warning : true, |
|
error : true |
|
} |
|
}, |
|
|
|
states : { |
|
active : true, |
|
disabled : true, |
|
error : true, |
|
loading : true, |
|
success : true, |
|
warning : true |
|
}, |
|
|
|
text : { |
|
disabled : false, |
|
flash : false, |
|
hover : false, |
|
active : false, |
|
inactive : false, |
|
activate : false, |
|
deactivate : false |
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
})( jQuery, window, document );
|
|
|