diffhtml-middleware-inline-transitions
Version:
Monitors inline attributes and assigns transition hooks
39 lines (35 loc) • 3.83 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.inlineTransitions = factory());
}(this, (function () { 'use strict';
var assign=Object.assign,keys=Object.keys;var eventsToTransitionName={attributechanged:"attributeChanged",textchanged:"textChanged"};// Store maps of elements to handlers that are associated to transitions.
var transitionsMap={attached:new Map,detached:new Map,replaced:new Map,attributechanged:new Map,textchanged:new Map};// Internal global transition state handlers, allows us to bind once and match.
var boundHandlers={};/**
* Binds inline transitions to the parent element and triggers for any matching
* nested children.
*/function inlineTransitions(){// Monitors whenever an element changes an attribute, if the attribute is a
// valid state name, add this element into the related Set.
var attributeChanged=function(domNode,name,_oldVal,newVal){var prefix=name.toLowerCase().slice(0,2);// Don't bother with non-events.
if(prefix!=="on"){return}// Normalize the event name to lowercase and without `on`.
name=name.toLowerCase().slice(2);var map=transitionsMap[name];var isFunction=typeof newVal==="function";// Abort early if not a valid transition or if the new value exists, but
// isn't a function.
if(!map||newVal&&!isFunction){return}// Add or remove based on the value existence and type.
map[isFunction?"set":"delete"](domNode,newVal);};var Internals=null;var subscribe=function(_Internals){Internals=_Internals;Internals.TransitionCache.get("attributeChanged").add(attributeChanged);// Add a transition for every type.
keys(transitionsMap).forEach(function(name){var map=transitionsMap[name];var transitionName=eventsToTransitionName[name]||name;// This handler is bound for every possible transition to help limit the
// amount of transitions bound.
var handler=function(childNode){for(var _len=arguments.length,rest=new Array(_len>1?_len-1:0),_key=1;_key<_len;_key++){rest[_key-1]=arguments[_key];}// Abort early if no childNode was present.
if(!childNode){return}// If the child element triggered in the transition is the root
// element, this is an easy lookup for the handler.
if(map.has(childNode)){return map.get(childNode).apply(void 0,[childNode,childNode].concat(rest))}// Text nodes are looked up on the parent.
else if(transitionName==="textChanged"){var parentNode=childNode.parentNode;if(map.has(parentNode)){return map.get(parentNode).apply(void 0,[parentNode,childNode].concat(rest))}}// Search if a parent is bound to this.
else {var promises=[];map.forEach(function(_,parentNode){if(parentNode.contains(childNode)){var ret=map.get(parentNode).apply(void 0,[parentNode,childNode].concat(rest));ret&&promises.push(ret);}});if(promises.length){return Promise.all(promises)}}};// Save the handler for later unbinding.
boundHandlers[transitionName]=handler;// Add the state handler.
Internals.TransitionCache.get(transitionName).add(handler);});};// This will unbind any internally bound transition states.
var unsubscribe=function(Internals){// Unbind all the transition states.
Internals.TransitionCache.get("attributeChanged").delete(attributeChanged);// Remove all elements from the internal cache.
keys(transitionsMap).forEach(function(name){var transitionName=eventsToTransitionName[name]||name;// Unbind the associated global handler.
var handler=boundHandlers[transitionName];Internals.TransitionCache.get(transitionName).delete(handler);});// Empty the bound handlers.
boundHandlers.length=0;};return assign(function(){},{displayName:"inlineTransitionsTask",subscribe:subscribe,unsubscribe:unsubscribe})}
return inlineTransitions;
})));