wishthis/semantic/dist/components/transition.js
2023-08-17 11:47:40 +02:00

1034 lines
43 KiB
JavaScript

/*!
* # Fomantic-UI 2.9.2 - Transition
* https://github.com/fomantic/Fomantic-UI/
*
*
* Released under the MIT license
* https://opensource.org/licenses/MIT
*
*/
(function ($, window, document) {
'use strict';
function isFunction(obj) {
return typeof obj === 'function' && typeof obj.nodeType !== 'number';
}
window = window !== undefined && window.Math === Math
? window
: globalThis;
$.fn.transition = function () {
var
$allModules = $(this),
moduleSelector = $allModules.selector || '',
time = Date.now(),
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,
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;
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.interval);
} 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) * interval
: index * interval;
module.debug('Delaying animation by', delay);
setTimeout(module.animate, delay);
},
animate: function (overrideSettings) {
settings = overrideSettings || settings;
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;
}
if (!settings.allowRepeats && module.is.occurring()) {
module.debug('Animation is already occurring, will not execute repeated animation', settings.animation);
return false;
}
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 inward, 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) {
if (typeof animation === 'object') { // single settings object
return $.extend(true, {}, $.fn.transition.settings, animation);
}
if (typeof onComplete === 'function') { // all arguments provided
return $.extend({}, $.fn.transition.settings, {
animation: animation,
onComplete: onComplete,
duration: duration,
});
}
if (typeof duration === 'string' || typeof duration === 'number') { // only duration provided
return $.extend({}, $.fn.transition.settings, {
animation: animation,
duration: duration,
});
}
if (typeof duration === 'object') { // duration is actually settings object
return $.extend({}, $.fn.transition.settings, duration, {
animation: animation,
});
}
if (typeof duration === 'function') { // duration is actually callback
return $.extend({}, $.fn.transition.settings, {
animation: animation,
onComplete: duration,
});
}
// only animation provided
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];
},
},
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')
;
$clone.detach().insertAfter($module);
inAnimation = $clone
.addClass(className.inward)
.css('animationName')
;
if (!displayType) {
$clone.detach().insertAfter($module);
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 () {
// keep method for backward compatibility until 2.10.0
return true;
},
},
hide: function () {
if (settings.onHide.call(element) === false) {
module.verbose('Hide callback returned false cancelling hide');
return false;
}
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();
settings.onBeforeHide.call(element, module.hideNow);
},
hideNow: function () {
module.set.hidden();
module.force.hidden();
settings.onHidden.call(element);
settings.onComplete.call(element);
},
show: function (display) {
if (module.force.visible() && settings.onShow.call(element) !== false) {
module.verbose('Showing element', display);
module.remove.hidden();
settings.onBeforeShow.call(element, module.showNow);
}
},
showNow: function () {
module.set.visible();
settings.onVisible.call(element);
settings.onComplete.call(element);
},
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 = Date.now();
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 (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 = context || element;
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 () {},
onBeforeShow: function (callback) {
callback.call(this);
},
onVisible: function () {},
onHide: function () {},
onHidden: function () {},
onBeforeHide: function (callback) {
callback.call(this);
},
// 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 suppress this warning in production.',
},
};
})(jQuery, window, document);