@launchmenu/core
Version:
An environment for visual keyboard controlled applets
196 lines • 14.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractUILayer = void 0;
const model_react_1 = require("model-react");
const UILayerMissingView_1 = require("./UILayerMissingView");
const uuid_1 = require("uuid");
const getContentAction_1 = require("../actions/types/content/getContentAction");
const catchAllKeyHandler_1 = require("../keyHandler/utils/catchAllKeyHandler");
/**
* An abstract class that can be used as a foundation for a UILayer
*/
class AbstractUILayer {
/**
* Creates a new abstract UI layer
* @param config The layer config
*/
constructor(config) {
// An overlay element to show in case this layer has no data for a given section
this.UIMissingData = {
ID: uuid_1.v4(),
contentView: UILayerMissingView_1.UIMissingView,
menuView: UILayerMissingView_1.UIMissingView,
fieldView: UILayerMissingView_1.UIMissingView,
overlayGroup: UILayerMissingView_1.standardOverlayGroup,
};
// Initialization management
this.closers = [];
this.context = new model_react_1.Field(null);
/**
* A cached getter for the absolute path
*/
this.absolutePath = new model_react_1.DataCacher(h => {
var _a;
const context = this.context.get(h);
if (!context)
return [];
const UI = context.getUI(h);
const index = UI.indexOf(this);
const parent = index >= 0 ? UI[index - 1] : undefined;
const current = (_a = parent === null || parent === void 0 ? void 0 : parent.getPath(h)) !== null && _a !== void 0 ? _a : [];
return this.layerConfig.path.split("/").reduce((cur, node) => {
if (node == ".") {
// Add itself to the top path
const top = cur[cur.length - 1];
if (top)
return [
...cur.slice(0, cur.length - 1),
{ name: top.name, layers: [...top.layers, this] },
];
else
return cur;
}
else if (node == "..") {
// Remove the top element form the path
return cur.slice(0, cur.length - 1);
}
else {
// Add an element to the path
return [...cur, { name: node, layers: [this] }];
}
}, current);
});
/**
* Contents that are visible from the currently selected menu items
*/
this.menuItemContents = new model_react_1.DataCacher(h => this.getContentMenus(h).flatMap(menu => {
const cursor = menu.getCursor(h);
if (!cursor)
return [];
const cursorContents = getContentAction_1.getContentAction.get([cursor], h);
const context = this.context.get(h);
if (!context)
return cursorContents.filter((item) => !(item instanceof Function));
else
return cursorContents.map(item => item instanceof Function ? item(context) : item);
}));
this.layerConfig = {
path: ".",
showNodataOverlay: true,
catchAllKeys: true,
...config,
};
}
/**
* A callback for when the UI layer is opened
* @param context The context that this layer was opened in
* @param close A method to close this layer from the given context
* @returns A callback for when this layer is closed (both when invoked by our close call, or closed external)
*/
async onOpen(context, close) {
this.closers.push(close);
const onClose = (await this.initialize(context, close)) || undefined;
this.context.set(context);
return async () => {
this.context.set(null);
const index = this.closers.indexOf(close);
if (index >= 0)
this.closers.splice(index, 1);
await (onClose === null || onClose === void 0 ? void 0 : onClose());
};
}
/**
* Closes this UILayer from all contexts it's opened in
*/
closeAll() {
this.closers.forEach(closer => closer());
}
// Path management
/**
* Retrieves the path to show to the user representing this layer
* @param hook The data hook to subscribe to changes
* @returns The path
*/
getPath(hook) {
return this.absolutePath.get(hook);
}
// Data management
// TODO: add a system to not call the hook if nothing changed for a given stack (menu/field/content)
/**
* Retrieves the menu data
* @param hook The data hook to subscribe to changes
* @param extendData The data to add to
* @returns The menu data of this layer
*/
getMenuData(hook, extendData = []) {
return this.layerConfig.showNodataOverlay
? [this.UIMissingData, ...extendData]
: extendData;
}
/**
* Retrieves the field data
* @param hook The data hook to subscribe to changes
* @param extendData The data to add to
* @returns The field data of this layer
*/
getFieldData(hook, extendData = []) {
return this.layerConfig.showNodataOverlay
? [this.UIMissingData, ...extendData]
: extendData;
}
/**
* Retrieves the menus to obtain the menu item content for
* @param hook The hook to subscribe to changes
* @returns The menus to get the content for
*/
getContentMenus(hook) {
return this.getMenuData(hook)
.filter(({ menu, hideItemContent }) => menu && !hideItemContent)
.map(({ menu }) => menu);
}
/**
* Retrieves the content data
* @param hook The data hook to subscribe to changes
* @param extendData The data to add to
* @returns The content data of this layer
*/
getContentData(hook, extendData = []) {
const itemContents = [...extendData];
this.menuItemContents.get(hook).forEach(item => {
// If data of other layers has been added directly, their menu item content may already be present (E.g. when using a MenuSearch layer in another layer)
if (!itemContents.find(({ ID }) => ID == item.ID))
itemContents.push(item);
});
return this.layerConfig.showNodataOverlay
? [this.UIMissingData, ...itemContents]
: itemContents;
}
/**
* Retrieves the key listener data
* @param hook The data hook to subscribe to changes
* @returns The key listener data of this layer
*/
getKeyHandlers(hook) {
return [
...(this.layerConfig.catchAllKeys ? [catchAllKeyHandler_1.catchAllKeyHandler] : []),
...this.getMenuData(hook).map(({ menuHandler }) => menuHandler),
...this.getFieldData(hook).map(({ fieldHandler }) => fieldHandler),
...this.getContentData(hook).map(({ contentHandler }) => contentHandler),
].filter((m) => !!m);
}
// Helpers
/**
* Checks whether this layer is on the top of the stack
* @param hook The hook to subscribe to changes
* @returns Whether this layer is on top
*/
isOnTop(hook) {
const context = this.context.get(hook);
if (!context)
return false;
const layers = context.getUI(hook);
return layers[layers.length - 1] == this;
}
}
exports.AbstractUILayer = AbstractUILayer;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RVSUxheWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3VpTGF5ZXJzL0Fic3RyYWN0VUlMYXllci50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQXlEO0FBUXpELDZEQUF5RTtBQUN6RSwrQkFBZ0M7QUFDaEMsZ0ZBQTJFO0FBRTNFLCtFQUEwRTtBQUcxRTs7R0FFRztBQUNILE1BQXNCLGVBQWU7SUFnQmpDOzs7T0FHRztJQUNILFlBQW1CLE1BQTJCO1FBakI5QyxnRkFBZ0Y7UUFDdEUsa0JBQWEsR0FBRztZQUN0QixFQUFFLEVBQUUsU0FBSSxFQUFFO1lBQ1YsV0FBVyxFQUFFLGtDQUFhO1lBQzFCLFFBQVEsRUFBRSxrQ0FBYTtZQUN2QixTQUFTLEVBQUUsa0NBQWE7WUFDeEIsWUFBWSxFQUFFLHlDQUFvQjtTQUNyQyxDQUFDO1FBRUYsNEJBQTRCO1FBQ2xCLFlBQU8sR0FBbUIsRUFBRSxDQUFDO1FBQzdCLFlBQU8sR0FBRyxJQUFJLG1CQUFLLENBQUMsSUFBeUIsQ0FBQyxDQUFDO1FBNER6RDs7V0FFRztRQUNPLGlCQUFZLEdBQUcsSUFBSSx3QkFBVSxDQUFxQixDQUFDLENBQUMsRUFBRTs7WUFDNUQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDcEMsSUFBSSxDQUFDLE9BQU87Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFFeEIsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM1QixNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQy9CLE1BQU0sTUFBTSxHQUFHLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztZQUN0RCxNQUFN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