cui-light
Version:
cUI light framework for the web
405 lines (404 loc) • 16.5 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to set private field on non-instance");
}
privateMap.set(receiver, value);
return value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver);
};
var _interactions, _emittedEvents, _attribute, _openEventId, _closeEventId, _keyCloseEventId, _openAct, _closeAct, _mutionHandler;
import { CuiLoggerFactory } from "../factories/logger";
import { CuiComponentMutationHandler } from "../observers/mutations";
import { AriaAttributes } from "../utils/aria";
import { CuiActionsHelper } from "../helpers/helpers";
import { CuiActionsListFactory } from "../utils/actions";
import { is, getActiveClass, clone } from "../utils/functions";
import { EVENTS } from "../utils/statics";
export class ComponentHelper {
constructor(interactions) {
_interactions.set(this, void 0);
__classPrivateFieldSet(this, _interactions, interactions);
}
hasClass(cls, element) {
return cls && element.classList.contains(cls) ? true : false;
}
setClass(cls, element) {
this.setClasses([cls], element);
}
setClasses(classes, element) {
if (element) {
element.classList.add(...classes);
}
}
setClassesAs(element, ...classes) {
__classPrivateFieldGet(this, _interactions).mutate(this.setClasses, this, classes, element);
}
removeClass(cls, element) {
this.removeClasses([cls], element);
}
removeClasses(classes, element) {
if (element) {
element.classList.remove(...classes);
}
}
removeClassesAs(element, ...classes) {
__classPrivateFieldGet(this, _interactions).mutate(this.removeClasses, this, classes, element);
}
removeAttribute(attributeName, element) {
if (element && element.hasAttribute(attributeName))
element.removeAttribute(attributeName);
}
setStyle(element, property, value) {
if (element && element["style"] && is(value)) {
element.style[property] = value;
}
}
}
_interactions = new WeakMap();
export class CuiComponentBase {
constructor(componentName, element, utils) {
_emittedEvents.set(this, void 0);
this._log = CuiLoggerFactory.get(componentName);
this.utils = utils;
this.element = element;
this.cuid = element.$cuid;
this.isLocked = false;
this._log.setId(this.cuid);
this.activeClassName = getActiveClass(utils.setup.prefix);
this.helper = new ComponentHelper(utils.interactions);
__classPrivateFieldSet(this, _emittedEvents, []);
this.componentName = componentName;
}
mutate(callback, ...args) {
this.utils.interactions.mutate(callback, this, ...args);
}
fetch(callback, ...args) {
this.utils.interactions.fetch(callback, this, ...args);
}
getEventName(name) {
return [name, this.cuid].join('-');
}
/**
* Emits event using passed data and cuid of the element
* NOTE: Don't use it to emit global events
* @param event Event name
* @param data Data to emit
*/
emitEvent(event, ...data) {
if (!__classPrivateFieldGet(this, _emittedEvents).includes(event))
__classPrivateFieldGet(this, _emittedEvents).push(event);
this.utils.bus.emit(event, this.cuid, ...data);
}
onEvent(event, callback) {
return this.utils.bus.on(event, callback, this.element);
}
detachEvent(event, id) {
if (id != null) {
this.utils.bus.detach(event, id);
id = "";
}
}
getId() {
return this.cuid;
}
checkLockAndWarn(fName) {
if (this.isLocked) {
this._log.warning("Component is locked", fName);
return true;
}
return false;
}
/**
* Helper which checks whether element has an active flag set
*/
isActive() {
return this.element.classList.contains(this.activeClassName);
}
detachEmiitedEvents() {
__classPrivateFieldGet(this, _emittedEvents).forEach(event => {
this.utils.bus.detachByCuid(event, this.cuid);
this._log.debug("Detaching event: " + event + " on component delete");
});
}
registerInDebug() {
this.utils.development.registerElement(this.element, this.cuid, this.componentName);
}
removeFromDebug() {
this.utils.development.unregisterElement(this.cuid, this.componentName);
}
setDebugProperty(name, value) {
this.utils.development.setProperty(this.cuid, this.componentName, name, value);
}
logInfo(message, functionName) {
this._log.debug(message, functionName);
this.utils.development.pushState(this.cuid, this.componentName, "info", message, functionName);
}
logWarning(message, functionName) {
this._log.warning(message, functionName);
this.utils.development.pushState(this.cuid, this.componentName, "warning", message, functionName);
}
pushDebugState(type, message, functionName) {
this.utils.development.pushState(this.cuid, this.componentName, type, message, functionName);
}
logError(message, functionName, error) {
this._log.error(message, functionName);
if (error) {
this._log.exception(error, functionName);
}
this.utils.development.pushState(this.cuid, this.componentName, "error", message, functionName);
}
}
_emittedEvents = new WeakMap();
export class CuiHandlerBase extends CuiComponentBase {
constructor(componentName, element, attribute, args, utils) {
super(componentName, element, utils);
_attribute.set(this, void 0);
this.args = args;
this.actionsHelper = new CuiActionsHelper(utils.interactions);
this.prevArgs = undefined;
this.isInitialized = false;
__classPrivateFieldSet(this, _attribute, attribute);
}
handle(args) {
this.logInfo("Init", 'handle');
if (this.isInitialized) {
this.logWarning("Trying to initialize component again", 'handle');
return;
}
this.args.parse(args);
if (!this.element.classList.contains(__classPrivateFieldGet(this, _attribute))) {
this.element.classList.add(__classPrivateFieldGet(this, _attribute));
}
this.registerInDebug();
this.onHandle();
this.isInitialized = true;
}
refresh(args) {
this.logInfo("Update", 'refresh');
if (!this.isInitialized) {
this.logError("Cannot update not initialized component", 'refresh');
return;
}
this.prevArgs = clone(this.args);
this.args.parse(args);
this.pushDebugState("info", "Component update", 'refresh');
this.onRefresh();
}
destroy() {
this.logInfo("Destroy", "destroy");
this.onRemove();
this.detachEmiitedEvents();
this.removeFromDebug();
this.isInitialized = false;
}
}
_attribute = new WeakMap();
export class CuiHandler extends CuiHandlerBase {
constructor(componentName, element, attribute, args, utils) {
super(componentName, element, attribute, args, utils);
}
onHandle() {
this.onInit();
}
onRefresh() {
this.onUpdate();
}
onRemove() {
this.onDestroy();
}
/**
* Helper created for elements that animate - perfroms an action *add*, after timeout it performs *remove*.
*
* @param action - action to perfrom
* @param timeout - timeout specified for action removal
* @param onFinish - callback to be performed after action is finished after removal
* @param callback - optional - callback to be executed in mutation on action removal, e.g. additional DOM changes on element
*/
performAction(actions, timeout, onFinish, callback) {
return __awaiter(this, void 0, void 0, function* () {
if (yield this.actionsHelper.performActions(this.element, actions, timeout, callback)) {
onFinish();
return true;
}
return false;
});
}
}
export class CuiInteractableHandler extends CuiHandlerBase {
constructor(componentName, element, attribute, args, utils) {
super(componentName, element, attribute, args, utils);
_openEventId.set(this, void 0);
_closeEventId.set(this, void 0);
_keyCloseEventId.set(this, void 0);
_openAct.set(this, void 0);
_closeAct.set(this, void 0);
__classPrivateFieldSet(this, _openEventId, null);
__classPrivateFieldSet(this, _closeEventId, null);
__classPrivateFieldSet(this, _keyCloseEventId, null);
__classPrivateFieldSet(this, _closeAct, []);
__classPrivateFieldSet(this, _openAct, []);
}
onHandle() {
__classPrivateFieldSet(this, _openEventId, this.onEvent(EVENTS.OPEN, this.openFromEvent.bind(this)));
__classPrivateFieldSet(this, _closeEventId, this.onEvent(EVENTS.CLOSE, this.closeFromEvent.bind(this)));
__classPrivateFieldSet(this, _openAct, CuiActionsListFactory.get(this.args.openAct));
__classPrivateFieldSet(this, _closeAct, CuiActionsListFactory.get(this.args.closeAct));
this.onInit();
}
onRefresh() {
if (!this.prevArgs || this.args.openAct !== this.prevArgs.openAct) {
__classPrivateFieldSet(this, _openAct, CuiActionsListFactory.get(this.args.openAct));
}
if (!this.prevArgs || this.args.closeAct !== this.prevArgs.closeAct) {
__classPrivateFieldSet(this, _closeAct, CuiActionsListFactory.get(this.args.closeAct));
}
this.onUpdate();
}
onRemove() {
this.detachEvent(EVENTS.CLOSE, __classPrivateFieldGet(this, _closeEventId));
this.detachEvent(EVENTS.OPEN, __classPrivateFieldGet(this, _openEventId));
this.onDestroy();
}
open(args) {
return __awaiter(this, void 0, void 0, function* () {
if (this.checkLockAndWarn("open")) {
return false;
}
if (this.isActive()) {
this.logWarning("Component is already opened");
return false;
}
if (this.args.escClose || is(this.args.keyClose)) {
__classPrivateFieldSet(this, _keyCloseEventId, this.onEvent(EVENTS.KEYDOWN, this.onKeyClose.bind(this)));
}
if (!this.onBeforeOpen()) {
return false;
}
this.isLocked = true;
return this.performAction(__classPrivateFieldGet(this, _openAct), this.args.timeout, this.onActionFinish.bind(this, this.onAfterOpen.bind(this), EVENTS.OPENED, args), () => {
this.helper.setClass(this.activeClassName, this.element);
AriaAttributes.setAria(this.element, 'aria-expanded', 'true');
});
;
});
}
close(args) {
return __awaiter(this, void 0, void 0, function* () {
if (this.checkLockAndWarn("close")) {
return false;
}
if (!this.isActive()) {
this.logWarning("Component is already closed");
return false;
}
this.detachEvent(EVENTS.KEYDOWN, __classPrivateFieldGet(this, _keyCloseEventId));
if (!this.onBeforeClose()) {
return false;
}
this.isLocked = true;
return this.performAction(__classPrivateFieldGet(this, _closeAct), this.args.timeout, this.onActionFinish.bind(this, this.onAfterClose.bind(this), EVENTS.CLOSED, args), () => {
this.helper.removeClass(this.activeClassName, this.element);
AriaAttributes.setAria(this.element, 'aria-expanded', 'false');
});
;
});
}
/**
* Helper created for elements that animate - perfroms an action *add*, after timeout it performs *remove*.
*
* @param action - action to perfrom
* @param timeout - timeout specified for action removal
* @param onFinish - callback to be performed after action is finished after removal
* @param callback - optional - callback to be executed in mutation on action removal, e.g. additional DOM changes on element
*/
performAction(actions, timeout, onFinish, callback) {
return __awaiter(this, void 0, void 0, function* () {
if (yield this.actionsHelper.performActions(this.element, actions, timeout, callback)) {
onFinish();
return true;
}
return false;
});
}
openFromEvent(args) {
this.open(args);
}
closeFromEvent(args) {
this.close(args);
}
onActionFinish(callback, event, args) {
callback();
this.emitEvent(event, {
timestamp: Date.now(),
state: args
});
this.isLocked = false;
}
onKeyClose(ev) {
return __awaiter(this, void 0, void 0, function* () {
if (this.args.escClose && ev.event.key === "Escape" || is(this.args.keyClose) && ev.event.key === this.args.keyClose) {
yield this.close('Closed by key');
}
});
}
}
_openEventId = new WeakMap(), _closeEventId = new WeakMap(), _keyCloseEventId = new WeakMap(), _openAct = new WeakMap(), _closeAct = new WeakMap();
export class CuiMutableHandler extends CuiHandlerBase {
constructor(componentName, element, attribute, args, utils) {
super(componentName, element, attribute, args, utils);
_mutionHandler.set(this, void 0);
__classPrivateFieldSet(this, _mutionHandler, new CuiComponentMutationHandler(element));
__classPrivateFieldGet(this, _mutionHandler).onMutation(this.mutation.bind(this));
}
onHandle() {
this.onInit();
__classPrivateFieldGet(this, _mutionHandler).observe();
}
onRefresh() {
__classPrivateFieldGet(this, _mutionHandler).unobserve();
this.onUpdate();
__classPrivateFieldGet(this, _mutionHandler).observe();
}
onRemove() {
__classPrivateFieldGet(this, _mutionHandler).unobserve();
this.onDestroy();
}
/**
* Callback attached to mutation observer set on root element
*
* @param record - mutation records
*/
mutation(records) {
this._log.debug("Element mutation", "mutation");
this.onMutation(records.reduce((result, item) => {
if (item.type !== "childList") {
return result;
}
if (item.addedNodes.length > 0) {
result.added.push(...item.addedNodes);
}
if (item.removedNodes.length > 0) {
result.removed.push(...item.removedNodes);
}
return result;
}, {
added: [],
removed: []
}));
}
}
_mutionHandler = new WeakMap();