@demos-europe/demosplan-ui 0.0.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.
- package/LICENSE +21 -0
- package/buildTokens.js +59 -0
- package/components/DpButton/DpButton.stories.mdx +136 -0
- package/components/DpButton/DpButton.vue +118 -0
- package/components/DpDetails/DpDetails.stories.mdx +55 -0
- package/components/DpDetails/DpDetails.vue +58 -0
- package/components/DpIcon/DpIcon.stories.mdx +396 -0
- package/components/DpIcon/DpIcon.vue +51 -0
- package/components/DpIcon/util/iconVariables.js +148 -0
- package/components/DpInput/DpInput.stories.mdx +127 -0
- package/components/DpInput/DpInput.vue +284 -0
- package/components/DpLabel/DpLabel.stories.mdx +103 -0
- package/components/DpLabel/DpLabel.vue +112 -0
- package/components/DpLoading/DpLoading.stories.mdx +63 -0
- package/components/DpLoading/DpLoading.vue +63 -0
- package/components/core/DpAccordion.vue +108 -0
- package/components/core/DpAnonymizeText.vue +136 -0
- package/components/core/DpAutocomplete.vue +133 -0
- package/components/core/DpBulkEditHeader.vue +53 -0
- package/components/core/DpButtonIcon.vue +47 -0
- package/components/core/DpButtonRow.vue +155 -0
- package/components/core/DpCard.vue +54 -0
- package/components/core/DpChangeStateAtDate.vue +223 -0
- package/components/core/DpCheckboxGroup.vue +93 -0
- package/components/core/DpContextualHelp.vue +54 -0
- package/components/core/DpCopyPasteButton.vue +47 -0
- package/components/core/DpDashboardTaskCard.vue +123 -0
- package/components/core/DpDataTable/DataTableSearch.js +44 -0
- package/components/core/DpDataTable/DpColumnSelector.vue +133 -0
- package/components/core/DpDataTable/DpDataTable.vue +647 -0
- package/components/core/DpDataTable/DpDataTableExtended.vue +377 -0
- package/components/core/DpDataTable/DpResizeHandle.vue +37 -0
- package/components/core/DpDataTable/DpSelectPageItemCount.vue +70 -0
- package/components/core/DpDataTable/DpTableHeader.vue +197 -0
- package/components/core/DpDataTable/DpTableRow.vue +355 -0
- package/components/core/DpDataTable/DpWrapTrigger.vue +48 -0
- package/components/core/DpDataTable/lib/ResizableColumns.js +83 -0
- package/components/core/DpEditableList.vue +161 -0
- package/components/core/DpEditor/DpBoilerPlate.vue +140 -0
- package/components/core/DpEditor/DpBoilerPlateModal.vue +166 -0
- package/components/core/DpEditor/DpEditor.vue +1281 -0
- package/components/core/DpEditor/DpLinkModal.vue +117 -0
- package/components/core/DpEditor/DpRecommendationModal/DpInsertableRecommendation.vue +137 -0
- package/components/core/DpEditor/DpRecommendationModal.vue +283 -0
- package/components/core/DpEditor/DpResizableImage.vue +121 -0
- package/components/core/DpEditor/DpUploadModal.vue +121 -0
- package/components/core/DpEditor/libs/Decoration.js +66 -0
- package/components/core/DpEditor/libs/SegmentRangeChangePlugin.js +35 -0
- package/components/core/DpEditor/libs/editorAnonymize.js +66 -0
- package/components/core/DpEditor/libs/editorBuildSuggestion.js +269 -0
- package/components/core/DpEditor/libs/editorCustomDelete.js +32 -0
- package/components/core/DpEditor/libs/editorCustomImage.js +100 -0
- package/components/core/DpEditor/libs/editorCustomInsert.js +32 -0
- package/components/core/DpEditor/libs/editorCustomLink.js +46 -0
- package/components/core/DpEditor/libs/editorCustomMark.js +32 -0
- package/components/core/DpEditor/libs/editorInsertAtCursorPos.js +41 -0
- package/components/core/DpEditor/libs/editorObscure.js +60 -0
- package/components/core/DpEditor/libs/editorUnAnonymize.js +56 -0
- package/components/core/DpEditor/libs/handleWordPaste.js +360 -0
- package/components/core/DpEditor/libs/preventDrop.js +31 -0
- package/components/core/DpEditor/libs/preventKeyboardInput.js +27 -0
- package/components/core/DpEditor/libs/preventPaste.js +28 -0
- package/components/core/DpFlyout.vue +119 -0
- package/components/core/DpInlineNotification.vue +116 -0
- package/components/core/DpModal.vue +208 -0
- package/components/core/DpObscure.vue +29 -0
- package/components/core/DpPager.vue +139 -0
- package/components/core/DpProgressBar.vue +67 -0
- package/components/core/DpRegisterFlyout.vue +58 -0
- package/components/core/DpResettableInput.vue +140 -0
- package/components/core/DpSkeletonBox.vue +32 -0
- package/components/core/DpSlidebar.vue +86 -0
- package/components/core/DpSlidingPagination.vue +45 -0
- package/components/core/DpSplitButton.vue +77 -0
- package/components/core/DpSwitcher.vue +62 -0
- package/components/core/DpTableCardList/DpTableCard.vue +61 -0
- package/components/core/DpTableCardList/DpTableCardListHeader.vue +83 -0
- package/components/core/DpTabs/DpTab.vue +52 -0
- package/components/core/DpTabs/DpTabs.vue +165 -0
- package/components/core/DpTextWrapper.vue +65 -0
- package/components/core/DpToggleForm.vue +72 -0
- package/components/core/DpTooltipIcon.vue +52 -0
- package/components/core/DpTransitionExpand.vue +87 -0
- package/components/core/DpTreeList/DpTreeList.vue +334 -0
- package/components/core/DpTreeList/DpTreeListCheckbox.vue +79 -0
- package/components/core/DpTreeList/DpTreeListNode.vue +348 -0
- package/components/core/DpTreeList/DpTreeListToggle.vue +71 -0
- package/components/core/DpTreeList/utils/constants.js +14 -0
- package/components/core/DpUpload/DpUpload.vue +223 -0
- package/components/core/DpUpload/DpUploadFiles.vue +269 -0
- package/components/core/DpUpload/DpUploadedFile.vue +80 -0
- package/components/core/DpUpload/DpUploadedFileList.vue +56 -0
- package/components/core/DpUpload/utils/GetFileIdsByHash.js +42 -0
- package/components/core/DpUpload/utils/UppyTranslations.js +31 -0
- package/components/core/DpVideoPlayer.vue +115 -0
- package/components/core/HeightLimit.vue +121 -0
- package/components/core/MultistepNav.vue +89 -0
- package/components/core/form/DpCheckbox.vue +108 -0
- package/components/core/form/DpDateRangePicker.vue +186 -0
- package/components/core/form/DpDatepicker.vue +160 -0
- package/components/core/form/DpDatetimePicker.vue +194 -0
- package/components/core/form/DpFormRow.vue +79 -0
- package/components/core/form/DpMultiselect.vue +164 -0
- package/components/core/form/DpRadio.vue +128 -0
- package/components/core/form/DpSearchField.vue +110 -0
- package/components/core/form/DpSelect.vue +149 -0
- package/components/core/form/DpTextArea.vue +152 -0
- package/components/core/form/DpTimePicker.vue +374 -0
- package/components/core/form/DpToggle.vue +78 -0
- package/components/core/index.js +132 -0
- package/components/core/notify/DpNotifyContainer.vue +122 -0
- package/components/core/notify/DpNotifyMessage.vue +95 -0
- package/components/core/shared/DpStickyElement.vue +95 -0
- package/components/index.js +24 -0
- package/components/shared/translations.js +15 -0
- package/directives/CleanHtml/CleanHtml.js +50 -0
- package/directives/CleanHtml/CleanHtml.stories.mdx +64 -0
- package/directives/Tooltip/Tooltip.js +40 -0
- package/directives/Tooltip/Tooltip.stories.mdx +42 -0
- package/directives/index.js +17 -0
- package/lib/index.js +14 -0
- package/lib/prefixClass.js +47 -0
- package/mixins/index.js +14 -0
- package/mixins/prefixClassMixin.js +22 -0
- package/package.json +52 -0
- package/shared/props.js +86 -0
- package/style/index.css +7 -0
- package/tailwind.config.js +24 -0
- package/tokens/color.json +358 -0
- package/tokens/color.stories.mdx +45 -0
- package/tokens/fontSize.json +100 -0
- package/tokens/space.json +33 -0
- package/utils/lengthHint.js +69 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (c) 2010-present DEMOS E-Partizipation GmbH.
|
|
3
|
+
*
|
|
4
|
+
* This file is part of the package @demos-europe/demosplan-ui,
|
|
5
|
+
* for more information see the license file.
|
|
6
|
+
*
|
|
7
|
+
* All rights reserved
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Extension, Plugin } from 'tiptap'
|
|
11
|
+
|
|
12
|
+
export default class preventPaste extends Extension {
|
|
13
|
+
get name () {
|
|
14
|
+
return 'PreventProp'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get plugins () {
|
|
18
|
+
return [
|
|
19
|
+
new Plugin({
|
|
20
|
+
props: {
|
|
21
|
+
handlePaste () {
|
|
22
|
+
return true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<license>
|
|
2
|
+
(c) 2010-present DEMOS E-Partizipation GmbH.
|
|
3
|
+
|
|
4
|
+
This file is part of the package @demos-europe/demosplan-ui,
|
|
5
|
+
for more information see the license file.
|
|
6
|
+
|
|
7
|
+
All rights reserved
|
|
8
|
+
</license>
|
|
9
|
+
|
|
10
|
+
<documentation>
|
|
11
|
+
<!--
|
|
12
|
+
|
|
13
|
+
The DpFlyout component renders a flyout that is intended to show stuff.
|
|
14
|
+
|
|
15
|
+
@improve use https://popper.js.org/docs/v2/ for positioning instead of basic css - or find
|
|
16
|
+
another way to make left/right offset dynamic.
|
|
17
|
+
|
|
18
|
+
-->
|
|
19
|
+
<usage variant="TBD">
|
|
20
|
+
</usage>
|
|
21
|
+
</documentation>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<span
|
|
25
|
+
class="o-flyout"
|
|
26
|
+
:class="{
|
|
27
|
+
'o-flyout--left': align === 'left',
|
|
28
|
+
'o-flyout--right': align === 'right',
|
|
29
|
+
'o-flyout--padded': padded,
|
|
30
|
+
'is-expanded': isExpanded,
|
|
31
|
+
'o-flyout--menu': hasMenu
|
|
32
|
+
}"
|
|
33
|
+
v-click-outside="close"
|
|
34
|
+
data-cy="flyoutTrigger">
|
|
35
|
+
<button
|
|
36
|
+
:disabled="disabled"
|
|
37
|
+
type="button"
|
|
38
|
+
aria-haspopup="true"
|
|
39
|
+
class="o-flyout__trigger btn--blank o-link--default u-ph-0_25 line-height--2 whitespace--nowrap"
|
|
40
|
+
@click="toggle">
|
|
41
|
+
<slot name="trigger">
|
|
42
|
+
<i class="fa fa-ellipsis-h" />
|
|
43
|
+
</slot>
|
|
44
|
+
</button>
|
|
45
|
+
<div
|
|
46
|
+
class="o-flyout__content box-shadow-1"
|
|
47
|
+
data-cy="flyout">
|
|
48
|
+
<slot />
|
|
49
|
+
</div>
|
|
50
|
+
</span>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script>
|
|
54
|
+
import ClickOutside from 'vue-click-outside'
|
|
55
|
+
|
|
56
|
+
export default {
|
|
57
|
+
name: 'DpFlyout',
|
|
58
|
+
|
|
59
|
+
directives: {
|
|
60
|
+
ClickOutside
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
props: {
|
|
64
|
+
align: {
|
|
65
|
+
required: false,
|
|
66
|
+
type: String,
|
|
67
|
+
default: 'right',
|
|
68
|
+
validator: (prop) => ['left', 'right'].includes(prop)
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
disabled: {
|
|
72
|
+
required: false,
|
|
73
|
+
type: Boolean,
|
|
74
|
+
default: false
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
hasMenu: {
|
|
78
|
+
required: false,
|
|
79
|
+
type: Boolean,
|
|
80
|
+
default: true
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
padded: {
|
|
84
|
+
required: false,
|
|
85
|
+
type: Boolean,
|
|
86
|
+
default: true
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
data () {
|
|
91
|
+
return {
|
|
92
|
+
isExpanded: false
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
methods: {
|
|
97
|
+
close () {
|
|
98
|
+
if (this.isExpanded === true) {
|
|
99
|
+
this.$emit('close')
|
|
100
|
+
this.isExpanded = false
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
toggle () {
|
|
105
|
+
this.isExpanded = !this.isExpanded
|
|
106
|
+
|
|
107
|
+
if (this.isExpanded) {
|
|
108
|
+
this.$emit('open')
|
|
109
|
+
} else {
|
|
110
|
+
this.$emit('close')
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
mounted () {
|
|
116
|
+
this.popupItem = this.$el
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
</script>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<license>
|
|
2
|
+
(c) 2010-present DEMOS E-Partizipation GmbH.
|
|
3
|
+
|
|
4
|
+
This file is part of the package @demos-europe/demosplan-ui,
|
|
5
|
+
for more information see the license file.
|
|
6
|
+
|
|
7
|
+
All rights reserved
|
|
8
|
+
</license>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
v-if="isDismissed === false"
|
|
13
|
+
:class="`flash flash-${type} flex`">
|
|
14
|
+
<i
|
|
15
|
+
class="fa u-pr-0_25 line-height--1_4"
|
|
16
|
+
:class="iconClasses[type]"
|
|
17
|
+
aria-hidden="true" />
|
|
18
|
+
<div class="space-stack-xs">
|
|
19
|
+
<div
|
|
20
|
+
v-if="message"
|
|
21
|
+
v-html="message" />
|
|
22
|
+
<slot />
|
|
23
|
+
<button
|
|
24
|
+
v-if="dismissible"
|
|
25
|
+
class="btn--blank o-link--default weight--bold"
|
|
26
|
+
v-text="Translator.trans('hint.dismiss')"
|
|
27
|
+
@click="dismiss" />
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div
|
|
31
|
+
v-else
|
|
32
|
+
class="cf">
|
|
33
|
+
<button
|
|
34
|
+
:aria-label="Translator.trans('hint.show')"
|
|
35
|
+
class="btn--blank color--grey float--right"
|
|
36
|
+
@click="show">
|
|
37
|
+
<dp-icon
|
|
38
|
+
icon="info"
|
|
39
|
+
aria-hidden="true" />
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<script>
|
|
45
|
+
import { DpIcon } from 'demosplan-ui/components'
|
|
46
|
+
import lscache from 'lscache'
|
|
47
|
+
|
|
48
|
+
export default {
|
|
49
|
+
name: 'DpInlineNotification',
|
|
50
|
+
|
|
51
|
+
components: {
|
|
52
|
+
DpIcon
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
props: {
|
|
56
|
+
/**
|
|
57
|
+
* A notification may be too prominent if permanently visible. In that case it can be dismissed.
|
|
58
|
+
* A small icon will take the place of the notification to bring it back if needed.
|
|
59
|
+
*/
|
|
60
|
+
dismissible: {
|
|
61
|
+
type: Boolean,
|
|
62
|
+
required: false,
|
|
63
|
+
default: false
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* If set, the dismissed state will be preserved via localStorage.
|
|
68
|
+
*/
|
|
69
|
+
dismissibleKey: {
|
|
70
|
+
type: String,
|
|
71
|
+
required: false,
|
|
72
|
+
default: null
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
message: {
|
|
76
|
+
type: String,
|
|
77
|
+
required: false,
|
|
78
|
+
default: null
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
type: {
|
|
82
|
+
type: String,
|
|
83
|
+
required: false,
|
|
84
|
+
default: 'error'
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
data () {
|
|
89
|
+
return {
|
|
90
|
+
iconClasses: {
|
|
91
|
+
confirm: 'fa-check',
|
|
92
|
+
error: 'fa-exclamation-circle',
|
|
93
|
+
info: 'fa-info-circle',
|
|
94
|
+
warning: 'fa-exclamation-triangle'
|
|
95
|
+
},
|
|
96
|
+
isDismissed: true
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
methods: {
|
|
101
|
+
dismiss () {
|
|
102
|
+
this.isDismissed = true
|
|
103
|
+
this.dismissibleKey && lscache.set(this.dismissibleKey, Date.now())
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
show () {
|
|
107
|
+
this.isDismissed = false
|
|
108
|
+
this.dismissibleKey && lscache.remove(this.dismissibleKey)
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
mounted () {
|
|
113
|
+
this.isDismissed = (this.dismissible && this.dismissibleKey) ? !!lscache.get(this.dismissibleKey) : false
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
</script>
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
<license>
|
|
2
|
+
(c) 2010-present DEMOS E-Partizipation GmbH.
|
|
3
|
+
|
|
4
|
+
This file is part of the package @demos-europe/demosplan-ui,
|
|
5
|
+
for more information see the license file.
|
|
6
|
+
|
|
7
|
+
All rights reserved
|
|
8
|
+
</license>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
:class="prefixClass('o-modal')"
|
|
13
|
+
@keydown="checkKeyEvent">
|
|
14
|
+
<transition
|
|
15
|
+
name="content"
|
|
16
|
+
appear
|
|
17
|
+
@enter="preventScroll">
|
|
18
|
+
<aside
|
|
19
|
+
v-if="isOpenModal"
|
|
20
|
+
:aria-label="ariaLabel"
|
|
21
|
+
:class="prefixClass('o-modal__content ' + contentClasses)"
|
|
22
|
+
role="dialog">
|
|
23
|
+
<button
|
|
24
|
+
:class="prefixClass('btn--blank o-link--default position--absolute u-right-0 u-p-0_5')"
|
|
25
|
+
:aria-label="Translator.trans('close.window')"
|
|
26
|
+
:title="Translator.trans('close.window')"
|
|
27
|
+
@click.prevent.stop="toggle()">
|
|
28
|
+
<dp-icon icon="close" />
|
|
29
|
+
</button>
|
|
30
|
+
<div :class="prefixClass('o-modal__body ' + contentBodyClasses)">
|
|
31
|
+
<h2
|
|
32
|
+
:class="prefixClass('font-size-h1 border--bottom u-pb-0_25 ' + contentHeaderClasses)"
|
|
33
|
+
v-if="hasHeader">
|
|
34
|
+
<slot name="header" />
|
|
35
|
+
</h2>
|
|
36
|
+
<slot name="default" />
|
|
37
|
+
</div>
|
|
38
|
+
</aside>
|
|
39
|
+
</transition>
|
|
40
|
+
<transition
|
|
41
|
+
name="backdrop"
|
|
42
|
+
appear
|
|
43
|
+
@after-leave="preventScroll(false)">
|
|
44
|
+
<div
|
|
45
|
+
v-if="isOpenModal"
|
|
46
|
+
@click.prevent.stop="toggle()"
|
|
47
|
+
:class="prefixClass('o-modal__backdrop')" />
|
|
48
|
+
</transition>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script>
|
|
53
|
+
import { DpIcon } from 'demosplan-ui/components'
|
|
54
|
+
import { prefixClassMixin } from 'demosplan-ui/mixins'
|
|
55
|
+
|
|
56
|
+
export default {
|
|
57
|
+
name: 'DpModal',
|
|
58
|
+
|
|
59
|
+
components: {
|
|
60
|
+
DpIcon
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
mixins: [prefixClassMixin],
|
|
64
|
+
|
|
65
|
+
props: {
|
|
66
|
+
ariaLabel: {
|
|
67
|
+
required: false,
|
|
68
|
+
type: String,
|
|
69
|
+
default: ''
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
contentBodyClasses: {
|
|
73
|
+
required: false,
|
|
74
|
+
type: String,
|
|
75
|
+
default: ''
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
contentClasses: {
|
|
79
|
+
required: false,
|
|
80
|
+
type: String,
|
|
81
|
+
default: ''
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
contentHeaderClasses: {
|
|
85
|
+
required: false,
|
|
86
|
+
type: String,
|
|
87
|
+
default: ''
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Required when toggling modal with toggleByEvent()
|
|
91
|
+
modalId: {
|
|
92
|
+
required: false,
|
|
93
|
+
type: String,
|
|
94
|
+
default: ''
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
data () {
|
|
99
|
+
return {
|
|
100
|
+
isOpenModal: false,
|
|
101
|
+
lastFocusedElement: '',
|
|
102
|
+
focusableElements: []
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
computed: {
|
|
107
|
+
hasHeader () {
|
|
108
|
+
return typeof this.$slots.header !== 'undefined'
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
methods: {
|
|
113
|
+
getFocusableElements () {
|
|
114
|
+
this.focusableElements = [...this.$el.querySelectorAll('a, button:not([disabled]), input, textarea, select, details, [tabindex]:not([tabindex="-1"])')].filter(el => this.isElementVisible(el))
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
isElementVisible (el) {
|
|
118
|
+
const isInDom = el.offsetParent !== null
|
|
119
|
+
const style = window.getComputedStyle(el)
|
|
120
|
+
const isDisplayed = style.display !== 'none' && style.opacity !== '0'
|
|
121
|
+
return isInDom && isDisplayed
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
toggleByEvent (modalId) {
|
|
125
|
+
// Do not execute without a specified modalId to prevent unintentional toggling of multiple modals
|
|
126
|
+
if (typeof modalId === 'undefined') {
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
// Check if event specifies the correct modal instance
|
|
130
|
+
if (this.modalId === modalId) {
|
|
131
|
+
this.toggle()
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
toggle () {
|
|
136
|
+
this.isOpenModal = (this.isOpenModal === false)
|
|
137
|
+
this.$emit('modal:toggled', this.isOpenModal)
|
|
138
|
+
if (this.isOpenModal === true) {
|
|
139
|
+
this.lastFocusedElement = document.activeElement
|
|
140
|
+
// On toggle get all focusable elements and focus the first one (after everything is rendered)
|
|
141
|
+
this.$nextTick(() => {
|
|
142
|
+
this.getFocusableElements()
|
|
143
|
+
if (this.focusableElements.length > 0) {
|
|
144
|
+
this.focusableElements[0].focus({ preventScroll: true })
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
} else {
|
|
148
|
+
this.lastFocusedElement.focus()
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* By setting the html element to overflow: hidden, content behind the opened modal is locked for scrolling.
|
|
154
|
+
* To prevent page jumps when the scroll bar disappears, a padding is put onto the body element.
|
|
155
|
+
*
|
|
156
|
+
* When toggling the modal in, this can be done immediately. When removing the modal, we have to wait for the
|
|
157
|
+
* transition to finish, otherwise the modal jumps a little to the left when the "real scrollbar" appears again.
|
|
158
|
+
* The @after-leave hook is called from the backdrop because the transition applied to it is slightly longer.
|
|
159
|
+
*
|
|
160
|
+
* @param {boolean} toggleIn
|
|
161
|
+
*/
|
|
162
|
+
preventScroll (toggleIn) {
|
|
163
|
+
const htmlElement = document.querySelector('html')
|
|
164
|
+
const bodyElement = document.querySelector('body')
|
|
165
|
+
if (toggleIn) {
|
|
166
|
+
htmlElement.style.overflow = 'hidden'
|
|
167
|
+
bodyElement.style.overflowY = 'scroll'
|
|
168
|
+
} else {
|
|
169
|
+
htmlElement.style.overflow = null
|
|
170
|
+
bodyElement.style.overflowY = null
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
checkKeyEvent (event) {
|
|
175
|
+
// Close modal and return early if escape
|
|
176
|
+
if (event.key === 'Escape') {
|
|
177
|
+
this.toggle()
|
|
178
|
+
} else if (event.key === 'Tab') {
|
|
179
|
+
event.preventDefault()
|
|
180
|
+
const eventTargetIndex = this.focusableElements.findIndex(el => el === event.target)
|
|
181
|
+
const last = this.focusableElements.length - 1
|
|
182
|
+
if (this.focusableElements.length < 2) {
|
|
183
|
+
// Do nothing if only 1 or no elements to focus
|
|
184
|
+
} else if (event.shiftKey === false && event.target === this.focusableElements[last]) {
|
|
185
|
+
// If last element was previously focused, on tab jump to the first element
|
|
186
|
+
this.focusableElements[0].focus()
|
|
187
|
+
} else if (event.shiftKey === true && event.target === this.focusableElements[0]) {
|
|
188
|
+
// If first element was focused, on tab+shift focus the last element
|
|
189
|
+
this.focusableElements[last].focus()
|
|
190
|
+
} else {
|
|
191
|
+
const idxToFocus = event.shiftKey ? eventTargetIndex - 1 : eventTargetIndex + 1
|
|
192
|
+
this.focusableElements[idxToFocus].focus()
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
mounted () {
|
|
199
|
+
this.$root.$on('modal:toggle', (modalId) => this.toggleByEvent(modalId))
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
updated () {
|
|
203
|
+
// When component is re-rendered, we have to collect all focusable elements again, as new ones may have appeared
|
|
204
|
+
this.$nextTick(() => this.getFocusableElements())
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
</script>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<license>
|
|
2
|
+
(c) 2010-present DEMOS E-Partizipation GmbH.
|
|
3
|
+
|
|
4
|
+
This file is part of the package @demos-europe/demosplan-ui,
|
|
5
|
+
for more information see the license file.
|
|
6
|
+
|
|
7
|
+
All rights reserved
|
|
8
|
+
</license>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<span
|
|
12
|
+
:class="obscureClass"
|
|
13
|
+
:title="Translator.trans('obscure.title')">
|
|
14
|
+
<slot />
|
|
15
|
+
</span>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
export default {
|
|
20
|
+
name: 'DpObscure',
|
|
21
|
+
|
|
22
|
+
computed: {
|
|
23
|
+
obscureClass () {
|
|
24
|
+
return (hasPermission('feature_obscure_text')) ? 'u-obscure' : ''
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<license>
|
|
2
|
+
(c) 2010-present DEMOS E-Partizipation GmbH.
|
|
3
|
+
|
|
4
|
+
This file is part of the package @demos-europe/demosplan-ui,
|
|
5
|
+
for more information see the license file.
|
|
6
|
+
|
|
7
|
+
All rights reserved
|
|
8
|
+
</license>
|
|
9
|
+
|
|
10
|
+
<documentation>
|
|
11
|
+
<!--
|
|
12
|
+
This is a wrapper for the dp-sliding-pagination component that adds a itemsPerPage Box
|
|
13
|
+
-->
|
|
14
|
+
<usage>
|
|
15
|
+
<dp-pager
|
|
16
|
+
current-page="pagination.current_page"
|
|
17
|
+
total-pages="pagination.total_pages"
|
|
18
|
+
total-items="pagination.total"
|
|
19
|
+
per-page="pagination.count"
|
|
20
|
+
limits="pagination.limits"
|
|
21
|
+
@page-change="handlePageChange"
|
|
22
|
+
@size-change="handleSizeChange"
|
|
23
|
+
></dp-pager>
|
|
24
|
+
</usage>
|
|
25
|
+
</documentation>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<div class="c-pager__dropdown">
|
|
29
|
+
<label
|
|
30
|
+
class="c-pager__dropdown-label u-m-0 u-p-0 weight--normal display--inline-block"
|
|
31
|
+
:aria-label="Translator.trans('pager.amount.multiple.label', { results: totalItems, items: Translator.trans('pager.amount.multiple.items') })">
|
|
32
|
+
<span aria-hidden="true">
|
|
33
|
+
{{ Translator.trans('pager.amount.multiple.show') }}
|
|
34
|
+
</span>
|
|
35
|
+
<div
|
|
36
|
+
class="display--inline-block"
|
|
37
|
+
v-if="totalItems > Math.min(...limits)">
|
|
38
|
+
<dp-multiselect
|
|
39
|
+
class="display--inline-block"
|
|
40
|
+
v-model="itemsPerPage"
|
|
41
|
+
@select="handleSizeChange"
|
|
42
|
+
:searchable="false"
|
|
43
|
+
selected-label=""
|
|
44
|
+
:options="filteredLimits" />
|
|
45
|
+
</div>
|
|
46
|
+
<span v-else>{{ totalItems }}</span>
|
|
47
|
+
<span aria-hidden="true">
|
|
48
|
+
{{ Translator.trans('pager.amount.multiple.of') }}
|
|
49
|
+
<span data-cy="totalItems">{{ totalItems }}</span>
|
|
50
|
+
{{ Translator.trans('pager.amount.multiple.items') }}
|
|
51
|
+
</span>
|
|
52
|
+
</label>
|
|
53
|
+
<dp-sliding-pagination
|
|
54
|
+
v-if="totalItems > Math.min(...limits)"
|
|
55
|
+
class="display--inline-block"
|
|
56
|
+
:current="currentPage"
|
|
57
|
+
:total="totalPages || 1"
|
|
58
|
+
@page-change="handlePageChange" />
|
|
59
|
+
</div>
|
|
60
|
+
</template>
|
|
61
|
+
|
|
62
|
+
<script>
|
|
63
|
+
import DpMultiselect from './form/DpMultiselect'
|
|
64
|
+
import DpSlidingPagination from './DpSlidingPagination'
|
|
65
|
+
|
|
66
|
+
export default {
|
|
67
|
+
name: 'DpPager',
|
|
68
|
+
|
|
69
|
+
components: {
|
|
70
|
+
DpSlidingPagination,
|
|
71
|
+
DpMultiselect
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
props: {
|
|
75
|
+
currentPage: {
|
|
76
|
+
required: false,
|
|
77
|
+
type: Number,
|
|
78
|
+
default: 1
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
totalItems: {
|
|
82
|
+
required: false,
|
|
83
|
+
type: Number,
|
|
84
|
+
default: 1
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
totalPages: {
|
|
88
|
+
required: false,
|
|
89
|
+
type: Number,
|
|
90
|
+
default: 1
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
perPage: {
|
|
94
|
+
required: false,
|
|
95
|
+
type: Number,
|
|
96
|
+
default: 1
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
limits: {
|
|
100
|
+
required: false,
|
|
101
|
+
type: Array,
|
|
102
|
+
default: () => []
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
data () {
|
|
107
|
+
return {
|
|
108
|
+
itemsPerPage: this.perPage <= this.totalItems ? this.perPage : this.totalItems
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
computed: {
|
|
113
|
+
filteredLimits () {
|
|
114
|
+
const filtered = this.limits.filter(limit => limit <= this.totalItems)
|
|
115
|
+
|
|
116
|
+
if (filtered.length < this.limits.length && this.totalItems > filtered[filtered.length - 1]) {
|
|
117
|
+
filtered.push(this.totalItems)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (filtered.includes(this.itemsPerPage) === false) {
|
|
121
|
+
filtered.push(this.itemsPerPage)
|
|
122
|
+
}
|
|
123
|
+
filtered.sort((a, b) => a - b)
|
|
124
|
+
|
|
125
|
+
return filtered
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
methods: {
|
|
130
|
+
handlePageChange (newPage) {
|
|
131
|
+
this.$emit('page-change', newPage)
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
handleSizeChange (selectedOption) {
|
|
135
|
+
this.$emit('size-change', parseInt(selectedOption))
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
</script>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<license>
|
|
2
|
+
(c) 2010-present DEMOS E-Partizipation GmbH.
|
|
3
|
+
|
|
4
|
+
This file is part of the package @demos-europe/demosplan-ui,
|
|
5
|
+
for more information see the license file.
|
|
6
|
+
|
|
7
|
+
All rights reserved
|
|
8
|
+
</license>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div class="c-progress-bar">
|
|
12
|
+
<template v-if="indeterminate">
|
|
13
|
+
<div class="u-mb-0_25 weight--bold">
|
|
14
|
+
{{ label }}
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="c-progress-bar__line is-animated" />
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<template v-else>
|
|
21
|
+
<div class="u-mb-0_25 weight--bold">
|
|
22
|
+
{{ label }}
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="bg-color--grey-light-2">
|
|
26
|
+
<div
|
|
27
|
+
class="u-mb-0_25 c-progress-bar__line"
|
|
28
|
+
:style="style" />
|
|
29
|
+
</div>
|
|
30
|
+
<span>
|
|
31
|
+
{{ percentage }}%
|
|
32
|
+
</span>
|
|
33
|
+
</template>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script>
|
|
38
|
+
export default {
|
|
39
|
+
name: 'DpProgressBar',
|
|
40
|
+
|
|
41
|
+
props: {
|
|
42
|
+
indeterminate: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
required: false,
|
|
45
|
+
default: false
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
label: {
|
|
49
|
+
type: String,
|
|
50
|
+
required: false,
|
|
51
|
+
default: ''
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
percentage: {
|
|
55
|
+
type: Number,
|
|
56
|
+
required: false,
|
|
57
|
+
default: 0
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
computed: {
|
|
62
|
+
style () {
|
|
63
|
+
return 'width: ' + this.percentage + '%;'
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
</script>
|