@compas-oscd/open-scd 0.34.0 → 0.34.1

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.
Files changed (233) hide show
  1. package/dist/WizardDivider.js +37 -0
  2. package/dist/WizardDivider.js.map +1 -0
  3. package/dist/Wizarding.js +38 -0
  4. package/dist/Wizarding.js.map +1 -0
  5. package/dist/action-icon.js +220 -0
  6. package/dist/action-icon.js.map +1 -0
  7. package/dist/action-pane.js +176 -0
  8. package/dist/action-pane.js.map +1 -0
  9. package/dist/addons/Editor.js +106 -0
  10. package/dist/addons/Editor.js.map +1 -0
  11. package/dist/addons/History.js +490 -0
  12. package/dist/addons/History.js.map +1 -0
  13. package/dist/addons/Layout.js +619 -0
  14. package/dist/addons/Layout.js.map +1 -0
  15. package/dist/addons/Settings.js +465 -0
  16. package/dist/addons/Settings.js.map +1 -0
  17. package/dist/addons/Waiter.js +45 -0
  18. package/dist/addons/Waiter.js.map +1 -0
  19. package/dist/addons/Wizards.js +48 -0
  20. package/dist/addons/Wizards.js.map +1 -0
  21. package/dist/addons/editor/edit-action-to-v1-converter.js +96 -0
  22. package/dist/addons/editor/edit-action-to-v1-converter.js.map +1 -0
  23. package/dist/addons/editor/edit-v1-to-v2-converter.js +37 -0
  24. package/dist/addons/editor/edit-v1-to-v2-converter.js.map +1 -0
  25. package/dist/addons/history/get-log-text.js +26 -0
  26. package/dist/addons/history/get-log-text.js.map +1 -0
  27. package/dist/addons/menu-tabs/menu-tabs.js +74 -0
  28. package/dist/addons/menu-tabs/menu-tabs.js.map +1 -0
  29. package/dist/addons/plugin-manager/custom-plugin-dialog.js +177 -0
  30. package/dist/addons/plugin-manager/custom-plugin-dialog.js.map +1 -0
  31. package/dist/addons/plugin-manager/plugin-manager.js +165 -0
  32. package/dist/addons/plugin-manager/plugin-manager.js.map +1 -0
  33. package/dist/core/api/api.js +7 -0
  34. package/dist/core/api/api.js.map +1 -0
  35. package/dist/core/api/editor/subject.js +22 -0
  36. package/dist/core/api/editor/subject.js.map +1 -0
  37. package/dist/core/api/editor/xml-editor.js +82 -0
  38. package/dist/core/api/editor/xml-editor.js.map +1 -0
  39. package/dist/core/api/plugin-state-api.js +27 -0
  40. package/dist/core/api/plugin-state-api.js.map +1 -0
  41. package/dist/core/foundation/cyrb64.js +26 -0
  42. package/dist/core/foundation/cyrb64.js.map +1 -0
  43. package/dist/core/foundation/deprecated/edit-event.js +44 -0
  44. package/dist/core/foundation/deprecated/edit-event.js.map +1 -0
  45. package/dist/core/foundation/deprecated/editor.js +94 -0
  46. package/dist/core/foundation/deprecated/editor.js.map +1 -0
  47. package/dist/core/foundation/deprecated/history.js +17 -0
  48. package/dist/core/foundation/deprecated/history.js.map +1 -0
  49. package/dist/core/foundation/deprecated/open-event.js +9 -0
  50. package/dist/core/foundation/deprecated/open-event.js.map +1 -0
  51. package/dist/core/foundation/deprecated/settings.js +19 -0
  52. package/dist/core/foundation/deprecated/settings.js.map +1 -0
  53. package/dist/core/foundation/deprecated/validation.js +8 -0
  54. package/dist/core/foundation/deprecated/validation.js.map +1 -0
  55. package/dist/core/foundation/deprecated/waiter.js +12 -0
  56. package/dist/core/foundation/deprecated/waiter.js.map +1 -0
  57. package/dist/core/foundation/edit-completed-event.js +11 -0
  58. package/dist/core/foundation/edit-completed-event.js.map +1 -0
  59. package/dist/core/foundation/edit-event.js +8 -0
  60. package/dist/core/foundation/edit-event.js.map +1 -0
  61. package/dist/core/foundation/edit.js +31 -0
  62. package/dist/core/foundation/edit.js.map +1 -0
  63. package/dist/core/foundation/handle-edit.js +151 -0
  64. package/dist/core/foundation/handle-edit.js.map +1 -0
  65. package/dist/core/foundation/open-event.js +8 -0
  66. package/dist/core/foundation/open-event.js.map +1 -0
  67. package/dist/core/foundation/plugin.js +2 -0
  68. package/dist/core/foundation/plugin.js.map +1 -0
  69. package/dist/core/foundation.js +14 -0
  70. package/dist/core/foundation.js.map +1 -0
  71. package/dist/core/locales.js +21 -0
  72. package/dist/core/locales.js.map +1 -0
  73. package/dist/filtered-list.js +168 -0
  74. package/dist/filtered-list.js.map +1 -0
  75. package/dist/finder-list.js +207 -0
  76. package/dist/finder-list.js.map +1 -0
  77. package/dist/foundation/compare.js +273 -0
  78. package/dist/foundation/compare.js.map +1 -0
  79. package/dist/foundation/dai.js +127 -0
  80. package/dist/foundation/dai.js.map +1 -0
  81. package/dist/foundation/generators.js +67 -0
  82. package/dist/foundation/generators.js.map +1 -0
  83. package/dist/foundation/ied.js +84 -0
  84. package/dist/foundation/ied.js.map +1 -0
  85. package/dist/foundation/nsd.js +13 -0
  86. package/dist/foundation/nsd.js.map +1 -0
  87. package/dist/foundation/nsdoc.js +180 -0
  88. package/dist/foundation/nsdoc.js.map +1 -0
  89. package/dist/foundation/scl.js +64 -0
  90. package/dist/foundation/scl.js.map +1 -0
  91. package/dist/foundation.js +1922 -0
  92. package/dist/foundation.js.map +1 -0
  93. package/dist/icons/compare.js +11 -0
  94. package/dist/icons/compare.js.map +1 -0
  95. package/dist/icons/icons.js +611 -0
  96. package/dist/icons/icons.js.map +1 -0
  97. package/dist/icons/ied-icons.js +11 -0
  98. package/dist/icons/ied-icons.js.map +1 -0
  99. package/dist/icons/lnode.js +50 -0
  100. package/dist/icons/lnode.js.map +1 -0
  101. package/dist/open-scd.js +483 -0
  102. package/dist/open-scd.js.map +1 -0
  103. package/dist/openscd/src/WizardDivider.js +37 -0
  104. package/dist/openscd/src/WizardDivider.js.map +1 -0
  105. package/dist/openscd/src/Wizarding.js +38 -0
  106. package/dist/openscd/src/Wizarding.js.map +1 -0
  107. package/dist/openscd/src/action-icon.js +220 -0
  108. package/dist/openscd/src/action-icon.js.map +1 -0
  109. package/dist/openscd/src/action-pane.js +176 -0
  110. package/dist/openscd/src/action-pane.js.map +1 -0
  111. package/dist/openscd/src/addons/Editor.js +106 -0
  112. package/dist/openscd/src/addons/Editor.js.map +1 -0
  113. package/dist/openscd/src/addons/History.js +490 -0
  114. package/dist/openscd/src/addons/History.js.map +1 -0
  115. package/dist/openscd/src/addons/Layout.js +619 -0
  116. package/dist/openscd/src/addons/Layout.js.map +1 -0
  117. package/dist/openscd/src/addons/Settings.js +465 -0
  118. package/dist/openscd/src/addons/Settings.js.map +1 -0
  119. package/dist/openscd/src/addons/Waiter.js +45 -0
  120. package/dist/openscd/src/addons/Waiter.js.map +1 -0
  121. package/dist/openscd/src/addons/Wizards.js +48 -0
  122. package/dist/openscd/src/addons/Wizards.js.map +1 -0
  123. package/dist/openscd/src/addons/editor/edit-action-to-v1-converter.js +96 -0
  124. package/dist/openscd/src/addons/editor/edit-action-to-v1-converter.js.map +1 -0
  125. package/dist/openscd/src/addons/editor/edit-v1-to-v2-converter.js +37 -0
  126. package/dist/openscd/src/addons/editor/edit-v1-to-v2-converter.js.map +1 -0
  127. package/dist/openscd/src/addons/history/get-log-text.js +26 -0
  128. package/dist/openscd/src/addons/history/get-log-text.js.map +1 -0
  129. package/dist/openscd/src/addons/menu-tabs/menu-tabs.js +74 -0
  130. package/dist/openscd/src/addons/menu-tabs/menu-tabs.js.map +1 -0
  131. package/dist/openscd/src/addons/plugin-manager/custom-plugin-dialog.js +177 -0
  132. package/dist/openscd/src/addons/plugin-manager/custom-plugin-dialog.js.map +1 -0
  133. package/dist/openscd/src/addons/plugin-manager/plugin-manager.js +165 -0
  134. package/dist/openscd/src/addons/plugin-manager/plugin-manager.js.map +1 -0
  135. package/dist/openscd/src/filtered-list.js +168 -0
  136. package/dist/openscd/src/filtered-list.js.map +1 -0
  137. package/dist/openscd/src/finder-list.js +207 -0
  138. package/dist/openscd/src/finder-list.js.map +1 -0
  139. package/dist/openscd/src/foundation/compare.js +273 -0
  140. package/dist/openscd/src/foundation/compare.js.map +1 -0
  141. package/dist/openscd/src/foundation/dai.js +127 -0
  142. package/dist/openscd/src/foundation/dai.js.map +1 -0
  143. package/dist/openscd/src/foundation/generators.js +67 -0
  144. package/dist/openscd/src/foundation/generators.js.map +1 -0
  145. package/dist/openscd/src/foundation/ied.js +84 -0
  146. package/dist/openscd/src/foundation/ied.js.map +1 -0
  147. package/dist/openscd/src/foundation/nsd.js +13 -0
  148. package/dist/openscd/src/foundation/nsd.js.map +1 -0
  149. package/dist/openscd/src/foundation/nsdoc.js +180 -0
  150. package/dist/openscd/src/foundation/nsdoc.js.map +1 -0
  151. package/dist/openscd/src/foundation/scl.js +64 -0
  152. package/dist/openscd/src/foundation/scl.js.map +1 -0
  153. package/dist/openscd/src/foundation.js +1922 -0
  154. package/dist/openscd/src/foundation.js.map +1 -0
  155. package/dist/openscd/src/icons/compare.js +11 -0
  156. package/dist/openscd/src/icons/compare.js.map +1 -0
  157. package/dist/openscd/src/icons/icons.js +611 -0
  158. package/dist/openscd/src/icons/icons.js.map +1 -0
  159. package/dist/openscd/src/icons/ied-icons.js +11 -0
  160. package/dist/openscd/src/icons/ied-icons.js.map +1 -0
  161. package/dist/openscd/src/icons/lnode.js +50 -0
  162. package/dist/openscd/src/icons/lnode.js.map +1 -0
  163. package/dist/openscd/src/open-scd.js +483 -0
  164. package/dist/openscd/src/open-scd.js.map +1 -0
  165. package/dist/openscd/src/oscd-filter-button.js +89 -0
  166. package/dist/openscd/src/oscd-filter-button.js.map +1 -0
  167. package/dist/openscd/src/plain-compare-list.js +132 -0
  168. package/dist/openscd/src/plain-compare-list.js.map +1 -0
  169. package/dist/openscd/src/plugin-tag.js +23 -0
  170. package/dist/openscd/src/plugin-tag.js.map +1 -0
  171. package/dist/openscd/src/plugin.events.js +12 -0
  172. package/dist/openscd/src/plugin.events.js.map +1 -0
  173. package/dist/openscd/src/plugin.js +2 -0
  174. package/dist/openscd/src/plugin.js.map +1 -0
  175. package/dist/openscd/src/plugins.js +256 -0
  176. package/dist/openscd/src/plugins.js.map +1 -0
  177. package/dist/openscd/src/schemas.js +9325 -0
  178. package/dist/openscd/src/schemas.js.map +1 -0
  179. package/dist/openscd/src/themes.js +122 -0
  180. package/dist/openscd/src/themes.js.map +1 -0
  181. package/dist/openscd/src/translations/de.js +954 -0
  182. package/dist/openscd/src/translations/de.js.map +1 -0
  183. package/dist/openscd/src/translations/en.js +950 -0
  184. package/dist/openscd/src/translations/en.js.map +1 -0
  185. package/dist/openscd/src/translations/loader.js +10 -0
  186. package/dist/openscd/src/translations/loader.js.map +1 -0
  187. package/dist/openscd/src/wizard-checkbox.js +152 -0
  188. package/dist/openscd/src/wizard-checkbox.js.map +1 -0
  189. package/dist/openscd/src/wizard-dialog.js +374 -0
  190. package/dist/openscd/src/wizard-dialog.js.map +1 -0
  191. package/dist/openscd/src/wizard-select.js +115 -0
  192. package/dist/openscd/src/wizard-select.js.map +1 -0
  193. package/dist/openscd/src/wizard-textfield.js +191 -0
  194. package/dist/openscd/src/wizard-textfield.js.map +1 -0
  195. package/dist/openscd/src/wizards.js +196 -0
  196. package/dist/openscd/src/wizards.js.map +1 -0
  197. package/dist/oscd-filter-button.js +89 -0
  198. package/dist/oscd-filter-button.js.map +1 -0
  199. package/dist/plain-compare-list.js +132 -0
  200. package/dist/plain-compare-list.js.map +1 -0
  201. package/dist/plugin-tag.js +23 -0
  202. package/dist/plugin-tag.js.map +1 -0
  203. package/dist/plugin.events.js +12 -0
  204. package/dist/plugin.events.js.map +1 -0
  205. package/dist/plugin.js +2 -0
  206. package/dist/plugin.js.map +1 -0
  207. package/dist/plugins.js +256 -0
  208. package/dist/plugins.js.map +1 -0
  209. package/dist/schemas.js +9325 -0
  210. package/dist/schemas.js.map +1 -0
  211. package/dist/themes.js +122 -0
  212. package/dist/themes.js.map +1 -0
  213. package/dist/translations/de.js +954 -0
  214. package/dist/translations/de.js.map +1 -0
  215. package/dist/translations/en.js +950 -0
  216. package/dist/translations/en.js.map +1 -0
  217. package/dist/translations/loader.js +10 -0
  218. package/dist/translations/loader.js.map +1 -0
  219. package/dist/wizard-checkbox.js +152 -0
  220. package/dist/wizard-checkbox.js.map +1 -0
  221. package/dist/wizard-dialog.js +374 -0
  222. package/dist/wizard-dialog.js.map +1 -0
  223. package/dist/wizard-select.js +115 -0
  224. package/dist/wizard-select.js.map +1 -0
  225. package/dist/wizard-textfield.js +191 -0
  226. package/dist/wizard-textfield.js.map +1 -0
  227. package/dist/wizards.js +196 -0
  228. package/dist/wizards.js.map +1 -0
  229. package/dist/xml/src/foundation.js +67 -0
  230. package/dist/xml/src/foundation.js.map +1 -0
  231. package/dist/xml/src/index.js +2 -0
  232. package/dist/xml/src/index.js.map +1 -0
  233. package/package.json +99 -4
