@xwiki/cristal-dsvuetify 0.11.0 → 0.13.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.
- package/CHANGELOG.md +29 -0
- package/dist/components/vuetifyDesignSystemLoader.d.ts +1 -1
- package/dist/{index-BMliq0dk.js → index-UP1o6s9t.js} +4151 -4114
- package/dist/index-UP1o6s9t.js.map +1 -0
- package/dist/index.es.js +5 -4
- package/dist/index.umd.js +9 -8
- package/dist/index.umd.js.map +1 -1
- package/dist/vue/x-alert.vue.d.ts +15 -1
- package/dist/vue/x-dialog.vue.d.ts +1 -0
- package/dist/vue/x-navigation-tree.vue.d.ts +1 -3
- package/dist/x-alert-Bmt4mXHQ.js +45 -0
- package/dist/x-alert-Bmt4mXHQ.js.map +1 -0
- package/dist/x-avatar-But_Z7ic.js.map +1 -1
- package/dist/x-breadcrumb-C2iUd4Sf.js.map +1 -1
- package/dist/x-btn-DNlhiqjD.js.map +1 -1
- package/dist/x-card-CRM9KUby.js.map +1 -1
- package/dist/x-dialog-C-dMkFJk.js +49 -0
- package/dist/x-dialog-C-dMkFJk.js.map +1 -0
- package/dist/{x-file-input-8euR7G64.js → x-file-input-BsaodA0p.js} +10 -9
- package/dist/x-file-input-BsaodA0p.js.map +1 -0
- package/dist/{x-form-UiBYkCKP.js → x-form-iQFXj1PW.js} +2 -2
- package/dist/{x-form-UiBYkCKP.js.map → x-form-iQFXj1PW.js.map} +1 -1
- package/dist/x-img-BYgs_O1F.js.map +1 -1
- package/dist/x-navigation-tree-DN2Qz7Sm.js +501 -0
- package/dist/x-navigation-tree-DN2Qz7Sm.js.map +1 -0
- package/dist/x-tab-group-ngNByee3.js.map +1 -1
- package/dist/x-text-field-CTsLZhLE.js +31 -0
- package/dist/x-text-field-CTsLZhLE.js.map +1 -0
- package/langs/translation-de.json +4 -0
- package/package.json +18 -10
- package/src/components/componentsInit.ts +1 -1
- package/src/components/vuetifyDesignSystemLoader.ts +12 -9
- package/src/vue/__tests__/utils/vuetify.ts +1 -0
- package/src/vue/__tests__/x-btn.test.ts +4 -3
- package/src/vue/css/style.css +12 -4
- package/src/vue/form/x-file-input.vue +3 -4
- package/src/vue/form/x-text-field.vue +9 -4
- package/src/vue/x-alert.vue +4 -1
- package/src/vue/x-btn.vue +1 -1
- package/src/vue/x-dialog.vue +14 -1
- package/src/vue/x-navigation-tree.vue +136 -46
- package/tsconfig.json +14 -8
- package/vitest.config.ts +1 -1
- package/dist/index-BMliq0dk.js.map +0 -1
- package/dist/x-alert-D8oy1BPL.js +0 -40
- package/dist/x-alert-D8oy1BPL.js.map +0 -1
- package/dist/x-dialog-Ce8KWptm.js +0 -38
- package/dist/x-dialog-Ce8KWptm.js.map +0 -1
- package/dist/x-file-input-8euR7G64.js.map +0 -1
- package/dist/x-navigation-tree-DkVWsvlI.js +0 -449
- package/dist/x-navigation-tree-DkVWsvlI.js.map +0 -1
- package/dist/x-text-field-uL1ePP_x.js +0 -29
- package/dist/x-text-field-uL1ePP_x.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xwiki/cristal-dsvuetify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"license": "LGPL 2.1",
|
|
5
5
|
"author": "XWiki Org Community <contact@xwiki.org>",
|
|
6
6
|
"homepage": "https://cristal.xwiki.org/",
|
|
@@ -22,18 +22,26 @@
|
|
|
22
22
|
},
|
|
23
23
|
"main": "./dist/index.es.js",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"inversify": "6.0
|
|
26
|
-
"vue": "3.5.
|
|
27
|
-
"vue-i18n": "10.0.
|
|
28
|
-
"vuetify": "3.7.
|
|
29
|
-
"@xwiki/cristal-api": "0.
|
|
30
|
-
"@xwiki/cristal-
|
|
31
|
-
"@xwiki/cristal-
|
|
25
|
+
"inversify": "6.2.0",
|
|
26
|
+
"vue": "3.5.13",
|
|
27
|
+
"vue-i18n": "10.0.5",
|
|
28
|
+
"vuetify": "3.7.5",
|
|
29
|
+
"@xwiki/cristal-document-api": "0.13.0",
|
|
30
|
+
"@xwiki/cristal-navigation-tree-api": "0.13.0",
|
|
31
|
+
"@xwiki/cristal-api": "0.13.0",
|
|
32
|
+
"@xwiki/cristal-dsapi": "0.13.0",
|
|
33
|
+
"@xwiki/cristal-model-api": "0.13.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"reflect-metadata": "0.2.2"
|
|
32
37
|
},
|
|
33
38
|
"devDependencies": {
|
|
34
39
|
"@vue/test-utils": "2.4.6",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
40
|
+
"reflect-metadata": "0.2.2",
|
|
41
|
+
"typescript": "5.6.3",
|
|
42
|
+
"vite": "6.0.3",
|
|
43
|
+
"vue-tsc": "2.1.10",
|
|
44
|
+
"@xwiki/cristal-dev-config": "0.13.0"
|
|
37
45
|
},
|
|
38
46
|
"scripts": {
|
|
39
47
|
"build": "pnpm compile",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
import { VuetifyDesignSystemLoader } from "./vuetifyDesignSystemLoader";
|
|
21
22
|
import type { DesignSystemLoader } from "@xwiki/cristal-api";
|
|
22
23
|
import type { Container } from "inversify";
|
|
23
|
-
import { VuetifyDesignSystemLoader } from "./vuetifyDesignSystemLoader";
|
|
24
24
|
|
|
25
25
|
export default class ComponentInit {
|
|
26
26
|
constructor(container: Container) {
|
|
@@ -18,20 +18,23 @@
|
|
|
18
18
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import
|
|
21
|
+
import { registerAsyncComponent } from "@xwiki/cristal-api";
|
|
22
|
+
import { injectable } from "inversify";
|
|
23
|
+
import { createVuetify } from "vuetify";
|
|
24
|
+
// eslint-disable-next-line import/namespace
|
|
22
25
|
import * as components from "vuetify/components";
|
|
23
26
|
import { VCol, VContainer, VRow, VTextField } from "vuetify/components";
|
|
24
|
-
import type { DesignSystemLoader } from "@xwiki/cristal-api";
|
|
25
27
|
|
|
26
|
-
import { createVuetify } from "vuetify";
|
|
27
|
-
import colors from "vuetify/util/colors";
|
|
28
|
-
import { mdi } from "vuetify/iconsets/mdi";
|
|
29
28
|
import * as directives from "vuetify/directives";
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
29
|
+
import { mdi } from "vuetify/iconsets/mdi";
|
|
30
|
+
import { blue, blueGrey } from "vuetify/util/colors";
|
|
31
|
+
import type { DesignSystemLoader } from "@xwiki/cristal-api";
|
|
32
|
+
import type { App } from "vue";
|
|
32
33
|
|
|
33
34
|
@injectable()
|
|
34
35
|
export class VuetifyDesignSystemLoader implements DesignSystemLoader {
|
|
36
|
+
// TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
|
|
37
|
+
// eslint-disable-next-line max-statements
|
|
35
38
|
loadDesignSystem(app: App): void {
|
|
36
39
|
/*
|
|
37
40
|
// Manuel importing to reduce build size
|
|
@@ -63,8 +66,8 @@ export class VuetifyDesignSystemLoader implements DesignSystemLoader {
|
|
|
63
66
|
dark: false,
|
|
64
67
|
colors: {
|
|
65
68
|
background: "#FFFFFF",
|
|
66
|
-
primary:
|
|
67
|
-
secondary:
|
|
69
|
+
primary: blue.darken4,
|
|
70
|
+
secondary: blueGrey.darken4,
|
|
68
71
|
},
|
|
69
72
|
},
|
|
70
73
|
},
|
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
18
18
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
19
19
|
*/
|
|
20
|
-
|
|
21
|
-
import { mount, VueWrapper } from "@vue/test-utils";
|
|
22
|
-
import XBtn from "../x-btn.vue";
|
|
20
|
+
|
|
23
21
|
import { addVuetifyOptions } from "./utils/vuetify";
|
|
22
|
+
import XBtn from "../x-btn.vue";
|
|
23
|
+
import { VueWrapper, mount } from "@vue/test-utils";
|
|
24
|
+
import { describe, expect, it } from "vitest";
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Mount a XBtn component with the default configuration.
|
package/src/vue/css/style.css
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
18
18
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
19
19
|
*/
|
|
20
|
+
|
|
20
21
|
.load-spinner {
|
|
21
22
|
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><circle fill="%23B9B9B9" stroke="%23B9B9B9" stroke-width="6" r="15" cx="40" cy="100"><animate attributeName="opacity" calcMode="spline" dur="2" values="1;0;1;" keySplines=".5 0 .5 1;.5 0 .5 1" repeatCount="indefinite" begin="-.4"></animate></circle><circle fill="%23B9B9B9" stroke="%23B9B9B9" stroke-width="6" r="15" cx="100" cy="100"><animate attributeName="opacity" calcMode="spline" dur="2" values="1;0;1;" keySplines=".5 0 .5 1;.5 0 .5 1" repeatCount="indefinite" begin="-.2"></animate></circle><circle fill="%23B9B9B9" stroke="%23B9B9B9" stroke-width="6" r="15" cx="160" cy="100"><animate attributeName="opacity" calcMode="spline" dur="2" values="1;0;1;" keySplines=".5 0 .5 1;.5 0 .5 1" repeatCount="indefinite" begin="0"></animate></circle></svg>');
|
|
22
23
|
background-size: cover;
|
|
@@ -31,7 +32,8 @@
|
|
|
31
32
|
--cr-sizes-collapsed-main-sidebar-width: 32px; /*The width of the bar that gets shown containing the menu button to reopen the standard main main sidebar*/
|
|
32
33
|
--cr-base-font-size: 16px;
|
|
33
34
|
--cr-base-text-color: var(--cr-color-gray-950);
|
|
34
|
-
|
|
35
|
+
--cr-base-link-color: var(--cr-color-sky-700);
|
|
36
|
+
--cr-base-visited-link-color: var(--cr-color-blue-700);
|
|
35
37
|
|
|
36
38
|
/*
|
|
37
39
|
* Typography
|
|
@@ -81,9 +83,9 @@
|
|
|
81
83
|
--cr-focus-ring: var(--cr-focus-ring-style) var(--cr-focus-ring-width) var(--cr-focus-ring-color);
|
|
82
84
|
--cr-focus-ring-offset: 1px;
|
|
83
85
|
|
|
84
|
-
/*
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
/*
|
|
87
|
+
* Color Primitives
|
|
88
|
+
*/
|
|
87
89
|
|
|
88
90
|
/* Gray */
|
|
89
91
|
--cr-color-gray-50: hsl(0 0% 97.5%);
|
|
@@ -534,6 +536,12 @@
|
|
|
534
536
|
--cr-panel-border-color: var(--cr-color-neutral-200);
|
|
535
537
|
--cr-panel-border-width: 1px;
|
|
536
538
|
|
|
539
|
+
/*
|
|
540
|
+
* Header
|
|
541
|
+
*/
|
|
542
|
+
|
|
543
|
+
--cr-panel-background-color: var(--cr-color-neutral-0);
|
|
544
|
+
|
|
537
545
|
/*
|
|
538
546
|
* Tooltips
|
|
539
547
|
*/
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { TextFieldModel, TextFieldProps } from "@xwiki/cristal-dsapi";
|
|
3
|
-
import { computed } from "vue";
|
|
4
|
-
import { VFileInput } from "vuetify/components/VFileInput";
|
|
5
2
|
import messages from "../../translations";
|
|
3
|
+
import { computed, defineModel } from "vue";
|
|
6
4
|
import { useI18n } from "vue-i18n";
|
|
7
|
-
import {
|
|
5
|
+
import { VFileInput } from "vuetify/components/VFileInput";
|
|
6
|
+
import type { TextFieldModel, TextFieldProps } from "@xwiki/cristal-dsapi";
|
|
8
7
|
|
|
9
8
|
const { t } = useI18n({
|
|
10
9
|
messages,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { type TextFieldProps } from "@xwiki/cristal-dsapi";
|
|
3
|
-
import { computed } from "vue";
|
|
4
|
-
import { VTextField } from "vuetify/components/VTextField";
|
|
5
2
|
import messages from "../../translations";
|
|
3
|
+
import { computed } from "vue";
|
|
6
4
|
import { useI18n } from "vue-i18n";
|
|
5
|
+
import { VTextField } from "vuetify/components/VTextField";
|
|
6
|
+
import type { TextFieldProps } from "@xwiki/cristal-dsapi";
|
|
7
7
|
|
|
8
8
|
const { t } = useI18n({
|
|
9
9
|
messages,
|
|
@@ -26,7 +26,12 @@ const rules = computed(() => {
|
|
|
26
26
|
</script>
|
|
27
27
|
|
|
28
28
|
<template>
|
|
29
|
-
<v-text-field
|
|
29
|
+
<v-text-field
|
|
30
|
+
:label="label"
|
|
31
|
+
:name="name"
|
|
32
|
+
:autofocus="autofocus"
|
|
33
|
+
:rules="rules"
|
|
34
|
+
></v-text-field>
|
|
30
35
|
</template>
|
|
31
36
|
|
|
32
37
|
<style scoped></style>
|
package/src/vue/x-alert.vue
CHANGED
|
@@ -23,7 +23,7 @@ import type { AlertProps } from "@xwiki/cristal-dsapi";
|
|
|
23
23
|
defineProps<AlertProps>();
|
|
24
24
|
</script>
|
|
25
25
|
<template>
|
|
26
|
-
<v-alert closable :title="title" :type="type" :text="description">
|
|
26
|
+
<v-alert :closable="closable" :title="title" :type="type" :text="description">
|
|
27
27
|
<x-btn
|
|
28
28
|
v-for="action of actions"
|
|
29
29
|
:key="action.name"
|
|
@@ -32,5 +32,8 @@ defineProps<AlertProps>();
|
|
|
32
32
|
@click="action.callback"
|
|
33
33
|
>{{ action.name }}</x-btn
|
|
34
34
|
>
|
|
35
|
+
<br v-if="details" />
|
|
36
|
+
<small v-if="details">{{ details }}</small>
|
|
37
|
+
<slot />
|
|
35
38
|
</v-alert>
|
|
36
39
|
</template>
|
package/src/vue/x-btn.vue
CHANGED
|
@@ -19,7 +19,7 @@ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
19
19
|
-->
|
|
20
20
|
<script lang="ts" setup>
|
|
21
21
|
import { computed } from "vue";
|
|
22
|
-
import {
|
|
22
|
+
import type { BtnProps } from "@xwiki/cristal-dsapi";
|
|
23
23
|
|
|
24
24
|
const { variant } = defineProps<BtnProps>();
|
|
25
25
|
|
package/src/vue/x-dialog.vue
CHANGED
|
@@ -18,16 +18,20 @@ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
18
18
|
02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
19
19
|
-->
|
|
20
20
|
<script lang="ts" setup>
|
|
21
|
+
import { useSlots } from "vue";
|
|
22
|
+
|
|
21
23
|
defineProps<{
|
|
22
24
|
title: string;
|
|
23
25
|
width: string | number | undefined;
|
|
24
26
|
}>();
|
|
25
27
|
|
|
28
|
+
const slots = useSlots();
|
|
29
|
+
|
|
26
30
|
// const innerIsActive = ref(props.isActive);
|
|
27
31
|
</script>
|
|
28
32
|
|
|
29
33
|
<template>
|
|
30
|
-
<v-dialog :width="width">
|
|
34
|
+
<v-dialog :width="width" scrollable>
|
|
31
35
|
<template #activator="{ props }">
|
|
32
36
|
<span v-bind="props">
|
|
33
37
|
<slot name="activator" />
|
|
@@ -38,7 +42,16 @@ defineProps<{
|
|
|
38
42
|
<v-card-text>
|
|
39
43
|
<slot name="default" />
|
|
40
44
|
</v-card-text>
|
|
45
|
+
<v-card-actions v-if="slots.footer">
|
|
46
|
+
<slot name="footer" />
|
|
47
|
+
</v-card-actions>
|
|
41
48
|
</v-card>
|
|
42
49
|
</template>
|
|
43
50
|
</v-dialog>
|
|
44
51
|
</template>
|
|
52
|
+
|
|
53
|
+
<style scoped>
|
|
54
|
+
:deep(.v-card-actions) {
|
|
55
|
+
padding: var(--cr-spacing-large);
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -29,38 +29,51 @@ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
29
29
|
* item was disabled. Default hover effects, such as darkening or changing
|
|
30
30
|
* the cursor on items, were also disabled.
|
|
31
31
|
*/
|
|
32
|
-
import {
|
|
32
|
+
import { inject, onBeforeMount, ref, watch } from "vue";
|
|
33
33
|
import { VTreeview } from "vuetify/labs/VTreeview";
|
|
34
|
-
import {
|
|
34
|
+
import type { CristalApp, PageData } from "@xwiki/cristal-api";
|
|
35
|
+
import type { DocumentService } from "@xwiki/cristal-document-api";
|
|
36
|
+
import type { SpaceReference } from "@xwiki/cristal-model-api";
|
|
35
37
|
import type {
|
|
36
|
-
NavigationTreeSource,
|
|
37
38
|
NavigationTreeNode,
|
|
39
|
+
NavigationTreeSource,
|
|
40
|
+
NavigationTreeSourceProvider,
|
|
38
41
|
} from "@xwiki/cristal-navigation-tree-api";
|
|
42
|
+
import type { Ref } from "vue";
|
|
39
43
|
|
|
40
44
|
type TreeItem = {
|
|
41
45
|
id: string;
|
|
42
46
|
title: string;
|
|
43
47
|
href: string;
|
|
44
48
|
children?: Array<TreeItem>;
|
|
45
|
-
_location:
|
|
49
|
+
_location: SpaceReference;
|
|
46
50
|
};
|
|
47
51
|
|
|
48
52
|
type OnClickAction = (node: NavigationTreeNode) => void;
|
|
49
53
|
|
|
54
|
+
const cristal: CristalApp = inject<CristalApp>("cristal")!;
|
|
55
|
+
const documentService: DocumentService = cristal
|
|
56
|
+
.getContainer()
|
|
57
|
+
.get<DocumentService>("DocumentService");
|
|
58
|
+
const treeSource: NavigationTreeSource = cristal
|
|
59
|
+
.getContainer()
|
|
60
|
+
.get<NavigationTreeSourceProvider>("NavigationTreeSourceProvider")
|
|
61
|
+
.get();
|
|
62
|
+
|
|
50
63
|
const rootNodes: Ref<Array<TreeItem>> = ref([]);
|
|
51
64
|
const tree: Ref<VTreeview | undefined> = ref(undefined);
|
|
52
65
|
|
|
53
66
|
const activatedNodes: Ref<Array<string>> = ref(new Array<string>());
|
|
54
67
|
const expandedNodes: Ref<Array<string>> = ref(new Array<string>());
|
|
68
|
+
var isExpanding: boolean = false;
|
|
55
69
|
|
|
56
70
|
const props = defineProps<{
|
|
57
|
-
treeSource: NavigationTreeSource;
|
|
58
71
|
clickAction?: OnClickAction;
|
|
59
72
|
currentPage?: PageData;
|
|
60
73
|
}>();
|
|
61
74
|
|
|
62
75
|
onBeforeMount(async () => {
|
|
63
|
-
for (const node of await
|
|
76
|
+
for (const node of await treeSource.getChildNodes("")) {
|
|
64
77
|
rootNodes.value.push({
|
|
65
78
|
id: node.id,
|
|
66
79
|
title: node.label,
|
|
@@ -69,62 +82,62 @@ onBeforeMount(async () => {
|
|
|
69
82
|
_location: node.location,
|
|
70
83
|
});
|
|
71
84
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
await expandTree();
|
|
86
|
+
|
|
87
|
+
documentService.registerDocumentChangeListener("delete", onDocumentDelete);
|
|
88
|
+
documentService.registerDocumentChangeListener("update", onDocumentUpdate);
|
|
75
89
|
});
|
|
76
90
|
|
|
77
|
-
watch(
|
|
78
|
-
() => props.currentPage,
|
|
79
|
-
async () => {
|
|
80
|
-
if (props.currentPage) {
|
|
81
|
-
await expandTree();
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
);
|
|
91
|
+
watch(() => props.currentPage, expandTree);
|
|
85
92
|
|
|
93
|
+
// TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
|
|
94
|
+
// eslint-disable-next-line max-statements
|
|
86
95
|
async function expandTree() {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
if (props.currentPage && !isExpanding) {
|
|
97
|
+
isExpanding = true;
|
|
98
|
+
const newExpandedNodes = treeSource.getParentNodesId(props.currentPage);
|
|
99
|
+
let i;
|
|
100
|
+
let currentNodes = rootNodes.value;
|
|
101
|
+
for (i = 0; i < newExpandedNodes.length - 1; i++) {
|
|
102
|
+
if (currentNodes) {
|
|
103
|
+
for (const node of currentNodes) {
|
|
104
|
+
if (node.id == newExpandedNodes[i]) {
|
|
105
|
+
if (node.children?.length == 0) {
|
|
106
|
+
await lazyLoadChildren(node);
|
|
107
|
+
}
|
|
108
|
+
if (!expandedNodes.value.includes(node.id)) {
|
|
109
|
+
expandedNodes.value.push(node.id);
|
|
110
|
+
}
|
|
111
|
+
currentNodes = node.children!;
|
|
96
112
|
}
|
|
97
|
-
if (!expandedNodes.value.includes(node.id)) {
|
|
98
|
-
expandedNodes.value.push(node.id);
|
|
99
|
-
}
|
|
100
|
-
currentNodes = node.children!;
|
|
101
113
|
}
|
|
102
114
|
}
|
|
103
115
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
116
|
+
if (currentNodes) {
|
|
117
|
+
for (const node of currentNodes) {
|
|
118
|
+
if (node.id == newExpandedNodes[i]) {
|
|
119
|
+
activatedNodes.value = [node.id];
|
|
120
|
+
// If we have a custom click action, we want to use it on dynamic
|
|
121
|
+
// selection.
|
|
122
|
+
if (props.clickAction) {
|
|
123
|
+
props.clickAction({
|
|
124
|
+
id: node.id,
|
|
125
|
+
label: node.title,
|
|
126
|
+
location: node._location,
|
|
127
|
+
url: node.href,
|
|
128
|
+
has_children: node.children !== undefined,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
119
131
|
}
|
|
120
132
|
}
|
|
121
133
|
}
|
|
134
|
+
isExpanding = false;
|
|
122
135
|
}
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
async function lazyLoadChildren(item: unknown) {
|
|
126
139
|
const treeItem = item as TreeItem;
|
|
127
|
-
const childNodes = await
|
|
140
|
+
const childNodes = await treeSource.getChildNodes(treeItem.id);
|
|
128
141
|
for (const child of childNodes) {
|
|
129
142
|
treeItem.children?.push({
|
|
130
143
|
id: child.id,
|
|
@@ -148,6 +161,83 @@ function clearSelection() {
|
|
|
148
161
|
activatedNodes.value.pop();
|
|
149
162
|
}
|
|
150
163
|
}
|
|
164
|
+
|
|
165
|
+
// TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
|
|
166
|
+
// eslint-disable-next-line max-statements
|
|
167
|
+
async function onDocumentDelete(page: PageData) {
|
|
168
|
+
const parents = treeSource.getParentNodesId(page);
|
|
169
|
+
let currentItems: TreeItem[] | undefined = rootNodes.value;
|
|
170
|
+
while (currentItems) {
|
|
171
|
+
for (const i of currentItems.keys()) {
|
|
172
|
+
if (currentItems[i].id == parents[0]) {
|
|
173
|
+
if (parents.length == 1) {
|
|
174
|
+
currentItems.splice(i, 1);
|
|
175
|
+
return;
|
|
176
|
+
} else {
|
|
177
|
+
currentItems = currentItems[i].children;
|
|
178
|
+
parents.shift();
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
|
|
187
|
+
// eslint-disable-next-line max-statements
|
|
188
|
+
async function onDocumentUpdate(page: PageData) {
|
|
189
|
+
const parents = treeSource.getParentNodesId(page);
|
|
190
|
+
let currentParent: string | undefined = undefined;
|
|
191
|
+
let currentItems: TreeItem[] | undefined = rootNodes.value;
|
|
192
|
+
let notFound = false;
|
|
193
|
+
|
|
194
|
+
currentItemsLoop: while (currentItems && !notFound) {
|
|
195
|
+
for (const i of currentItems.keys()) {
|
|
196
|
+
if (currentItems[i].id == parents[0]) {
|
|
197
|
+
if (parents.length == 1) {
|
|
198
|
+
// Page update
|
|
199
|
+
const newItems = await treeSource.getChildNodes(
|
|
200
|
+
currentParent ? currentParent : "",
|
|
201
|
+
);
|
|
202
|
+
for (const newItem of newItems) {
|
|
203
|
+
if (newItem.id == currentItems[i].id) {
|
|
204
|
+
currentItems[i].title = newItem.label;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
currentParent = currentItems[i].id;
|
|
210
|
+
if (!currentItems[i].children) {
|
|
211
|
+
currentItems[i].children = [];
|
|
212
|
+
}
|
|
213
|
+
currentItems = currentItems[i].children;
|
|
214
|
+
parents.shift();
|
|
215
|
+
continue currentItemsLoop;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
notFound = true;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// New page
|
|
223
|
+
const newItems = await treeSource.getChildNodes(
|
|
224
|
+
currentParent ? currentParent : "",
|
|
225
|
+
);
|
|
226
|
+
newItemsLoop: for (const newItem of newItems) {
|
|
227
|
+
for (const i of currentItems!.keys()) {
|
|
228
|
+
if (newItem.id == currentItems![i].id) {
|
|
229
|
+
continue newItemsLoop;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
currentItems!.push({
|
|
233
|
+
id: newItem.id,
|
|
234
|
+
title: newItem.label,
|
|
235
|
+
href: newItem.url,
|
|
236
|
+
children: newItem.has_children ? [] : undefined,
|
|
237
|
+
_location: newItem.location,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
151
241
|
</script>
|
|
152
242
|
|
|
153
243
|
<template>
|
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"rootDir": "src",
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"isolatedDeclarations": false
|
|
6
|
+
},
|
|
7
|
+
"extends": "./../../tsconfig.json",
|
|
8
|
+
"include": [
|
|
9
|
+
"./src/index.ts",
|
|
10
|
+
"./src/**/*"
|
|
11
|
+
],
|
|
12
|
+
"exclude": [
|
|
13
|
+
"**/*.spec.ts",
|
|
14
|
+
"**/*.test.ts"
|
|
15
|
+
]
|
|
10
16
|
}
|
package/vitest.config.ts
CHANGED
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
import localConfig from "./vite.config";
|
|
21
22
|
import { defineConfig, mergeConfig } from "vitest/config";
|
|
22
23
|
import defaultConfig from "@xwiki/cristal-dev-config/vitest-vue.config";
|
|
23
|
-
import localConfig from "./vite.config";
|
|
24
24
|
|
|
25
25
|
export default mergeConfig(
|
|
26
26
|
mergeConfig(defaultConfig, localConfig),
|