@xwiki/cristal-dsvuetify 0.25.0 → 1.0.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.
Files changed (48) hide show
  1. package/dist/{index-D7wZ4Kvq.js → index-CkeFEgm6.js} +8741 -8708
  2. package/dist/index-CkeFEgm6.js.map +1 -0
  3. package/dist/index.es.js +6 -8
  4. package/dist/index.umd.js +12 -14
  5. package/dist/index.umd.js.map +1 -1
  6. package/dist/translations-CXVK8zyA.js +21 -0
  7. package/dist/{translations-BVK9UR9x.js.map → translations-CXVK8zyA.js.map} +1 -1
  8. package/dist/vue/form/x-text-field.vue.d.ts +16 -1
  9. package/dist/vue/x-tree.vue.d.ts +19 -14
  10. package/dist/{x-checkbox-CN6QxF3B.js → x-checkbox-CxPnLGd0.js} +5 -5
  11. package/dist/{x-checkbox-CN6QxF3B.js.map → x-checkbox-CxPnLGd0.js.map} +1 -1
  12. package/dist/{x-file-input-CkjbGsMG.js → x-file-input-CEz4Wmf4.js} +3 -3
  13. package/dist/{x-file-input-CkjbGsMG.js.map → x-file-input-CEz4Wmf4.js.map} +1 -1
  14. package/dist/{x-form-dk8EltHS.js → x-form-SvpVocOb.js} +2 -2
  15. package/dist/{x-form-dk8EltHS.js.map → x-form-SvpVocOb.js.map} +1 -1
  16. package/dist/x-menu-DUp-JvdG.js +31 -0
  17. package/dist/{x-menu-CZMwPcag.js.map → x-menu-DUp-JvdG.js.map} +1 -1
  18. package/dist/{x-select-CpWujZTj.js → x-select-BduzHCet.js} +6 -6
  19. package/dist/{x-select-CpWujZTj.js.map → x-select-BduzHCet.js.map} +1 -1
  20. package/dist/x-text-field-CvC6id2f.js +50 -0
  21. package/dist/{x-text-field-wiH4MWRR.js.map → x-text-field-CvC6id2f.js.map} +1 -1
  22. package/dist/x-tree-CbliYwVw.js +70 -0
  23. package/dist/x-tree-CbliYwVw.js.map +1 -0
  24. package/langs/translation-de.json +1 -3
  25. package/langs/translation-en.json +1 -3
  26. package/langs/translation-fr.json +1 -3
  27. package/package.json +15 -15
  28. package/src/components/vuetifyDesignSystemLoader.ts +0 -10
  29. package/src/vue/css/style.css +1 -0
  30. package/src/vue/form/x-text-field.vue +5 -1
  31. package/src/vue/x-menu.vue +1 -1
  32. package/src/vue/x-tree.vue +24 -5
  33. package/dist/index-D7wZ4Kvq.js.map +0 -1
  34. package/dist/index.es-BOA77_Kh.js +0 -10
  35. package/dist/index.es-BOA77_Kh.js.map +0 -1
  36. package/dist/translations-BVK9UR9x.js +0 -27
  37. package/dist/vue/form/x-navigation-tree-select.vue.d.ts +0 -14
  38. package/dist/vue/x-navigation-tree.vue.d.ts +0 -5
  39. package/dist/x-menu-CZMwPcag.js +0 -31
  40. package/dist/x-navigation-tree-BkJKd5J2.js +0 -188
  41. package/dist/x-navigation-tree-BkJKd5J2.js.map +0 -1
  42. package/dist/x-navigation-tree-select-VRsQSFA3.js +0 -109
  43. package/dist/x-navigation-tree-select-VRsQSFA3.js.map +0 -1
  44. package/dist/x-text-field-wiH4MWRR.js +0 -45
  45. package/dist/x-tree-CkUElkU9.js +0 -51
  46. package/dist/x-tree-CkUElkU9.js.map +0 -1
  47. package/src/vue/form/x-navigation-tree-select.vue +0 -146
  48. package/src/vue/x-navigation-tree.vue +0 -355
