@cccsaurora/howler-ui 2.14.0-dev.228 → 2.14.0-dev.245

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.
package/plugins/store.js CHANGED
@@ -6,6 +6,12 @@ export class HitEvent extends Event {
6
6
  this.hit = hit;
7
7
  }
8
8
  }
9
+ export var MainMenuInsertOperation;
10
+ (function (MainMenuInsertOperation) {
11
+ MainMenuInsertOperation["Insert"] = "INSERT";
12
+ MainMenuInsertOperation["InsertAfter"] = "AFTER";
13
+ MainMenuInsertOperation["InsertBefore"] = "BEFORE";
14
+ })(MainMenuInsertOperation || (MainMenuInsertOperation = {}));
9
15
  class HowlerPluginStore {
10
16
  _pluginStore = createPluginStore();
11
17
  plugins = [];
@@ -14,6 +20,9 @@ class HowlerPluginStore {
14
20
  _operations = [];
15
21
  _userMenuItems = [];
16
22
  _adminMenuItems = [];
23
+ _mainMenuOperations = [];
24
+ _routes = [];
25
+ _sitemaps = [];
17
26
  install(plugin) {
18
27
  console.log(`Installing plugin ${plugin.getPluginName()} by ${plugin.author}`);
19
28
  this.plugins.push(plugin.name);
@@ -33,6 +42,21 @@ class HowlerPluginStore {
33
42
  this._pivotFormats.push(format);
34
43
  return true;
35
44
  }
45
+ addUserMenuItem(menuItem) {
46
+ this._userMenuItems.push(menuItem);
47
+ }
48
+ addAdminMenuItem(menuItem) {
49
+ this._adminMenuItems.push(menuItem);
50
+ }
51
+ addMainMenuItem(menuOperation) {
52
+ this._mainMenuOperations.push(menuOperation);
53
+ }
54
+ addRoute(route) {
55
+ this._routes.push(route);
56
+ }
57
+ addSitemap(sitemap) {
58
+ this._sitemaps.push(sitemap);
59
+ }
36
60
  addOperation(format) {
37
61
  if (this._operations.includes(format)) {
38
62
  return false;
@@ -40,24 +64,6 @@ class HowlerPluginStore {
40
64
  this._operations.push(format);
41
65
  return true;
42
66
  }
43
- /**
44
- * Adds a single menu item to the User Menu group under the Avatar Menu,
45
- * items are added before the 'Settings' and 'Logout' menu items.
46
- *
47
- * @param menuItem Menu Item {i18nKey, route, icon}
48
- */
49
- addUserMenuItem(menuItem) {
50
- this._userMenuItems.push(menuItem);
51
- }
52
- /**
53
- * Adds a single menu item to the Admin Menu group under the Avatar Menu,
54
- * items are added to the end of the existing Admin menu items.
55
- *
56
- * @param menuItem Menu Item {i18nKey, route, icon}
57
- */
58
- addAdminMenuItem(menuItem) {
59
- this._adminMenuItems.push(menuItem);
60
- }
61
67
  get leadFormats() {
62
68
  return this._leadFormats;
63
69
  }
@@ -67,15 +73,24 @@ class HowlerPluginStore {
67
73
  get operations() {
68
74
  return this._operations;
69
75
  }
70
- get pluginStore() {
71
- return this._pluginStore;
72
- }
73
76
  get userMenuItems() {
74
77
  return this._userMenuItems;
75
78
  }
76
79
  get adminMenuItems() {
77
80
  return this._adminMenuItems;
78
81
  }
82
+ get mainMenuOperations() {
83
+ return this._mainMenuOperations;
84
+ }
85
+ get routes() {
86
+ return this._routes;
87
+ }
88
+ get sitemaps() {
89
+ return this._sitemaps;
90
+ }
91
+ get pluginStore() {
92
+ return this._pluginStore;
93
+ }
79
94
  }
80
95
  const howlerPluginStore = new HowlerPluginStore();
81
96
  export default howlerPluginStore;
@@ -0,0 +1,89 @@
1
+ import type { AppLeftNavElement, AppLeftNavItem } from '../commons/components/app/AppConfigs';
2
+ declare class AppMenuBuilder {
3
+ private items;
4
+ private indexMap;
5
+ constructor(defaultMenu: AppLeftNavElement[]);
6
+ /**
7
+ * Applies a collection of Menu Operation objects created by the plugin system
8
+ *
9
+ * @param operations Operations created by the plugin system
10
+ */
11
+ applyOperations(operations: {
12
+ operation: string;
13
+ targetId: string;
14
+ item: AppLeftNavElement;
15
+ }[]): void;
16
+ /**
17
+ * Get the completed menu structure
18
+ */
19
+ get menu(): AppLeftNavElement[];
20
+ /**
21
+ * Insert provided menu item at the menu object identified by targetId.
22
+ *
23
+ * If the target menu is a group then item will be placed at end of sub items
24
+ *
25
+ * If the target menu is a standard item then group will be created and new item added, warning this removes
26
+ * the route from the new group parent item, be sure to add it back.
27
+ *
28
+ * If the target is 'root' then item will be added to end of root menu
29
+ *
30
+ * @param targetId Identifier of menu to insert to
31
+ * @param item Menu Item to insert
32
+ */
33
+ insert(targetId: string, item: AppLeftNavElement): void;
34
+ /**
35
+ * Insert provided menu item before the menu object identified by targetId.
36
+ *
37
+ * @param targetId Identifier of menu to insert to
38
+ * @param item Menu Item to insert
39
+ */
40
+ insertBefore(targetId: string, item: AppLeftNavElement): void;
41
+ /**
42
+ * Insert provided menu item after the menu object identified by targetId.
43
+ *
44
+ * @param targetId Identifier of menu to insert to
45
+ * @param item Menu Item to insert
46
+ */
47
+ insertAfter(targetId: string, item: AppLeftNavElement): void;
48
+ /**
49
+ * Locates menu location in menu structure by menu id.
50
+ *
51
+ * @param id Menu Id to search for
52
+ * @return {index: number, subIndex: number} A dictionary containing indexes needed to access Menu Item
53
+ */
54
+ indexOfMenuId(id: string): {
55
+ index: number;
56
+ subIndex?: number;
57
+ };
58
+ /**
59
+ * Grabs a menu by indexes, helper function to account for an index of -1
60
+ * to represent the root menu
61
+ *
62
+ * @param index First level index
63
+ * @param subIndex Second level index
64
+ * @return {} Menu item
65
+ */
66
+ menuFromIndex(index: number, subIndex?: number): AppLeftNavElement[] | AppLeftNavElement | AppLeftNavItem;
67
+ /**
68
+ * Determine if provided element is a group element
69
+ *
70
+ * @param elem Element to check
71
+ * @private
72
+ */
73
+ private isGroupElement;
74
+ /**
75
+ * Determine if provided element is an item element
76
+ *
77
+ * @param elem Element to check
78
+ * @private
79
+ */
80
+ private isItemElement;
81
+ /**
82
+ * Creates a flat list of menu items and subitems by menu id
83
+ * for quick lookup.
84
+ *
85
+ * @private
86
+ */
87
+ private updateMenuMap;
88
+ }
89
+ export default AppMenuBuilder;
@@ -0,0 +1,243 @@
1
+ import { MainMenuInsertOperation } from '../plugins/store';
2
+ import { isNil } from 'lodash-es';
3
+ class AppMenuBuilder {
4
+ items;
5
+ indexMap;
6
+ constructor(defaultMenu) {
7
+ this.items = defaultMenu;
8
+ this.updateMenuMap();
9
+ }
10
+ /**
11
+ * Applies a collection of Menu Operation objects created by the plugin system
12
+ *
13
+ * @param operations Operations created by the plugin system
14
+ */
15
+ applyOperations(operations) {
16
+ for (const operation of operations) {
17
+ switch (operation.operation) {
18
+ case MainMenuInsertOperation.Insert:
19
+ // Inserts at end or adds to sub-elements
20
+ this.insert(operation.targetId, operation.item);
21
+ break;
22
+ case MainMenuInsertOperation.InsertBefore:
23
+ // Inserts before target element
24
+ this.insertBefore(operation.targetId, operation.item);
25
+ break;
26
+ case MainMenuInsertOperation.InsertAfter:
27
+ // Inserts after target element
28
+ this.insertAfter(operation.targetId, operation.item);
29
+ break;
30
+ }
31
+ this.updateMenuMap();
32
+ }
33
+ }
34
+ /**
35
+ * Get the completed menu structure
36
+ */
37
+ get menu() {
38
+ return this.items;
39
+ }
40
+ /**
41
+ * Insert provided menu item at the menu object identified by targetId.
42
+ *
43
+ * If the target menu is a group then item will be placed at end of sub items
44
+ *
45
+ * If the target menu is a standard item then group will be created and new item added, warning this removes
46
+ * the route from the new group parent item, be sure to add it back.
47
+ *
48
+ * If the target is 'root' then item will be added to end of root menu
49
+ *
50
+ * @param targetId Identifier of menu to insert to
51
+ * @param item Menu Item to insert
52
+ */
53
+ insert(targetId, item) {
54
+ const menuLocation = this.indexOfMenuId(targetId);
55
+ const target = this.menuFromIndex(menuLocation.index, menuLocation.subIndex);
56
+ if (!Array.isArray(target) && this.isGroupElement(target)) {
57
+ if (item.type === 'divider') {
58
+ console.warn(`Skipping DIVIDER Operation: INSERT on Target: ${targetId}, Dividers cannot be inserted to sub-menus`);
59
+ return;
60
+ }
61
+ const group = target.element;
62
+ const newItem = { ...item.element, nested: true };
63
+ group.items = [...group.items, newItem];
64
+ return;
65
+ }
66
+ if (Array.isArray(target)) {
67
+ target.push(item);
68
+ return;
69
+ }
70
+ if (menuLocation.index !== -1 && isNil(menuLocation.subIndex)) {
71
+ if (item.type === 'divider') {
72
+ console.warn(`Skipping DIVIDER Operation: INSERT on Target: ${targetId}, Dividers cannot be inserted to sub-menus`);
73
+ return;
74
+ }
75
+ if (!this.isItemElement(target)) {
76
+ return;
77
+ }
78
+ const header = target.element;
79
+ const inserted = { ...item.element, nested: true };
80
+ const newGroup = {
81
+ type: 'group',
82
+ element: {
83
+ id: header.id,
84
+ open: true,
85
+ i18nKey: header.i18nKey,
86
+ title: header.text,
87
+ userPropValidators: header.userPropValidators,
88
+ icon: header.icon,
89
+ items: [inserted]
90
+ }
91
+ };
92
+ this.items[menuLocation.index] = newGroup;
93
+ return;
94
+ }
95
+ }
96
+ /**
97
+ * Insert provided menu item before the menu object identified by targetId.
98
+ *
99
+ * @param targetId Identifier of menu to insert to
100
+ * @param item Menu Item to insert
101
+ */
102
+ insertBefore(targetId, item) {
103
+ const menuLocation = this.indexOfMenuId(targetId);
104
+ if (!isNil(menuLocation.subIndex)) {
105
+ if (item.type === 'divider') {
106
+ console.warn(`Skipping DIVIDER Operation: INSERT on Target: ${targetId}, Dividers cannot be inserted to sub-menus`);
107
+ return;
108
+ }
109
+ const parentElement = this.menuFromIndex(menuLocation.index);
110
+ if (!Array.isArray(parentElement) && this.isGroupElement(parentElement)) {
111
+ const group = parentElement.element;
112
+ const newItem = { ...item.element, nested: true };
113
+ group.items = [
114
+ ...group.items.slice(0, menuLocation.subIndex),
115
+ newItem,
116
+ ...group.items.slice(menuLocation.subIndex)
117
+ ];
118
+ }
119
+ return;
120
+ }
121
+ // Root level insertion before target index
122
+ if (menuLocation.index < 0) {
123
+ menuLocation.index = 0;
124
+ }
125
+ this.items = [...this.items.slice(0, menuLocation.index), item, ...this.items.slice(menuLocation.index)];
126
+ }
127
+ /**
128
+ * Insert provided menu item after the menu object identified by targetId.
129
+ *
130
+ * @param targetId Identifier of menu to insert to
131
+ * @param item Menu Item to insert
132
+ */
133
+ insertAfter(targetId, item) {
134
+ const menuLocation = this.indexOfMenuId(targetId);
135
+ if (!isNil(menuLocation.subIndex)) {
136
+ if (item.type === 'divider') {
137
+ console.warn(`Skipping DIVIDER Operation: INSERT on Target: ${targetId}, Dividers cannot be inserted to sub-menus`);
138
+ return;
139
+ }
140
+ const parentElement = this.menuFromIndex(menuLocation.index);
141
+ if (!Array.isArray(parentElement) && this.isGroupElement(parentElement)) {
142
+ const group = parentElement.element;
143
+ const newItem = { ...item.element, nested: true };
144
+ group.items = [
145
+ ...group.items.slice(0, menuLocation.subIndex + 1),
146
+ newItem,
147
+ ...group.items.slice(menuLocation.subIndex + 1)
148
+ ];
149
+ }
150
+ return;
151
+ }
152
+ // Root level insertion after target index
153
+ if (menuLocation.index < 0) {
154
+ menuLocation.index = this.items.length;
155
+ }
156
+ this.items = [...this.items.slice(0, menuLocation.index + 1), item, ...this.items.slice(menuLocation.index + 1)];
157
+ }
158
+ /**
159
+ * Locates menu location in menu structure by menu id.
160
+ *
161
+ * @param id Menu Id to search for
162
+ * @return {index: number, subIndex: number} A dictionary containing indexes needed to access Menu Item
163
+ */
164
+ indexOfMenuId(id) {
165
+ if (id === 'root') {
166
+ // Root item so return entire menu
167
+ return { index: -1 };
168
+ }
169
+ else if (id in this.indexMap) {
170
+ // Item exists, check if it's a subitem
171
+ if ('parent' in this.indexMap[id]) {
172
+ return { index: this.indexMap[id].parent, subIndex: this.indexMap[id].index };
173
+ }
174
+ return { index: this.indexMap[id].index };
175
+ }
176
+ else {
177
+ throw new Error(`Menu element with id of '${id}' not found.`);
178
+ }
179
+ }
180
+ /**
181
+ * Grabs a menu by indexes, helper function to account for an index of -1
182
+ * to represent the root menu
183
+ *
184
+ * @param index First level index
185
+ * @param subIndex Second level index
186
+ * @return {} Menu item
187
+ */
188
+ menuFromIndex(index, subIndex) {
189
+ if (index === -1) {
190
+ return this.items;
191
+ }
192
+ if (isNil(subIndex)) {
193
+ return this.items[index];
194
+ }
195
+ const menuItem = this.items[index];
196
+ if (menuItem.type === 'group') {
197
+ return menuItem.element.items[subIndex];
198
+ }
199
+ throw new Error(`Menu item at index ${index} is not a group and does not have sub-items.`);
200
+ }
201
+ /**
202
+ * Determine if provided element is a group element
203
+ *
204
+ * @param elem Element to check
205
+ * @private
206
+ */
207
+ isGroupElement(elem) {
208
+ return !!elem && typeof elem === 'object' && elem.type === 'group';
209
+ }
210
+ /**
211
+ * Determine if provided element is an item element
212
+ *
213
+ * @param elem Element to check
214
+ * @private
215
+ */
216
+ isItemElement(elem) {
217
+ return !!elem && typeof elem === 'object' && elem.type === 'item';
218
+ }
219
+ /**
220
+ * Creates a flat list of menu items and subitems by menu id
221
+ * for quick lookup.
222
+ *
223
+ * @private
224
+ */
225
+ updateMenuMap() {
226
+ const indexMap = {};
227
+ for (let index = 0; index < this.items.length; index++) {
228
+ const menuItem = this.items[index];
229
+ if (menuItem.type === 'divider') {
230
+ continue;
231
+ }
232
+ indexMap[menuItem.element.id] = { index };
233
+ if (menuItem.type === 'group') {
234
+ for (let subIndex = 0; subIndex < menuItem.element.items.length; subIndex++) {
235
+ const subMenuItem = menuItem.element.items[subIndex];
236
+ indexMap[subMenuItem.id] = { index: subIndex, parent: index };
237
+ }
238
+ }
239
+ }
240
+ this.indexMap = indexMap;
241
+ }
242
+ }
243
+ export default AppMenuBuilder;