@vived/app 2.24.0 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ import { KeyboardController, KeyboardInput, ToolRepository } from "../Entities";
2
+ export declare class ToolHotkeys<ToolTypes> implements KeyboardController {
3
+ private toolRepo;
4
+ onKeyDown: (e: KeyboardEvent) => void;
5
+ constructor(toolRepo: ToolRepository<ToolTypes>, keyboardInput: KeyboardInput);
6
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolHotkeys = void 0;
4
+ class ToolHotkeys {
5
+ constructor(toolRepo, keyboardInput) {
6
+ this.toolRepo = toolRepo;
7
+ this.onKeyDown = (e) => {
8
+ if (e.repeat)
9
+ return;
10
+ const currentKey = {
11
+ keyCode: e.code,
12
+ alt: e.altKey,
13
+ control: e.ctrlKey,
14
+ meta: e.metaKey,
15
+ shift: e.shiftKey,
16
+ };
17
+ const tool = this.toolRepo.getToolForHotkey(currentKey);
18
+ if (!tool)
19
+ return;
20
+ this.toolRepo.triggerTool(tool.type);
21
+ };
22
+ keyboardInput.registerController(this);
23
+ }
24
+ }
25
+ exports.ToolHotkeys = ToolHotkeys;
@@ -0,0 +1 @@
1
+ export * from "./ToolHotkeys";
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./ToolHotkeys"), exports);
@@ -1,41 +1,52 @@
1
1
  import { ObservableEntity } from "./ObservableEntity";
2
2
  export declare enum ToolState {
3
- HIDDEN = 0,
4
- DISABLED = 1,
5
- ENABLED = 2,
6
- ACTIVE = 3
3
+ HIDDEN = "HIDDEN",
4
+ DISABLED = "DISABLED",
5
+ ENABLED = "ENABLED",
6
+ ACTIVE = "ACTIVE"
7
7
  }
8
- export interface ToolData {
9
- id: string;
8
+ export interface ToolData<ToolTypes> {
9
+ type: ToolTypes;
10
10
  isDefault: boolean;
11
11
  label: string;
12
12
  shortcutLabel: string;
13
+ hotkeys: HotKey[];
14
+ }
15
+ export interface HotKey {
13
16
  keyCode: string;
17
+ control?: boolean;
18
+ shift?: boolean;
19
+ meta?: boolean;
20
+ alt?: boolean;
14
21
  }
15
- export declare abstract class Tool extends ObservableEntity {
22
+ export declare abstract class Tool<ToolTypes> extends ObservableEntity {
16
23
  /**
17
- * The tool's unique identifier
24
+ * The tool's type
18
25
  */
19
- abstract readonly id: string;
26
+ abstract readonly type: ToolTypes;
20
27
  /**
21
- * The shortcut key code for this tool.
22
- * Example: 'KeyZ'
28
+ * Gets label for this tool. This will be human readable
23
29
  */
24
- abstract readonly keyCode: string;
30
+ abstract get label(): string;
25
31
  /**
26
- * The label for this tool. This should be human readable
32
+ * Sets label for this tool. This should be human readable. A change will notify
27
33
  */
28
- abstract readonly label: string;
34
+ abstract set label(toolLabel: string);
29
35
  /**
30
36
  * Is this the default tool? The default tool is what is initiall set Active and
31
37
  * is what will be set active if the currently active tool is hidden or disabled.
32
38
  */
33
39
  abstract readonly isDefault: boolean;
34
40
  /**
35
- * The keyboard shorcut label. This will be displayed to the user via the tool tip
41
+ * Gets the keyboard shorcut label. This will be displayed to the user via the tool tip
36
42
  * Example 'z'
37
43
  */
38
- abstract readonly shortcutLabel: string;
44
+ abstract get shortcutLabel(): string;
45
+ /**
46
+ * Sets the keyboard shorcut label. This will be displayed to the user via the tool tip
47
+ * Example 'z'. This will notify when changed
48
+ */
49
+ abstract set shortcutLabel(shorcut: string);
39
50
  /**
40
51
  * Get the current tool state
41
52
  */
@@ -44,5 +55,27 @@ export declare abstract class Tool extends ObservableEntity {
44
55
  * Sets the current tool state. This will notify on change
45
56
  */
46
57
  abstract set state(val: ToolState);
58
+ /**
59
+ * The keyboard shortcuts for this tool
60
+ */
61
+ abstract readonly hotkeys: HotKey[];
62
+ /**
63
+ * Is this tool an action tool. In other words do you just click it and something should happen
64
+ */
65
+ abstract get isAction(): boolean;
66
+ /**
67
+ * If this is an action tool calling this will trigger any actions that have been registered
68
+ */
69
+ abstract triggerActions(): void;
70
+ /**
71
+ * Registers an action with this tool. This action will be called when this tool is triggered
72
+ * @param action The action to call when this tool is triggered
73
+ */
74
+ abstract registerAction(action: () => void): void;
75
+ /**
76
+ * Returns a true if the passed hotkey is in my hotkey list
77
+ * @param hotkey The Hotkey to chekc
78
+ */
79
+ abstract isMyHotkey(hotkey: HotKey): boolean;
47
80
  }
48
- export declare function makeTool(data: ToolData): Tool;
81
+ export declare function makeTool<ToolTypes>(data: ToolData<ToolTypes>): Tool<ToolTypes>;
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeTool = exports.Tool = exports.ToolState = void 0;
4
- const MemoizedNumber_1 = require("./MemoizedNumber");
4
+ const MemoizedString_1 = require("./MemoizedString");
5
5
  const ObservableEntity_1 = require("./ObservableEntity");
6
6
  var ToolState;
7
7
  (function (ToolState) {
8
- ToolState[ToolState["HIDDEN"] = 0] = "HIDDEN";
9
- ToolState[ToolState["DISABLED"] = 1] = "DISABLED";
10
- ToolState[ToolState["ENABLED"] = 2] = "ENABLED";
11
- ToolState[ToolState["ACTIVE"] = 3] = "ACTIVE";
8
+ ToolState["HIDDEN"] = "HIDDEN";
9
+ ToolState["DISABLED"] = "DISABLED";
10
+ ToolState["ENABLED"] = "ENABLED";
11
+ ToolState["ACTIVE"] = "ACTIVE";
12
12
  })(ToolState = exports.ToolState || (exports.ToolState = {}));
13
13
  class Tool extends ObservableEntity_1.ObservableEntity {
14
14
  }
@@ -20,12 +20,44 @@ exports.makeTool = makeTool;
20
20
  class ToolImp extends Tool {
21
21
  constructor(data) {
22
22
  super();
23
- this.memoizedState = new MemoizedNumber_1.MemoizedNumber(ToolState.ENABLED, this.notify);
24
- this.id = data.id;
25
- this.keyCode = data.keyCode;
26
- this.label = data.label;
23
+ this.memoizedState = new MemoizedString_1.MemoizedString(ToolState.ENABLED, this.notify);
24
+ this.actions = [];
25
+ this._isAction = false;
26
+ this.registerAction = (action) => {
27
+ this.actions.push(action);
28
+ this._isAction = true;
29
+ };
30
+ this.triggerActions = () => {
31
+ this.actions.forEach((action) => {
32
+ action();
33
+ });
34
+ };
35
+ this.isMyHotkey = (hotkey) => {
36
+ let isMine = false;
37
+ this.hotkeys.forEach((myHotkey) => {
38
+ if (this.hotkeysMatch(myHotkey, hotkey)) {
39
+ isMine = true;
40
+ }
41
+ });
42
+ return isMine;
43
+ };
44
+ this.type = data.type;
45
+ this.memoizedLabel = new MemoizedString_1.MemoizedString(data.label, this.notify);
27
46
  this.isDefault = data.isDefault;
28
- this.shortcutLabel = data.shortcutLabel;
47
+ this.memoizedShortcut = new MemoizedString_1.MemoizedString(data.shortcutLabel, this.notify);
48
+ this.hotkeys = data.hotkeys;
49
+ }
50
+ get label() {
51
+ return this.memoizedLabel.val;
52
+ }
53
+ set label(toolLabel) {
54
+ this.memoizedLabel.val = toolLabel;
55
+ }
56
+ get shortcutLabel() {
57
+ return this.memoizedShortcut.val;
58
+ }
59
+ set shortcutLabel(shorcut) {
60
+ this.memoizedShortcut.val = shorcut;
29
61
  }
30
62
  get state() {
31
63
  return this.memoizedState.val;
@@ -33,4 +65,30 @@ class ToolImp extends Tool {
33
65
  set state(val) {
34
66
  this.memoizedState.val = val;
35
67
  }
68
+ get isAction() {
69
+ return this._isAction;
70
+ }
71
+ hotkeysMatch(a, b) {
72
+ if (a.keyCode !== b.keyCode)
73
+ return false;
74
+ const aComplete = this.fillInMissingModifiers(a);
75
+ const bComplete = this.fillInMissingModifiers(b);
76
+ if (aComplete.alt !== bComplete.alt)
77
+ return false;
78
+ if (aComplete.control !== bComplete.control)
79
+ return false;
80
+ if (aComplete.meta !== bComplete.meta)
81
+ return false;
82
+ if (aComplete.shift !== bComplete.shift)
83
+ return false;
84
+ return true;
85
+ }
86
+ fillInMissingModifiers(hotkey) {
87
+ const rVal = Object.assign({}, hotkey);
88
+ rVal.alt = hotkey.alt === undefined ? false : hotkey.alt;
89
+ rVal.control = hotkey.control === undefined ? false : hotkey.control;
90
+ rVal.meta = hotkey.meta === undefined ? false : hotkey.meta;
91
+ rVal.shift = hotkey.shift === undefined ? false : hotkey.shift;
92
+ return rVal;
93
+ }
36
94
  }
@@ -1,46 +1,46 @@
1
1
  import { ObservableEntity } from "./ObservableEntity";
2
- import { Tool, ToolData } from "./Tool";
3
- export declare abstract class ToolRepository extends ObservableEntity {
2
+ import { HotKey, Tool, ToolData } from "./Tool";
3
+ export declare abstract class ToolRepository<ToolTypes> extends ObservableEntity {
4
4
  /**
5
5
  * Retuns the active tool. If no tool is active it will return undefined.
6
6
  */
7
- abstract get activeTool(): Tool | undefined;
7
+ abstract get activeTool(): Tool<ToolTypes> | undefined;
8
8
  /**
9
9
  * Returns all the tools.
10
10
  */
11
- abstract get allTools(): Tool[];
11
+ abstract get allTools(): Tool<ToolTypes>[];
12
12
  /**
13
13
  * Set up the tools from a JSON data file. This should be called during construction.
14
14
  * It is assumed this is only called once.
15
15
  * @param toolData
16
16
  */
17
- abstract setupToolsFromData(toolData: ToolData[]): void;
17
+ abstract setupToolsFromData(toolData: ToolData<ToolTypes>[]): void;
18
18
  /**
19
- * Get's a tool by it's ID. Retruns undefined if no tool could be found
20
- * @param id The tool ID
19
+ * Get's a tool by it's type. Retruns undefined if no tool could be found
20
+ * @param toolType The tool type
21
21
  */
22
- abstract getTool(id: string): Tool | undefined;
22
+ abstract getTool(toolType: ToolTypes): Tool<ToolTypes> | undefined;
23
23
  /**
24
24
  * Returns the tool that has been assinged to a particular key code.
25
25
  * Will return undefined of no tool is found
26
- * @param keyCode Key Code
26
+ * @param hotkey Key Code
27
27
  */
28
- abstract getToolForKey(keyCode: string): Tool | undefined;
28
+ abstract getToolForHotkey(hotkey: HotKey): Tool<ToolTypes> | undefined;
29
29
  /**
30
30
  * Call this to set the default tool as active
31
31
  */
32
32
  abstract setDefaultToolActive(): void;
33
33
  /**
34
- * Sets a tool active by ID.
35
- * @param id Tool ID
34
+ * Triggers a tool of type
35
+ * @param toolType Tool's type
36
36
  */
37
- abstract setToolActive(id: string): void;
37
+ abstract triggerTool(toolType: ToolTypes): void;
38
38
  /**
39
39
  * Toggls a tool between Hidden and shown.
40
40
  * If the tool is tool is currently Active, the default tool will be set active
41
41
  * The Default Tool cannot be toggled
42
- * @param id Tool ID
42
+ * @param toolType Tool's type
43
43
  */
44
- abstract toggleToolVisibility(id: string): void;
44
+ abstract toggleToolVisibility(toolType: ToolTypes): void;
45
45
  }
46
- export declare function makeToolRepo(): ToolRepository;
46
+ export declare function makeToolRepo<ToolTypes>(): ToolRepository<ToolTypes>;
@@ -14,15 +14,13 @@ class ToolRepositoryImp extends ToolRepository {
14
14
  constructor() {
15
15
  super(...arguments);
16
16
  this.toolLookup = new Map();
17
- this._defaultToolID = "";
18
- this._activeToolID = "";
19
17
  }
20
18
  get allTools() {
21
19
  return Array.from(this.toolLookup.values());
22
20
  }
23
21
  setDefaultToolActive() {
24
- if (this._defaultToolID) {
25
- this.setToolActive(this._defaultToolID);
22
+ if (this._defaultToolType !== undefined) {
23
+ this.triggerTool(this._defaultToolType);
26
24
  }
27
25
  else {
28
26
  console.warn(`[ToolRepository] No default tools has been specified`);
@@ -30,58 +28,65 @@ class ToolRepositoryImp extends ToolRepository {
30
28
  }
31
29
  setupToolsFromData(toolDatas) {
32
30
  toolDatas.forEach((toolData) => {
33
- if (this.toolLookup.has(toolData.id)) {
34
- console.warn(`[ToolRepository] A tool with the ID ${toolData.id} already exists. Replacing`);
31
+ const type = toolData.type;
32
+ if (this.toolLookup.has(type)) {
33
+ console.warn(`[ToolRepository] A tool with the ID ${toolData.type} already exists. Replacing`);
35
34
  }
36
35
  const tool = Tool_1.makeTool(toolData);
37
- this.toolLookup.set(tool.id, tool);
36
+ this.toolLookup.set(type, tool);
38
37
  if (toolData.isDefault) {
39
- if (this._defaultToolID) {
38
+ if (this._defaultToolType) {
40
39
  console.warn(`[ToolRepository] More than one tools is marked as default. Replacing`);
41
40
  }
42
- this._defaultToolID = tool.id;
41
+ this._defaultToolType = type;
43
42
  }
44
43
  });
45
- if (!this._defaultToolID) {
44
+ if (!this._defaultToolType) {
46
45
  console.warn(`[ToolRepository] No default tools was specified. Defaulting to the first tool in the list`);
47
- this._defaultToolID = Array.from(this.toolLookup.values())[0].id;
46
+ this._defaultToolType = Array.from(this.toolLookup.keys())[0];
47
+ }
48
+ if (this._defaultToolType) {
49
+ this.triggerTool(this._defaultToolType);
48
50
  }
49
- this.setToolActive(this._defaultToolID);
50
51
  }
51
- getTool(id) {
52
- return this.toolLookup.get(id);
52
+ getTool(type) {
53
+ return this.toolLookup.get(type);
53
54
  }
54
- getToolForKey(keyCode) {
55
+ getToolForHotkey(hotkey) {
55
56
  let tool;
56
57
  this.allTools.forEach((t) => {
57
- if (t.keyCode === keyCode) {
58
+ if (t.isMyHotkey(hotkey)) {
58
59
  tool = t;
59
60
  }
60
61
  });
61
62
  return tool;
62
63
  }
63
64
  get activeTool() {
64
- return this.getTool(this._activeToolID);
65
+ if (!this._activeToolType)
66
+ return undefined;
67
+ return this.getTool(this._activeToolType);
65
68
  }
66
- setToolActive(id) {
67
- if (this._activeToolID === id)
69
+ triggerTool(type) {
70
+ if (this._activeToolType === type)
68
71
  return;
69
- const newActiveTool = this.toolLookup.get(id);
72
+ const newActiveTool = this.toolLookup.get(type);
70
73
  if (!newActiveTool) {
71
- console.warn(`[ToolRepository] Unable to find tool ${id}`);
74
+ console.warn(`[ToolRepository] Unable to find tool ${type}`);
75
+ return;
76
+ }
77
+ if (newActiveTool.isAction) {
78
+ newActiveTool.triggerActions();
72
79
  return;
73
80
  }
74
81
  if (newActiveTool.state === Tool_1.ToolState.DISABLED) {
75
- console.warn(`[ToolRepository] ${newActiveTool.label} cannot be set active because it is disabled`);
76
82
  return;
77
83
  }
78
84
  if (newActiveTool.state === Tool_1.ToolState.HIDDEN) {
79
- console.warn(`[ToolRepository] ${newActiveTool.label} cannot be set active because it is hidden`);
80
85
  return;
81
86
  }
82
87
  this.toolLookup.forEach((tool) => {
83
- if (tool.id === id) {
84
- this._activeToolID = id;
88
+ if (tool.type === type) {
89
+ this._activeToolType = type;
85
90
  tool.state = Tool_1.ToolState.ACTIVE;
86
91
  }
87
92
  else if (tool.state === Tool_1.ToolState.ACTIVE) {
@@ -90,13 +95,13 @@ class ToolRepositoryImp extends ToolRepository {
90
95
  });
91
96
  this.notify();
92
97
  }
93
- toggleToolVisibility(id) {
94
- const tool = this.getTool(id);
98
+ toggleToolVisibility(type) {
99
+ const tool = this.getTool(type);
95
100
  if (!tool) {
96
- console.warn(`[ToolRepository] Unable to find tool to toggle: ${id}`);
101
+ console.warn(`[ToolRepository] Unable to find tool to toggle: ${type}`);
97
102
  return;
98
103
  }
99
- if (tool.id === this._defaultToolID) {
104
+ if (tool.type === this._defaultToolType) {
100
105
  console.warn(`[ToolRepository] The default tool's visibility cannot be toggled`);
101
106
  return;
102
107
  }
@@ -1,7 +1,7 @@
1
1
  import { Tool } from "../Entities";
2
2
  import { PresentionManager } from "./PresentationManager";
3
- export interface ToolVM {
4
- toolID: string;
3
+ export interface ToolVM<ToolType> {
4
+ type: ToolType;
5
5
  label: string;
6
6
  enabled: boolean;
7
7
  selected: boolean;
@@ -9,10 +9,9 @@ export interface ToolVM {
9
9
  shortcutLabel: string;
10
10
  tooltipLabel: string;
11
11
  }
12
- export declare class ToolPM extends PresentionManager {
12
+ export declare class ToolPM<ToolType> extends PresentionManager {
13
13
  private tool;
14
14
  private updateView;
15
15
  doUpdateView: () => void;
16
- constructor(tool: Tool, updateView: (tools: ToolVM) => void);
16
+ constructor(tool: Tool<ToolType>, updateView: (tools: ToolVM<ToolType>) => void);
17
17
  }
18
- export declare const defaultToolVM: ToolVM;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultToolVM = exports.ToolPM = void 0;
3
+ exports.ToolPM = void 0;
4
4
  const Entities_1 = require("../Entities");
5
5
  const PresentationManager_1 = require("./PresentationManager");
6
6
  class ToolPM extends PresentationManager_1.PresentionManager {
@@ -9,21 +9,22 @@ class ToolPM extends PresentationManager_1.PresentionManager {
9
9
  this.tool = tool;
10
10
  this.updateView = updateView;
11
11
  this.doUpdateView = () => {
12
+ const { type, state, label, shortcutLabel } = this.tool;
12
13
  let enabled = false;
13
- if (this.tool.state === Entities_1.ToolState.ACTIVE ||
14
- this.tool.state === Entities_1.ToolState.ENABLED) {
14
+ if (state === Entities_1.ToolState.ACTIVE ||
15
+ state === Entities_1.ToolState.ENABLED) {
15
16
  enabled = true;
16
17
  }
17
- const selected = this.tool.state === Entities_1.ToolState.ACTIVE ? true : false;
18
- const show = this.tool.state === Entities_1.ToolState.HIDDEN ? false : true;
19
- const tooltipLabel = `${this.tool.label} [${this.tool.shortcutLabel}]`;
18
+ const selected = state === Entities_1.ToolState.ACTIVE ? true : false;
19
+ const show = state === Entities_1.ToolState.HIDDEN ? false : true;
20
+ const tooltipLabel = `${label} [${shortcutLabel}]`;
20
21
  const vm = {
21
- toolID: this.tool.id,
22
+ type,
22
23
  enabled,
23
- label: this.tool.label,
24
+ label,
24
25
  selected,
25
26
  show,
26
- shortcutLabel: this.tool.shortcutLabel,
27
+ shortcutLabel,
27
28
  tooltipLabel,
28
29
  };
29
30
  this.updateView(vm);
@@ -32,12 +33,3 @@ class ToolPM extends PresentationManager_1.PresentionManager {
32
33
  }
33
34
  }
34
35
  exports.ToolPM = ToolPM;
35
- exports.defaultToolVM = {
36
- toolID: "",
37
- enabled: false,
38
- label: "",
39
- selected: false,
40
- shortcutLabel: "",
41
- show: false,
42
- tooltipLabel: "",
43
- };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vived/app",
3
- "version": "2.24.0",
3
+ "version": "2.25.0",
4
4
  "description": "Public package for the VIVED Learning App system",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",