@@ -1,146 +0,0 @@
1
- <!--
2
- See the LICENSE file distributed with this work for additional
3
- information regarding copyright ownership.
4
-
5
- This is free software; you can redistribute it and/or modify it
6
- under the terms of the GNU Lesser General Public License as
7
- published by the Free Software Foundation; either version 2.1 of
8
- the License, or (at your option) any later version.
9
-
10
- This software is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- Lesser General Public License for more details.
14
-
15
- You should have received a copy of the GNU Lesser General Public
16
- License along with this software; if not, write to the Free
17
- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
- 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
- -->
20
- <script setup lang="ts">
21
- import messages from "../../translations";
22
- import XBreadcrumb from "../x-breadcrumb.vue";
23
- import { navigationTreeSelectPropsDefaults } from "@xwiki/platform-dsapi";
24
- import { EntityType, SpaceReference } from "@xwiki/platform-model-api";
25
- import { inject, onMounted, ref } from "vue";
26
- import { useI18n } from "vue-i18n";
27
- import { VTextField } from "vuetify/components/VTextField";
28
- import type {
29
- PageHierarchyItem,
30
- PageHierarchyResolver,
31
- PageHierarchyResolverProvider,
32
- } from "@xwiki/cristal-hierarchy-api";
33
- import type { CristalApp } from "@xwiki/platform-api";
34
- import type { NavigationTreeSelectProps } from "@xwiki/platform-dsapi";
35
- import type { DocumentReference } from "@xwiki/platform-model-api";
36
- import type {
37
- ModelReferenceHandler,
38
- ModelReferenceHandlerProvider,
39
- } from "@xwiki/platform-model-reference-api";
40
- import type { NavigationTreeNode } from "@xwiki/platform-navigation-tree-api";
41
- import type { Ref } from "vue";
42
-
43
- const cristal: CristalApp = inject<CristalApp>("cristal")!;
44
- const hierarchyResolver: PageHierarchyResolver = cristal
45
- .getContainer()
46
- .get<PageHierarchyResolverProvider>("PageHierarchyResolverProvider")
47
- .get()!;
48
- const referenceHandler: ModelReferenceHandler = cristal
49
- .getContainer()
50
- .get<ModelReferenceHandlerProvider>("ModelReferenceHandlerProvider")
51
- .get()!;
52
-
53
- const { t } = useI18n({
54
- messages,
55
- });
56
- const props = withDefaults(
57
- defineProps<NavigationTreeSelectProps>(),
58
- navigationTreeSelectPropsDefaults,
59
- );
60
- const model = defineModel<SpaceReference | DocumentReference>();
61
-
62
- const openedLocationDialog: Ref<boolean> = ref(false);
63
- const hierarchy: Ref<Array<PageHierarchyItem>> = ref([]);
64
- let selectedPage: DocumentReference | undefined;
65
-
66
- onMounted(async () => {
67
- selectedPage = props.currentPageReference;
68
- model.value = props.currentPageReference!.space;
69
- hierarchy.value = await hierarchyResolver.getPageHierarchy(
70
- props.currentPageReference!.space!,
71
- false,
72
- );
73
- });
74
-
75
- async function treeNodeClickAction(node: NavigationTreeNode) {
76
- if (node.location.type == EntityType.SPACE) {
77
- if (node.location.names.length > 0) {
78
- selectedPage = referenceHandler.createDocumentReference(
79
- node.location.names[node.location.names.length - 1],
80
- new SpaceReference(
81
- node.location.wiki,
82
- ...node.location.names.slice(0, -1),
83
- ),
84
- );
85
- hierarchy.value = await hierarchyResolver.getPageHierarchy(
86
- selectedPage,
87
- false,
88
- );
89
- } else {
90
- selectedPage = undefined;
91
- hierarchy.value = [{ label: node.label, pageId: "", url: node.url }];
92
- }
93
- } else {
94
- selectedPage = node.location;
95
- hierarchy.value = await hierarchyResolver.getPageHierarchy(
96
- selectedPage,
97
- false,
98
- );
99
- }
100
- model.value = node.location;
101
- }
102
- </script>
103
-
104
- <template>
105
- <v-text-field
106
- :label="label"
107
- :hint="help"
108
- :persistent-hint="help !== undefined"
109
- :active="hierarchy.length > 0"
110
- readonly
111
- >
112
- <template #default>
113
- <XBreadcrumb :items="hierarchy"></XBreadcrumb>
114
- </template>
115
- </v-text-field>
116
- <XDialog
117
- v-model="openedLocationDialog"
118
- width="auto"
119
- :title="t('vuetify.tree.select.location.label')"
120
- >
121
- <template #activator>
122
- <x-btn id="change-page-location-button" size="small" color="secondary">
123
- {{ t("vuetify.tree.select.location.label") }}
124
- </x-btn>
125
- </template>
126
- <template #default>
127
- <XNavigationTree
128
- :current-page-reference="selectedPage"
129
- :click-action="treeNodeClickAction"
130
- :include-terminals="includeTerminals"
131
- show-root-node
132
- ></XNavigationTree>
133
- </template>
134
- <template #footer>
135
- <XBtn variant="primary" @click="openedLocationDialog = false">
136
- {{ t("vuetify.tree.select.location.select") }}
137
- </XBtn>
138
- </template>
139
- </XDialog>
140
- </template>
141
-
142
- <style scoped>
143
- .v-treeview {
144
- overflow: auto;
145
- }
146
- </style>
@@ -1,355 +0,0 @@
1
- <!--
2
- See the LICENSE file distributed with this work for additional
3
- information regarding copyright ownership.
4
-
5
- This is free software; you can redistribute it and/or modify it
6
- under the terms of the GNU Lesser General Public License as
7
- published by the Free Software Foundation; either version 2.1 of
8
- the License, or (at your option) any later version.
9
-
10
- This software is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- Lesser General Public License for more details.
14
-
15
- You should have received a copy of the GNU Lesser General Public
16
- License along with this software; if not, write to the Free
17
- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
- 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
- -->
20
- <script setup lang="ts">
21
- /**
22
- * Navigation Tree implemented using Vuetify's VTreeView component.
23
- * In order to use the initial component as a proper Navigation Tree for
24
- * Cristal, a few changes were made:
25
- * - The only node activated matches the current page, or the clicked link if
26
- * the component has a custom clickAction. We want to use actual links so
27
- * that the user can click them normally (to e.g., open them in a new tab).
28
- * So the default behavior of activating a node by clicking anywhere on the
29
- * item was disabled. Default hover effects, such as darkening or changing
30
- * the cursor on items, were also disabled.
31
- */
32
- import { navigationTreePropsDefaults } from "@xwiki/platform-dsapi";
33
- import { SpaceReference } from "@xwiki/platform-model-api";
34
- import { inject, onBeforeMount, ref, watch } from "vue";
35
- import { VTreeview } from "vuetify/components/VTreeview";
36
- import type { CristalApp } from "@xwiki/platform-api";
37
- import type { DocumentService } from "@xwiki/platform-document-api";
38
- import type { NavigationTreeProps } from "@xwiki/platform-dsapi";
39
- import type { DocumentReference } from "@xwiki/platform-model-api";
40
- import type {
41
- NavigationTreeSource,
42
- NavigationTreeSourceProvider,
43
- } from "@xwiki/platform-navigation-tree-api";
44
- import type { Ref } from "vue";
45
-
46
- type TreeItem = {
47
- id: string;
48
- title: string;
49
- href: string;
50
- children?: Array<TreeItem>;
51
- _location: SpaceReference | DocumentReference;
52
- _is_terminal: boolean;
53
- };
54
-
55
- const cristal: CristalApp = inject<CristalApp>("cristal")!;
56
- const documentService: DocumentService = cristal
57
- .getContainer()
58
- .get<DocumentService>("DocumentService");
59
- const treeSource: NavigationTreeSource = cristal
60
- .getContainer()
61
- .get<NavigationTreeSourceProvider>("NavigationTreeSourceProvider")
62
- .get();
63
-
64
- const rootNodes: Ref<Array<TreeItem>> = ref([]);
65
-
66
- const activatedNodes: Ref<Array<string>> = ref(new Array<string>());
67
- const expandedNodes: Ref<unknown> = ref([]);
68
- var isExpanding: boolean = false;
69
-
70
- const props = withDefaults(
71
- defineProps<NavigationTreeProps>(),
72
- navigationTreePropsDefaults,
73
- );
74
-
75
- onBeforeMount(async () => {
76
- const newRootNodes: Array<TreeItem> = [];
77
- for (const node of await getChildNodes("")) {
78
- newRootNodes.push({
79
- id: node.id,
80
- title: node.label,
81
- href: node.url,
82
- children: node.has_children ? [] : undefined,
83
- _location: node.location,
84
- _is_terminal: node.is_terminal,
85
- });
86
- }
87
- if (props.showRootNode) {
88
- rootNodes.value.push({
89
- id: "",
90
- title: "Root",
91
- href: ".",
92
- children: newRootNodes,
93
- _location: new SpaceReference(),
94
- _is_terminal: false,
95
- });
96
- } else {
97
- rootNodes.value.push(...newRootNodes);
98
- }
99
- await expandTree();
100
-
101
- documentService.registerDocumentChangeListener("delete", onDocumentDelete);
102
- documentService.registerDocumentChangeListener("update", onDocumentUpdate);
103
- });
104
-
105
- watch(() => props.currentPageReference, expandTree);
106
-
107
- // TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
108
- // eslint-disable-next-line max-statements
109
- async function expandTree() {
110
- if (props.currentPageReference && !isExpanding) {
111
- isExpanding = true;
112
- const newExpandedNodes = treeSource.getParentNodesId(
113
- props.currentPageReference!,
114
- props.includeTerminals,
115
- props.showRootNode,
116
- );
117
- let i;
118
- let currentNodes = rootNodes.value;
119
- for (i = 0; i < newExpandedNodes.length - 1; i++) {
120
- if (currentNodes) {
121
- for (const node of currentNodes) {
122
- if (node.id == newExpandedNodes[i]) {
123
- if (node.children?.length == 0) {
124
- await lazyLoadChildren(node);
125
- }
126
- if (!(expandedNodes.value as unknown[]).includes(node.id)) {
127
- (expandedNodes.value as unknown[]).push(node.id);
128
- }
129
- currentNodes = node.children!;
130
- }
131
- }
132
- }
133
- }
134
- if (currentNodes) {
135
- for (const node of currentNodes) {
136
- if (node.id == newExpandedNodes[i]) {
137
- activatedNodes.value = [node.id];
138
- // If we have a custom click action, we want to use it on dynamic
139
- // selection.
140
- if (props.clickAction) {
141
- props.clickAction({
142
- id: node.id,
143
- label: node.title,
144
- location: node._location,
145
- url: node.href,
146
- has_children: node.children !== undefined,
147
- is_terminal: node._is_terminal,
148
- });
149
- }
150
- }
151
- }
152
- }
153
- isExpanding = false;
154
- }
155
- }
156
-
157
- async function lazyLoadChildren(item: unknown) {
158
- const treeItem = item as TreeItem;
159
- const childNodes = await getChildNodes(treeItem.id);
160
- for (const child of childNodes) {
161
- treeItem.children?.push({
162
- id: child.id,
163
- title: child.label,
164
- href: child.url,
165
- children: child.has_children ? [] : undefined,
166
- _location: child.location,
167
- _is_terminal: child.is_terminal,
168
- });
169
- }
170
- // If the node doesn't have any children, we update it.
171
- if (childNodes.length == 0) {
172
- treeItem.children = undefined;
173
- }
174
- }
175
-
176
- function clearSelection() {
177
- // Clicking on a node would activate it and this can't be disabled easily.
178
- // With this listener, we ensure that only the first activated node stays
179
- // active.
180
- if (activatedNodes.value.length > 1) {
181
- activatedNodes.value.pop();
182
- }
183
- }
184
-
185
- // TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
186
- // eslint-disable-next-line max-statements
187
- async function onDocumentDelete(page: DocumentReference) {
188
- const parents = treeSource.getParentNodesId(
189
- page,
190
- props.includeTerminals,
191
- props.showRootNode,
192
- );
193
- let currentItem: TreeItem | undefined = undefined;
194
- let currentItemChildren: TreeItem[] | undefined = rootNodes.value;
195
- let notFound = false;
196
-
197
- currentItemsLoop: while (currentItemChildren && !notFound) {
198
- for (const i of currentItemChildren.keys()) {
199
- if (currentItemChildren[i].id == parents[0]) {
200
- if (parents.length == 1) {
201
- currentItemChildren.splice(i, 1);
202
- if (currentItem && currentItemChildren.length == 0) {
203
- currentItem!.children = undefined;
204
- }
205
- return;
206
- } else {
207
- currentItem = currentItemChildren[i];
208
- currentItemChildren = currentItem.children;
209
- parents.shift();
210
- continue currentItemsLoop;
211
- }
212
- }
213
- }
214
- notFound = true;
215
- }
216
- }
217
-
218
- // TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
219
- // eslint-disable-next-line max-statements
220
- async function onDocumentUpdate(page: DocumentReference) {
221
- const parents = treeSource.getParentNodesId(
222
- page,
223
- props.includeTerminals,
224
- props.showRootNode,
225
- );
226
- let currentParent: string | undefined = undefined;
227
- let currentItems: TreeItem[] | undefined = rootNodes.value;
228
- let notFound = false;
229
- let isRoot = true;
230
-
231
- currentItemsLoop: while (currentItems && !notFound) {
232
- for (const i of currentItems.keys()) {
233
- if (currentItems[i].id == parents[0]) {
234
- if (parents.length == 1) {
235
- // Page update
236
- const newItems = await getChildNodes(
237
- currentParent ? currentParent : "",
238
- );
239
- for (const newItem of newItems) {
240
- if (newItem.id == currentItems[i].id) {
241
- currentItems[i].title = newItem.label;
242
- return;
243
- }
244
- }
245
- } else {
246
- currentParent = currentItems[i].id;
247
- if (!currentItems[i].children) {
248
- // This node had no children, we reset this so new ones can be
249
- // loaded lazily.
250
- currentItems[i].children = [];
251
- }
252
- currentItems = currentItems[i].children;
253
- parents.shift();
254
- isRoot = false;
255
- continue currentItemsLoop;
256
- }
257
- }
258
- }
259
- notFound = true;
260
- }
261
-
262
- // New page
263
- if (currentItems.length == 0 && !isRoot) {
264
- // We don't do anything because this node will be loaded lazily anyway.
265
- return;
266
- }
267
- const newItems = await getChildNodes(currentParent ? currentParent : "");
268
- const currentPageParents = props.currentPageReference
269
- ? treeSource.getParentNodesId(
270
- props.currentPageReference!,
271
- props.includeTerminals,
272
- )
273
- : [];
274
- newItemsLoop: for (const newItem of newItems) {
275
- for (const i of currentItems!.keys()) {
276
- if (newItem.id == currentItems![i].id) {
277
- continue newItemsLoop;
278
- }
279
- }
280
- currentItems!.push({
281
- id: newItem.id,
282
- title: newItem.label,
283
- href: newItem.url,
284
- children: newItem.has_children ? [] : undefined,
285
- _location: newItem.location,
286
- _is_terminal: newItem.is_terminal,
287
- });
288
- if (
289
- currentPageParents.length > 0 &&
290
- currentPageParents[currentPageParents.length - 1] === newItem.id
291
- ) {
292
- // If we add a node, and it's the current page, it should be activated.
293
- activatedNodes.value = [newItem.id];
294
- }
295
- }
296
- }
297
-
298
- async function getChildNodes(id: string) {
299
- return (await treeSource.getChildNodes(id)).filter(
300
- (c) => props.includeTerminals || !c.is_terminal,
301
- );
302
- }
303
- </script>
304
-
305
- <template>
306
- <v-treeview
307
- v-model:opened="expandedNodes"
308
- density="compact"
309
- :activated="activatedNodes"
310
- :items="rootNodes"
311
- :load-children="lazyLoadChildren"
312
- activatable
313
- active-strategy="independent"
314
- item-value="id"
315
- @update:activated="clearSelection"
316
- >
317
- <template #title="{ item }: { item: any }">
318
- <a
319
- v-if="props.clickAction"
320
- :href="item.href"
321
- @click.prevent="
322
- activatedNodes = [item.id];
323
- clickAction!({
324
- id: item.id,
325
- label: item.title,
326
- location: item._location,
327
- url: item.href,
328
- has_children: item.children !== undefined,
329
- is_terminal: item._is_terminal,
330
- });
331
- "
332
- >{{ item.title }}</a
333
- >
334
- <a v-else :href="item.href">{{ item.title }}</a>
335
- </template>
336
- </v-treeview>
337
- </template>
338
-
339
- <style scoped>
340
- .v-list {
341
- background: none;
342
- }
343
- :deep(a) {
344
- text-decoration: none;
345
- color: var(--cr-base-text-color);
346
- }
347
- /* Disable hover on items. */
348
- :deep(.v-list-item__overlay) {
349
- --v-hover-opacity: 0;
350
- }
351
- /* Disable hand cursor on items, since we disable the default click action. */
352
- :deep(.v-list-item--link) {
353
- cursor: default;
354
- }
355
- </style>