comand-component-library 3.3.75 → 3.3.76

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.
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="['cmd-headline', {'has-pre-headline-text': preHeadlineText, 'has-icon': headlineIcon?.iconClass}, getTextAlign]">
2
+ <div v-if="!editModeContext?.editing" :class="['cmd-headline', {'has-pre-headline-text': preHeadlineText, 'has-icon': headlineIcon?.iconClass}, getTextAlign]">
3
3
  <!-- begin CmdIcon -->
4
4
  <CmdIcon v-if="headlineIcon" :iconClass="headlineIcon?.iconClass" :type="headlineIcon?.iconType" />
5
5
  <!-- end CmdIcon -->
@@ -18,11 +18,24 @@
18
18
  <!-- end slot -->
19
19
  </component>
20
20
  </div>
21
+ <!-- begin edit-mode -->
22
+ <input v-else type="text" :class="['edit-mode', 'headline', 'h'+ headlineLevel]" v-model="editableHeadlineText" />
23
+ <!-- end edit-mode -->
21
24
  </template>
22
25
 
23
26
  <script>
24
27
  export default {
25
28
  name: "CmdHeadline",
29
+ inject: {
30
+ editModeContext: {
31
+ default: null
32
+ }
33
+ },
34
+ data() {
35
+ return {
36
+ editableHeadlineText: this.headlineText
37
+ }
38
+ },
26
39
  props: {
27
40
  /**
28
41
  * text for headline
@@ -60,8 +73,14 @@ export default {
60
73
  textAlign: {
61
74
  type: String,
62
75
  default: null
76
+ },
77
+ editModeContextData: {
78
+ type: Object
63
79
  }
64
80
  },
81
+ mounted() {
82
+ this.editModeContext?.addSaveHandler(this.onSave)
83
+ },
65
84
  computed: {
66
85
  getHeadlineTag() {
67
86
  if(this.headlineLevel) {
@@ -75,59 +94,73 @@ export default {
75
94
  }
76
95
  return ""
77
96
  }
97
+ },
98
+ methods: {
99
+ onSave() {
100
+ const headlineText = this.editableHeadlineText
101
+ return {
102
+ editModeContextData: {
103
+ ...(this.editModeContextData || {})
104
+ },
105
+ headlineText,
106
+ update(props) {
107
+ props.headlineText = headlineText
108
+ }
109
+ }
110
+ }
78
111
  }
79
112
  }
80
113
  </script>
81
114
 
82
115
  <style lang="scss">
83
116
  /* begin cmd-headline ------------------------------------------------------------------------------------------ */
84
- @import '../assets/styles/variables';
117
+ //@import '../assets/styles/variables';
85
118
 
86
119
  .cmd-headline {
87
- margin-bottom: var(--default-margin);
88
- gap: calc(var(--default-gap) / 2);
120
+ margin-bottom: var(--default-margin);
121
+ gap: calc(var(--default-gap) / 2);
89
122
 
90
- &.text-center > * {
91
- text-align: center;
92
- }
123
+ &.text-center > * {
124
+ text-align: center;
125
+ }
93
126
 
94
- &.text-right > * {
95
- text-align: right;
96
- }
127
+ &.text-right > * {
128
+ text-align: right;
129
+ }
97
130
 
98
- &.has-icon {
99
- display: flex;
100
- align-items: center;
101
- }
131
+ &.has-icon {
132
+ display: flex;
133
+ align-items: center;
134
+ }
102
135
 
103
- &.has-pre-headline-text {
104
- text-align: inherit;
136
+ &.has-pre-headline-text {
137
+ text-align: inherit;
105
138
 
106
- [class*="icon-"] {
107
- font-size: 5rem;
108
- }
139
+ [class*="icon-"] {
140
+ font-size: 5rem;
109
141
  }
142
+ }
110
143
 
111
- p {
112
- margin-bottom: 0;
113
- }
144
+ p {
145
+ margin-bottom: 0;
146
+ }
114
147
 
115
- h1, h2, h3, h4, h5, h6 {
116
- margin: 0;
148
+ h1, h2, h3, h4, h5, h6 {
149
+ margin: 0;
117
150
 
118
- &:only-child {
119
- flex: none;
120
- width: 100%;
121
- }
151
+ &:only-child {
152
+ flex: none;
153
+ width: 100%;
122
154
  }
155
+ }
123
156
 
124
- @media only screen and (max-width: $small-max-width) {
125
- flex-direction: column;
126
-
127
- h1 {
128
- margin-bottom: calc(var(--default-margin) * 2);
129
- }
130
- }
157
+ //@media only screen and (max-width: $small-max-width) {
158
+ // flex-direction: column;
159
+ //
160
+ // h1 {
161
+ // margin-bottom: calc(var(--default-margin) * 2);
162
+ // }
163
+ //}
131
164
  }
132
165
  /* end cmd-headline ------------------------------------------------------------------------------------------ */
133
166
  </style>
@@ -1,24 +1,142 @@
1
1
  <template>
2
- <figure :class="['cmd-image', getTextAlign]">
3
- <figcaption v-if="figcaption?.show && figcaption?.position === 'top'">{{figcaption?.text}}</figcaption>
4
- <img :src="imageSource" :alt="image.alt" :title="image.tooltip" />
5
- <figcaption v-if="figcaption?.show && figcaption?.position !== 'top'">{{figcaption?.text}}</figcaption>
2
+ <!-- begin edit-mode -->
3
+ <figure v-if="editModeContext?.editing" :class="['cmd-image flex-container vertical', getTextAlign]">
4
+ <CmdFormElement
5
+ element="input"
6
+ type="checkbox"
7
+ :toggleSwitch="true"
8
+ labelText="Show figcaption"
9
+ v-model="editableShowFigcaption"
10
+ />
11
+ <CmdFormElement
12
+ element="select"
13
+ labelText="Figcaption Position"
14
+ :selectOptions="positionOptions"
15
+ :disabled="!showFigcaption"
16
+ v-model="editableFigcaptionPosition"
17
+ />
18
+ <CmdFormElement
19
+ element="select"
20
+ labelText="Figcaption text alignment"
21
+ :selectOptions="textAlignOptions"
22
+ :disabled="!showFigcaption"
23
+ v-model="editableFigcaptionTextAlign"
24
+ />
25
+ <CmdFormElement element="input" type="text" :required="true" labelText="Alternative Text"
26
+ v-model="editableAlternativeText"/>
27
+ <CmdFormElement element="input" type="text" :required="false" labelText="Tooltip" v-model="editableTooltip"/>
28
+
29
+ <template v-if="figcaption?.position === 'top'">
30
+ <CmdFormElement element="input" type="text" :required="true" labelText="Text figcaption"
31
+ v-model="editableFigcaptionText"/>
32
+ </template>
33
+ <div :class="['box drop-area flex-container vertical', { 'allow-drop': allowDrop }]" v-on="dragAndDropHandler" title="Drag new image to this area to replace old one!">
34
+ <span class="icon-image"></span>
35
+ <img ref="contentImage" :src="image.src" :alt="image.alt" :title="image.tooltip"/>
36
+ </div>
37
+ <button
38
+ type="button"
39
+ :class="['button upload primary', { disabled: uploadInitiated }]"
40
+ :disabled="uploadInitiated"
41
+ @click="selectFiles()"
42
+ >
43
+ <!-- begin CmdIcon -->
44
+ <CmdIcon iconClass="icon-loop"/>
45
+ <!-- end CmdIcon -->
46
+ <span>Select image</span>
47
+ </button>
48
+ <template v-if="figcaption?.position !== 'top'">
49
+ <CmdFormElement
50
+ element="input"
51
+ type="text"
52
+ :class="getTextAlign"
53
+ :required="true"
54
+ labelText="Text figcaption"
55
+ v-model="editableFigcaptionText"
56
+ />
57
+ </template>
58
+ </figure>
59
+
60
+ <!-- begin CmdFormElement -->
61
+ <CmdFormElement
62
+ v-if="editModeContext?.editing"
63
+ class="hidden"
64
+ element="input"
65
+ type="file"
66
+ labelText="Select file"
67
+ :disabled="uploadInitiated"
68
+ @change="fileSelected"
69
+ ref="formElement"
70
+ />
71
+ <!-- end CmdFormElement -->
72
+ <!-- end edit-mode -->
73
+
74
+ <figure v-else :class="['cmd-image', getTextAlign]">
75
+ <figcaption v-if="figcaption?.show && figcaption?.position === 'top'">{{ figcaption?.text }}</figcaption>
76
+ <img :src="imageSource" :alt="image.alt" :title="image.tooltip"/>
77
+ <figcaption v-if="figcaption?.show && figcaption?.position !== 'top'">{{ figcaption?.text }}</figcaption>
6
78
  </figure>
7
79
  </template>
8
80
 
9
81
  <script>
82
+ import {getFileExtension} from "../utils/getFileExtension"
83
+
10
84
  export default {
85
+ name: "CmdImage",
86
+ inject: {
87
+ editModeContext: {
88
+ default: null
89
+ }
90
+ },
11
91
  data() {
12
92
  return {
13
93
  mediumMaxWidth: 1023,
14
94
  smallMaxWidth: 600,
15
- currentWindowWidth: window.innerWidth
95
+ currentWindowWidth: window.innerWidth,
96
+ allowedFileExtensions: ["jpg", "jpeg", "png"],
97
+ uploadInitiated: false,
98
+ allowDrop: false,
99
+ showFigcaption: true,
100
+ figcaptionPosition: null,
101
+ figcaptionTextAlign: null,
102
+ tooltip: null,
103
+ alternativeText: null,
104
+ positionOptions: [
105
+ {
106
+ text: "Above image",
107
+ value: "top"
108
+ },
109
+ {
110
+ text: "Below image",
111
+ value: "bottom"
112
+ }
113
+ ],
114
+ textAlignOptions: [
115
+ {
116
+ text: "Left",
117
+ value: "left"
118
+ },
119
+ {
120
+ text: "Center",
121
+ value: "center"
122
+ },
123
+ {
124
+ text: "Right",
125
+ value: "right"
126
+ }
127
+ ],
128
+ figcaptionText: null
16
129
  }
17
130
  },
18
- name: "CmdImage",
131
+ mounted() {
132
+ this.editModeContext?.addSaveHandler(this.onSave)
133
+ },
19
134
  props: {
135
+ editModeContextData: {
136
+ type: Object
137
+ },
20
138
  /**
21
- * image-object including source(s), alternative text, tooltip (not required)
139
+ * image-object including source, alternative text, tooltip (not required)
22
140
  */
23
141
  image: {
24
142
  type: Object,
@@ -30,6 +148,17 @@ export default {
30
148
  figcaption: {
31
149
  type: Object,
32
150
  required: false
151
+ },
152
+ /**
153
+ * max file size (in bytes) for file to upload
154
+ */
155
+ maxFileUploadSize: {
156
+ type: Number,
157
+ default: 500000
158
+ },
159
+ minImageWidth: {
160
+ type: Number,
161
+ default: 1025
33
162
  }
34
163
  },
35
164
  created() {
@@ -45,12 +174,6 @@ export default {
45
174
  window.removeEventListener("resize", this.updateWindowWidth)
46
175
  },
47
176
  computed: {
48
- getTextAlign() {
49
- if(this.figcaption?.textAlign) {
50
- return "text-" + this.figcaption.textAlign
51
- }
52
- return ''
53
- },
54
177
  imageSource() {
55
178
  // if only one src exists
56
179
  const imgSrc = this.image.src
@@ -70,11 +193,193 @@ export default {
70
193
  }
71
194
  // else return large (will be used if images for small-and -medium-devices do not exist or if screen resolution is larger than mediumMaxWidth)
72
195
  return imgSrc.large
196
+ },
197
+ dragAndDropHandler() {
198
+ // register handlers only if drag-and-drop is enabled
199
+ return {
200
+ dragenter: this.dragEnter,
201
+ dragover: this.dragOver,
202
+ dragleave: this.dragLeave,
203
+ drop: this.drop
204
+ }
205
+ },
206
+ getTextAlign() {
207
+ if (this.figcaption?.textAlign) {
208
+ return "text-" + this.figcaption.textAlign
209
+ }
210
+ return ''
211
+ },
212
+ editableAlternativeText: {
213
+ get() {
214
+ return this.alternativeText == null ? this.image.alt : this.alternativeText
215
+ },
216
+ set(value) {
217
+ this.alternativeText = value
218
+ }
219
+ },
220
+ editableTooltip: {
221
+ get() {
222
+ return this.tooltip == null ? this.image.tooltip : this.tooltip
223
+ },
224
+ set(value) {
225
+ this.tooltip = value
226
+ }
227
+ },
228
+ editableShowFigcaption: {
229
+ get() {
230
+ return this.showFigcaption == null ? this.figcaption.show : this.showFigcaption
231
+ },
232
+ set(value) {
233
+ this.showFigcaption = value
234
+ }
235
+ },
236
+ editableFigcaptionPosition: {
237
+ get() {
238
+ return this.figcaptionPosition == null ? this.figcaption.position : this.figcaptionPosition
239
+ },
240
+ set(value) {
241
+ this.figcaptionPosition = value
242
+ }
243
+ },
244
+ editableFigcaptionTextAlign: {
245
+ get() {
246
+ return this.figcaptionTextAlign || this.figcaption.textAlign
247
+ },
248
+ set(value) {
249
+ this.figcaptionTextAlign = value
250
+ }
251
+ },
252
+ editableFigcaptionText: {
253
+ get() {
254
+ return this.figcaptionText || this.figcaption.text
255
+ },
256
+ set(value) {
257
+ this.figcaptionText = value
258
+ }
73
259
  }
74
260
  },
75
261
  methods: {
76
262
  updateWindowWidth() {
77
263
  this.currentWindowWidth = window.innerWidth
264
+ },
265
+ getImage() {
266
+ return {
267
+ image: {...this.image},
268
+ figcaption: {
269
+ show: this.editableShowFigcaption,
270
+ position: this.editableFigcaptionPosition,
271
+ textAlign: this.editableFigcaptionTextAlign,
272
+ text: this.editableFigcaptionText
273
+ }
274
+ }
275
+ },
276
+ fileSelected(event) {
277
+ if (event.target.files.length > 0) {
278
+ this.checkAndUploadFile(event.target.files[0])
279
+ }
280
+ },
281
+ selectFiles() {
282
+ let inputFile = this.$refs.formElement.getDomElement().querySelector("input[type='file']")
283
+ inputFile.click()
284
+ },
285
+ dragEnter(event) {
286
+ this.dragOver(event)
287
+ },
288
+ dragOver(event) {
289
+ if (event.dataTransfer && event.dataTransfer.items && event.dataTransfer.items.length > 0) {
290
+ event.dataTransfer.dropEffect = "none"
291
+
292
+ let item = event.dataTransfer.items[0]
293
+
294
+ if (item.kind === "file") {
295
+ event.preventDefault()
296
+ event.dataTransfer.dropEffect = "copy"
297
+ this.allowDrop = true
298
+ // this._handle_dragover(event)
299
+ }
300
+ }
301
+ },
302
+ dragLeave() {
303
+ this.allowDrop = false
304
+ },
305
+ drop(event) {
306
+ this.allowDrop = false
307
+ if (event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files.length > 0) {
308
+ event.preventDefault()
309
+ this.checkAndUploadFile(event.dataTransfer.files[0])
310
+ }
311
+ },
312
+ onSave() {
313
+ const data = {
314
+ image: {
315
+ alt: this.editableAlternativeText,
316
+ tooltip: this.editableTooltip
317
+ },
318
+ figcaption: {
319
+ position: this.editableFigcaptionPosition,
320
+ textAlign: this.editableFigcaptionTextAlign,
321
+ text: this.editableFigcaptionText,
322
+ show: this.editableShowFigcaption
323
+ }
324
+ }
325
+ return {
326
+ editModeContextData: this.editModeContextData,
327
+ ...data,
328
+ update(props) {
329
+ console.log("CmdImage.update", props)
330
+ if (!props.image) {
331
+ props.image = {}
332
+ }
333
+ props.image.alt = data.image.alt
334
+ props.image.tooltip = data.image.tooltip
335
+ if (!props.figcaption) {
336
+ props.figcaption = {}
337
+ }
338
+ props.figcaption.position = data.figcaption.position
339
+ props.figcaption.textAlign = data.figcaption.textAlign
340
+ props.figcaption.text = data.figcaption.text
341
+ props.figcaption.show = data.figcaption.show
342
+ }
343
+ }
344
+ },
345
+ checkAndUploadFile(file) {
346
+ const errorMessages = []
347
+
348
+ // check size for current file
349
+ if (file.size > this.maxFileUploadSize) {
350
+ errorMessages.push("file too large")
351
+ }
352
+
353
+ // check if current file has allowed file-type
354
+ if (!this.allowedFileExtensions.includes(getFileExtension(file.name))) {
355
+ errorMessages.push("disallowed file extension")
356
+ }
357
+
358
+ if (errorMessages.length) {
359
+ alert(errorMessages)
360
+ return
361
+ }
362
+
363
+ // check for min dimensions
364
+ const image = new Image()
365
+
366
+ image.onload = () => {
367
+ if (image.width < this.minImageWidth) {
368
+ // errorMessages.push("width (" + image.width + " px) too small - at least " + this.minImageWidth + " px required!")
369
+ const confirmUpload = confirm("width (" + image.width + " px) too small - at least " + this.minImageWidth + " px required! Use trotzdem!")
370
+ if (!confirmUpload) {
371
+ alert("Abbruch")
372
+ return
373
+ }
374
+ }
375
+ // revoke URL to clean memory
376
+ URL.revokeObjectURL(image.src)
377
+
378
+ // show preview-image by assigning image.src (containing image date (not its path) to do existing contentImage source
379
+ this.$refs.contentImage.src = image.src
380
+ }
381
+ // create data-url (contains content of a file (not its path))
382
+ image.src = URL.createObjectURL(file)
78
383
  }
79
384
  }
80
385
  }
@@ -83,17 +388,46 @@ export default {
83
388
  <style lang="scss">
84
389
  /* begin cmd-image ------------------------------------------------------------------------------------------ */
85
390
  .cmd-image {
86
- &.text-center {
87
- figcaption {
88
- text-align: center;
89
- }
391
+ &.text-center {
392
+ figcaption {
393
+ text-align: center;
90
394
  }
395
+ }
91
396
 
92
- &.text-right {
93
- figcaption {
94
- text-align: right;
95
- }
397
+ &.text-right {
398
+ figcaption {
399
+ text-align: right;
400
+ }
401
+ }
402
+
403
+ .drop-area {
404
+ border: 0;
405
+ align-items: center;
406
+ justify-content: center;
407
+ padding: 0;
408
+
409
+ > [class*="icon"] {
410
+ position: absolute;
411
+ top: 50%;
412
+ left: 50%;
413
+ transform: translateX(-50%) translateY(-50%);
414
+ font-size: 10rem;
415
+ color: var(--pure-white);
416
+ text-shadow: var(--text-shadow);
417
+ z-index: 10;
96
418
  }
419
+
420
+ img {
421
+ opacity: .7;
422
+ transition: var(--default-transition);
423
+
424
+ &:hover, :active, :focus {
425
+ opacity: 1;
426
+ transition: var(--default-transition);
427
+ }
428
+ }
429
+ }
97
430
  }
431
+
98
432
  /* end cmd-image ------------------------------------------------------------------------------------------ */
99
433
  </style>