lisn.js
Version:
Simply handle user gestures and actions. Includes widgets.
170 lines (162 loc) • 5.63 kB
JavaScript
/**
* @module Widgets
*/
import * as MC from "../globals/minification-constants.js";
import * as MH from "../globals/minification-helpers.js";
import { hideElement } from "../utils/css-alter.js";
import { hideAndRemoveElement } from "../utils/dom-alter.js";
import { waitForPageReady } from "../utils/dom-events.js";
import { validateString, validateNumber } from "../utils/validation.js";
import { DOMWatcher } from "../watchers/dom-watcher.js";
import { Widget, registerWidget } from "./widget.js";
/**
* Configures the given element as an {@link AutoHide} widget.
*
* The AutoHide widget automatically hides (and optionally removes) the given
* element, or children of it that match a given selector, after a certain
* delay.
*
* It executes these actions every time the matching element(s) have a change
* of attribute or appear (are inserted) into the DOM.
*
* To use with auto-widgets (HTML API) (see
* {@link Settings.settings.autoWidgets | settings.autoWidgets}), the following
* CSS classes or data attributes are recognized:
* - `lisn-auto-hide` class or `data-lisn-auto-hide` attribute
* - `lisn-auto-remove` class or `data-lisn-auto-remove` attribute (enables
* {@link AutoHideConfig.remove})
*
* **NOTE:** This widget supports multiple instances per element, you can
* specify multiple widget configurations, separated with ";".
*
* See below examples for what values you can use set for the data attributes
* in order to modify the configuration of the automatically created widget.
*
* @example
* This will automatically hide (with class `lisn-hide`) the element 3 seconds
* (default delay) after it is inserted into the DOM or after it gets any
* attributes changed on it (for example that might show it again).
*
* ```html
* <div class="lisn-auto-hide">
* Automatically hidden in 3s.
* </div>
* ```
*
* @example
* This will automatically hide and then remove the element 3 seconds (default
* delay) after it is inserted into the DOM.
*
* ```html
* <div class="lisn-auto-remove">
* Automatically hidden and removed in 3s.
* </div>
* ```
*
* @example
* This will automatically
* - hide `p` elements with class `message` 2 seconds after they are inserted
* or changed
* - hide `p` elements with class `warning` 5 seconds after they are inserted
* or changed; and it will save that particular {@link AutoHide} widget with
* ID `myID` so that it can be looked up using {@link AutoHide.get}
* - remove `p` elements with class `disposable` 3 seconds (default delay)
* after they are inserted or changed
*
* ```html
* <div data-lisn-auto-hide="selector=p.message delay=2000 ;
* selector=p.warning delay=5000 id=myID"
* data-lisn-auto-remove="selector=p.disposable">
* <p>Some text, this will stay.</p>
* <p class="message">
* Automatically hidden in 2s.
* </p>
* <p class="warning">
* Automatically hidden in 5s.
* </p>
* <p class="disposable">
* Automatically hidden and removed in 3s.
* </p>
* </div>
* ```
*/
export class AutoHide extends Widget {
static get(element, id) {
const instance = super.get(element, id);
if (MH.isInstanceOf(instance, AutoHide)) {
return instance;
}
return null;
}
static register() {
for (const [name, remove] of [[WIDGET_NAME_HIDE, false], [WIDGET_NAME_REMOVE, true]]) {
registerWidget(name, (element, config) => {
return new AutoHide(element, config);
}, newConfigValidator(remove), {
supportsMultiple: true
});
}
}
constructor(element, config) {
super(element, config);
const selector = config === null || config === void 0 ? void 0 : config.selector;
const watcher = DOMWatcher.create({
root: element,
subtree: selector ? true : false
});
// Watch for attribute change on this element, and for relevant children
// being added/changed
const watcherOptions = selector ? {
selector: selector,
categories: [MC.S_ADDED, MC.S_ATTRIBUTE],
[MC.S_SKIP_INITIAL]: true
} : {
categories: [MC.S_ATTRIBUTE],
[MC.S_SKIP_INITIAL]: true
};
const hideOrRemoveEl = config !== null && config !== void 0 && config.remove ? hideAndRemoveElement : hideElement;
const hideRelevant = () => {
if (this.isDisabled()) {
return;
}
const targetElements = selector ? MH.querySelectorAll(element, selector) : [element];
for (const elem of targetElements) {
var _config$delay;
hideOrRemoveEl(elem, (_config$delay = config === null || config === void 0 ? void 0 : config.delay) !== null && _config$delay !== void 0 ? _config$delay : DEFAULT_DELAY);
}
};
const addWatcher = () => watcher.onMutation(hideRelevant, watcherOptions);
const removeWatcher = () => watcher.offMutation(hideRelevant);
// ------------------------------
// Don't hide/remove before the page is loaded
waitForPageReady().then(() => {
// Hide initially
if (this.isDestroyed()) {
return;
}
hideRelevant();
addWatcher();
});
this.onDisable(removeWatcher);
this.onEnable(() => {
hideRelevant();
addWatcher();
});
}
}
/**
* @interface
*/
// ------------------------------
const WIDGET_NAME_HIDE = "auto-hide";
const WIDGET_NAME_REMOVE = "auto-remove";
const DEFAULT_DELAY = 3000;
const newConfigValidator = autoRemove => {
return {
id: validateString,
remove: () => autoRemove,
selector: validateString,
delay: validateNumber
};
};
//# sourceMappingURL=auto-hide.js.map