@vcmap/ui 6.0.0-rc.2 → 6.0.0-rc.5
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/build/build.js +40 -60
- package/build/buildHelpers.js +62 -19
- package/build/bundle.js +1 -1
- package/build/info/conf.json +1 -1
- package/build/info/publish.js +25 -31
- package/build/lintTypes.js +5 -0
- package/config/base.config.json +2 -1
- package/config/dev.config.json +7 -1
- package/config/projects.config.json +2 -1
- package/config/splashscreen.config.json +45 -0
- package/config/www.config.json +25 -22
- package/dist/.htaccess +7 -0
- package/dist/assets/@mdi/font/README.md +25 -0
- package/dist/assets/@mdi/font/css/materialdesignicons.min-680621ca.css +3 -0
- package/dist/assets/@mdi/font/css/materialdesignicons.min.css.map +16 -0
- package/dist/assets/@mdi/font/fonts/materialdesignicons-webfont.woff2 +0 -0
- package/dist/assets/{cesium.0b750d.js → cesium-126f111a.js} +272 -385
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core.cbf44a.js → core-1c8b8674.js} +2015 -2019
- package/dist/assets/core.js +1 -1
- package/dist/assets/{ol.86e93c.js → ol-27f9b3f3.js} +42521 -44394
- package/dist/assets/ol.js +1 -1
- package/dist/assets/ui-7214428e.css +1 -0
- package/dist/assets/{ui.7c276c.js → ui-7214428e.js} +13968 -13907
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue-c78a5f76.js +6083 -0
- package/dist/assets/vue.js +1 -1
- package/dist/assets/{vuetify.4d18fe.css → vuetify-88a2fabe.css} +2 -2
- package/dist/assets/{vuetify.4d18fe.js → vuetify-88a2fabe.js} +7793 -7940
- package/dist/assets/vuetify.js +1 -1
- package/dist/index.html +11 -10
- package/index.d.ts +11 -11
- package/index.html +5 -5
- package/index.js +9 -7
- package/lib/olLib.js +84 -23
- package/package.json +19 -19
- package/plugins/@vcmap-show-case/flight-component-example/src/FlightExample.vue +41 -1
- package/plugins/@vcmap-show-case/form-inputs-example/src/FormInputsExample.vue +71 -32
- package/plugins/@vcmap-show-case/form-inputs-example/src/exampleActions.js +7 -11
- package/plugins/@vcmap-show-case/form-inputs-example/src/index.js +2 -2
- package/plugins/@vcmap-show-case/list-example/src/ListExample.vue +21 -8
- package/plugins/@vcmap-show-case/project-selector/src/ModulesListComponent.vue +18 -11
- package/plugins/@vcmap-show-case/search-example/src/index.js +1 -0
- package/plugins/@vcmap-show-case/search-example/src/searchImpl.js +35 -5
- package/plugins/@vcmap-show-case/style-input-example/src/StyleExample.vue +29 -90
- package/plugins/@vcmap-show-case/toolbox-example/src/index.js +2 -1
- package/plugins/package.json +3 -23
- package/public/assets/@mdi/font/README.md +25 -0
- package/public/assets/@mdi/font/css/materialdesignicons.min.css +2 -2
- package/public/assets/@mdi/font/css/materialdesignicons.min.css.map +16 -0
- package/public/assets/@mdi/font/fonts/materialdesignicons-webfont.woff2 +0 -0
- package/src/actions/StyleSelector.vue +1 -1
- package/src/actions/actionHelper.js +33 -22
- package/src/actions/flightActions.js +5 -5
- package/src/actions/listActions.d.ts +4 -11
- package/src/actions/listActions.js +6 -22
- package/src/actions/stateRefAction.js +2 -2
- package/src/application/VcsApp.vue +147 -57
- package/src/application/VcsApp.vue.d.ts +298 -4
- package/src/application/VcsAttributions.vue +2 -13
- package/src/application/VcsAttributionsFooter.vue +10 -11
- package/src/application/VcsContainer.vue +26 -9
- package/src/application/VcsContainer.vue.d.ts +237 -0
- package/src/application/VcsMainMap.vue +7 -7
- package/src/application/VcsMainMap.vue.d.ts +2 -2
- package/src/application/VcsNavbar.vue +5 -1
- package/src/application/VcsPositionDisplay.vue +8 -23
- package/src/application/VcsPositionDisplay.vue.d.ts +0 -1
- package/src/application/VcsSettings.vue +10 -17
- package/src/application/VcsSplashScreen.vue +21 -40
- package/src/application/VcsSplashScreen.vue.d.ts +0 -2
- package/src/application/VcsTextPage.vue +12 -43
- package/src/application/VcsTextPage.vue.d.ts +4 -8
- package/src/application/VcsTextPageFooter.vue +23 -40
- package/src/components/buttons/VcsActionButtonList.vue +59 -3
- package/src/components/buttons/VcsActionButtonList.vue.d.ts +28 -0
- package/src/components/extent/VcsExtentEditor.vue +1 -1
- package/src/components/flight/VcsFlightAnchorsComponent.vue +63 -36
- package/src/components/flight/VcsFlightComponent.vue +16 -21
- package/src/components/flight/VcsFlightPlayer.vue +27 -5
- package/src/components/form-inputs-controls/VcsCheckbox.vue +9 -5
- package/src/components/form-inputs-controls/VcsChipArrayInput.vue +15 -13
- package/src/components/form-inputs-controls/VcsChipArrayInput.vue.d.ts +3 -4
- package/src/components/form-inputs-controls/VcsCoordinate.vue +17 -4
- package/src/components/form-inputs-controls/VcsCoordinate.vue.d.ts +5 -2
- package/src/components/form-inputs-controls/VcsDatePicker.vue +34 -60
- package/src/components/form-inputs-controls/VcsDatePicker.vue.d.ts +1 -63
- package/src/components/form-inputs-controls/VcsFileInput.vue +17 -18
- package/src/components/form-inputs-controls/VcsFileInput.vue.d.ts +1 -0
- package/src/components/form-inputs-controls/VcsLabel.vue +1 -1
- package/src/components/form-inputs-controls/VcsRadio.vue +17 -3
- package/src/components/form-inputs-controls/VcsRadio.vue.d.ts +1 -0
- package/src/components/form-inputs-controls/VcsSelect.vue +40 -31
- package/src/components/form-inputs-controls/VcsSelect.vue.d.ts +5 -2
- package/src/components/form-inputs-controls/VcsSlider.vue +13 -1
- package/src/components/form-inputs-controls/VcsSlider.vue.d.ts +1 -0
- package/src/components/form-inputs-controls/VcsTextArea.vue +27 -26
- package/src/components/form-inputs-controls/VcsTextArea.vue.d.ts +1 -0
- package/src/components/form-inputs-controls/VcsTextField.vue +20 -4
- package/src/components/form-inputs-controls/VcsTextField.vue.d.ts +9 -0
- package/src/components/form-inputs-controls/VcsWizardStep.vue +3 -6
- package/src/components/form-inputs-controls/vcsTextField.scss +9 -12
- package/src/components/form-output/VcsFormattedNumber.vue +21 -5
- package/src/components/form-output/VcsFormattedNumber.vue.d.ts +9 -0
- package/src/components/form-output/VcsMarkdown.vue +15 -12
- package/src/components/form-output/VcsMarkdown.vue.d.ts +1 -0
- package/src/components/form-output/markdownHelper.d.ts +30 -0
- package/src/components/form-output/markdownHelper.js +398 -0
- package/src/components/import/VcsFileDrop.vue +8 -5
- package/src/components/import/VcsImportComponent.vue +4 -3
- package/src/components/import/VcsImportComponent.vue.d.ts +1 -2
- package/src/components/lists/VcsActionList.vue +11 -7
- package/src/components/lists/VcsList.vue +30 -52
- package/src/components/lists/VcsList.vue.d.ts +14 -59
- package/src/components/lists/{VcsListItem.vue → VcsListItemComponent.vue} +68 -22
- package/src/components/lists/VcsListItemComponent.vue.d.ts +69 -0
- package/src/components/lists/VcsTreeview.vue +43 -16
- package/src/components/lists/VcsTreeview.vue.d.ts +14 -3
- package/src/components/lists/VcsTreeviewLeaf.vue +15 -6
- package/src/components/lists/VcsTreeviewSearchbar.vue +2 -2
- package/src/components/notification/VcsHelp.vue +1 -1
- package/src/components/notification/VcsHelp.vue.d.ts +3 -2
- package/src/components/section/VcsExpansionPanel.vue +101 -0
- package/src/components/section/VcsExpansionPanel.vue.d.ts +19 -0
- package/src/components/{form-inputs-controls → section}/VcsFormSection.vue +10 -4
- package/src/components/{form-inputs-controls → section}/VcsFormSection.vue.d.ts +1 -2
- package/src/components/style/MenuWrapper.vue +24 -26
- package/src/components/style/MenuWrapper.vue.d.ts +4 -4
- package/src/components/style/VcsFillMenu.vue +9 -16
- package/src/components/style/VcsFillMenu.vue.d.ts +0 -18
- package/src/components/style/VcsFillSelector.vue +13 -16
- package/src/components/style/VcsImageMenu.vue +8 -25
- package/src/components/style/VcsImageMenu.vue.d.ts +0 -27
- package/src/components/style/VcsImageSelector.vue +102 -167
- package/src/components/style/VcsImageSelector.vue.d.ts +15 -15
- package/src/components/style/VcsStrokeMenu.vue +8 -15
- package/src/components/style/VcsStrokeMenu.vue.d.ts +0 -18
- package/src/components/style/VcsStrokeSelector.vue +11 -18
- package/src/components/style/VcsTextMenu.vue +9 -12
- package/src/components/style/VcsTextMenu.vue.d.ts +0 -9
- package/src/components/style/VcsTextSelector.vue +79 -95
- package/src/components/style/VcsTextSelector.vue.d.ts +20 -22
- package/src/components/style/VcsVectorStyleComponent.vue +8 -19
- package/src/components/style/VcsVectorStyleComponent.vue.d.ts +1 -1
- package/src/components/style/composables.d.ts +0 -14
- package/src/components/style/composables.js +0 -49
- package/src/components/tables/VcsDataTable.vue +28 -22
- package/src/components/tables/VcsTable.vue +45 -62
- package/src/components/tables/VcsTable.vue.d.ts +30 -17
- package/src/components/tables/VcsTableCell.vue +72 -0
- package/src/components/tables/VcsTableCell.vue.d.ts +13 -0
- package/src/components/vector-properties/VcsFeatureEditingWindow.vue +43 -9
- package/src/components/vector-properties/VcsFeatureTransforms.vue +5 -0
- package/src/components/vector-properties/VcsVectorPropertiesComponent.vue +1 -1
- package/src/components/viewpoint/VcsViewpointComponent.vue +23 -10
- package/src/components/viewpoint/VcsViewpointEditor.vue +2 -1
- package/src/contentTree/LayerTree.vue +9 -27
- package/src/contentTree/LayerTree.vue.d.ts +1 -1
- package/src/contentTree/contentTreeCollection.d.ts +1 -0
- package/src/contentTree/contentTreeCollection.js +45 -11
- package/src/contentTree/contentTreeItem.d.ts +2 -2
- package/src/contentTree/contentTreeItem.js +7 -7
- package/src/featureInfo/BalloonComponent.vue +14 -15
- package/src/featureInfo/MarkdownBalloonComponent.vue +4 -2
- package/src/featureInfo/MarkdownBalloonComponent.vue.d.ts +2 -2
- package/src/featureInfo/abstractFeatureInfoView.d.ts +6 -0
- package/src/featureInfo/abstractFeatureInfoView.js +15 -7
- package/src/featureInfo/featureInfo.d.ts +5 -5
- package/src/featureInfo/featureInfo.js +59 -41
- package/src/featureInfo/iframeFeatureInfoView.d.ts +8 -2
- package/src/featureInfo/iframeFeatureInfoView.js +15 -5
- package/src/featureInfo/markdownBalloonFeatureInfoView.d.ts +1 -1
- package/src/featureInfo/markdownBalloonFeatureInfoView.js +5 -5
- package/src/featureInfo/markdownFeatureInfoView.d.ts +1 -1
- package/src/featureInfo/markdownFeatureInfoView.js +9 -11
- package/src/featureInfo/tableFeatureInfoView.js +13 -4
- package/src/init.d.ts +5 -38
- package/src/init.js +19 -18
- package/src/legend/StyleLegendItem.vue +4 -9
- package/src/legend/VcsLegend.vue +28 -54
- package/src/manager/buttonManager.js +4 -4
- package/src/manager/collectionManager/CollectionComponent.vue +17 -42
- package/src/manager/collectionManager/CollectionComponent.vue.d.ts +4 -2
- package/src/manager/collectionManager/CollectionComponentContent.vue +7 -6
- package/src/manager/collectionManager/CollectionComponentContent.vue.d.ts +3 -1
- package/src/manager/collectionManager/CollectionComponentList.vue +11 -9
- package/src/manager/collectionManager/CollectionComponentList.vue.d.ts +6 -4
- package/src/manager/collectionManager/CollectionComponentProvider.vue +1 -1
- package/src/manager/collectionManager/CollectionComponentStandalone.vue +3 -2
- package/src/manager/collectionManager/CollectionManager.vue +1 -1
- package/src/manager/collectionManager/collectionComponentClass.d.ts +1 -1
- package/src/manager/collectionManager/collectionComponentClass.js +7 -10
- package/src/manager/collectionManager/collectionManager.js +10 -10
- package/src/manager/collectionManager/editorCollectionComponentClass.js +6 -5
- package/src/manager/contextMenu/contextMenuManager.js +2 -2
- package/src/manager/navbarManager.js +2 -2
- package/src/manager/panel/PanelComponent.vue +2 -9
- package/src/manager/panel/PanelManagerComponent.vue +7 -3
- package/src/manager/panel/panelHelper.js +3 -3
- package/src/manager/panel/panelManager.d.ts +9 -1
- package/src/manager/panel/panelManager.js +18 -6
- package/src/manager/toolbox/GroupToolboxComponent.vue +8 -4
- package/src/manager/toolbox/GroupToolboxComponent.vue.d.ts +1 -0
- package/src/manager/toolbox/SelectToolboxComponent.vue +7 -4
- package/src/manager/toolbox/SelectToolboxComponent.vue.d.ts +1 -0
- package/src/manager/toolbox/ToolboxManager.vue +9 -6
- package/src/manager/toolbox/ToolboxManager.vue.d.ts +1 -0
- package/src/manager/toolbox/toolboxManager.js +10 -10
- package/src/manager/window/WindowComponent.vue +12 -8
- package/src/manager/window/WindowComponentHeader.vue +29 -8
- package/src/manager/window/WindowComponentHeader.vue.d.ts +2 -0
- package/src/manager/window/WindowManager.vue +2 -2
- package/src/manager/window/windowManager.d.ts +2 -2
- package/src/manager/window/windowManager.js +4 -4
- package/src/navigation/MapNavigation.vue +20 -0
- package/src/navigation/locatorHelper.js +1 -1
- package/src/navigation/overviewMap.js +1 -1
- package/src/notifier/NotifierComponent.vue +18 -15
- package/src/search/ResultItem.vue +18 -6
- package/src/search/ResultsComponent.vue +31 -20
- package/src/search/ResultsComponent.vue.d.ts +2 -1
- package/src/search/SearchComponent.vue +8 -14
- package/src/search/SearchComponent.vue.d.ts +1 -0
- package/src/search/search.js +2 -2
- package/src/siteConfig.js +9 -9
- package/src/state.js +4 -4
- package/src/styles/_typography.scss +0 -2
- package/src/styles/main.scss +0 -4
- package/src/uiConfig.d.ts +300 -5
- package/src/uiConfig.js +28 -16
- package/src/vcsUiApp.d.ts +21 -17
- package/src/vcsUiApp.js +11 -10
- package/src/vuePlugins/vuetify.d.ts +2 -0
- package/src/vuePlugins/vuetify.js +14 -0
- package/dist/assets/@mdi/font/css/materialdesignicons.css.map +0 -16
- package/dist/assets/@mdi/font/css/materialdesignicons.min.e3f476.css +0 -3
- package/dist/assets/index-8eGauqjA.js +0 -1
- package/dist/assets/ui.7c276c.css +0 -1
- package/dist/assets/vue.a3cd64.js +0 -6096
- package/public/assets/@mdi/font/css/materialdesignicons.css.map +0 -16
- package/src/application/VcsCustomScreen.vue +0 -45
- package/src/application/VcsCustomScreen.vue.d.ts +0 -15
- package/src/application/markdownHelper.d.ts +0 -12
- package/src/application/markdownHelper.js +0 -70
- package/src/components/lists/VcsListItem.vue.d.ts +0 -21
- package/src/components/notification/VcsTooltip.vue +0 -156
- package/src/components/notification/VcsTooltip.vue.d.ts +0 -27
- package/src/featureInfo/MarkdownComponent.vue +0 -16
- package/src/featureInfo/MarkdownComponent.vue.d.ts +0 -7
- package/src/styles/_theming.scss +0 -73
- package/src/styles/settings.scss +0 -6
- package/src/styles/shades.scss +0 -4
- package/src/styles/variables.scss +0 -140
- package/src/styles/vcsFont.scss +0 -2
- package/src/styles/vcsGrid.scss +0 -3
- /package/dist/assets/{favicon-128.4c4ce5.png → favicon-128-4c4ce5df.png} +0 -0
- /package/dist/assets/{favicon-180.5b99c0.png → favicon-180-4c4ce5df.png} +0 -0
- /package/dist/assets/{favicon-192.0e205e.png → favicon-192-4c4ce5df.png} +0 -0
- /package/dist/assets/{favicon-32.6b9add.png → favicon-32-4c4ce5df.png} +0 -0
- /package/dist/assets/{favicon.d5ec97.svg → favicon-4c4ce5df.svg} +0 -0
- /package/dist/assets/font/{TitilliumWeb-Regular.9ca076.woff2 → TitilliumWeb-Regular-9ca076be.woff2} +0 -0
- /package/dist/assets/style/{icon-marker.70960f.png → icon-marker-70960f05.png} +0 -0
- /package/dist/assets/style/{icon-marker-blue.534e37.png → icon-marker-blue-534e374b.png} +0 -0
- /package/dist/assets/style/{icon-marker-green.0b6a92.png → icon-marker-green-0b6a92bc.png} +0 -0
- /package/dist/assets/style/{icon-marker-o.036477.png → icon-marker-o-036477fa.png} +0 -0
- /package/dist/assets/style/{icon-marker-o-blue.7b6d62.png → icon-marker-o-blue-7b6d6279.png} +0 -0
- /package/dist/assets/style/{icon-marker-o-green.c863c0.png → icon-marker-o-green-c863c0fa.png} +0 -0
- /package/dist/assets/style/{icon-marker-o-red.93ff58.png → icon-marker-o-red-93ff58df.png} +0 -0
- /package/dist/assets/style/{icon-marker-red.313d03.png → icon-marker-red-313d03e8.png} +0 -0
- /package/dist/assets/style/{icon-pin.b7ce77.png → icon-pin-b7ce771e.png} +0 -0
- /package/dist/assets/style/{icon-pin-blue.7be369.png → icon-pin-blue-7be369a3.png} +0 -0
- /package/dist/assets/style/{icon-pin-green.cbb935.png → icon-pin-green-cbb935fe.png} +0 -0
- /package/dist/assets/style/{icon-pin-red.3f25b2.png → icon-pin-red-3f25b245.png} +0 -0
- /package/public/assets/{favicon-128.png → favicon-128-4c4ce5df.png} +0 -0
- /package/public/assets/{favicon-180.png → favicon-180-4c4ce5df.png} +0 -0
- /package/public/assets/{favicon-192.png → favicon-192-4c4ce5df.png} +0 -0
- /package/public/assets/{favicon-32.png → favicon-32-4c4ce5df.png} +0 -0
- /package/public/assets/{favicon.svg → favicon-4c4ce5df.svg} +0 -0
@@ -1,5 +1,11 @@
|
|
1
1
|
<template>
|
2
|
-
<div
|
2
|
+
<div
|
3
|
+
class="marked"
|
4
|
+
:class="{
|
5
|
+
'pa-2': !paddingProvided,
|
6
|
+
}"
|
7
|
+
v-html="markedHtml"
|
8
|
+
></div>
|
3
9
|
</template>
|
4
10
|
<style lang="scss" scoped>
|
5
11
|
div {
|
@@ -10,19 +16,13 @@
|
|
10
16
|
margin-bottom: calc(var(--v-vcs-font-size) * 1);
|
11
17
|
}
|
12
18
|
:deep(h2) {
|
13
|
-
margin-bottom: calc(
|
14
|
-
var(--v-vcs-font-size) * 1
|
15
|
-
); /* or any other value you prefer */
|
19
|
+
margin-bottom: calc(var(--v-vcs-font-size) * 1);
|
16
20
|
}
|
17
21
|
:deep(ul) {
|
18
|
-
margin-bottom: calc(
|
19
|
-
var(--v-vcs-font-size) * 1
|
20
|
-
); /* or any other value you prefer */
|
22
|
+
margin-bottom: calc(var(--v-vcs-font-size) * 1);
|
21
23
|
}
|
22
24
|
:deep(ol) {
|
23
|
-
margin-bottom: calc(
|
24
|
-
var(--v-vcs-font-size) * 1
|
25
|
-
); /* or any other value you prefer */
|
25
|
+
margin-bottom: calc(var(--v-vcs-font-size) * 1);
|
26
26
|
}
|
27
27
|
:deep(li) {
|
28
28
|
margin-left: 1.5em;
|
@@ -31,7 +31,8 @@
|
|
31
31
|
</style>
|
32
32
|
<script>
|
33
33
|
import { computed } from 'vue';
|
34
|
-
import { parseAndSanitizeMarkdown } from '
|
34
|
+
import { parseAndSanitizeMarkdown } from './markdownHelper.js';
|
35
|
+
import { usePadding } from '../composables.js';
|
35
36
|
|
36
37
|
export default {
|
37
38
|
name: 'VcsMarkdown',
|
@@ -41,12 +42,14 @@
|
|
41
42
|
default: undefined,
|
42
43
|
},
|
43
44
|
},
|
44
|
-
setup(props) {
|
45
|
+
setup(props, { attrs }) {
|
45
46
|
const markedHtml = computed(() =>
|
46
47
|
parseAndSanitizeMarkdown(props.content),
|
47
48
|
);
|
49
|
+
const paddingProvided = usePadding(attrs);
|
48
50
|
return {
|
49
51
|
markedHtml,
|
52
|
+
paddingProvided,
|
50
53
|
};
|
51
54
|
},
|
52
55
|
};
|
@@ -5,6 +5,7 @@ declare const _default: import("vue").DefineComponent<{
|
|
5
5
|
};
|
6
6
|
}, {
|
7
7
|
markedHtml: import("vue").ComputedRef<string>;
|
8
|
+
paddingProvided: import("vue").ComputedRef<boolean>;
|
8
9
|
}, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
9
10
|
content: {
|
10
11
|
type: StringConstructor;
|
@@ -0,0 +1,30 @@
|
|
1
|
+
/**
|
2
|
+
* @typedef {Object} Block
|
3
|
+
* @property {RegExpExecArray} opening
|
4
|
+
* @property {RegExpExecArray} closing
|
5
|
+
*/
|
6
|
+
/**
|
7
|
+
* @typedef {Block} ConditionalBlock
|
8
|
+
* @property {RegExpExecArray|undefined} elseStatement
|
9
|
+
* @property {RegExpExecArray[]} elseIfs
|
10
|
+
*/
|
11
|
+
/**
|
12
|
+
* @param {string} content
|
13
|
+
* @returns {string}
|
14
|
+
*/
|
15
|
+
export function parseAndSanitizeMarkdown(content: string): string;
|
16
|
+
/**
|
17
|
+
* Renders a template in these steps
|
18
|
+
* 1. expand conditional blocks. this will remove any blocks that do not match their expressions and choose from if / elseif / else block which of them to render
|
19
|
+
* 2. expand iterations. this will create new templates for each iteration and re-run the rendering for those blocks
|
20
|
+
* 3. render attributes. this will add the attributes to all the blocks not within each blocks
|
21
|
+
* @param {string|string[]} template
|
22
|
+
* @param {Record<string, unknown>} data
|
23
|
+
* @returns {string}
|
24
|
+
*/
|
25
|
+
export function renderTemplate(template: string | string[], data: Record<string, unknown>): string;
|
26
|
+
export type Block = {
|
27
|
+
opening: RegExpExecArray;
|
28
|
+
closing: RegExpExecArray;
|
29
|
+
};
|
30
|
+
export type ConditionalBlock = Block;
|
@@ -0,0 +1,398 @@
|
|
1
|
+
import { marked } from 'marked';
|
2
|
+
import DOMPurify from 'dompurify';
|
3
|
+
import {
|
4
|
+
BooleanType,
|
5
|
+
newParsingContext,
|
6
|
+
StringType,
|
7
|
+
NoneType,
|
8
|
+
} from 'ol/expr/expression';
|
9
|
+
import { buildExpression, newEvaluationContext } from 'ol/expr/cpu';
|
10
|
+
import { is } from '@vcsuite/check';
|
11
|
+
|
12
|
+
/**
|
13
|
+
* @typedef {Object} Block
|
14
|
+
* @property {RegExpExecArray} opening
|
15
|
+
* @property {RegExpExecArray} closing
|
16
|
+
*/
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @typedef {Block} ConditionalBlock
|
20
|
+
* @property {RegExpExecArray|undefined} elseStatement
|
21
|
+
* @property {RegExpExecArray[]} elseIfs
|
22
|
+
*/
|
23
|
+
|
24
|
+
/**
|
25
|
+
* @param {string} content
|
26
|
+
* @returns {string}
|
27
|
+
*/
|
28
|
+
export function parseAndSanitizeMarkdown(content) {
|
29
|
+
const html = marked.parse(content, { breaks: true });
|
30
|
+
|
31
|
+
// Then sanitize the HTML using DOMPurify
|
32
|
+
return DOMPurify.sanitize(html, { ADD_ATTR: ['target'] });
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @param {string} expressionString
|
37
|
+
* @param {Record<string, unknown>} data
|
38
|
+
* @param {number} evaluationType
|
39
|
+
* @returns {*}
|
40
|
+
*/
|
41
|
+
function evaluateExpression(expressionString, data, evaluationType) {
|
42
|
+
const parsed = expressionString.startsWith('[')
|
43
|
+
? JSON.parse(expressionString)
|
44
|
+
: [
|
45
|
+
'get',
|
46
|
+
...expressionString
|
47
|
+
.replace(/\[([^\]]+)]/g, '.$1')
|
48
|
+
.split('.')
|
49
|
+
.filter((f) => f),
|
50
|
+
];
|
51
|
+
|
52
|
+
const compiledExpression = buildExpression(
|
53
|
+
parsed,
|
54
|
+
evaluationType,
|
55
|
+
newParsingContext(),
|
56
|
+
);
|
57
|
+
const evaluationContext = newEvaluationContext();
|
58
|
+
evaluationContext.properties = data;
|
59
|
+
return compiledExpression(evaluationContext);
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Replaces template strings by provided attributes, e.g. {{myAttribute}}
|
64
|
+
* @param {string} template
|
65
|
+
* @param {Record<string, unknown>} data
|
66
|
+
* @returns {string}
|
67
|
+
*/
|
68
|
+
function replaceAttributes(template, data) {
|
69
|
+
const pattern = /\{\{([^}]+)}}/g;
|
70
|
+
return template.replace(pattern, (p, value) => {
|
71
|
+
return evaluateExpression(value.trim(), data, StringType) ?? '';
|
72
|
+
});
|
73
|
+
}
|
74
|
+
|
75
|
+
/**
|
76
|
+
* @param {RegExp} regexp
|
77
|
+
* @param {string} string
|
78
|
+
* @returns {RegExpExecArray[]}
|
79
|
+
*/
|
80
|
+
function regexHits(regexp, string) {
|
81
|
+
const hits = [];
|
82
|
+
let hit;
|
83
|
+
// eslint-disable-next-line no-cond-assign
|
84
|
+
while ((hit = regexp.exec(string))) {
|
85
|
+
hits.push(hit);
|
86
|
+
}
|
87
|
+
|
88
|
+
return hits;
|
89
|
+
}
|
90
|
+
|
91
|
+
/**
|
92
|
+
* @param {RegExpExecArray[]} openings
|
93
|
+
* @param {RegExpExecArray[]} closings
|
94
|
+
* @param {(Block) => void} accepted
|
95
|
+
* @param {(Block) => void} rejected
|
96
|
+
* @returns {void}
|
97
|
+
*/
|
98
|
+
function findTopLevelBlock(openings, closings, accepted, rejected) {
|
99
|
+
const localOpenings = openings.slice();
|
100
|
+
const localClosings = closings.slice();
|
101
|
+
while (localOpenings.length > 0) {
|
102
|
+
let matchingClosing;
|
103
|
+
let matchingOpening;
|
104
|
+
while (!matchingClosing && localClosings.length > 0) {
|
105
|
+
const currentClosing = localClosings.shift();
|
106
|
+
const openingDistances = localOpenings.map(
|
107
|
+
(o) => currentClosing.index - o.index,
|
108
|
+
);
|
109
|
+
const minDistance = openingDistances.reduce((min, currentDistance) => {
|
110
|
+
if (currentDistance > 0 && currentDistance < min) {
|
111
|
+
return currentDistance;
|
112
|
+
}
|
113
|
+
return min;
|
114
|
+
}, Infinity);
|
115
|
+
const matchingOpeningIndex = openingDistances.indexOf(minDistance);
|
116
|
+
matchingOpening = localOpenings[matchingOpeningIndex];
|
117
|
+
|
118
|
+
if (matchingOpeningIndex === 0) {
|
119
|
+
matchingClosing = currentClosing;
|
120
|
+
} else {
|
121
|
+
rejected({ opening: matchingOpening, closing: currentClosing });
|
122
|
+
}
|
123
|
+
localOpenings.splice(matchingOpeningIndex, 1);
|
124
|
+
}
|
125
|
+
|
126
|
+
if (matchingClosing) {
|
127
|
+
accepted({ opening: matchingOpening, closing: matchingClosing });
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* @param {RegExpExecArray} tag
|
134
|
+
* @param {Block} block
|
135
|
+
* @returns {boolean}
|
136
|
+
*/
|
137
|
+
function tagWithinBlock(tag, block) {
|
138
|
+
return tag.index > block.opening.index && tag.index < block.closing.index;
|
139
|
+
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* @param {string} template
|
143
|
+
* @returns {Block[]}
|
144
|
+
*/
|
145
|
+
function getForEachBlocks(template) {
|
146
|
+
const forEachBlocks = [];
|
147
|
+
const forEachOpenings = regexHits(
|
148
|
+
/\s*{{#each\s\(([^.)]+)\)\sin\s([^}]+)}}\s*/g,
|
149
|
+
template,
|
150
|
+
);
|
151
|
+
const forEachClosings = regexHits(/\s*{{\/each}}\s*/g, template);
|
152
|
+
|
153
|
+
if (forEachClosings.length > forEachOpenings.length) {
|
154
|
+
throw new Error(
|
155
|
+
'Template failed to render, missing opening tag for each statements',
|
156
|
+
);
|
157
|
+
} else if (forEachClosings.length < forEachOpenings.length) {
|
158
|
+
throw new Error(
|
159
|
+
'Template failed to render, missing closing tag for each statements',
|
160
|
+
);
|
161
|
+
}
|
162
|
+
|
163
|
+
findTopLevelBlock(
|
164
|
+
forEachOpenings,
|
165
|
+
forEachClosings,
|
166
|
+
(block) => {
|
167
|
+
forEachBlocks.push(block);
|
168
|
+
},
|
169
|
+
() => {},
|
170
|
+
);
|
171
|
+
|
172
|
+
return forEachBlocks;
|
173
|
+
}
|
174
|
+
|
175
|
+
/**
|
176
|
+
* @param {string} template
|
177
|
+
* @param {Block[]} forEachBlocks
|
178
|
+
* @returns {ConditionalBlock[]}
|
179
|
+
*/
|
180
|
+
function getConditionalBlocks(template, forEachBlocks) {
|
181
|
+
const conditionalBlocks = [];
|
182
|
+
let conditionalOpenings = regexHits(/\s*{{#if\s([^}]*)}}\s*/g, template);
|
183
|
+
let conditionalClosings = regexHits(/\s*{{\/if}}\s*/g, template);
|
184
|
+
let elseIfs = regexHits(/\s*{{elseif\s([^}]*)}}\s*/g, template);
|
185
|
+
let elses = regexHits(/\s*{{else}}\s*/g, template);
|
186
|
+
|
187
|
+
const withinForEachBlock = (tag) =>
|
188
|
+
forEachBlocks.find((block) => tagWithinBlock(tag, block));
|
189
|
+
|
190
|
+
// conditionals within a for each blocks are rendered with the for each block, ignore
|
191
|
+
conditionalOpenings = conditionalOpenings.filter(
|
192
|
+
(t) => !withinForEachBlock(t),
|
193
|
+
);
|
194
|
+
conditionalClosings = conditionalClosings.filter(
|
195
|
+
(t) => !withinForEachBlock(t),
|
196
|
+
);
|
197
|
+
|
198
|
+
if (conditionalClosings.length > conditionalOpenings.length) {
|
199
|
+
throw new Error(
|
200
|
+
'Template failed to render, missing closing tag for if statements',
|
201
|
+
);
|
202
|
+
} else if (conditionalClosings.length < conditionalOpenings.length) {
|
203
|
+
throw new Error(
|
204
|
+
'Template failed to render, missing opening tag for if statements',
|
205
|
+
);
|
206
|
+
}
|
207
|
+
|
208
|
+
const filterElseIfElse = (block) => {
|
209
|
+
elseIfs = elseIfs.filter((tag) => !tagWithinBlock(tag, block));
|
210
|
+
elses = elses.filter((tag) => !tagWithinBlock(tag, block));
|
211
|
+
};
|
212
|
+
|
213
|
+
findTopLevelBlock(
|
214
|
+
conditionalOpenings,
|
215
|
+
conditionalClosings,
|
216
|
+
(block) => {
|
217
|
+
const elsIfs = elseIfs.filter((tag) => tagWithinBlock(tag, block));
|
218
|
+
const elseStatement = elses.find((tag) => tagWithinBlock(tag, block));
|
219
|
+
if (
|
220
|
+
elseStatement &&
|
221
|
+
elsIfs.length > 0 &&
|
222
|
+
elseStatement.index < elsIfs.at(-1).index
|
223
|
+
) {
|
224
|
+
throw new Error('{{else}} must be the last entry in a block');
|
225
|
+
}
|
226
|
+
conditionalBlocks.push({
|
227
|
+
...block,
|
228
|
+
elseStatement,
|
229
|
+
elseIfs,
|
230
|
+
});
|
231
|
+
},
|
232
|
+
(block) => {
|
233
|
+
filterElseIfElse(block);
|
234
|
+
},
|
235
|
+
);
|
236
|
+
|
237
|
+
return conditionalBlocks;
|
238
|
+
}
|
239
|
+
|
240
|
+
/**
|
241
|
+
* @param {string} openingTag
|
242
|
+
* @returns {boolean}
|
243
|
+
*/
|
244
|
+
function shouldRemoveWhiteSpace(openingTag) {
|
245
|
+
return /\n\s*\{/.test(openingTag) && /}\s*\n/.test(openingTag);
|
246
|
+
}
|
247
|
+
|
248
|
+
/**
|
249
|
+
* This will extract the block to render separately. This will depend on the white space handling. If the
|
250
|
+
* opening is placed on its own line, whitespace after the opening and before the closing blocks will be removed
|
251
|
+
* from the sub template, up to the first new line feed.
|
252
|
+
* @param {string} template
|
253
|
+
* @param {Block} block
|
254
|
+
* @returns {string}
|
255
|
+
*/
|
256
|
+
function getSubTemplateForBlock(template, block) {
|
257
|
+
const removeWhiteSpace = shouldRemoveWhiteSpace(block.opening[0]);
|
258
|
+
let startIndex = block.opening.index + block.opening[0].indexOf('}') + 2;
|
259
|
+
let endIndex = block.closing.index + block.closing[0].indexOf('{');
|
260
|
+
if (removeWhiteSpace) {
|
261
|
+
startIndex += (/}\s*\n/.exec(block.opening[0])?.[0].length ?? 1) - 1;
|
262
|
+
endIndex -= (/\n\s*\{/.exec(block.closing[0])?.[0].length ?? 2) - 2;
|
263
|
+
}
|
264
|
+
|
265
|
+
return template.substring(startIndex, endIndex);
|
266
|
+
}
|
267
|
+
|
268
|
+
/**
|
269
|
+
* This will replace a block with a previously extracted blocks rendered template.
|
270
|
+
* This will depend on the white space handling. If the opening is placed on its own line,
|
271
|
+
* whitespace before the opening and after the closing blocks will be removed up to the first new line feed,
|
272
|
+
* from the new template string all together.
|
273
|
+
* @param {string} template
|
274
|
+
* @param {Block} block
|
275
|
+
* @param {string} replacement
|
276
|
+
* @returns {string}
|
277
|
+
*/
|
278
|
+
function replaceBlock(template, block, replacement) {
|
279
|
+
const removeWhiteSpace = shouldRemoveWhiteSpace(block.opening[0]);
|
280
|
+
let startIndex = block.opening.index + block.opening[0].indexOf('{');
|
281
|
+
let endIndex = block.closing.index + block.closing[0].indexOf('}') + 2;
|
282
|
+
if (removeWhiteSpace) {
|
283
|
+
startIndex -= (/\n\s*\{/.exec(block.opening[0])?.[0].length ?? 2) - 2;
|
284
|
+
endIndex += (/}\s*\n/.exec(block.closing[0])?.[0].length ?? 1) - 1;
|
285
|
+
}
|
286
|
+
|
287
|
+
return `${template.substring(0, startIndex)}${replacement}${template.substring(endIndex)}`;
|
288
|
+
}
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Replaces {{#if }} blocks
|
292
|
+
* @param {string} template
|
293
|
+
* @param {Record<string, unknown>} data
|
294
|
+
* @returns {string}
|
295
|
+
*/
|
296
|
+
function expandConditionalsAndLoops(template, data) {
|
297
|
+
let renderedTemplate = template;
|
298
|
+
const forEachBlocks = getForEachBlocks(template);
|
299
|
+
|
300
|
+
getConditionalBlocks(template, forEachBlocks)
|
301
|
+
.reverse()
|
302
|
+
.forEach(
|
303
|
+
/** @param {ConditionalBlock} block */ (block) => {
|
304
|
+
const partialBlocks = [block.opening];
|
305
|
+
if (block.elseIfs) {
|
306
|
+
partialBlocks.push(...block.elseIfs);
|
307
|
+
}
|
308
|
+
let trueStatementIndex = partialBlocks.findIndex((s) =>
|
309
|
+
evaluateExpression(s[1], data, BooleanType),
|
310
|
+
);
|
311
|
+
if (trueStatementIndex === -1 && block.elseStatement) {
|
312
|
+
trueStatementIndex = partialBlocks.length;
|
313
|
+
}
|
314
|
+
|
315
|
+
let renderedBlock = '';
|
316
|
+
if (trueStatementIndex > -1) {
|
317
|
+
if (block.elseStatement) {
|
318
|
+
partialBlocks.push(block.elseStatement);
|
319
|
+
}
|
320
|
+
partialBlocks.push(block.closing);
|
321
|
+
|
322
|
+
const blockTemplate = getSubTemplateForBlock(template, {
|
323
|
+
opening: partialBlocks[trueStatementIndex],
|
324
|
+
closing: partialBlocks[trueStatementIndex + 1],
|
325
|
+
});
|
326
|
+
|
327
|
+
renderedBlock = expandConditionalsAndLoops(blockTemplate, data);
|
328
|
+
}
|
329
|
+
|
330
|
+
renderedTemplate = replaceBlock(renderedTemplate, block, renderedBlock);
|
331
|
+
},
|
332
|
+
);
|
333
|
+
|
334
|
+
// only iterate over blocks not removed by conditionals
|
335
|
+
getForEachBlocks(renderedTemplate)
|
336
|
+
.reverse()
|
337
|
+
.forEach((block) => {
|
338
|
+
const obj = evaluateExpression(block.opening[2], data, NoneType);
|
339
|
+
let keyValuePairs;
|
340
|
+
if (is(obj, Object)) {
|
341
|
+
keyValuePairs = Object.entries(obj);
|
342
|
+
} else if (Array.isArray(obj)) {
|
343
|
+
keyValuePairs = obj.entries();
|
344
|
+
}
|
345
|
+
const renderedBlocks = [];
|
346
|
+
if (keyValuePairs) {
|
347
|
+
let index = 0;
|
348
|
+
const [valueName, keyName, indexName] = block.opening[1]
|
349
|
+
.split(',')
|
350
|
+
.map((e) => e.trim())
|
351
|
+
.slice(0, 3);
|
352
|
+
|
353
|
+
const blockTemplate = getSubTemplateForBlock(renderedTemplate, block);
|
354
|
+
// eslint-disable-next-line no-restricted-syntax
|
355
|
+
for (const args of keyValuePairs) {
|
356
|
+
const forEachData = structuredClone(data);
|
357
|
+
forEachData[valueName] = args[1];
|
358
|
+
if (keyName) {
|
359
|
+
forEachData[keyName] = args[0];
|
360
|
+
}
|
361
|
+
if (indexName) {
|
362
|
+
forEachData[indexName] = index;
|
363
|
+
}
|
364
|
+
const currentBlock = expandConditionalsAndLoops(
|
365
|
+
blockTemplate,
|
366
|
+
forEachData,
|
367
|
+
);
|
368
|
+
renderedBlocks.push(replaceAttributes(currentBlock, forEachData));
|
369
|
+
index += 1;
|
370
|
+
}
|
371
|
+
}
|
372
|
+
|
373
|
+
renderedTemplate = replaceBlock(
|
374
|
+
renderedTemplate,
|
375
|
+
block,
|
376
|
+
renderedBlocks.join(''),
|
377
|
+
);
|
378
|
+
});
|
379
|
+
|
380
|
+
return renderedTemplate;
|
381
|
+
}
|
382
|
+
|
383
|
+
/**
|
384
|
+
* Renders a template in these steps
|
385
|
+
* 1. expand conditional blocks. this will remove any blocks that do not match their expressions and choose from if / elseif / else block which of them to render
|
386
|
+
* 2. expand iterations. this will create new templates for each iteration and re-run the rendering for those blocks
|
387
|
+
* 3. render attributes. this will add the attributes to all the blocks not within each blocks
|
388
|
+
* @param {string|string[]} template
|
389
|
+
* @param {Record<string, unknown>} data
|
390
|
+
* @returns {string}
|
391
|
+
*/
|
392
|
+
export function renderTemplate(template, data) {
|
393
|
+
const templateString = Array.isArray(template)
|
394
|
+
? template.join('\n')
|
395
|
+
: template;
|
396
|
+
const conditionalTemplate = expandConditionalsAndLoops(templateString, data);
|
397
|
+
return replaceAttributes(conditionalTemplate, data);
|
398
|
+
}
|
@@ -7,10 +7,13 @@
|
|
7
7
|
class="d-flex justify-center drop-field"
|
8
8
|
:class="{ dragging: isDragging }"
|
9
9
|
:dragging="isDragging"
|
10
|
+
flat
|
10
11
|
v-bind="$attrs"
|
11
12
|
>
|
12
13
|
<slot>
|
13
|
-
<v-card-title class="d-flex align-center">{{
|
14
|
+
<v-card-title class="d-flex align-center text-primary">{{
|
15
|
+
$st(title)
|
16
|
+
}}</v-card-title>
|
14
17
|
</slot>
|
15
18
|
</v-card>
|
16
19
|
</template>
|
@@ -68,13 +71,13 @@
|
|
68
71
|
|
69
72
|
<style scoped lang="scss">
|
70
73
|
.drop-field {
|
71
|
-
|
72
|
-
outline
|
74
|
+
margin: 8px 8px;
|
75
|
+
outline: 2px dashed rgb(var(--v-theme-primary));
|
76
|
+
border-radius: 4px;
|
73
77
|
background-color: rgb(var(--v-theme-base-lighten-4));
|
74
78
|
}
|
75
79
|
|
76
80
|
.dragging {
|
77
|
-
|
78
|
-
background-color: rgb(var(--v-theme-base-lighten-1));
|
81
|
+
background-color: rgb(var(--v-theme-primary-lighten-3));
|
79
82
|
}
|
80
83
|
</style>
|
@@ -1,8 +1,7 @@
|
|
1
1
|
<template>
|
2
2
|
<v-card flat class="pa-2">
|
3
3
|
<vcs-file-drop
|
4
|
-
|
5
|
-
:height="2 * useItemHeight().value"
|
4
|
+
:height="3 * itemHeight"
|
6
5
|
:multiple="multiple"
|
7
6
|
v-model="files"
|
8
7
|
/>
|
@@ -78,11 +77,13 @@
|
|
78
77
|
|
79
78
|
const noListenerAttrs = computed(() => removeListenersFromAttrs(attrs));
|
80
79
|
|
80
|
+
const itemHeight = useItemHeight();
|
81
|
+
|
81
82
|
return {
|
82
83
|
files,
|
83
84
|
loading,
|
84
85
|
noListenerAttrs,
|
85
|
-
|
86
|
+
itemHeight,
|
86
87
|
async doImport() {
|
87
88
|
loading.value = true;
|
88
89
|
try {
|
@@ -15,7 +15,7 @@ declare const _default: import("vue").DefineComponent<{
|
|
15
15
|
files: WritableComputedRef<File[]>;
|
16
16
|
loading: import("vue").Ref<boolean>;
|
17
17
|
noListenerAttrs: import("vue").ComputedRef<Record<string, unknown>>;
|
18
|
-
|
18
|
+
itemHeight: import("vue").ComputedRef<number>;
|
19
19
|
doImport(): Promise<void>;
|
20
20
|
}, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
21
21
|
importFiles: {
|
@@ -35,4 +35,3 @@ declare const _default: import("vue").DefineComponent<{
|
|
35
35
|
fileTypes: unknown[];
|
36
36
|
}, {}>;
|
37
37
|
export default _default;
|
38
|
-
import { useItemHeight } from '../../vuePlugins/vuetify.js';
|
@@ -27,6 +27,10 @@
|
|
27
27
|
.v-list-item-title {
|
28
28
|
color: rgb(var(--v-theme-primary));
|
29
29
|
}
|
30
|
+
.v-icon {
|
31
|
+
// the icon color slightly differs from the text color, darken-1 seems to fit better
|
32
|
+
color: rgb(var(--v-theme-primary-darken-1));
|
33
|
+
}
|
30
34
|
}
|
31
35
|
:deep(.v-list-item .v-list-item__prepend .v-list-item__spacer) {
|
32
36
|
width: 8px;
|
@@ -34,7 +38,7 @@
|
|
34
38
|
</style>
|
35
39
|
<script>
|
36
40
|
import { computed } from 'vue';
|
37
|
-
import { is } from '@vcsuite/check';
|
41
|
+
import { is, optional } from '@vcsuite/check';
|
38
42
|
import {
|
39
43
|
VIcon,
|
40
44
|
VList,
|
@@ -50,13 +54,13 @@
|
|
50
54
|
*/
|
51
55
|
export const ActionPattern = {
|
52
56
|
name: String,
|
53
|
-
title:
|
54
|
-
icon:
|
57
|
+
title: optional(String),
|
58
|
+
icon: optional(String),
|
55
59
|
callback: Function,
|
56
|
-
active:
|
57
|
-
background:
|
58
|
-
hasUpdate:
|
59
|
-
disabled:
|
60
|
+
active: optional(Boolean),
|
61
|
+
background: optional(Boolean),
|
62
|
+
hasUpdate: optional(Boolean),
|
63
|
+
disabled: optional(Boolean),
|
60
64
|
};
|
61
65
|
|
62
66
|
/**
|