improve domObserver

This commit is contained in:
Rene
2021-01-20 01:04:34 +01:00
parent d70a8aa99d
commit 323d05beec
19 changed files with 913 additions and 251 deletions
+267 -57
View File
@@ -1,7 +1,13 @@
const ElementNodeType = Node.ELEMENT_NODE;
const { toString, hasOwnProperty } = Object.prototype;
function isUndefined(obj) {
return obj === undefined;
}
function isNull(obj) {
return obj === null;
}
const type = (obj) => {
return obj === undefined || obj === null
return isUndefined(obj) || isNull(obj)
? `${obj}`
: toString
.call(obj)
@@ -17,12 +23,6 @@ function isString(obj) {
function isFunction(obj) {
return typeof obj === 'function';
}
function isUndefined(obj) {
return obj === undefined;
}
function isNull(obj) {
return obj === null;
}
function isArray(obj) {
return Array.isArray(obj);
}
@@ -121,6 +121,7 @@ function each(source, callback) {
return source;
}
const indexOf = (arr, item, fromIndex) => arr.indexOf(item, fromIndex);
const push = (array, items, arrayIsSingleItem) => {
!arrayIsSingleItem && !isString(items) && isArrayLike(items) ? Array.prototype.push.apply(array, items) : array.push(items);
return array;
@@ -136,6 +137,7 @@ const from = (arr) => {
});
return result;
};
const isEmptyArray = (array) => array && array.length === 0;
const runEach = (arr, p1) => {
const runFn = (fn) => fn && fn(p1);
@@ -148,6 +150,12 @@ const runEach = (arr, p1) => {
const elmPrototype = Element.prototype;
const find = (selector, elm) => {
const arr = [];
const rootElm = elm ? (isElement(elm) ? elm : null) : document;
return rootElm ? push(arr, rootElm.querySelectorAll(selector)) : arr;
};
const is = (elm, selector) => {
if (isElement(elm)) {
const fn = elmPrototype.matches || elmPrototype.msMatchesSelector;
@@ -260,7 +268,7 @@ const getBoundingClientRect = (elm) => elm.getBoundingClientRect();
let passiveEventsSupport;
const supportPassiveEvents = () => {
if (passiveEventsSupport === undefined) {
if (isUndefined(passiveEventsSupport)) {
passiveEventsSupport = false;
try {
@@ -373,6 +381,75 @@ function isEmptyObject(obj) {
return true;
}
const firstLetterToUpper = (str) => str.charAt(0).toUpperCase() + str.slice(1);
const getDummyStyle = () => createDiv().style;
const cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];
const jsPrefixes = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
const jsCache = {};
const cssCache = {};
const cssProperty = (name) => {
let result = cssCache[name];
if (hasOwnProperty$1(cssCache, name)) {
return result;
}
const uppercasedName = firstLetterToUpper(name);
const elmStyle = getDummyStyle();
each(cssPrefixes, (prefix) => {
const prefixWithoutDashes = prefix.replace(/-/g, '');
const resultPossibilities = [name, prefix + name, prefixWithoutDashes + uppercasedName, firstLetterToUpper(prefixWithoutDashes) + uppercasedName];
result = resultPossibilities.find((resultPossibility) => elmStyle[resultPossibility] !== undefined);
return !result;
});
cssCache[name] = result;
return result;
};
const jsAPI = (name) => {
let result = jsCache[name] || window[name];
if (hasOwnProperty$1(jsCache, name)) {
return result;
}
each(jsPrefixes, (prefix) => {
result = result || window[prefix + firstLetterToUpper(name)];
return !result;
});
jsCache[name] = result;
return result;
};
const MutationObserverConstructor = jsAPI('MutationObserver');
const IntersectionObserverConstructor = jsAPI('IntersectionObserver');
const ResizeObserverConstructor = jsAPI('ResizeObserver');
const cAF = jsAPI('cancelAnimationFrame');
const rAF = jsAPI('requestAnimationFrame');
const debounce = (functionToDebounce, timeout, maxWait) => {
let timeoutId;
let lastCallTime;
const hasTimeout = isNumber(timeout) && timeout > 0;
const hasMaxWait = isNumber(maxWait) && maxWait > 0;
const cancel = hasTimeout ? window.clearTimeout : cAF;
const set = hasTimeout ? window.setTimeout : rAF;
const setFn = function setFn(args) {
lastCallTime = hasMaxWait ? performance.now() : 0;
timeoutId && cancel(timeoutId);
functionToDebounce.apply(this, args);
};
return function () {
const boundSetFn = setFn.bind(this, arguments);
const forceCall = hasMaxWait ? performance.now() - lastCallTime >= maxWait : false;
timeoutId && cancel(timeoutId);
timeoutId = forceCall ? boundSetFn() : set(boundSetFn, timeout);
};
};
const cssNumber = {
animationiterationcount: 1,
columncount: 1,
@@ -481,53 +558,6 @@ const createCache = (update, options) => {
};
};
const firstLetterToUpper = (str) => str.charAt(0).toUpperCase() + str.slice(1);
const getDummyStyle = () => createDiv().style;
const cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];
const jsPrefixes = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
const jsCache = {};
const cssCache = {};
const cssProperty = (name) => {
let result = cssCache[name];
if (hasOwnProperty$1(cssCache, name)) {
return result;
}
const uppercasedName = firstLetterToUpper(name);
const elmStyle = getDummyStyle();
each(cssPrefixes, (prefix) => {
const prefixWithoutDashes = prefix.replace(/-/g, '');
const resultPossibilities = [name, prefix + name, prefixWithoutDashes + uppercasedName, firstLetterToUpper(prefixWithoutDashes) + uppercasedName];
result = resultPossibilities.find((resultPossibility) => elmStyle[resultPossibility] !== undefined);
return !result;
});
cssCache[name] = result;
return result;
};
const jsAPI = (name) => {
let result = jsCache[name] || window[name];
if (hasOwnProperty$1(jsCache, name)) {
return result;
}
each(jsPrefixes, (prefix) => {
result = result || window[prefix + firstLetterToUpper(name)];
return !result;
});
jsCache[name] = result;
return result;
};
const MutationObserverConstructor = jsAPI('MutationObserver');
const IntersectionObserverConstructor = jsAPI('IntersectionObserver');
const ResizeObserverConstructor = jsAPI('ResizeObserver');
const cAF = jsAPI('cancelAnimationFrame');
const rAF = jsAPI('requestAnimationFrame');
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
@@ -599,7 +629,7 @@ const validateRecursive = (options, template, optionsDiff, doWriteErrors, propPa
typeString = key;
}
});
const isEnumString = typeString === undefined;
const isEnumString = isUndefined(typeString);
if (isEnumString && isString(optionsValue)) {
const enumStringSplit = currTemplateType.split(' ');
@@ -1160,6 +1190,174 @@ const createTrinsicObserver = (target, onTrinsicChangedCallback) => {
};
};
const createEventContentChange = (target, eventContentChange, map, callback) => {
let eventContentChangeRef;
const addEvent = (elm, eventName) => {
const entry = map.get(elm);
const newEntry = isUndefined(entry);
const registerEvent = () => {
map.set(elm, eventName);
on(elm, eventName, callback);
};
if (!newEntry && eventName !== entry) {
off(elm, entry, callback);
registerEvent();
} else if (newEntry) {
registerEvent();
}
};
const _destroy = () => {
map.forEach((eventName, elm) => {
off(elm, eventName, callback);
});
map.clear();
};
const _updateElements = (getElements) => {
if (eventContentChangeRef) {
const eventElmList = eventContentChangeRef.reduce((arr, item) => {
if (item) {
const selector = item[0];
const eventName = item[1];
const elements = eventName && selector && (getElements ? getElements(selector) : find(selector, target));
if (elements) {
push(arr, [elements, isFunction(eventName) ? eventName(elements) : eventName], true);
}
}
return arr;
}, []);
each(eventElmList, (item) => {
const elements = item[0];
const eventName = item[1];
each(elements, (elm) => {
addEvent(elm, eventName);
});
});
}
};
const _update = (newEventContentChange) => {
eventContentChangeRef = newEventContentChange;
_destroy();
_updateElements();
};
if (eventContentChange) {
_update(eventContentChange);
}
return {
_destroy,
_updateElements,
_update,
};
};
const getAttributeChanged = (mutationTarget, attributeName, oldValue) => oldValue !== attr(mutationTarget, attributeName);
const createDOMObserver = (target, callback, options) => {
let isConnected = false;
const { _observeContent, _attributes, _styleChangingAttributes, _ignoreContentChange, _eventContentChange } = options || {};
const {
_updateElements: updateEventContentChangeElements,
_destroy: destroyEventContentChange,
_update: updateEventContentChange,
} = createEventContentChange(
target,
_observeContent && _eventContentChange,
new Map(),
debounce(() => {
if (isConnected) {
callback([], false, true);
}
}, 80)
);
const finalAttributes = _attributes || [];
const finalStyleChangingAttributes = _styleChangingAttributes || [];
const observedAttributes = finalAttributes.concat(finalStyleChangingAttributes);
const observerCallback = (mutations) => {
const targetChangedAttrs = [];
const totalAddedNodes = [];
let targetStyleChanged = false;
let contentChanged = false;
let childListChanged = false;
each(mutations, (mutation) => {
const { attributeName, target: mutationTarget, type, oldValue, addedNodes } = mutation;
const isAttributesType = type === 'attributes';
const isChildListType = type === 'childList';
const targetIsMutationTarget = target === mutationTarget;
const attributeChanged = isAttributesType && isString(attributeName) && getAttributeChanged(mutationTarget, attributeName, oldValue);
const targetAttrChanged = attributeChanged && targetIsMutationTarget && !_observeContent;
const styleChangingAttrChanged = indexOf(finalStyleChangingAttributes, attributeName) > -1 && attributeChanged;
targetStyleChanged = targetStyleChanged || (targetAttrChanged && styleChangingAttrChanged);
if (targetAttrChanged) {
push(targetChangedAttrs, attributeName);
}
if (_observeContent) {
const notOnlyAttrChanged = !isAttributesType;
const contentAttrChanged = isAttributesType && styleChangingAttrChanged && !targetIsMutationTarget;
const contentFinalChanged =
(notOnlyAttrChanged || contentAttrChanged) && (_ignoreContentChange ? !_ignoreContentChange(mutation, target, options) : _observeContent);
push(totalAddedNodes, addedNodes);
contentChanged = contentChanged || contentFinalChanged;
childListChanged = childListChanged || isChildListType;
}
});
if (childListChanged && !isEmptyArray(totalAddedNodes)) {
updateEventContentChangeElements((selector) =>
totalAddedNodes.reduce((arr, node) => {
push(arr, find(selector, node));
return is(node, selector) ? push(arr, node) : arr;
}, [])
);
}
if (!isEmptyArray(targetChangedAttrs) || targetStyleChanged || contentChanged) {
callback(targetChangedAttrs, targetStyleChanged, contentChanged);
}
};
const mutationObserver = new MutationObserverConstructor(observerCallback);
mutationObserver.observe(target, {
attributes: true,
attributeOldValue: true,
attributeFilter: observedAttributes,
subtree: _observeContent,
childList: _observeContent,
characterData: _observeContent,
});
isConnected = true;
return {
_disconnect: () => {
if (isConnected) {
destroyEventContentChange();
mutationObserver.disconnect();
isConnected = false;
}
},
_updateEventContentChange: (newEventContentChange) => {
updateEventContentChange(isConnected && _observeContent && newEventContentChange);
},
_update: () => {
if (isConnected) {
observerCallback(mutationObserver.takeRecords());
}
},
};
};
const normalizeTarget = (target) => {
if (isHTMLElement(target)) {
const isTextarea = is(target, 'textarea');
@@ -1197,7 +1395,7 @@ const normalizeTarget = (target) => {
const OverlayScrollbars = (target, options, extensions) => {
const osTarget = normalizeTarget(target);
const lifecycles = [];
const { host } = osTarget;
const { host, content } = osTarget;
push(lifecycles, createStructureLifecycle(osTarget));
const onSizeChanged = (directionCache) => {
@@ -1223,6 +1421,18 @@ const OverlayScrollbars = (target, options, extensions) => {
_direction: true,
});
createTrinsicObserver(host, onTrinsicChanged);
createDOMObserver(host, () => {
return null;
});
createDOMObserver(
content,
() => {
return null;
},
{
_observeContent: true,
}
);
};
var index = () => {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+291 -63
View File
@@ -11,8 +11,14 @@
var _Object$prototype = Object.prototype,
toString = _Object$prototype.toString,
hasOwnProperty = _Object$prototype.hasOwnProperty;
function isUndefined(obj) {
return obj === undefined;
}
function isNull(obj) {
return obj === null;
}
var type = function type(obj) {
return obj === undefined || obj === null
return isUndefined(obj) || isNull(obj)
? '' + obj
: toString
.call(obj)
@@ -28,12 +34,6 @@
function isFunction(obj) {
return typeof obj === 'function';
}
function isUndefined(obj) {
return obj === undefined;
}
function isNull(obj) {
return obj === null;
}
function isArray(obj) {
return Array.isArray(obj);
}
@@ -136,6 +136,9 @@
return source;
}
var indexOf = function indexOf(arr, item, fromIndex) {
return arr.indexOf(item, fromIndex);
};
var push = function push(array, items, arrayIsSingleItem) {
!arrayIsSingleItem && !isString(items) && isArrayLike(items) ? Array.prototype.push.apply(array, items) : array.push(items);
return array;
@@ -151,6 +154,9 @@
});
return result;
};
var isEmptyArray = function isEmptyArray(array) {
return array && array.length === 0;
};
var runEach = function runEach(arr, p1) {
var runFn = function runFn(fn) {
return fn && fn(p1);
@@ -165,6 +171,12 @@
var elmPrototype = Element.prototype;
var find = function find(selector, elm) {
var arr = [];
var rootElm = elm ? (isElement(elm) ? elm : null) : document;
return rootElm ? push(arr, rootElm.querySelectorAll(selector)) : arr;
};
var is = function is(elm, selector) {
if (isElement(elm)) {
var fn = elmPrototype.matches || elmPrototype.msMatchesSelector;
@@ -292,7 +304,7 @@
var passiveEventsSupport;
var supportPassiveEvents = function supportPassiveEvents() {
if (passiveEventsSupport === undefined) {
if (isUndefined(passiveEventsSupport)) {
passiveEventsSupport = false;
try {
@@ -423,6 +435,81 @@
return true;
}
var firstLetterToUpper = function firstLetterToUpper(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
var getDummyStyle = function getDummyStyle() {
return createDiv().style;
};
var cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];
var jsPrefixes = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
var jsCache = {};
var cssCache = {};
var cssProperty = function cssProperty(name) {
var result = cssCache[name];
if (hasOwnProperty$1(cssCache, name)) {
return result;
}
var uppercasedName = firstLetterToUpper(name);
var elmStyle = getDummyStyle();
each(cssPrefixes, function (prefix) {
var prefixWithoutDashes = prefix.replace(/-/g, '');
var resultPossibilities = [name, prefix + name, prefixWithoutDashes + uppercasedName, firstLetterToUpper(prefixWithoutDashes) + uppercasedName];
result = resultPossibilities.find(function (resultPossibility) {
return elmStyle[resultPossibility] !== undefined;
});
return !result;
});
cssCache[name] = result;
return result;
};
var jsAPI = function jsAPI(name) {
var result = jsCache[name] || window[name];
if (hasOwnProperty$1(jsCache, name)) {
return result;
}
each(jsPrefixes, function (prefix) {
result = result || window[prefix + firstLetterToUpper(name)];
return !result;
});
jsCache[name] = result;
return result;
};
var MutationObserverConstructor = jsAPI('MutationObserver');
var IntersectionObserverConstructor = jsAPI('IntersectionObserver');
var ResizeObserverConstructor = jsAPI('ResizeObserver');
var cAF = jsAPI('cancelAnimationFrame');
var rAF = jsAPI('requestAnimationFrame');
var debounce = function debounce(functionToDebounce, timeout, maxWait) {
var timeoutId;
var lastCallTime;
var hasTimeout = isNumber(timeout) && timeout > 0;
var hasMaxWait = isNumber(maxWait) && maxWait > 0;
var cancel = hasTimeout ? window.clearTimeout : cAF;
var set = hasTimeout ? window.setTimeout : rAF;
var setFn = function setFn(args) {
lastCallTime = hasMaxWait ? performance.now() : 0;
timeoutId && cancel(timeoutId);
functionToDebounce.apply(this, args);
};
return function () {
var boundSetFn = setFn.bind(this, arguments);
var forceCall = hasMaxWait ? performance.now() - lastCallTime >= maxWait : false;
timeoutId && cancel(timeoutId);
timeoutId = forceCall ? boundSetFn() : set(boundSetFn, timeout);
};
};
var cssNumber = {
animationiterationcount: 1,
columncount: 1,
@@ -540,59 +627,6 @@
};
};
var firstLetterToUpper = function firstLetterToUpper(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
var getDummyStyle = function getDummyStyle() {
return createDiv().style;
};
var cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];
var jsPrefixes = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
var jsCache = {};
var cssCache = {};
var cssProperty = function cssProperty(name) {
var result = cssCache[name];
if (hasOwnProperty$1(cssCache, name)) {
return result;
}
var uppercasedName = firstLetterToUpper(name);
var elmStyle = getDummyStyle();
each(cssPrefixes, function (prefix) {
var prefixWithoutDashes = prefix.replace(/-/g, '');
var resultPossibilities = [name, prefix + name, prefixWithoutDashes + uppercasedName, firstLetterToUpper(prefixWithoutDashes) + uppercasedName];
result = resultPossibilities.find(function (resultPossibility) {
return elmStyle[resultPossibility] !== undefined;
});
return !result;
});
cssCache[name] = result;
return result;
};
var jsAPI = function jsAPI(name) {
var result = jsCache[name] || window[name];
if (hasOwnProperty$1(jsCache, name)) {
return result;
}
each(jsPrefixes, function (prefix) {
result = result || window[prefix + firstLetterToUpper(name)];
return !result;
});
jsCache[name] = result;
return result;
};
var MutationObserverConstructor = jsAPI('MutationObserver');
var IntersectionObserverConstructor = jsAPI('IntersectionObserver');
var ResizeObserverConstructor = jsAPI('ResizeObserver');
var cAF = jsAPI('cancelAnimationFrame');
var rAF = jsAPI('requestAnimationFrame');
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
@@ -666,7 +700,7 @@
typeString = key;
}
});
var isEnumString = typeString === undefined;
var isEnumString = isUndefined(typeString);
if (isEnumString && isString(optionsValue)) {
var enumStringSplit = currTemplateType.split(' ');
@@ -1298,6 +1332,187 @@
};
};
var createEventContentChange = function createEventContentChange(target, eventContentChange, map, callback) {
var eventContentChangeRef;
var addEvent = function addEvent(elm, eventName) {
var entry = map.get(elm);
var newEntry = isUndefined(entry);
var registerEvent = function registerEvent() {
map.set(elm, eventName);
on(elm, eventName, callback);
};
if (!newEntry && eventName !== entry) {
off(elm, entry, callback);
registerEvent();
} else if (newEntry) {
registerEvent();
}
};
var _destroy = function _destroy() {
map.forEach(function (eventName, elm) {
off(elm, eventName, callback);
});
map.clear();
};
var _updateElements = function _updateElements(getElements) {
if (eventContentChangeRef) {
var eventElmList = eventContentChangeRef.reduce(function (arr, item) {
if (item) {
var selector = item[0];
var eventName = item[1];
var elements = eventName && selector && (getElements ? getElements(selector) : find(selector, target));
if (elements) {
push(arr, [elements, isFunction(eventName) ? eventName(elements) : eventName], true);
}
}
return arr;
}, []);
each(eventElmList, function (item) {
var elements = item[0];
var eventName = item[1];
each(elements, function (elm) {
addEvent(elm, eventName);
});
});
}
};
var _update = function _update(newEventContentChange) {
eventContentChangeRef = newEventContentChange;
_destroy();
_updateElements();
};
if (eventContentChange) {
_update(eventContentChange);
}
return {
_destroy: _destroy,
_updateElements: _updateElements,
_update: _update,
};
};
var getAttributeChanged = function getAttributeChanged(mutationTarget, attributeName, oldValue) {
return oldValue !== attr(mutationTarget, attributeName);
};
var createDOMObserver = function createDOMObserver(target, callback, options) {
var isConnected = false;
var _ref = options || {},
_observeContent = _ref._observeContent,
_attributes = _ref._attributes,
_styleChangingAttributes = _ref._styleChangingAttributes,
_ignoreContentChange = _ref._ignoreContentChange,
_eventContentChange = _ref._eventContentChange;
var _createEventContentCh = createEventContentChange(
target,
_observeContent && _eventContentChange,
new Map(),
debounce(function () {
if (isConnected) {
callback([], false, true);
}
}, 80)
),
updateEventContentChangeElements = _createEventContentCh._updateElements,
destroyEventContentChange = _createEventContentCh._destroy,
updateEventContentChange = _createEventContentCh._update;
var finalAttributes = _attributes || [];
var finalStyleChangingAttributes = _styleChangingAttributes || [];
var observedAttributes = finalAttributes.concat(finalStyleChangingAttributes);
var observerCallback = function observerCallback(mutations) {
var targetChangedAttrs = [];
var totalAddedNodes = [];
var targetStyleChanged = false;
var contentChanged = false;
var childListChanged = false;
each(mutations, function (mutation) {
var attributeName = mutation.attributeName,
mutationTarget = mutation.target,
type = mutation.type,
oldValue = mutation.oldValue,
addedNodes = mutation.addedNodes;
var isAttributesType = type === 'attributes';
var isChildListType = type === 'childList';
var targetIsMutationTarget = target === mutationTarget;
var attributeChanged = isAttributesType && isString(attributeName) && getAttributeChanged(mutationTarget, attributeName, oldValue);
var targetAttrChanged = attributeChanged && targetIsMutationTarget && !_observeContent;
var styleChangingAttrChanged = indexOf(finalStyleChangingAttributes, attributeName) > -1 && attributeChanged;
targetStyleChanged = targetStyleChanged || (targetAttrChanged && styleChangingAttrChanged);
if (targetAttrChanged) {
push(targetChangedAttrs, attributeName);
}
if (_observeContent) {
var notOnlyAttrChanged = !isAttributesType;
var contentAttrChanged = isAttributesType && styleChangingAttrChanged && !targetIsMutationTarget;
var contentFinalChanged =
(notOnlyAttrChanged || contentAttrChanged) && (_ignoreContentChange ? !_ignoreContentChange(mutation, target, options) : _observeContent);
push(totalAddedNodes, addedNodes);
contentChanged = contentChanged || contentFinalChanged;
childListChanged = childListChanged || isChildListType;
}
});
if (childListChanged && !isEmptyArray(totalAddedNodes)) {
updateEventContentChangeElements(function (selector) {
return totalAddedNodes.reduce(function (arr, node) {
push(arr, find(selector, node));
return is(node, selector) ? push(arr, node) : arr;
}, []);
});
}
if (!isEmptyArray(targetChangedAttrs) || targetStyleChanged || contentChanged) {
callback(targetChangedAttrs, targetStyleChanged, contentChanged);
}
};
var mutationObserver = new MutationObserverConstructor(observerCallback);
mutationObserver.observe(target, {
attributes: true,
attributeOldValue: true,
attributeFilter: observedAttributes,
subtree: _observeContent,
childList: _observeContent,
characterData: _observeContent,
});
isConnected = true;
return {
_disconnect: function _disconnect() {
if (isConnected) {
destroyEventContentChange();
mutationObserver.disconnect();
isConnected = false;
}
},
_updateEventContentChange: function _updateEventContentChange(newEventContentChange) {
updateEventContentChange(isConnected && _observeContent && newEventContentChange);
},
_update: function _update() {
if (isConnected) {
observerCallback(mutationObserver.takeRecords());
}
},
};
};
var normalizeTarget = function normalizeTarget(target) {
if (isHTMLElement(target)) {
var isTextarea = is(target, 'textarea');
@@ -1338,7 +1553,8 @@
var OverlayScrollbars = function OverlayScrollbars(target, options, extensions) {
var osTarget = normalizeTarget(target);
var lifecycles = [];
var host = osTarget.host;
var host = osTarget.host,
content = osTarget.content;
push(lifecycles, createStructureLifecycle(osTarget));
var onSizeChanged = function onSizeChanged(directionCache) {
@@ -1364,6 +1580,18 @@
_direction: true,
});
createTrinsicObserver(host, onTrinsicChanged);
createDOMObserver(host, function () {
return null;
});
createDOMObserver(
content,
function () {
return null;
},
{
_observeContent: true,
}
);
};
var index = function () {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,27 +1,116 @@
import { each, debounce, indexOf, isString, MutationObserverConstructor, isEmptyArray, on, off, attr, is, find, push } from 'support';
import {
each,
debounce,
indexOf,
isString,
MutationObserverConstructor,
isEmptyArray,
on,
off,
attr,
is,
find,
push,
isUndefined,
isFunction,
} from 'support';
type StringNullUndefined = string | null | undefined;
export type DOMOvserverEventContentChangeResult = Array<[StringNullUndefined, StringNullUndefined] | null | undefined>; // [selector, eventname]
export type DOMOvserverEventContentChange = () => DOMOvserverEventContentChangeResult;
export type DOMObserverEventContentChange =
| Array<[StringNullUndefined, ((elms: Node[]) => string) | StringNullUndefined] | null | undefined>
| false
| null
| undefined;
export type DOMObserverIgnoreContentChange = (
mutation: MutationRecord,
domObserverTarget: HTMLElement,
domObserverOptions: DOMObserverOptions | undefined
) => boolean | null | undefined;
export interface DOMObserverOptions {
_observeContent?: boolean;
_attributes?: string[];
_observeContent?: boolean; // do observe children and trigger content change
_attributes?: string[]; // observed attributes
_styleChangingAttributes?: string[]; // list of attributes that trigger a content change if changed
_eventContentChange?: DOMObserverEventContentChange; // [selector, eventname]
_ignoreContentChange?: DOMObserverIgnoreContentChange;
_eventContentChange?: DOMOvserverEventContentChange;
}
export interface DOMObserver {
_disconnect: () => void;
_updateEventContentChange: (newEventContentChange?: DOMObserverEventContentChange) => void;
_update: () => void;
}
const styleChangingAttributes = ['id', 'class', 'style', 'open'];
const mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];
// const styleChangingAttributes = ['id', 'class', 'style', 'open'];
// const mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];
const createEventContentChange = (
target: Element,
eventContentChange: DOMObserverEventContentChange,
map: Map<Node, string>,
callback: (...args: any) => any
) => {
let eventContentChangeRef: DOMObserverEventContentChange;
const addEvent = (elm: Node, eventName: string) => {
const entry = map.get(elm);
const newEntry = isUndefined(entry);
const registerEvent = () => {
map.set(elm, eventName);
on(elm, eventName, callback);
};
if (!newEntry && eventName !== entry) {
off(elm, entry!, callback);
registerEvent();
} else if (newEntry) {
registerEvent();
}
};
const _destroy = () => {
map.forEach((eventName: string, elm: Node) => {
off(elm, eventName, callback);
});
map.clear();
};
const _updateElements = (getElements?: (selector: string) => Node[]) => {
if (eventContentChangeRef) {
const eventElmList = eventContentChangeRef.reduce<Array<[Node[], string]>>((arr, item) => {
if (item) {
const selector = item[0];
const eventName = item[1];
const elements = eventName && selector && (getElements ? getElements(selector) : find(selector, target));
if (elements) {
push(arr, [elements, isFunction(eventName) ? eventName(elements) : eventName!], true);
}
}
return arr;
}, []);
each(eventElmList, (item) => {
const elements = item[0];
const eventName = item[1];
each(elements, (elm) => {
addEvent(elm, eventName);
});
});
}
};
const _update = (newEventContentChange: DOMObserverEventContentChange) => {
eventContentChangeRef = newEventContentChange;
_destroy();
_updateElements();
};
if (eventContentChange) {
_update(eventContentChange);
}
return {
_destroy,
_updateElements,
_update,
};
};
const getAttributeChanged = (mutationTarget: Node, attributeName: string, oldValue: string | null): boolean =>
oldValue !== attr(mutationTarget as HTMLElement, attributeName);
@@ -31,42 +120,26 @@ export const createDOMObserver = (
options?: DOMObserverOptions
): DOMObserver => {
let isConnected = false;
const { _observeContent, _attributes, _ignoreContentChange, _eventContentChange } = options || {};
const eventContentChangeCallback = debounce(() => {
if (isConnected) {
callback([], false, true);
}
});
const refreshEventContentChange = (getElements: (selector: string) => Node[]) => {
if (_eventContentChange) {
const eventContentChanges = _eventContentChange();
const eventElmList = eventContentChanges.reduce<Array<[string, Node[]]>>((arr, item) => {
if (item) {
const selector = item[0];
const eventName = item[1];
const elements = eventName && selector && getElements(selector);
if (elements) {
push(arr, [eventName!, elements], true);
}
}
return arr;
}, []);
each(eventElmList, (item) => {
const eventName = item[0];
const elements = item[1];
each(elements, (elm) => {
off(elm, eventName, eventContentChangeCallback);
on(elm, eventName, eventContentChangeCallback);
});
});
}
};
const { _observeContent, _attributes, _styleChangingAttributes, _eventContentChange, _ignoreContentChange } = options || {};
const {
_updateElements: updateEventContentChangeElements,
_destroy: destroyEventContentChange,
_update: updateEventContentChange,
} = createEventContentChange(
target,
_observeContent && _eventContentChange,
new Map<Node, string>(),
debounce(() => {
if (isConnected) {
callback([], false, true);
}
}, 80)
);
// MutationObserver
const observedAttributes = (_attributes || []).concat(styleChangingAttributes); // TODO: observer textarea attrs if textarea
const finalAttributes = _attributes || [];
const finalStyleChangingAttributes = _styleChangingAttributes || [];
const observedAttributes = finalAttributes.concat(finalStyleChangingAttributes); // TODO: observer textarea attrs if textarea
const observerCallback = (mutations: MutationRecord[]) => {
const targetChangedAttrs: string[] = [];
const totalAddedNodes: Node[] = [];
@@ -80,7 +153,7 @@ export const createDOMObserver = (
const targetIsMutationTarget = target === mutationTarget;
const attributeChanged = isAttributesType && isString(attributeName) && getAttributeChanged(mutationTarget, attributeName!, oldValue);
const targetAttrChanged = attributeChanged && targetIsMutationTarget && !_observeContent;
const styleChangingAttrChanged = indexOf(styleChangingAttributes, attributeName) > -1 && attributeChanged;
const styleChangingAttrChanged = indexOf(finalStyleChangingAttributes, attributeName) > -1 && attributeChanged;
targetStyleChanged = targetStyleChanged || (targetAttrChanged && styleChangingAttrChanged);
@@ -101,7 +174,7 @@ export const createDOMObserver = (
});
if (childListChanged && !isEmptyArray(totalAddedNodes)) {
refreshEventContentChange((selector) =>
updateEventContentChangeElements((selector) =>
totalAddedNodes.reduce<Node[]>((arr, node) => {
push(arr, find(selector, node));
return is(node, selector) ? push(arr, node) : arr;
@@ -114,6 +187,7 @@ export const createDOMObserver = (
};
const mutationObserver: MutationObserver = new MutationObserverConstructor!(observerCallback);
// Connect
mutationObserver.observe(target, {
attributes: true,
attributeOldValue: true,
@@ -122,17 +196,18 @@ export const createDOMObserver = (
childList: _observeContent,
characterData: _observeContent,
});
isConnected = true;
if (_observeContent) {
refreshEventContentChange((selector) => find(selector, target));
}
return {
_disconnect: () => {
mutationObserver.disconnect();
isConnected = false;
if (isConnected) {
destroyEventContentChange();
mutationObserver.disconnect();
isConnected = false;
}
},
_updateEventContentChange: (newEventContentChange?: DOMObserverEventContentChange) => {
updateEventContentChange(isConnected && _observeContent && newEventContentChange);
},
_update: () => {
if (isConnected) {
@@ -3,6 +3,7 @@ import { createStructureLifecycle } from 'lifecycles/structureLifecycle';
import { Cache, appendChildren, addClass, contents, is, isHTMLElement, createDiv, each, push } from 'support';
import { createSizeObserver } from 'observers/sizeObserver';
import { createTrinsicObserver } from 'observers/trinsicObserver';
import { createDOMObserver } from 'observers/domObserver';
import { Lifecycle } from 'lifecycles/lifecycleBase';
import { classNameHost, classNamePadding, classNameViewport, classNameContent } from 'classnames';
@@ -42,7 +43,7 @@ const normalizeTarget = (target: OSTarget): OSTargetObject => {
const OverlayScrollbars = (target: OSTarget, options?: any, extensions?: any): void => {
const osTarget: OSTargetObject = normalizeTarget(target);
const lifecycles: Lifecycle<any>[] = [];
const { host } = osTarget;
const { host, content } = osTarget;
push(lifecycles, createStructureLifecycle(osTarget));
@@ -66,6 +67,16 @@ const OverlayScrollbars = (target: OSTarget, options?: any, extensions?: any): v
createSizeObserver(host, onSizeChanged, { _appear: true, _direction: true });
createTrinsicObserver(host, onTrinsicChanged);
createDOMObserver(host, () => {
return null;
});
createDOMObserver(
content,
() => {
return null;
},
{ _observeContent: true }
);
};
export { OverlayScrollbars };
@@ -1,8 +1,9 @@
import { isUndefined } from 'support/utils/types';
import { each, push, runEach } from 'support/utils/array';
let passiveEventsSupport: boolean;
const supportPassiveEvents = (): boolean => {
if (passiveEventsSupport === undefined) {
if (isUndefined(passiveEventsSupport)) {
passiveEventsSupport = false;
try {
/* eslint-disable */
@@ -86,7 +86,7 @@ const validateRecursive = <T extends PlainObject>(
typeString = key;
}
});
const isEnumString = typeString === undefined;
const isEnumString = isUndefined(typeString);
if (isEnumString && isString(optionsValue)) {
// split it into a array which contains all possible values for example: ["yes", "no", "maybe"]
const enumStringSplit = currTemplateType.split(' ');
@@ -3,8 +3,16 @@ import { PlainObject } from 'typings';
const ElementNodeType = Node.ELEMENT_NODE;
const { toString, hasOwnProperty } = Object.prototype;
export function isUndefined(obj: any): obj is undefined {
return obj === undefined;
}
export function isNull(obj: any): obj is null {
return obj === null;
}
export const type: (obj: any) => string = (obj) => {
return obj === undefined || obj === null
return isUndefined(obj) || isNull(obj)
? `${obj}`
: toString
.call(obj)
@@ -28,14 +36,6 @@ export function isFunction(obj: any): obj is (...args: Array<unknown>) => unknow
return typeof obj === 'function';
}
export function isUndefined(obj: any): obj is undefined {
return obj === undefined;
}
export function isNull(obj: any): obj is null {
return obj === null;
}
export function isArray(obj: any): obj is Array<any> {
return Array.isArray(obj);
}
@@ -4,7 +4,7 @@ import should from 'should';
import { generateSelectCallback, iterateSelect } from '@/testing-browser/Select';
import { timeout } from '@/testing-browser/timeout';
import { setTestResult, waitForOrFailTest } from '@/testing-browser/TestResult';
import { appendChildren, createDiv, removeElements, children, isArray, isNumber, liesBetween, hasClass } from 'support';
import { appendChildren, createDiv, removeElements, children, isArray, isNumber, liesBetween, hasClass, addClass, removeClass, on } from 'support';
import { createDOMObserver } from 'observers/domObserver';
@@ -29,11 +29,13 @@ const targetElmsSlot = document.querySelector('#target .host-nest-item');
const targetContentElmsSlot = document.querySelector('#target .content .content-nest');
const targetContentBetweenElmsSlot = document.querySelector('#content-host');
const imgElmsSlot = document.querySelector('#target .content-nest');
const transitionElmsSlot = document.querySelector('#content-host .content');
const addRemoveTargetElms: HTMLButtonElement | null = document.querySelector('#addRemoveTargetElms');
const addRemoveTargetContentElms: HTMLButtonElement | null = document.querySelector('#addRemoveTargetContentElms');
const addRemoveTargetContentBetweenElms: HTMLButtonElement | null = document.querySelector('#addRemoveTargetContentBetweenElms');
const addImgElms: HTMLButtonElement | null = document.querySelector('#addImgElms');
const addRemoveImgElms: HTMLButtonElement | null = document.querySelector('#addRemoveImgElms');
const addRemoveTransitionElms: HTMLButtonElement | null = document.querySelector('#addRemoveTransitionElms');
const setTargetAttr: HTMLSelectElement | null = document.querySelector('#setTargetAttr');
const setFilteredTargetAttr: HTMLSelectElement | null = document.querySelector('#setFilteredTargetAttr');
const setContentAttr: HTMLSelectElement | null = document.querySelector('#setContentAttr');
@@ -47,8 +49,48 @@ const summaryBetween: HTMLElement | null = document.querySelector('#summary-betw
const startBtn: HTMLButtonElement | null = document.querySelector('#start');
const attrs = ['id', 'class', 'style', 'open'];
const contentChangeArr: Array<[string, string | ((elms: Node[]) => string)]> = [['img', 'load']];
const targetElmObservations: DOMObserverResult[] = [];
const targetElmContentElmObservations: DOMObserverResult[] = [];
createDOMObserver(
document.querySelector('#target') as HTMLElement,
(changedTargetAttrs: string[], styleChanged: boolean, contentChanged: boolean) => {
targetElmObservations.push({ changedTargetAttrs, styleChanged, contentChanged });
requestAnimationFrame(() => {
if (targetChangesCountSlot) {
targetChangesCountSlot.textContent = `${targetElmObservations.length}`;
}
});
},
{
_styleChangingAttributes: attrs,
_attributes: attrs.concat(['data-target']),
}
);
const { _updateEventContentChange } = createDOMObserver(
document.querySelector('#target .content') as HTMLElement,
(changedTargetAttrs: string[], styleChanged: boolean, contentChanged: boolean) => {
targetElmContentElmObservations.push({ changedTargetAttrs, styleChanged, contentChanged });
requestAnimationFrame(() => {
if (contentChangesCountSlot) {
contentChangesCountSlot.textContent = `${targetElmContentElmObservations.length}`;
}
});
},
{
_observeContent: true,
_styleChangingAttributes: attrs,
_attributes: attrs,
_eventContentChange: contentChangeArr,
_ignoreContentChange: (mutation) => {
const { target, attributeName } = mutation;
return attributeName ? !hasClass(target as Element, 'host') && liesBetween(target as Element, '.host', '.content') : false;
},
}
);
const getTotalObservations = () => targetElmObservations.length + targetElmContentElmObservations.length;
const getLast = <T>(arr: T[], indexFromLast = 0): T => arr[arr.length - 1 - indexFromLast] || ({} as T);
const changedThrough = (observationLists?: Array<DOMObserverResult[]> | DOMObserverResult[]) => {
@@ -231,8 +273,7 @@ const addRemoveTargetContentElmsFn = async () => {
const addRemoveTargetContentBetweenElmsFn = async () => {
await addRemoveElementsTest(targetContentBetweenElmsSlot, targetElmContentElmObservations);
};
const addImgElmsFn = async () => {
/*
const addRemoveImgElmsFn = async () => {
const add = async () => {
const img = new Image(1, 1);
img.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
@@ -263,21 +304,124 @@ const addImgElmsFn = async () => {
await add();
await add();
await add();
*/
const add = async () => {
const img = new Image(1, 1);
img.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
//const { before, after, compare } = changedThrough(targetElmContentElmObservations);
const imgHolder = createDiv('img');
appendChildren(imgHolder, img);
// test event content change debounce
const addMultiple = async () => {
const { before, after, compare } = changedThrough(targetElmContentElmObservations);
const addMultipleItem = () => {
const img = new Image(1, 1);
img.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
appendChildren(imgElmsSlot, imgHolder);
const imgHolder = createDiv('img');
appendChildren(imgHolder, img);
appendChildren(imgElmsSlot, imgHolder);
};
before();
addMultipleItem();
addMultipleItem();
addMultipleItem();
await waitForOrFailTest(() => {
after();
compare(2);
const mutationObserverObservation = getLast(targetElmContentElmObservations, 1);
should(mutationObserverObservation.contentChanged).equal(true);
should(mutationObserverObservation.styleChanged).equal(false);
should(mutationObserverObservation.changedTargetAttrs.length).equal(0);
const eventObservation = getLast(targetElmContentElmObservations);
should(eventObservation.contentChanged).equal(true);
should(eventObservation.styleChanged).equal(false);
should(eventObservation.changedTargetAttrs.length).equal(0);
});
};
add();
add();
add();
await addMultiple();
removeElements(document.querySelectorAll('.img'));
await timeout(250);
};
const addRemoveTransitionElmsFn = async () => {
const startTransition = async (elm: Element, expectTransitionEndContentChange: boolean) => {
await timeout(50); // time for css to apply class a bit later to trigger transition
const { before: beforeTransition, after: afterTransition, compare: compareTransition } = changedThrough(targetElmContentElmObservations);
beforeTransition();
removeClass(elm, 'resetTransition'); // IE...
addClass(elm, 'active');
await new Promise((resolve) => {
on(
elm,
'transitionend',
async () => {
await waitForOrFailTest(() => {
afterTransition();
compareTransition(expectTransitionEndContentChange ? 2 : 1); // 2 because 1: added class mutation and 2: transition end event
const eventObservation = getLast(targetElmContentElmObservations);
should(eventObservation.contentChanged).equal(true);
should(eventObservation.styleChanged).equal(false);
should(eventObservation.changedTargetAttrs.length).equal(0);
resolve(1);
});
},
{ _once: true }
);
});
removeClass(elm, 'active');
addClass(elm, 'resetTransition'); // IE...
};
const add = async (expectTransitionEndContentChange: boolean) => {
const elm = createDiv(`transition ${expectTransitionEndContentChange ? 'highlight' : ''}`);
const { before, after, compare } = changedThrough(targetElmContentElmObservations);
before();
appendChildren(transitionElmsSlot, elm);
await waitForOrFailTest(() => {
after();
compare(1);
const eventObservation = getLast(targetElmContentElmObservations);
should(eventObservation.contentChanged).equal(true);
should(eventObservation.styleChanged).equal(false);
should(eventObservation.changedTargetAttrs.length).equal(0);
});
await startTransition(elm, expectTransitionEndContentChange && true);
_updateEventContentChange(contentChangeArr);
await startTransition(elm, expectTransitionEndContentChange && false);
removeElements(elm);
await timeout(250);
};
await add(false);
_updateEventContentChange(
contentChangeArr.concat([
[
'.transition',
(elms) => {
elms.forEach((elm) => {
should(hasClass(elm as Element, 'transition')).equal(true);
});
return 'transitionend';
},
],
])
);
await add(true);
};
const iterateTargetAttrChange = async () => {
await iterateAttrChange(setTargetAttr, targetElmObservations, (observation, selected) => {
@@ -320,7 +464,8 @@ const triggerBetweenSummaryChange = async () => {
addRemoveTargetElms?.addEventListener('click', addRemoveTargetElmsFn);
addRemoveTargetContentElms?.addEventListener('click', addRemoveTargetContentElmsFn);
addRemoveTargetContentBetweenElms?.addEventListener('click', addRemoveTargetContentBetweenElmsFn);
addImgElms?.addEventListener('click', addImgElmsFn);
addRemoveImgElms?.addEventListener('click', addRemoveImgElmsFn);
addRemoveTransitionElms?.addEventListener('click', addRemoveTransitionElmsFn);
setTargetAttr?.addEventListener('change', attrChangeListener(targetElm));
setFilteredTargetAttr?.addEventListener('change', attrChangeListener(targetElm));
setContentAttr?.addEventListener('change', attrChangeListener(contentElmAttrChange));
@@ -330,62 +475,26 @@ setFilteredContentBetweenAttr?.addEventListener('change', attrChangeListener(con
setContentHostElmAttr?.addEventListener('change', attrChangeListener(contentHostElmAttrChange));
setFilteredContentHostElmAttr?.addEventListener('change', attrChangeListener(contentHostElmAttrChange));
createDOMObserver(
document.querySelector('#target') as HTMLElement,
(changedTargetAttrs: string[], styleChanged: boolean, contentChanged: boolean) => {
targetElmObservations.push({ changedTargetAttrs, styleChanged, contentChanged });
requestAnimationFrame(() => {
if (targetChangesCountSlot) {
targetChangesCountSlot.textContent = `${targetElmObservations.length}`;
}
});
},
{
_attributes: ['data-target'],
}
);
createDOMObserver(
document.querySelector('#target .content') as HTMLElement,
(changedTargetAttrs: string[], styleChanged: boolean, contentChanged: boolean) => {
targetElmContentElmObservations.push({ changedTargetAttrs, styleChanged, contentChanged });
requestAnimationFrame(() => {
if (contentChangesCountSlot) {
contentChangesCountSlot.textContent = `${targetElmContentElmObservations.length}`;
}
});
},
{
_observeContent: true,
_eventContentChange: () => {
return [
['img', 'load'],
['iframe', 'load'],
];
},
_ignoreContentChange: (mutation) => {
const { target, attributeName } = mutation;
return attributeName ? !hasClass(target as Element, 'host') && liesBetween(target as Element, '.host', '.content') : false;
},
}
);
const start = async () => {
setTestResult(null);
await addImgElmsFn();
await addRemoveTargetElmsFn();
await addRemoveTargetContentElmsFn();
await addRemoveTargetContentBetweenElmsFn();
await iterateTargetAttrChange();
await iterateContentAttrChange();
await addRemoveTransitionElmsFn();
await iterateContentBetweenAttrChange();
await iterateContentHostElmAttrChange();
await triggerContentSummaryChange();
await triggerBetweenSummaryChange();
await addRemoveImgElmsFn();
setTestResult(true);
};
@@ -2,7 +2,8 @@
<button id="addRemoveTargetElms">Target Elements</button>
<button id="addRemoveTargetContentElms">Content Elements</button>
<button id="addRemoveTargetContentBetweenElms">Content Between Elements</button>
<button id="addImgElms">Image Elements</button>
<button id="addRemoveImgElms">Image Elements</button>
<button id="addRemoveTransitionElms">Transition Elements</button>
<label for="setTargetAttr">setTargetAttr</label>
<select name="setTargetAttr" id="setTargetAttr">
@@ -88,3 +88,22 @@ body {
visibility: hidden;
}
}
.transition {
width: 0;
height: 50px;
background: gray;
&.highlight {
background: cyan;
}
&.resetTransition {
transition: none;
}
&.active {
transition: width 2s ease;
width: 100%;
}
}
@@ -1,15 +1,16 @@
declare type StringNullUndefined = string | null | undefined;
export declare type DOMOvserverEventContentChangeResult = Array<[StringNullUndefined, StringNullUndefined] | null | undefined>;
export declare type DOMOvserverEventContentChange = () => DOMOvserverEventContentChangeResult;
export declare type DOMObserverEventContentChange = Array<[StringNullUndefined, ((elms: Node[]) => string) | StringNullUndefined] | null | undefined> | false | null | undefined;
export declare type DOMObserverIgnoreContentChange = (mutation: MutationRecord, domObserverTarget: HTMLElement, domObserverOptions: DOMObserverOptions | undefined) => boolean | null | undefined;
export interface DOMObserverOptions {
_observeContent?: boolean;
_attributes?: string[];
_styleChangingAttributes?: string[];
_eventContentChange?: DOMObserverEventContentChange;
_ignoreContentChange?: DOMObserverIgnoreContentChange;
_eventContentChange?: DOMOvserverEventContentChange;
}
export interface DOMObserver {
_disconnect: () => void;
_updateEventContentChange: (newEventContentChange?: DOMObserverEventContentChange) => void;
_update: () => void;
}
export declare const createDOMObserver: (target: HTMLElement, callback: (targetChangedAttrs: string[], targetStyleChanged: boolean, contentChanged: boolean) => any, options?: DOMObserverOptions | undefined) => DOMObserver;
@@ -0,0 +1 @@
export declare const debounce: (functionToDebounce: (...args: any) => any, timeout?: number | undefined, maxWait?: number | undefined) => () => void;
@@ -1,5 +1,6 @@
export * from 'support/utils/array';
export * from 'support/utils/equal';
export * from 'support/utils/function';
export * from 'support/utils/lexicon';
export * from 'support/utils/object';
export * from 'support/utils/types';
+2 -2
View File
@@ -1,11 +1,11 @@
import { PlainObject } from 'typings';
export declare function isUndefined(obj: any): obj is undefined;
export declare function isNull(obj: any): obj is null;
export declare const type: (obj: any) => string;
export declare function isNumber(obj: any): obj is number;
export declare function isString(obj: any): obj is string;
export declare function isBoolean(obj: any): obj is boolean;
export declare function isFunction(obj: any): obj is (...args: Array<unknown>) => unknown;
export declare function isUndefined(obj: any): obj is undefined;
export declare function isNull(obj: any): obj is null;
export declare function isArray(obj: any): obj is Array<any>;
export declare function isObject(obj: any): boolean;
export declare function isArrayLike<T extends PlainObject = any>(obj: any): obj is ArrayLike<T>;
@@ -6,6 +6,11 @@ export const setTestResult = (result: boolean | null) => {
const elm = getTestResultElm();
if (elm) {
if (typeof result === 'boolean') {
if (result) {
if (elm.getAttribute('class') === 'failed') {
return;
}
}
elm.setAttribute('class', result ? 'passed' : 'failed');
} else {
elm.removeAttribute('class');