@@ -0,0 +1,165 @@
1
+ import { __decorate } from "tslib";
2
+ import { customElement, html, LitElement, property, query, css } from 'lit-element';
3
+ import { get } from 'lit-translate';
4
+ import '@material/mwc-dialog';
5
+ import '@material/mwc-list';
6
+ import { newResetPluginsEvent, newSetPluginsEvent, pluginIcons } from '../../open-scd.js';
7
+ let OscdPluginManager = class OscdPluginManager extends LitElement {
8
+ constructor() {
9
+ super(...arguments);
10
+ /** The plugins to render the layout. */
11
+ this.plugins = [];
12
+ }
13
+ render() {
14
+ return html `
15
+ <mwc-dialog
16
+ stacked
17
+ id="plugin-manager-root"
18
+ heading="${get('plugins.heading')}"
19
+ >
20
+ <mwc-list
21
+ id="pluginList"
22
+ multi
23
+ @selected=${(e) => {
24
+ const selectedPlugins = this.pluginList.items
25
+ .filter((item, index) => e.detail.index.has(index))
26
+ // @ts-expect-error: we add plugin to the list item
27
+ .map(item => item.plugin);
28
+ this.dispatchEvent(newSetPluginsEvent(selectedPlugins));
29
+ }}
30
+ >
31
+ <mwc-list-item graphic="avatar" noninteractive>
32
+ <strong>${get(`plugins.editor`)}</strong>
33
+ <mwc-icon slot="graphic" class="inverted">
34
+ ${pluginIcons['editor']}
35
+ </mwc-icon>
36
+ </mwc-list-item>
37
+
38
+ <li divider role="separator"></li>
39
+
40
+ ${this.generateEditorListItems()}
41
+
42
+ <mwc-list-item graphic="avatar" noninteractive>
43
+ <strong>${get(`plugins.menu`)}</strong>
44
+ <mwc-icon slot="graphic" class="inverted">
45
+ <strong>${pluginIcons['menu']}</strong></mwc-icon>
46
+ </mwc-list-item>
47
+ <li divider role="separator"></li>
48
+
49
+ ${this.generateMenuListItems('top')}
50
+
51
+ <li divider role="separator" inset></li>
52
+
53
+ ${this.generateValidatorListItems()}
54
+
55
+ <li divider role="separator" inset></li>
56
+
57
+ ${this.generateMenuListItems('middle')}
58
+
59
+ <li divider role="separator" inset></li>
60
+
61
+ ${this.generateMenuListItems('bottom')}
62
+
63
+ </mwc-list>
64
+ <mwc-button
65
+ slot="secondaryAction"
66
+ icon="refresh"
67
+ label="${get('reset')}"
68
+ @click=${async () => {
69
+ this.dispatchEvent(newResetPluginsEvent());
70
+ this.requestUpdate();
71
+ }}
72
+ style="--mdc-theme-primary: var(--mdc-theme-error)"
73
+ >
74
+ </mwc-button>
75
+ <mwc-button
76
+ slot="secondaryAction"
77
+ icon=""
78
+ label="${get('close')}"
79
+ dialogAction="close">
80
+ </mwc-button>
81
+ <mwc-button
82
+ outlined
83
+ trailingIcon
84
+ slot="primaryAction"
85
+ icon="library_add"
86
+ label="${get('plugins.add.heading')}&hellip;"
87
+ @click=${() => this.dispatchOpenCustomPluginDialogEvent()}>
88
+ </mwc-button>
89
+ </mwc-dialog>
90
+ `;
91
+ }
92
+ show() {
93
+ this.root.show();
94
+ }
95
+ generateEditorListItems() {
96
+ return this.plugins
97
+ .filter(p => p.kind === 'editor')
98
+ .map(this.renderPluginListItem);
99
+ }
100
+ generateMenuListItems(position) {
101
+ return this.plugins
102
+ .filter(p => p.kind === 'menu' && p.position === position)
103
+ .map(this.renderPluginListItem);
104
+ }
105
+ generateValidatorListItems() {
106
+ return this.plugins
107
+ .filter(p => p.kind === 'validator')
108
+ .map(this.renderPluginListItem);
109
+ }
110
+ dispatchOpenCustomPluginDialogEvent() {
111
+ const event = new CustomEvent('open-plugin-download', {
112
+ bubbles: true,
113
+ composed: true,
114
+ });
115
+ this.dispatchEvent(event);
116
+ }
117
+ renderPluginListItem(plugin) {
118
+ if (!plugin) {
119
+ return html ``;
120
+ }
121
+ return html `
122
+ <mwc-check-list-item
123
+ class="${plugin.official ? 'official' : 'external'}"
124
+ value="${plugin.src}"
125
+ .plugin=${plugin}
126
+ ?selected=${plugin.active}
127
+ @request-selected=${(e) => {
128
+ if (e.detail.source !== 'interaction') {
129
+ e.preventDefault();
130
+ e.stopPropagation();
131
+ e.stopImmediatePropagation();
132
+ return false;
133
+ }
134
+ }}
135
+ hasMeta
136
+ left
137
+ >
138
+ <mwc-icon slot="meta">
139
+ ${plugin.icon || pluginIcons[plugin.kind]}
140
+ </mwc-icon>
141
+ ${plugin.name}
142
+ </mwc-check-list-item>
143
+
144
+ `;
145
+ }
146
+ };
147
+ OscdPluginManager.styles = css `
148
+ mwc-dialog {
149
+ --mdc-dialog-max-width: 98vw;
150
+ }
151
+ `;
152
+ __decorate([
153
+ property({ type: Array })
154
+ ], OscdPluginManager.prototype, "plugins", void 0);
155
+ __decorate([
156
+ query('#plugin-manager-root')
157
+ ], OscdPluginManager.prototype, "root", void 0);
158
+ __decorate([
159
+ query('#pluginList')
160
+ ], OscdPluginManager.prototype, "pluginList", void 0);
161
+ OscdPluginManager = __decorate([
162
+ customElement('oscd-plugin-manager')
163
+ ], OscdPluginManager);
164
+ export { OscdPluginManager };
165
+ //# sourceMappingURL=plugin-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-manager.js","sourceRoot":"","sources":["../../../../../src/addons/plugin-manager/plugin-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n customElement,\n html,\n LitElement,\n property,\n query,\n TemplateResult,\n css\n} from 'lit-element';\nimport { get } from 'lit-translate';\n\nimport type { ActionDetail } from '@material/mwc-list';\nimport type { MultiSelectedEvent } from '@material/mwc-list/mwc-list-foundation.js';\nimport type { Dialog } from '@material/mwc-dialog';\nimport '@material/mwc-dialog';\nimport '@material/mwc-list';\nimport type {List} from '@material/mwc-list';\n\nimport {\n newResetPluginsEvent,\n newSetPluginsEvent,\n pluginIcons\n} from '../../open-scd.js';\n\nimport {\n MenuPosition,\n Plugin,\n} from \"../../plugin.js\";\n\n@customElement('oscd-plugin-manager')\nexport class OscdPluginManager extends LitElement {\n\n /** The plugins to render the layout. */\n @property({ type: Array }) plugins: Plugin[] = [];\n @query('#plugin-manager-root') root!: Dialog\n @query('#pluginList') pluginList!: List\n\n render(): TemplateResult {\n return html`\n <mwc-dialog\n stacked\n id=\"plugin-manager-root\"\n heading=\"${get('plugins.heading')}\"\n >\n <mwc-list\n id=\"pluginList\"\n multi\n @selected=${(e: MultiSelectedEvent) => {\n const selectedPlugins = this.pluginList.items\n .filter((item, index) => e.detail.index.has(index))\n // @ts-expect-error: we add plugin to the list item\n .map(item => item.plugin) as Plugin[]\n\n this.dispatchEvent(newSetPluginsEvent(selectedPlugins))\n }}\n >\n <mwc-list-item graphic=\"avatar\" noninteractive>\n <strong>${get(`plugins.editor`)}</strong>\n <mwc-icon slot=\"graphic\" class=\"inverted\">\n ${pluginIcons['editor']}\n </mwc-icon>\n </mwc-list-item>\n\n <li divider role=\"separator\"></li>\n\n ${this.generateEditorListItems()}\n\n <mwc-list-item graphic=\"avatar\" noninteractive>\n <strong>${get(`plugins.menu`)}</strong>\n <mwc-icon slot=\"graphic\" class=\"inverted\">\n <strong>${pluginIcons['menu']}</strong></mwc-icon>\n </mwc-list-item>\n <li divider role=\"separator\"></li>\n\n ${this.generateMenuListItems('top')}\n\n <li divider role=\"separator\" inset></li>\n\n ${this.generateValidatorListItems()}\n\n <li divider role=\"separator\" inset></li>\n\n ${this.generateMenuListItems('middle')}\n\n <li divider role=\"separator\" inset></li>\n\n ${this.generateMenuListItems('bottom')}\n\n </mwc-list>\n <mwc-button\n slot=\"secondaryAction\"\n icon=\"refresh\"\n label=\"${get('reset')}\"\n @click=${async () => {\n this.dispatchEvent(newResetPluginsEvent());\n this.requestUpdate();\n }}\n style=\"--mdc-theme-primary: var(--mdc-theme-error)\"\n >\n </mwc-button>\n <mwc-button\n slot=\"secondaryAction\"\n icon=\"\"\n label=\"${get('close')}\"\n dialogAction=\"close\">\n </mwc-button>\n <mwc-button\n outlined\n trailingIcon\n slot=\"primaryAction\"\n icon=\"library_add\"\n label=\"${get('plugins.add.heading')}&hellip;\"\n @click=${() => this.dispatchOpenCustomPluginDialogEvent()}>\n </mwc-button>\n </mwc-dialog>\n `;\n }\n\n static styles = css`\n mwc-dialog {\n --mdc-dialog-max-width: 98vw;\n }\n `\n\n public show(){\n this.root.show()\n }\n\n\n private generateEditorListItems(): TemplateResult[] {\n return this.plugins\n .filter(p => p.kind === 'editor')\n .map(this.renderPluginListItem)\n }\n\n private generateMenuListItems(position: MenuPosition): TemplateResult[] {\n return this.plugins\n .filter(p => p.kind === 'menu' && p.position === position)\n .map(this.renderPluginListItem)\n }\n\n private generateValidatorListItems(): TemplateResult[] {\n return this.plugins\n .filter(p => p.kind === 'validator')\n .map(this.renderPluginListItem)\n }\n\n private dispatchOpenCustomPluginDialogEvent(): void {\n const event = new CustomEvent('open-plugin-download', {\n bubbles: true,\n composed: true,\n });\n\n this.dispatchEvent(event);\n }\n\n private renderPluginListItem(plugin?: Plugin): TemplateResult {\n if(!plugin){ return html`` }\n\n return html`\n <mwc-check-list-item\n class=\"${plugin.official ? 'official' : 'external'}\"\n value=\"${plugin.src}\"\n .plugin=${plugin}\n ?selected=${plugin.active}\n @request-selected=${(e: CustomEvent<{source: string}>) => {\n if(e.detail.source !== 'interaction'){\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n return false;\n }\n }}\n hasMeta\n left\n >\n <mwc-icon slot=\"meta\">\n ${plugin.icon || pluginIcons[plugin.kind]}\n </mwc-icon>\n ${plugin.name}\n </mwc-check-list-item>\n\n `;\n }\n\n}\n"]}
@@ -0,0 +1,168 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, customElement, html, property, query, state, unsafeCSS, } from 'lit-element';
3
+ import { get } from 'lit-translate';
4
+ import '@material/mwc-checkbox';
5
+ import '@material/mwc-formfield';
6
+ import '@material/mwc-textfield';
7
+ import { CheckListItem } from '@material/mwc-list/mwc-check-list-item';
8
+ import { List } from '@material/mwc-list';
9
+ import { ListBase } from '@material/mwc-list/mwc-list-base';
10
+ function slotItem(item) {
11
+ if (!item.closest('filtered-list') || !item.parentElement)
12
+ return item;
13
+ if (item.parentElement instanceof FilteredList)
14
+ return item;
15
+ return slotItem(item.parentElement);
16
+ }
17
+ function hideFiltered(item, searchText) {
18
+ const itemInnerText = item.innerText + '\n';
19
+ const childInnerText = Array.from(item.children)
20
+ .map(child => child.innerText)
21
+ .join('\n');
22
+ const value = item.value;
23
+ const filterTarget = (itemInnerText +
24
+ childInnerText +
25
+ value).toUpperCase();
26
+ const terms = searchText
27
+ .toUpperCase()
28
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
29
+ .trim()
30
+ .split(/\s+/g);
31
+ (terms.length === 1 && terms[0] === '') ||
32
+ terms.every(term => {
33
+ // regexp escape
34
+ const reTerm = new RegExp(`*${term}*`.replace(/\*/g, '.*').replace(/\?/g, '.{1}'), 'i');
35
+ return reTerm.test(filterTarget);
36
+ })
37
+ ? slotItem(item).classList.remove('hidden')
38
+ : slotItem(item).classList.add('hidden');
39
+ }
40
+ /**
41
+ * A mwc-list with mwc-textfield that filters the list items for given or separated terms
42
+ */
43
+ let FilteredList = class FilteredList extends ListBase {
44
+ get existCheckListItem() {
45
+ return this.items.some(item => item instanceof CheckListItem);
46
+ }
47
+ get isAllSelected() {
48
+ return this.items
49
+ .filter(item => !item.disabled)
50
+ .filter(item => item instanceof CheckListItem)
51
+ .every(checkItem => checkItem.selected);
52
+ }
53
+ get isSomeSelected() {
54
+ return this.items
55
+ .filter(item => !item.disabled)
56
+ .filter(item => item instanceof CheckListItem)
57
+ .some(checkItem => checkItem.selected);
58
+ }
59
+ onCheckAll() {
60
+ const select = !this.isAllSelected;
61
+ this.items
62
+ .filter(item => !item.disabled && !item.classList.contains('hidden'))
63
+ .forEach(item => (item.selected = select));
64
+ }
65
+ onFilterInput() {
66
+ Array.from(this.querySelectorAll('mwc-list-item, mwc-check-list-item, mwc-radio-list-item')).forEach(item => hideFiltered(item, this.searchField.value));
67
+ }
68
+ onListItemConnected(e) {
69
+ super.onListItemConnected(e);
70
+ this.requestUpdate();
71
+ }
72
+ update(changedProperties) {
73
+ super.update(changedProperties);
74
+ // regenerate filtering of text
75
+ this.onFilterInput();
76
+ }
77
+ constructor() {
78
+ super();
79
+ /** Whether the check all option (checkbox next to search text field) is activated */
80
+ this.disableCheckAll = false;
81
+ this.addEventListener('selected', () => {
82
+ this.requestUpdate();
83
+ });
84
+ }
85
+ renderCheckAll() {
86
+ return this.existCheckListItem && !this.disableCheckAll
87
+ ? html `<mwc-formfield class="checkall"
88
+ ><mwc-checkbox
89
+ ?indeterminate=${!this.isAllSelected && this.isSomeSelected}
90
+ ?checked=${this.isAllSelected}
91
+ @change=${() => {
92
+ this.onCheckAll();
93
+ }}
94
+ ></mwc-checkbox
95
+ ></mwc-formfield>`
96
+ : html ``;
97
+ }
98
+ render() {
99
+ return html `<div id="tfcontainer">
100
+ <abbr title="${this.searchFieldLabel ?? get('filter')}"
101
+ ><mwc-textfield
102
+ label="${this.searchFieldLabel ?? ''}"
103
+ iconTrailing="search"
104
+ outlined
105
+ @input=${() => this.onFilterInput()}
106
+ ></mwc-textfield
107
+ ></abbr>
108
+ ${this.renderCheckAll()}
109
+ </div>
110
+ ${super.render()}`;
111
+ }
112
+ };
113
+ FilteredList.styles = css `
114
+ ${unsafeCSS(List.styles)}
115
+
116
+ #tfcontainer {
117
+ display: flex;
118
+ flex: auto;
119
+ }
120
+
121
+ ::slotted(.hidden) {
122
+ display: none;
123
+ }
124
+
125
+ abbr {
126
+ display: flex;
127
+ flex: auto;
128
+ margin: 8px;
129
+ text-decoration: none;
130
+ border-bottom: none;
131
+ }
132
+
133
+ mwc-textfield {
134
+ width: 100%;
135
+ --mdc-shape-small: 28px;
136
+ }
137
+
138
+ mwc-formfield.checkall {
139
+ padding-right: 8px;
140
+ }
141
+
142
+ .mdc-list {
143
+ padding-inline-start: 0px;
144
+ }
145
+ `;
146
+ __decorate([
147
+ property({ type: String })
148
+ ], FilteredList.prototype, "searchFieldLabel", void 0);
149
+ __decorate([
150
+ property({ type: Boolean })
151
+ ], FilteredList.prototype, "disableCheckAll", void 0);
152
+ __decorate([
153
+ state()
154
+ ], FilteredList.prototype, "existCheckListItem", null);
155
+ __decorate([
156
+ state()
157
+ ], FilteredList.prototype, "isAllSelected", null);
158
+ __decorate([
159
+ state()
160
+ ], FilteredList.prototype, "isSomeSelected", null);
161
+ __decorate([
162
+ query('mwc-textfield')
163
+ ], FilteredList.prototype, "searchField", void 0);
164
+ FilteredList = __decorate([
165
+ customElement('filtered-list')
166
+ ], FilteredList);
167
+ export { FilteredList };
168
+ //# sourceMappingURL=filtered-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filtered-list.js","sourceRoot":"","sources":["../../../src/filtered-list.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n customElement,\n html,\n property,\n query,\n state,\n TemplateResult,\n unsafeCSS,\n} from 'lit-element';\nimport { get } from 'lit-translate';\n\nimport '@material/mwc-checkbox';\nimport '@material/mwc-formfield';\nimport '@material/mwc-textfield';\nimport { CheckListItem } from '@material/mwc-list/mwc-check-list-item';\nimport { List } from '@material/mwc-list';\nimport { ListBase } from '@material/mwc-list/mwc-list-base';\nimport { ListItemBase } from '@material/mwc-list/mwc-list-item-base';\nimport { TextField } from '@material/mwc-textfield';\n\nfunction slotItem(item: Element): Element {\n if (!item.closest('filtered-list') || !item.parentElement) return item;\n if (item.parentElement instanceof FilteredList) return item;\n return slotItem(item.parentElement);\n}\n\nfunction hideFiltered(item: ListItemBase, searchText: string): void {\n const itemInnerText = item.innerText + '\\n';\n const childInnerText = Array.from(item.children)\n .map(child => (<HTMLElement>child).innerText)\n .join('\\n');\n const value = item.value;\n\n const filterTarget: string = (\n itemInnerText +\n childInnerText +\n value\n ).toUpperCase();\n\n const terms: string[] = searchText\n .toUpperCase()\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .trim()\n .split(/\\s+/g);\n\n (terms.length === 1 && terms[0] === '') ||\n terms.every(term => {\n // regexp escape\n const reTerm = new RegExp(\n `*${term}*`.replace(/\\*/g, '.*').replace(/\\?/g, '.{1}'),\n 'i'\n );\n return reTerm.test(filterTarget);\n })\n ? slotItem(item).classList.remove('hidden')\n : slotItem(item).classList.add('hidden');\n}\n\n/**\n * A mwc-list with mwc-textfield that filters the list items for given or separated terms\n */\n@customElement('filtered-list')\nexport class FilteredList extends ListBase {\n /** search mwc-textfield label property */\n @property({ type: String })\n searchFieldLabel?: string;\n /** Whether the check all option (checkbox next to search text field) is activated */\n @property({ type: Boolean })\n disableCheckAll = false;\n\n @state()\n private get existCheckListItem(): boolean {\n return this.items.some(item => item instanceof CheckListItem);\n }\n\n @state()\n private get isAllSelected(): boolean {\n return this.items\n .filter(item => !item.disabled)\n .filter(item => item instanceof CheckListItem)\n .every(checkItem => checkItem.selected);\n }\n\n @state()\n private get isSomeSelected(): boolean {\n return this.items\n .filter(item => !item.disabled)\n .filter(item => item instanceof CheckListItem)\n .some(checkItem => checkItem.selected);\n }\n\n @query('mwc-textfield') searchField!: TextField;\n\n private onCheckAll(): void {\n const select = !this.isAllSelected;\n this.items\n .filter(item => !item.disabled && !item.classList.contains('hidden'))\n .forEach(item => (item.selected = select));\n }\n\n onFilterInput(): void {\n Array.from(\n this.querySelectorAll(\n 'mwc-list-item, mwc-check-list-item, mwc-radio-list-item'\n )\n ).forEach(item =>\n hideFiltered(item as ListItemBase, this.searchField.value)\n );\n }\n\n protected onListItemConnected(e: CustomEvent): void {\n super.onListItemConnected(e);\n this.requestUpdate();\n }\n\n protected update(\n changedProperties: Map<string | number | symbol, unknown>\n ): void {\n super.update(changedProperties);\n // regenerate filtering of text\n this.onFilterInput();\n }\n\n constructor() {\n super();\n this.addEventListener('selected', () => {\n this.requestUpdate();\n });\n }\n\n private renderCheckAll(): TemplateResult {\n return this.existCheckListItem && !this.disableCheckAll\n ? html`<mwc-formfield class=\"checkall\"\n ><mwc-checkbox\n ?indeterminate=${!this.isAllSelected && this.isSomeSelected}\n ?checked=${this.isAllSelected}\n @change=${() => {\n this.onCheckAll();\n }}\n ></mwc-checkbox\n ></mwc-formfield>`\n : html``;\n }\n\n render(): TemplateResult {\n return html`<div id=\"tfcontainer\">\n <abbr title=\"${this.searchFieldLabel ?? get('filter')}\"\n ><mwc-textfield\n label=\"${this.searchFieldLabel ?? ''}\"\n iconTrailing=\"search\"\n outlined\n @input=${() => this.onFilterInput()}\n ></mwc-textfield\n ></abbr>\n ${this.renderCheckAll()}\n </div>\n ${super.render()}`;\n }\n\n static styles = css`\n ${unsafeCSS(List.styles)}\n\n #tfcontainer {\n display: flex;\n flex: auto;\n }\n\n ::slotted(.hidden) {\n display: none;\n }\n\n abbr {\n display: flex;\n flex: auto;\n margin: 8px;\n text-decoration: none;\n border-bottom: none;\n }\n\n mwc-textfield {\n width: 100%;\n --mdc-shape-small: 28px;\n }\n\n mwc-formfield.checkall {\n padding-right: 8px;\n }\n\n .mdc-list {\n padding-inline-start: 0px;\n }\n `;\n}\n"]}
@@ -0,0 +1,207 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, customElement, html, LitElement, property, query, } from 'lit-element';
3
+ import { until } from 'lit-html/directives/until';
4
+ import { get } from 'lit-translate';
5
+ import '@material/mwc-icon';
6
+ import '@material/mwc-list';
7
+ import '@material/mwc-list/mwc-list-item';
8
+ import './filtered-list.js';
9
+ import { depth } from './foundation.js';
10
+ import { ifDefined } from 'lit-html/directives/if-defined';
11
+ const waitingList = html `<div class="column">
12
+ <mwc-list
13
+ ><mwc-list-item noninteractive hasMeta
14
+ >${get('loading')}<mwc-icon slot="meta">pending</mwc-icon></mwc-list-item
15
+ ></mwc-list
16
+ >
17
+ </div>`;
18
+ let FinderList = class FinderList extends LitElement {
19
+ constructor() {
20
+ super(...arguments);
21
+ this.selection = {};
22
+ this.multi = false;
23
+ this.read = async (path) => {
24
+ return {
25
+ path,
26
+ header: html `<h2>${'/' + path.join('/')}</h2>`,
27
+ entries: [],
28
+ };
29
+ };
30
+ this.loaded = Promise.resolve();
31
+ }
32
+ get depth() {
33
+ return depth(this.selection);
34
+ }
35
+ get paths() {
36
+ return this.getPaths();
37
+ }
38
+ set paths(paths) {
39
+ const selection = {};
40
+ for (const path of paths) {
41
+ let i = selection;
42
+ for (const name of path) {
43
+ if (!Object.prototype.hasOwnProperty.call(i, name))
44
+ i[name] = {};
45
+ i = i[name];
46
+ }
47
+ }
48
+ this.selection = selection;
49
+ }
50
+ get path() {
51
+ return this.paths[0] ?? [];
52
+ }
53
+ set path(path) {
54
+ this.paths = [path];
55
+ }
56
+ getTitle(path) {
57
+ return path.join('/');
58
+ }
59
+ getDisplayString(entry, path) {
60
+ return entry;
61
+ }
62
+ getPaths(depth) {
63
+ let paths = Object.keys(this.selection).map(key => [key]);
64
+ let i = depth ?? this.depth - 1;
65
+ while (i-- > 0) {
66
+ paths = paths.flatMap(path => {
67
+ let dir = this.selection;
68
+ for (const entry of path)
69
+ dir = dir[entry]; // recursive descent
70
+ const newPaths = Object.keys(dir).map(entry => path.concat(entry));
71
+ return newPaths.length === 0 ? [path] : newPaths;
72
+ });
73
+ }
74
+ return depth === undefined
75
+ ? paths
76
+ : paths.filter(path => path.length > depth);
77
+ }
78
+ multiSelect(event, path, clicked) {
79
+ let dir = this.selection;
80
+ for (const entry of path)
81
+ dir = dir[entry]; // recursive descent
82
+ if (dir && dir[clicked])
83
+ delete dir[clicked];
84
+ // deselect if selected
85
+ else
86
+ dir[clicked] = {}; // select otherwise
87
+ }
88
+ singleSelect(event, path, clicked) {
89
+ if (this.path[path.length] === clicked)
90
+ this.path = path;
91
+ // deselect if selected
92
+ else
93
+ this.path = path.concat(clicked); // select otherwise
94
+ }
95
+ async select(event, path) {
96
+ const clicked = event.target.selected.value;
97
+ if (this.multi)
98
+ this.multiSelect(event, path, clicked);
99
+ else
100
+ this.singleSelect(event, path, clicked);
101
+ this.requestUpdate();
102
+ await this.updateComplete;
103
+ await new Promise(resolve => setTimeout(resolve, 250));
104
+ this.container.scrollLeft = 1000 * this.depth;
105
+ }
106
+ renderDirectory(path, entries) {
107
+ return html `<filtered-list
108
+ @selected=${(e) => this.select(e, path)}
109
+ searchFieldLabel="${this.getTitle(path)}"
110
+ >
111
+ ${entries.map(entry => html `<mwc-list-item
112
+ value="${entry}"
113
+ ?activated=${this.getPaths(path.length)
114
+ .map(p => JSON.stringify(p))
115
+ .includes(JSON.stringify(path.concat(entry)))}
116
+ >${this.getDisplayString(entry, path)}</mwc-list-item
117
+ >`)}
118
+ </filtered-list>`;
119
+ }
120
+ async renderColumn(column) {
121
+ const paths = this.getPaths(column);
122
+ const dirs = paths.map(path => this.read(path));
123
+ const lists = [];
124
+ for await (const { header, entries, path } of dirs) {
125
+ if (header || entries.length > 0)
126
+ lists.push(html `${ifDefined(header)} ${this.renderDirectory(path, entries)}`);
127
+ }
128
+ if (lists.length === 0)
129
+ return html ``;
130
+ return html `<div class="column">${lists}</div>`;
131
+ }
132
+ render() {
133
+ const columns = new Array(this.depth)
134
+ .fill(0)
135
+ .map((_, index) => this.renderColumn(index));
136
+ this.loaded = Promise.allSettled(columns).then();
137
+ return html `<div class="pane">
138
+ ${columns.map(column => until(column, waitingList))}
139
+ </div>`;
140
+ }
141
+ };
142
+ FinderList.styles = css `
143
+ div.pane {
144
+ display: flex;
145
+ flex-direction: row;
146
+ overflow: auto;
147
+ }
148
+
149
+ h2 {
150
+ color: var(--mdc-theme-primary);
151
+ }
152
+
153
+ section {
154
+ display: flex;
155
+ flex-direction: column;
156
+ width: max-content;
157
+ }
158
+
159
+ section > mwc-list {
160
+ margin-top: 76px;
161
+ }
162
+
163
+ a {
164
+ font-weight: 600;
165
+ font-variant: small-caps;
166
+ text-transform: lowercase;
167
+ text-decoration: none;
168
+ color: var(--mdc-theme-primary);
169
+ }
170
+
171
+ a:link {
172
+ color: var(--mdc-theme-error);
173
+ }
174
+
175
+ a:visited {
176
+ color: var(--mdc-theme-secondary);
177
+ }
178
+ `;
179
+ __decorate([
180
+ property({ type: Object })
181
+ ], FinderList.prototype, "selection", void 0);
182
+ __decorate([
183
+ property({ type: Boolean })
184
+ ], FinderList.prototype, "multi", void 0);
185
+ __decorate([
186
+ property({ type: Number })
187
+ ], FinderList.prototype, "depth", null);
188
+ __decorate([
189
+ property({ type: Array })
190
+ ], FinderList.prototype, "paths", null);
191
+ __decorate([
192
+ property({ type: Array })
193
+ ], FinderList.prototype, "path", null);
194
+ __decorate([
195
+ property({ attribute: false })
196
+ ], FinderList.prototype, "read", void 0);
197
+ __decorate([
198
+ property({ attribute: false })
199
+ ], FinderList.prototype, "loaded", void 0);
200
+ __decorate([
201
+ query('div')
202
+ ], FinderList.prototype, "container", void 0);
203
+ FinderList = __decorate([
204
+ customElement('finder-list')
205
+ ], FinderList);
206
+ export { FinderList };
207
+ //# sourceMappingURL=finder-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finder-list.js","sourceRoot":"","sources":["../../../src/finder-list.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n customElement,\n html,\n LitElement,\n property,\n query,\n TemplateResult,\n} from 'lit-element';\nimport { until } from 'lit-html/directives/until';\nimport { get } from 'lit-translate';\n\nimport '@material/mwc-icon';\nimport '@material/mwc-list';\nimport '@material/mwc-list/mwc-list-item';\nimport { List } from '@material/mwc-list';\nimport { SingleSelectedEvent } from '@material/mwc-list/mwc-list-foundation';\nimport { ListItem } from '@material/mwc-list/mwc-list-item';\n\nimport './filtered-list.js';\nimport { depth } from './foundation.js';\nimport { ifDefined } from 'lit-html/directives/if-defined';\n\nexport type Selection = { [name: string]: Selection };\n\nexport type Path = string[];\nexport interface Directory {\n path: Path;\n header?: TemplateResult;\n entries: string[];\n}\n\nconst waitingList = html`<div class=\"column\">\n <mwc-list\n ><mwc-list-item noninteractive hasMeta\n >${get('loading')}<mwc-icon slot=\"meta\">pending</mwc-icon></mwc-list-item\n ></mwc-list\n >\n</div>`;\n\n@customElement('finder-list')\nexport class FinderList extends LitElement {\n @property({ type: Object })\n selection: Selection = {};\n\n @property({ type: Boolean })\n multi = false;\n\n @property({ type: Number })\n get depth(): number {\n return depth(this.selection);\n }\n\n @property({ type: Array })\n get paths(): Path[] {\n return this.getPaths();\n }\n set paths(paths: Path[]) {\n const selection: Selection = {};\n for (const path of paths) {\n let i = selection;\n for (const name of path) {\n if (!Object.prototype.hasOwnProperty.call(i, name)) i[name] = {};\n i = i[name];\n }\n }\n this.selection = selection;\n }\n\n @property({ type: Array })\n get path(): Path {\n return this.paths[0] ?? [];\n }\n set path(path: Path) {\n this.paths = [path];\n }\n\n @property({ attribute: false })\n read: (path: Path) => Promise<Directory> = async path => {\n return {\n path,\n header: html`<h2>${'/' + path.join('/')}</h2>`,\n entries: [],\n };\n };\n\n @property({ attribute: false })\n loaded: Promise<void> = Promise.resolve();\n\n getTitle(path: string[]): string {\n return path.join('/');\n }\n\n getDisplayString(entry: string, path: string[]): string {\n return entry;\n }\n\n @query('div')\n container!: Element;\n\n private getPaths(depth?: number): Path[] {\n let paths: Path[] = Object.keys(this.selection).map(key => [key]);\n\n let i = depth ?? this.depth - 1;\n while (i-- > 0) {\n paths = paths.flatMap(path => {\n let dir = this.selection;\n for (const entry of path) dir = dir[entry]; // recursive descent\n const newPaths = Object.keys(dir).map(entry => path.concat(entry));\n return newPaths.length === 0 ? [path] : newPaths;\n });\n }\n\n return depth === undefined\n ? paths\n : paths.filter(path => path.length > depth);\n }\n\n multiSelect(event: SingleSelectedEvent, path: Path, clicked: string): void {\n let dir = this.selection;\n for (const entry of path) dir = dir[entry]; // recursive descent\n\n if (dir && dir[clicked]) delete dir[clicked];\n // deselect if selected\n else dir[clicked] = {}; // select otherwise\n }\n\n singleSelect(event: SingleSelectedEvent, path: Path, clicked: string): void {\n if (this.path[path.length] === clicked) this.path = path;\n // deselect if selected\n else this.path = path.concat(clicked); // select otherwise\n }\n\n async select(event: SingleSelectedEvent, path: Path): Promise<void> {\n const clicked = (<ListItem>(<List>event.target).selected).value;\n\n if (this.multi) this.multiSelect(event, path, clicked);\n else this.singleSelect(event, path, clicked);\n\n this.requestUpdate();\n await this.updateComplete;\n await new Promise(resolve => setTimeout(resolve, 250));\n this.container.scrollLeft = 1000 * this.depth;\n }\n\n renderDirectory(path: Path, entries: string[]): TemplateResult {\n return html`<filtered-list\n @selected=${(e: SingleSelectedEvent) => this.select(e, path)}\n searchFieldLabel=\"${this.getTitle(path)}\"\n >\n ${entries.map(\n entry =>\n html`<mwc-list-item\n value=\"${entry}\"\n ?activated=${this.getPaths(path.length)\n .map(p => JSON.stringify(p))\n .includes(JSON.stringify(path.concat(entry)))}\n >${this.getDisplayString(entry, path)}</mwc-list-item\n >`\n )}\n </filtered-list>`;\n }\n\n async renderColumn(column: number): Promise<TemplateResult> {\n const paths = this.getPaths(column);\n\n const dirs = paths.map(path => this.read(path));\n const lists: TemplateResult[] = [];\n\n for await (const { header, entries, path } of dirs) {\n if (header || entries.length > 0)\n lists.push(\n html`${ifDefined(header)} ${this.renderDirectory(path, entries)}`\n );\n }\n\n if (lists.length === 0) return html``;\n return html`<div class=\"column\">${lists}</div>`;\n }\n\n render(): TemplateResult {\n const columns = new Array(this.depth)\n .fill(0)\n .map((_, index) => this.renderColumn(index));\n this.loaded = Promise.allSettled(columns).then();\n return html`<div class=\"pane\">\n ${columns.map(column => until(column, waitingList))}\n </div>`;\n }\n\n static styles = css`\n div.pane {\n display: flex;\n flex-direction: row;\n overflow: auto;\n }\n\n h2 {\n color: var(--mdc-theme-primary);\n }\n\n section {\n display: flex;\n flex-direction: column;\n width: max-content;\n }\n\n section > mwc-list {\n margin-top: 76px;\n }\n\n a {\n font-weight: 600;\n font-variant: small-caps;\n text-transform: lowercase;\n text-decoration: none;\n color: var(--mdc-theme-primary);\n }\n\n a:link {\n color: var(--mdc-theme-error);\n }\n\n a:visited {\n color: var(--mdc-theme-secondary);\n }\n `;\n}\n"]}