@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,348 @@
|
|
|
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
|
+
<li
|
|
12
|
+
class="border--top position--relative"
|
|
13
|
+
data-cy="treeListNode">
|
|
14
|
+
<div class="c-treelist__node flex">
|
|
15
|
+
<div
|
|
16
|
+
class="display--inline-block u-p-0_25 u-pr-0 u-mt-0_125"
|
|
17
|
+
:class="dragHandle"
|
|
18
|
+
v-if="isDraggable">
|
|
19
|
+
<dp-icon
|
|
20
|
+
class="c-treelist__drag-handle-icon"
|
|
21
|
+
icon="drag-handle" />
|
|
22
|
+
</div>
|
|
23
|
+
<dp-tree-list-checkbox
|
|
24
|
+
v-if="isSelectable"
|
|
25
|
+
:checked="isSelected"
|
|
26
|
+
:name="checkboxIdentifier"
|
|
27
|
+
:string-value="nodeId"
|
|
28
|
+
@check="setSelectionState({ selectionState: !isSelected })" />
|
|
29
|
+
<div
|
|
30
|
+
class="flex flex-grow flex-items-start"
|
|
31
|
+
:style="indentationStyle">
|
|
32
|
+
<dp-tree-list-toggle
|
|
33
|
+
class="c-treelist__folder text--left u-pv-0_25"
|
|
34
|
+
:class="{'pointer-events-none': 0 === children.length}"
|
|
35
|
+
:icon-class-prop="iconClassFolder"
|
|
36
|
+
v-if="isBranch"
|
|
37
|
+
v-model="isExpanded" />
|
|
38
|
+
<div class="flex-grow u-pl-0 u-p-0_25">
|
|
39
|
+
<slot
|
|
40
|
+
v-if="isBranch"
|
|
41
|
+
name="branch"
|
|
42
|
+
:node-element="node"
|
|
43
|
+
:node-children="children"
|
|
44
|
+
:node-id="nodeId"
|
|
45
|
+
:parent-id="parentId" />
|
|
46
|
+
<slot
|
|
47
|
+
v-if="isLeaf"
|
|
48
|
+
name="leaf"
|
|
49
|
+
:node-element="node"
|
|
50
|
+
:node-id="nodeId"
|
|
51
|
+
:parent-id="parentId" />
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<dp-tree-list-toggle
|
|
55
|
+
data-cy="treeListToggle"
|
|
56
|
+
v-if="isBranch"
|
|
57
|
+
class="align-self-start"
|
|
58
|
+
:disabled="!hasToggle"
|
|
59
|
+
v-tooltip="Translator.trans(!hasToggle ? 'no.elements.existing' : '')"
|
|
60
|
+
v-model="isExpanded" />
|
|
61
|
+
<div
|
|
62
|
+
v-else
|
|
63
|
+
class="min-width-25" />
|
|
64
|
+
</div>
|
|
65
|
+
<draggable
|
|
66
|
+
v-model="tree"
|
|
67
|
+
v-bind="options.draggable"
|
|
68
|
+
class="list-style-none u-mb-0 u-1-of-1"
|
|
69
|
+
:disabled="hasDraggableChildren === false"
|
|
70
|
+
:group="options.dragAcrossBranches ? 'treelistgroup' : nodeId"
|
|
71
|
+
tag="ul"
|
|
72
|
+
:move="onMove"
|
|
73
|
+
@change="(action) => handleChange(action, nodeId)"
|
|
74
|
+
@end="handleDrag('end')"
|
|
75
|
+
@start="handleDrag('start')">
|
|
76
|
+
<dp-tree-list-node
|
|
77
|
+
v-for="child in children"
|
|
78
|
+
v-show="true === isExpanded"
|
|
79
|
+
:ref="`node_${child.id}`"
|
|
80
|
+
:key="child.id"
|
|
81
|
+
:check-branch="checkBranch"
|
|
82
|
+
:children="child.children || []"
|
|
83
|
+
:handle-change="handleChange"
|
|
84
|
+
:handle-drag="handleDrag"
|
|
85
|
+
:level="level + 1"
|
|
86
|
+
:node="child"
|
|
87
|
+
:node-id="child.id"
|
|
88
|
+
:on-move="onMove"
|
|
89
|
+
:options="options"
|
|
90
|
+
:parent-id="nodeId"
|
|
91
|
+
:parent-selected="isSelected"
|
|
92
|
+
@draggable-change="bubbleDraggableChange"
|
|
93
|
+
@end="handleDrag('end')"
|
|
94
|
+
@node-selected="handleChildSelectionChange"
|
|
95
|
+
@start="handleDrag('start')"
|
|
96
|
+
@tree-data-change="bubbleChangeEvent">
|
|
97
|
+
<template
|
|
98
|
+
v-for="slot in Object.keys($scopedSlots)"
|
|
99
|
+
v-slot:[slot]="scope">
|
|
100
|
+
<slot
|
|
101
|
+
:name="slot"
|
|
102
|
+
v-bind="scope" />
|
|
103
|
+
</template>
|
|
104
|
+
</dp-tree-list-node>
|
|
105
|
+
</draggable>
|
|
106
|
+
</li>
|
|
107
|
+
</template>
|
|
108
|
+
|
|
109
|
+
<script>
|
|
110
|
+
import { checkboxWidth, dragHandleWidth, levelIndentationWidth } from './utils/constants'
|
|
111
|
+
import { DpIcon } from 'demosplan-ui/components'
|
|
112
|
+
import DpTreeListCheckbox from './DpTreeListCheckbox'
|
|
113
|
+
import DpTreeListToggle from './DpTreeListToggle'
|
|
114
|
+
import draggable from 'vuedraggable'
|
|
115
|
+
|
|
116
|
+
export default {
|
|
117
|
+
name: 'DpTreeListNode',
|
|
118
|
+
|
|
119
|
+
components: {
|
|
120
|
+
DpIcon,
|
|
121
|
+
DpTreeListCheckbox,
|
|
122
|
+
DpTreeListToggle,
|
|
123
|
+
draggable
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
props: {
|
|
127
|
+
checkBranch: {
|
|
128
|
+
type: Function,
|
|
129
|
+
required: true
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
children: {
|
|
133
|
+
type: Array,
|
|
134
|
+
required: true
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
draggable: {
|
|
138
|
+
type: Boolean,
|
|
139
|
+
required: false,
|
|
140
|
+
default: true
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/*
|
|
144
|
+
* The function to handle the draggable "change" event is passed as a prop here.
|
|
145
|
+
* This way we do not run into performance issues with deeply nested lists.
|
|
146
|
+
* @see https://www.digitalocean.com/community/tutorials/vuejs-communicating-recursive-components
|
|
147
|
+
*/
|
|
148
|
+
handleChange: {
|
|
149
|
+
type: Function,
|
|
150
|
+
required: true
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
* The function to handle the draggable "start" and "end" events is passed as a prop here.
|
|
155
|
+
*/
|
|
156
|
+
handleDrag: {
|
|
157
|
+
type: Function,
|
|
158
|
+
required: true
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
level: {
|
|
162
|
+
type: Number,
|
|
163
|
+
required: true
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
node: {
|
|
167
|
+
type: Object,
|
|
168
|
+
required: true
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
nodeId: {
|
|
172
|
+
type: String,
|
|
173
|
+
required: true
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
onMove: {
|
|
177
|
+
type: Function,
|
|
178
|
+
required: true
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
options: {
|
|
182
|
+
type: Object,
|
|
183
|
+
required: false,
|
|
184
|
+
default: () => ({})
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
parentId: {
|
|
188
|
+
type: String,
|
|
189
|
+
required: false,
|
|
190
|
+
default: ''
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
parentSelected: {
|
|
194
|
+
type: Boolean,
|
|
195
|
+
required: false,
|
|
196
|
+
default: false
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
data () {
|
|
201
|
+
return {
|
|
202
|
+
isExpanded: false,
|
|
203
|
+
isSelected: false
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
computed: {
|
|
208
|
+
checkboxIdentifier () {
|
|
209
|
+
const prefix = this.isBranch
|
|
210
|
+
? this.options.checkboxIdentifier.branch
|
|
211
|
+
: this.options.checkboxIdentifier.leaf
|
|
212
|
+
return prefix + ':' + this.nodeId
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
dragHandle () {
|
|
216
|
+
const str = this.options.draggable.handle
|
|
217
|
+
return str.substring(1, str.length)
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
hasDraggableChildren () {
|
|
221
|
+
return this.isBranch && (this.options.dragLeaves || this.options.dragBranches) && this.draggable
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
hasToggle () {
|
|
225
|
+
return this.isBranch && this.children.length > 0
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
iconClassFolder () {
|
|
229
|
+
const hasContent = this.children.length > 0
|
|
230
|
+
let folderClass
|
|
231
|
+
if (hasContent) {
|
|
232
|
+
folderClass = this.isExpanded ? 'fa-folder-open' : 'fa-folder'
|
|
233
|
+
} else {
|
|
234
|
+
folderClass = 'fa-folder-o'
|
|
235
|
+
}
|
|
236
|
+
return 'fa ' + folderClass
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
indentationStyle () {
|
|
240
|
+
let margin = this.level * levelIndentationWidth
|
|
241
|
+
|
|
242
|
+
// If leaves are draggable, but branches are not, or vice versa, add extra space
|
|
243
|
+
if ((this.isBranch && !this.options.dragBranches && this.options.dragLeaves) ||
|
|
244
|
+
(this.isLeaf && this.options.dragBranches && !this.options.dragLeaves)) {
|
|
245
|
+
margin += dragHandleWidth
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// If leaves are selectable, but branches are not, or vice versa, add extra space
|
|
249
|
+
if ((this.isBranch && !this.options.branchesSelectable && this.options.leavesSelectable) ||
|
|
250
|
+
(this.isLeaf && this.options.branchesSelectable && !this.options.leavesSelectable)) {
|
|
251
|
+
margin += checkboxWidth
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return `margin-left: ${margin}px;`
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
isBranch () {
|
|
258
|
+
return this.checkBranch({ node: this.node, children: this.children, id: this.nodeId })
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
isDraggable () {
|
|
262
|
+
return this.isDraggableLeaf || this.isDraggableBranch
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
isDraggableBranch () {
|
|
266
|
+
return this.options.dragBranches && this.isBranch
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
isDraggableLeaf () {
|
|
270
|
+
return this.options.dragLeaves && this.isLeaf
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
isLeaf () {
|
|
274
|
+
return this.isBranch === false
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
isSelectable () {
|
|
278
|
+
return (this.isBranch && this.options.branchesSelectable) || (this.isLeaf && this.options.leavesSelectable) || false
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
// See docblock in `tree` computed of parent component.
|
|
282
|
+
tree: {
|
|
283
|
+
get () {
|
|
284
|
+
return this.children
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
set (val) {
|
|
288
|
+
this.$emit('tree-data-change', { nodeId: this.nodeId, newOrder: val })
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
watch: {
|
|
294
|
+
parentSelected (val) {
|
|
295
|
+
if (this.options.selectOn.parentSelect && val === true && this.isSelected === false) {
|
|
296
|
+
this.setSelectionState({ selectionState: val, fromParent: true })
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (this.options.deselectOn.parentDeselect && val === false && this.isSelected === true) {
|
|
300
|
+
this.setSelectionState({ selectionState: val, fromParent: true })
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
methods: {
|
|
306
|
+
bubbleChangeEvent (payload) {
|
|
307
|
+
this.$emit('tree-data-change', payload)
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
bubbleDraggableChange (payload) {
|
|
311
|
+
this.$emit('draggable-change', payload)
|
|
312
|
+
},
|
|
313
|
+
|
|
314
|
+
handleChildSelectionChange (selections) {
|
|
315
|
+
// Extract child selection state from the latest selection event
|
|
316
|
+
const childSelectionState = selections[selections.length - 1].selectionState
|
|
317
|
+
|
|
318
|
+
if (this.options.deselectOn.childDeselect && childSelectionState === false && this.isSelected === true) {
|
|
319
|
+
this.setSelectionState({ selectionState: childSelectionState, selections })
|
|
320
|
+
} else if (this.options.selectOn.childSelect && childSelectionState === true && this.isSelected === false) {
|
|
321
|
+
this.setSelectionState({ selectionState: childSelectionState, selections })
|
|
322
|
+
// Just bubble the event if the current node doesn't require any changes
|
|
323
|
+
} else {
|
|
324
|
+
this.$emit('node-selected', selections)
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
setSelectionState ({ selectionState, selections = [], fromParent = false }) {
|
|
329
|
+
const selectionsCpy = [...selections]
|
|
330
|
+
|
|
331
|
+
this.isSelected = selectionState
|
|
332
|
+
selectionsCpy.push({
|
|
333
|
+
nodeId: this.nodeId,
|
|
334
|
+
nodeType: this.isBranch === true ? 'branch' : 'leaf',
|
|
335
|
+
selectionState: selectionState
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
if (fromParent === false) {
|
|
339
|
+
this.$emit('node-selected', selectionsCpy)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
mounted () {
|
|
345
|
+
this.$root.$on('treelist:toggle-all', (expanded) => (this.isExpanded = expanded))
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
</script>
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
<button
|
|
12
|
+
type="button"
|
|
13
|
+
class="o-link--default btn--blank"
|
|
14
|
+
:aria-label="label"
|
|
15
|
+
@click="toggle">
|
|
16
|
+
<i
|
|
17
|
+
:class="iconClass"
|
|
18
|
+
aria-hidden="true" />
|
|
19
|
+
</button>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script>
|
|
23
|
+
export default {
|
|
24
|
+
name: 'DpTreeListToggle',
|
|
25
|
+
|
|
26
|
+
props: {
|
|
27
|
+
value: {
|
|
28
|
+
type: Boolean,
|
|
29
|
+
required: false,
|
|
30
|
+
default: false
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
iconClassProp: {
|
|
34
|
+
type: String,
|
|
35
|
+
required: false,
|
|
36
|
+
default: ''
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
toggleAll: {
|
|
40
|
+
type: Boolean,
|
|
41
|
+
required: false,
|
|
42
|
+
default: false
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
computed: {
|
|
47
|
+
/*
|
|
48
|
+
* May be passed from outside, but defaults to angle icon controlled by state.
|
|
49
|
+
* This is somewhat messy but removes cruft from DpTreeListNode.
|
|
50
|
+
*/
|
|
51
|
+
iconClass () {
|
|
52
|
+
return this.iconClassProp !== ''
|
|
53
|
+
? this.iconClassProp
|
|
54
|
+
: ('font-size-large line-height--1 u-p-0_25 fa ' + (this.value ? 'fa-angle-up' : 'fa-angle-down'))
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
label () {
|
|
58
|
+
// Here, the relatively generic term "element" is chosen to keep the wording generic.
|
|
59
|
+
return this.toggleAll
|
|
60
|
+
? Translator.trans(this.value ? 'aria.collapse.all' : 'aria.expand.all')
|
|
61
|
+
: Translator.trans(this.value ? 'aria.collapse' : 'aria.expand')
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
methods: {
|
|
66
|
+
toggle () {
|
|
67
|
+
this.$emit('input', !this.value)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
</script>
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
const checkboxWidth = 30
|
|
11
|
+
const dragHandleWidth = 22
|
|
12
|
+
const levelIndentationWidth = 25
|
|
13
|
+
|
|
14
|
+
export { checkboxWidth, dragHandleWidth, levelIndentationWidth }
|
|
@@ -0,0 +1,223 @@
|
|
|
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 ref="fileInput" />
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import { de } from './utils/UppyTranslations'
|
|
16
|
+
import DragDrop from '@uppy/drag-drop'
|
|
17
|
+
import { getFileTypes } from 'demosplan-utils/lib/FileInfo'
|
|
18
|
+
import { hasOwnProp } from 'demosplan-utils'
|
|
19
|
+
import ProgressBar from '@uppy/progress-bar'
|
|
20
|
+
import Tus from '@uppy/tus'
|
|
21
|
+
import Uppy from '@uppy/core'
|
|
22
|
+
|
|
23
|
+
export default {
|
|
24
|
+
name: 'DpUpload',
|
|
25
|
+
|
|
26
|
+
props: {
|
|
27
|
+
/**
|
|
28
|
+
* Array of mimeTypes or a defined preset as String
|
|
29
|
+
* @see '@DemosPlanCoreBundle/lib/FileInfo'
|
|
30
|
+
*/
|
|
31
|
+
allowedFileTypes: {
|
|
32
|
+
type: [Array, String],
|
|
33
|
+
required: false,
|
|
34
|
+
default: 'pdf'
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Warning message that will be rendered if files are added that are not allowed in `allowedFileTypes`.
|
|
39
|
+
*/
|
|
40
|
+
allowedFileTypesWarning: {
|
|
41
|
+
type: String,
|
|
42
|
+
default: 'warning.filetype'
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Allow users to upload more files after uploading some
|
|
47
|
+
*/
|
|
48
|
+
allowMultipleUploads: {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Define chunk size for huge files like PDFs
|
|
55
|
+
*/
|
|
56
|
+
chunkSize: {
|
|
57
|
+
type: Number,
|
|
58
|
+
default: Infinity,
|
|
59
|
+
required: false
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Maximum file size in bytes for each individual file
|
|
64
|
+
*/
|
|
65
|
+
maxFileSize: {
|
|
66
|
+
type: Number,
|
|
67
|
+
default: 10000000
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Maximum number of files that can be uploaded.
|
|
72
|
+
* By default its a single file upload.
|
|
73
|
+
*/
|
|
74
|
+
maxNumberOfFiles: {
|
|
75
|
+
type: Number,
|
|
76
|
+
required: false,
|
|
77
|
+
default: 1
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
translations: {
|
|
81
|
+
type: Object,
|
|
82
|
+
required: false,
|
|
83
|
+
default: () => ({})
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
data () {
|
|
88
|
+
return {
|
|
89
|
+
currentFileHash: '',
|
|
90
|
+
currentFileId: '',
|
|
91
|
+
uppy: null
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
computed: {
|
|
96
|
+
allowedFileTypeArray () {
|
|
97
|
+
return getFileTypes(this.allowedFileTypes)
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
methods: {
|
|
102
|
+
getCookieValue (a) {
|
|
103
|
+
const b = document.cookie.match('(^|[^;]+)\\s*' + a + '\\s*=\\s*([^;]+)')
|
|
104
|
+
return b ? b.pop() : ''
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
initialize () {
|
|
108
|
+
const locale = { strings: { ...de().strings, ...this.translations } }
|
|
109
|
+
this.uppy = new Uppy({
|
|
110
|
+
disabled: true,
|
|
111
|
+
autoProceed: true,
|
|
112
|
+
allowMultipleUploads: this.allowMultipleUploads,
|
|
113
|
+
restrictions: {
|
|
114
|
+
allowedFileTypes: this.allowedFileTypeArray,
|
|
115
|
+
maxFileSize: this.maxFileSize,
|
|
116
|
+
maxNumberOfFiles: this.maxNumberOfFiles
|
|
117
|
+
},
|
|
118
|
+
locale: locale
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
this.uppy.use(DragDrop, {
|
|
122
|
+
target: this.$refs.fileInput,
|
|
123
|
+
width: '100%',
|
|
124
|
+
note: null,
|
|
125
|
+
locale: locale
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
this.uppy.use(ProgressBar, {
|
|
129
|
+
target: this.$refs.fileInput,
|
|
130
|
+
fixed: false,
|
|
131
|
+
hideAfterFinish: false
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
let currentProcedureId = null
|
|
135
|
+
|
|
136
|
+
if (typeof dplan !== 'undefined' && hasOwnProp(dplan, 'procedureId')) {
|
|
137
|
+
currentProcedureId = dplan.procedureId
|
|
138
|
+
}
|
|
139
|
+
const headers = {}
|
|
140
|
+
// Add current procedure id only if set
|
|
141
|
+
if (currentProcedureId !== null && currentProcedureId !== '0') {
|
|
142
|
+
headers['X-Demosplan-Procedure-Id'] = currentProcedureId
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// If we have a basic auth, for some reason it has to be added to the header
|
|
146
|
+
if (dplan.settings.basicAuth !== '') {
|
|
147
|
+
headers.Authorization = dplan.settings.basicAuth
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
this.uppy.use(Tus, {
|
|
151
|
+
endpoint: dplan.paths.uploadPost,
|
|
152
|
+
chunkSize: 819200, // 800 KiB
|
|
153
|
+
limit: 5,
|
|
154
|
+
onAfterResponse: (_req, res) => {
|
|
155
|
+
this.currentFileHash = res.getHeader('X-Demosplan-File-Hash')
|
|
156
|
+
this.currentFileId = res.getHeader('X-Demosplan-File-Id')
|
|
157
|
+
},
|
|
158
|
+
removeFingerprintOnSuccess: true,
|
|
159
|
+
headers
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
mounted () {
|
|
165
|
+
this.initialize()
|
|
166
|
+
|
|
167
|
+
this.uppy.on('complete', result => {
|
|
168
|
+
setTimeout(() => {
|
|
169
|
+
/*
|
|
170
|
+
* Triggers uppy file-removed event (we are instead using a custom file-remove event. we do not want files to
|
|
171
|
+
* be removed on resetting the uppy ui
|
|
172
|
+
*/
|
|
173
|
+
this.uppy.cancelAll()
|
|
174
|
+
}, 2000)
|
|
175
|
+
|
|
176
|
+
this.$emit('uploads-completed', result)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
this.uppy.on('upload-error', (file, error, response) => {
|
|
180
|
+
console.error(error)
|
|
181
|
+
dplan.notify.error(Translator.trans('error.fileupload'))
|
|
182
|
+
this.$emit('file-error', { file, error, response })
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
this.uppy.on('file-added', file => {
|
|
186
|
+
this.$emit('file-added', file)
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
this.uppy.on('upload', data => {
|
|
190
|
+
this.$emit('upload', data)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
this.uppy.on('restriction-failed', () => {
|
|
194
|
+
dplan.notify.warning(Translator.trans(this.allowedFileTypesWarning))
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
/*
|
|
198
|
+
* `upload-success` fires each time a single upload completes successfully.
|
|
199
|
+
* @see https://uppy.io/docs/uppy/#upload-success
|
|
200
|
+
*/
|
|
201
|
+
this.uppy.on('upload-success', (file) => {
|
|
202
|
+
const { name, size, type } = file.data
|
|
203
|
+
const newFile = {
|
|
204
|
+
name: name,
|
|
205
|
+
hash: this.currentFileHash,
|
|
206
|
+
size: size,
|
|
207
|
+
type: type,
|
|
208
|
+
id: file.id, // The uppy internal file id
|
|
209
|
+
fileId: this.currentFileId // The id of the file within demosplan
|
|
210
|
+
}
|
|
211
|
+
this.currentFileHash = ''
|
|
212
|
+
this.currentFileId = ''
|
|
213
|
+
this.$emit('upload-success', newFile)
|
|
214
|
+
})
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
beforeDestroy () {
|
|
218
|
+
if (this.uppy) {
|
|
219
|
+
this.uppy.close()
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
</script>
|