@launchmenu/core
Version:
An environment for visual keyboard controlled applets
348 lines • 27 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LMSession = void 0;
const model_react_1 = require("model-react");
const react_1 = __importDefault(require("react"));
const IOContext_1 = require("../../context/IOContext");
const SettingsContext_1 = require("../../settings/SettingsContext");
const TextField_1 = require("../../textFields/TextField");
const createHighlighterWithSearchPattern_1 = require("../../uiLayers/types/menuSearch/createHighlighterWithSearchPattern");
const UndoRedoFacility_1 = require("../../undoRedo/UndoRedoFacility");
const ApplicationLayout_1 = require("../components/ApplicationLayout");
const uuid_1 = require("uuid");
const LMSessionMenu_1 = require("./LMSessionMenu");
const adjustSearchable_1 = require("../../utils/searchExecuter/adjustSearchable");
const withSession_1 = require("../applets/declaration/withSession");
const emitContextEvent_1 = require("../../context/uiExtracters/emitContextEvent");
const createStandardMenuKeyHandler_1 = require("../../menus/menu/interaction/keyHandler/createStandardMenuKeyHandler");
const getCategoryAction_1 = require("../../actions/types/category/getCategoryAction");
const adjustSubscribable_1 = require("../../utils/subscribables/adjustSubscribable");
const SearchExecuter_1 = require("../../utils/searchExecuter/SearchExecuter");
const MainMenuView_1 = require("../components/MainMenuView");
const LMSessionLayer_1 = require("./LMSessionLayer");
const useLMSession_1 = require("../hooks/useLMSession");
const TextFieldView_1 = require("../../components/fields/TextFieldView");
const InstantOpenTransition_1 = require("../../components/context/stacks/transitions/open/InstantOpenTransition");
/**
* An application session
*/
class LMSession {
/**
* Creates a new app session
* @param lm The LM instance this is a session for
*/
constructor(lm) {
/** The unique runtime id of this session */
this.ID = uuid_1.v4();
/** Additional applets for this session */
this.extraApplets = new model_react_1.Field([]);
/** Additional searchable sources for this session */
this.extraSearchables = new model_react_1.Field([]);
/** The applet that's currently selected */
this.selectedApplet = new model_react_1.Field(null);
/* Observers that track changes */
this.observers = {};
/** Listeners that listen for close events */
this.closeListeners = [];
/**
* The applet data obtained from the applet manager
*/
this.appletData = new model_react_1.DataCacher((h, currentAppletData = []) => {
const managerApplets = this.LM.getAppletManager().getAppletsData(h);
// Dispose the sessions related data for any applet that will no longer exist
currentAppletData.map(appletData => {
var _a, _b;
const stillExists = managerApplets.find(({ applet }) => applet == appletData.applet);
if (!stillExists)
(_b = (_a = appletData.initializedApplet).onCloseSession) === null || _b === void 0 ? void 0 : _b.call(_a);
});
// Obtain the new applet data list
const newData = managerApplets.map(({ applet, version }) => {
var _a;
let updated = false;
let searchableID = `${applet.ID}-${version}`;
// Find the current data for this applet
const current = currentAppletData.find(({ applet: { ID } }) => ID == applet.ID);
if (current) {
updated = current.version != version;
if (!updated)
return current;
// If it has updated, change the search id
if (((_a = current.searchable) === null || _a === void 0 ? void 0 : _a.ID) == searchableID)
searchableID = "updated-" + searchableID;
}
// Initialize the new applet
const initializedApplet = withSession_1.withSession(applet, this);
if (updated && this.LM.isInDevMode())
this.callAppletReload(initializedApplet);
// Obtain the searchable and return the data
const searchable = initializedApplet.search &&
this.getAppletSearchWithCategory(initializedApplet, searchableID);
return { initializedApplet, applet, searchable, version };
});
return newData;
});
this.LM = lm;
this.setupContext();
this.setupView();
this.setupUI();
}
/**
* Disposes of all data attached to this session
*/
destroy() {
var _a, _b, _c, _d;
(_a = this.observers.search) === null || _a === void 0 ? void 0 : _a.destroy();
(_b = this.observers.settingsContext) === null || _b === void 0 ? void 0 : _b.destroy();
(_c = this.observers.menuCursor) === null || _c === void 0 ? void 0 : _c.destroy();
(_d = this.context) === null || _d === void 0 ? void 0 : _d.destroy();
}
/**
* Emits a key event to the session
* @param event The event to dispatch
* @returns Whether the event was caught
*/
emit(event) {
return emitContextEvent_1.emitContextEvent(this.context, event);
}
/**
* Initializes the ioContext for this session
*/
setupContext() {
this.context = new IOContext_1.IOContext({
isInDevMode: h => this.LM.isInDevMode(h),
undoRedo: new UndoRedoFacility_1.UndoRedoFacility(),
settings: new SettingsContext_1.SettingsContext(),
contextMenuBindings: this.getGlobalContextMenuBindings(),
session: this,
});
// Retrieve the settings context from LM which includes all base settings data, and listen for changes
this.observers.settingsContext = new model_react_1.Observer(h => {
this.LM.getAppletManager().getApplets(h);
return this.LM.getSettingsManager().getSettingsContext(h);
}).listen(settingsContext => {
this.context.settings = settingsContext;
}, true);
}
/**
* Retrieves the context menu items that should be global in this session
* @returns The menu items
*/
getGlobalContextMenuBindings() {
return hook => this.getApplets(hook).flatMap(applet => {
var _a;
return applet.globalContextMenuBindings instanceof Function
? applet.globalContextMenuBindings(hook)
: (_a = applet.globalContextMenuBindings) !== null && _a !== void 0 ? _a : [];
});
}
/**
* Initializes the view for this session
*/
setupView() {
this.view = (react_1.default.createElement(useLMSession_1.LMSessionProvider, { value: this },
react_1.default.createElement(ApplicationLayout_1.ApplicationLayout, { key: this.ID, context: this.context })));
}
// Sets up the interface
/**
* Initializes all the UI
*/
async setupUI() {
const menu = await this.setupMenu();
const field = await this.setupField();
this.homeLayer = new LMSessionLayer_1.LMSessionLayer([...menu, ...field]);
this.context.open(this.homeLayer);
}
/**
* Initializes the menu to be displayed
*/
async setupMenu() {
this.menu = new LMSessionMenu_1.LMSessionMenu(this.context);
// Update the selected applet based on what category a given item belongs to
const appletManager = this.LM.getAppletManager();
this.observers.menuCursor = new model_react_1.Observer(h => this.menu.getCursor(h)).listen(item => {
if (item) {
const category = getCategoryAction_1.getCategoryAction.getCategory(item);
const appletData = appletManager
.getAppletCategories()
.find(({ category: cat }) => cat == category);
if (appletData)
this.selectedApplet.set(appletData.applet);
}
}, true);
// Setup a search executer
this.searchExecuter = new SearchExecuter_1.SearchExecuter({
searchable: {
ID: "root",
search: async (query, hook) => ({
children: this.getSearchables(hook),
}),
},
onAdd: item => {
// console.log("Added", item);
this.menu.addItem(item);
},
onRemove: item => {
// console.log("Removed", item);
this.menu.removeItem(item);
},
});
// Create the menu key handler
const { handler, destroy } = createStandardMenuKeyHandler_1.createStandardMenuKeyHandler(this.menu, {
onExit: () => {
if (this.searchField.get() == "")
this.emitClose();
else
this.searchField.set("");
},
});
// Return the UI to be shown:
return [
{
menu: this.menu,
menuView: react_1.default.createElement(MainMenuView_1.MainMenuView, { menu: this.menu }),
searchable: false,
menuHandler: handler,
onClose: destroy,
},
];
}
/**
* Initializes the field to be displayed
*/
async setupField() {
// Create a text field and connect it to the search executer
this.searchField = new TextField_1.TextField();
this.observers.search = new model_react_1.Observer(h => this.searchField.get(h)).listen(search => {
var _a;
const query = { search, context: this.context };
this.searchExecuter.setQuery(query);
(_a = this.menu) === null || _a === void 0 ? void 0 : _a.setQuery(query);
});
const highlighter = createHighlighterWithSearchPattern_1.createHighlighterWithSearchPattern(h => this.searchExecuter.getPatterns(h));
// Return the UI to be shown
return [
{
field: this.searchField,
highlighter,
icon: "search",
fieldView: {
view: (react_1.default.createElement(TextFieldView_1.TextFieldView, { highlighter: highlighter, icon: "search", field: this.searchField })),
transitions: { Open: InstantOpenTransition_1.InstantOpenTransition },
},
},
];
}
// Close listeners
/**
* Adds a listener that listens for close events
* @param listener The listener to be added
*/
addCloseListener(listener) {
if (!this.closeListeners.includes(listener))
this.closeListeners.push(listener);
}
/**
* Removes a listener that listens for close events
* @param listener The listener to be removed
*/
removeCloseListener(listener) {
const index = this.closeListeners.indexOf(listener);
if (index != -1)
this.closeListeners.splice(index, 1);
}
/**
* Emits the close event
*/
emitClose() {
this.closeListeners.forEach(listener => listener());
}
/**
* Checks whether this session is on the "home screen", I.e. has no menu opens on top
* @param hook The hook to subscribe to changes
* @returns Whether on the home screen
*/
isHome(hook) {
var _a;
const layers = this.context.getUI(hook);
return (layers[layers.length - 1] == this.homeLayer &&
((_a = this.searchField) === null || _a === void 0 ? void 0 : _a.get(hook)) == "");
}
/**
* Closes all layers and removes the search input
* @param close Whether to also exit LM
*/
async goHome(close) {
this.searchField.set("");
if (close)
this.emitClose();
await this.context.closeAll();
}
// Applet management
/**
* Retrieves the applets initialized with this session data
* @param hook The hook to subscribe to changes
* @returns The initialized applets
*/
getApplets(hook) {
return [
...this.appletData.get(hook).map(({ initializedApplet }) => initializedApplet),
...this.extraApplets.get(hook),
];
}
/**
* Retrieves the searchables in this session
* @param hook The hook to subscribe to changes
* @returns The searchables
*/
getSearchables(hook) {
return [
...this.appletData.get(hook).flatMap(({ searchable }) => searchable !== null && searchable !== void 0 ? searchable : []),
...this.extraSearchables.get(hook),
];
}
/**
* Calls the reload of the given applet and sets up the disposers (Modifies the onCloseSession of the applet)
* @param applet The applet to call reload on
*/
callAppletReload(applet) {
var _a, _b;
const disposer = (_b = (_a = applet === null || applet === void 0 ? void 0 : applet.development) === null || _a === void 0 ? void 0 : _a.onReload) === null || _b === void 0 ? void 0 : _b.call(_a);
if (disposer) {
const oldOnClose = applet.onCloseSession;
applet.onCloseSession = () => {
disposer();
oldOnClose === null || oldOnClose === void 0 ? void 0 : oldOnClose();
};
}
}
/**
* Wraps the search method of an applet to inject the applets category into the results
* @param applet The applet to retrieve the searchable with results for
* @param ID The ID of the searchable
* @returns The menu searchable
*/
getAppletSearchWithCategory(applet, ID = applet.ID) {
const category = this.LM.getAppletManager().getAppletCategory(applet);
if (!category)
return { ...applet, ID };
const categoryBinding = getCategoryAction_1.getCategoryAction.createBinding(category);
return adjustSearchable_1.adjustSearchable({ ...applet, ID }, {
item: result => result
? {
...result,
item: {
...result.item,
actionBindings: adjustSubscribable_1.adjustSubscribable(result.item.actionBindings, bindings => [...bindings, categoryBinding] //search category takes priority
),
},
}
: result,
});
}
}
exports.LMSession = LMSession;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTE1TZXNzaW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwcGxpY2F0aW9uL0xNU2Vzc2lvbi9MTVNlc3Npb24udHN4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDZDQUFtRjtBQUNuRixrREFBMEI7QUFDMUIsdURBQWtEO0FBR2xELG9FQUErRDtBQUUvRCwwREFBcUQ7QUFDckQsMkhBQXNIO0FBQ3RILHNFQUFpRTtBQUNqRSx1RUFBa0U7QUFFbEUsK0JBQWdDO0FBRWhDLG1EQUE4QztBQUM5QyxrRkFBNkU7QUFHN0Usb0VBQStEO0FBRS9ELGtGQUE2RTtBQUM3RSx1SEFBa0g7QUFDbEgsc0ZBQWlGO0FBR2pGLHFGQUFnRjtBQUVoRiw4RUFBeUU7QUFDekUsNkRBQXdEO0FBQ3hELHFEQUFnRDtBQUNoRCx3REFBd0Q7QUFDeEQseUVBQW9FO0FBQ3BFLGtIQUE2RztBQUU3Rzs7R0FFRztBQUNILE1BQWEsU0FBUztJQXVDbEI7OztPQUdHO0lBQ0gsWUFBbUIsRUFBYztRQXBDakMsNENBQTRDO1FBQzVCLE9BQUUsR0FBRyxTQUFJLEVBQUUsQ0FBQztRQVU1QiwwQ0FBMEM7UUFDbkMsaUJBQVksR0FBRyxJQUFJLG1CQUFLLENBQUMsRUFBZSxDQUFDLENBQUM7UUFDakQscURBQXFEO1FBQzlDLHFCQUFnQixHQUFHLElBQUksbUJBQUssQ0FBQyxFQUF1QixDQUFDLENBQUM7UUFLN0QsMkNBQTJDO1FBQ3BDLG1CQUFjLEdBQUcsSUFBSSxtQkFBSyxDQUFDLElBQXNCLENBQUMsQ0FBQztRQUUxRCxrQ0FBa0M7UUFDM0IsY0FBUyxHQUlaLEVBQUUsQ0FBQztRQUVQLDZDQUE2QztRQUNuQyxtQkFBYyxHQUFtQixFQUFFLENBQUM7UUF1UTlDOztXQUVHO1FBQ0ksZUFBVSxHQUFHLElBQUksd0JBQVUsQ0FPaEMsQ0FBQyxDQUFDLEVBQUUsaUJBQWlCLEdBQUcsRUFBRSxFQUFFLEVBQUU7WUFDNUIsTUFBTSxjQUFjLEdB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