PHP Classes

File: modules/system/assets/js/snowboard/extras/Transition.js

Recommend this page to a friend!
  Packages of Luke Towers   Winter   modules/system/assets/js/snowboard/extras/Transition.js   Download  
File: modules/system/assets/js/snowboard/extras/Transition.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Winter
Content management system that uses MVC
Author: By
Last change:
Date: 7 months ago
Size: 6,386 bytes
 

Contents

Class file image Download
import PluginBase from '../abstracts/PluginBase'; /** * Provides transition support for elements. * * Transition allows CSS transitions to be controlled and callbacks to be run once completed. It works similar to Vue * transitions with 3 stages of transition, and classes assigned to the element with the transition name suffixed with * the stage of transition: * * - `in`: A class assigned to the element for the first frame of the transition, removed afterwards. This should be * used to define the initial state of the transition. * - `active`: A class assigned to the element for the duration of the transition. This should be used to define the * transition itself. * - `out`: A class assigned to the element after the first frame of the transition and kept to the end of the * transition. This should define the end state of the transition. * * Usage: * Snowboard.transition(document.element, 'transition', () => { * console.log('Remove element after 7 seconds'); * this.remove(); * }, '7s'); * * @copyright 2021 Winter. * @author Ben Thomson <git@alfreido.com> */ export default class Transition extends PluginBase { /** * Constructor. * * @param {HTMLElement} element The element to transition * @param {string} transition The name of the transition, this prefixes the stages of transition. * @param {Function} callback An optional callback to call when the transition ends. * @param {Number} duration An optional override on the transition duration. Must be specified as 's' (secs) or 'ms' (msecs). * @param {Boolean} trailTo If true, the "out" class will remain after the end of the transition. */ construct(element, transition, callback, duration, trailTo) { if (element instanceof HTMLElement === false) { throw new Error('A HTMLElement must be provided for transitioning'); } this.element = element; if (typeof transition !== 'string') { throw new Error('Transition name must be specified as a string'); } this.transition = transition; if (callback && typeof callback !== 'function') { throw new Error('Callback must be a valid function'); } this.callback = callback; if (duration) { this.duration = this.parseDuration(duration); } else { this.duration = null; } this.trailTo = (trailTo === true); this.doTransition(); } /** * Maps event classes to the given transition state. * * @param {...any} args * @returns {Array} */ eventClasses(...args) { const eventClasses = { in: `${this.transition}-in`, active: `${this.transition}-active`, out: `${this.transition}-out`, }; if (args.length === 0) { return Object.values(eventClasses); } const returnClasses = []; Object.entries(eventClasses).forEach((entry) => { const [key, value] = entry; if (args.indexOf(key) !== -1) { returnClasses.push(value); } }); return returnClasses; } /** * Executes the transition. * * @returns {void} */ doTransition() { // Add duration override if (this.duration !== null) { this.element.style.transitionDuration = this.duration; } this.resetClasses(); // Start transition - show "in" and "active" classes this.eventClasses('in', 'active').forEach((eventClass) => { this.element.classList.add(eventClass); }); window.requestAnimationFrame(() => { // Ensure a transition exists if (window.getComputedStyle(this.element)['transition-duration'] !== '0s') { // Listen for the transition to end this.element.addEventListener('transitionend', () => this.onTransitionEnd(), { once: true, }); window.requestAnimationFrame(() => { this.element.classList.remove(this.eventClasses('in')[0]); this.element.classList.add(this.eventClasses('out')[0]); }); } else { this.resetClasses(); if (this.callback) { this.callback.apply(this.element); } this.destruct(); } }); } /** * Callback function when the transition ends. * * When a transition ends, the instance of the transition is automatically destructed. * * @returns {void} */ onTransitionEnd() { this.eventClasses('active', (!this.trailTo) ? 'out' : '').forEach((eventClass) => { this.element.classList.remove(eventClass); }); if (this.callback) { this.callback.apply(this.element); } // Remove duration override if (this.duration !== null) { this.element.style.transitionDuration = null; } this.destruct(); } /** * Cancels a transition. * * @returns {void} */ cancel() { this.element.removeEventListener('transitionend', () => this.onTransitionEnd, { once: true, }); this.resetClasses(); // Remove duration override if (this.duration !== null) { this.element.style.transitionDuration = null; } // Call destructor this.destruct(); } /** * Resets the classes, removing any transition classes. * * @returns {void} */ resetClasses() { this.eventClasses().forEach((eventClass) => { this.element.classList.remove(eventClass); }); } /** * Parses a given duration and converts it to a "ms" value. * * @param {String} duration * @returns {String} */ parseDuration(duration) { const parsed = /^([0-9]+(\.[0-9]+)?)(m?s)?$/.exec(duration); const amount = Number(parsed[1]); const unit = (parsed[3] === 's') ? 'sec' : 'msec'; return (unit === 'sec') ? `${amount * 1000}ms` : `${Math.floor(amount)}ms`; } }