@blokkli/editor 1.0.1 → 1.0.3
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/dist/module.json +1 -1
- package/dist/module.mjs +31 -1
- package/dist/runtime/adapter/drupal/graphqlMiddleware.js +9 -1
- package/dist/runtime/adapter/index.d.ts +4 -0
- package/dist/runtime/components/Blocks/FromLibrary/index.vue +2 -3
- package/dist/runtime/components/Edit/Dialog/index.vue +14 -1
- package/dist/runtime/components/Edit/DragInteractions/index.vue +6 -7
- package/dist/runtime/components/Edit/EditProvider.vue +1 -0
- package/dist/runtime/components/Edit/Features/Edit/index.vue +63 -14
- package/dist/runtime/components/Edit/Features/Exit/index.vue +2 -1
- package/dist/runtime/components/Edit/Features/Library/EditReusable/index.vue +206 -0
- package/dist/runtime/components/Edit/Features/Library/index.vue +25 -2
- package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +2 -4
- package/dist/runtime/components/Edit/Features/Publish/index.vue +4 -1
- package/dist/runtime/components/Edit/Features/Translations/index.vue +43 -1
- package/dist/runtime/css/output.css +1 -1
- package/dist/runtime/helpers/broadcastProvider.d.ts +10 -2
- package/dist/runtime/helpers/composables/onBroadcastEvent.d.ts +2 -0
- package/dist/runtime/helpers/composables/onBroadcastEvent.js +10 -0
- package/dist/runtime/helpers/index.js +2 -2
- package/dist/runtime/helpers/runtimeHelpers/index.d.ts +5 -0
- package/dist/runtime/helpers/runtimeHelpers/index.js +4 -6
- package/dist/runtime/types/index.d.ts +12 -2
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { createUnplugin } from 'unplugin';
|
|
|
6
6
|
import MagicString from 'magic-string';
|
|
7
7
|
import { walk } from 'estree-walker-ts';
|
|
8
8
|
|
|
9
|
-
const version = "1.0.
|
|
9
|
+
const version = "1.0.3";
|
|
10
10
|
|
|
11
11
|
function sortObjectKeys(obj) {
|
|
12
12
|
const sortedKeys = Object.keys(obj).sort();
|
|
@@ -1155,6 +1155,14 @@ const libraryError$2 = {
|
|
|
1155
1155
|
source: "Failed to add block to library.",
|
|
1156
1156
|
translation: "Das Element konnte nicht wiederverwendbar gemacht werden."
|
|
1157
1157
|
};
|
|
1158
|
+
const libraryItemEditOverlayBack$2 = {
|
|
1159
|
+
source: "Back to page",
|
|
1160
|
+
translation: "Zurück zur Seite"
|
|
1161
|
+
};
|
|
1162
|
+
const libraryItemEditOverlayTitle$2 = {
|
|
1163
|
+
source: "Edit reusable block",
|
|
1164
|
+
translation: "Wiederverwendbaren Block bearbeiten"
|
|
1165
|
+
};
|
|
1158
1166
|
const libraryPlaceBundleSelectLabel$2 = {
|
|
1159
1167
|
source: "Bundle",
|
|
1160
1168
|
translation: "Typ"
|
|
@@ -1692,6 +1700,8 @@ const de = {
|
|
|
1692
1700
|
libraryDialogTitle: libraryDialogTitle$2,
|
|
1693
1701
|
libraryDialogTitleInputPlaceholder: libraryDialogTitleInputPlaceholder$2,
|
|
1694
1702
|
libraryError: libraryError$2,
|
|
1703
|
+
libraryItemEditOverlayBack: libraryItemEditOverlayBack$2,
|
|
1704
|
+
libraryItemEditOverlayTitle: libraryItemEditOverlayTitle$2,
|
|
1695
1705
|
libraryPlaceBundleSelectLabel: libraryPlaceBundleSelectLabel$2,
|
|
1696
1706
|
libraryPlaceDialogLead: libraryPlaceDialogLead$2,
|
|
1697
1707
|
libraryPlaceDialogSubmit: libraryPlaceDialogSubmit$2,
|
|
@@ -2298,6 +2308,14 @@ const libraryError$1 = {
|
|
|
2298
2308
|
source: "Failed to add block to library.",
|
|
2299
2309
|
translation: "L'élément n’a pas pu être rendu réutilisable."
|
|
2300
2310
|
};
|
|
2311
|
+
const libraryItemEditOverlayBack$1 = {
|
|
2312
|
+
source: "Back to page",
|
|
2313
|
+
translation: ""
|
|
2314
|
+
};
|
|
2315
|
+
const libraryItemEditOverlayTitle$1 = {
|
|
2316
|
+
source: "Edit reusable block",
|
|
2317
|
+
translation: ""
|
|
2318
|
+
};
|
|
2301
2319
|
const libraryPlaceBundleSelectLabel$1 = {
|
|
2302
2320
|
source: "Bundle",
|
|
2303
2321
|
translation: ""
|
|
@@ -2835,6 +2853,8 @@ const fr = {
|
|
|
2835
2853
|
libraryDialogTitle: libraryDialogTitle$1,
|
|
2836
2854
|
libraryDialogTitleInputPlaceholder: libraryDialogTitleInputPlaceholder$1,
|
|
2837
2855
|
libraryError: libraryError$1,
|
|
2856
|
+
libraryItemEditOverlayBack: libraryItemEditOverlayBack$1,
|
|
2857
|
+
libraryItemEditOverlayTitle: libraryItemEditOverlayTitle$1,
|
|
2838
2858
|
libraryPlaceBundleSelectLabel: libraryPlaceBundleSelectLabel$1,
|
|
2839
2859
|
libraryPlaceDialogLead: libraryPlaceDialogLead$1,
|
|
2840
2860
|
libraryPlaceDialogSubmit: libraryPlaceDialogSubmit$1,
|
|
@@ -3441,6 +3461,14 @@ const libraryError = {
|
|
|
3441
3461
|
source: "Failed to add block to library.",
|
|
3442
3462
|
translation: "L'elemento non può essere reso riutilizzabile."
|
|
3443
3463
|
};
|
|
3464
|
+
const libraryItemEditOverlayBack = {
|
|
3465
|
+
source: "Back to page",
|
|
3466
|
+
translation: ""
|
|
3467
|
+
};
|
|
3468
|
+
const libraryItemEditOverlayTitle = {
|
|
3469
|
+
source: "Edit reusable block",
|
|
3470
|
+
translation: ""
|
|
3471
|
+
};
|
|
3444
3472
|
const libraryPlaceBundleSelectLabel = {
|
|
3445
3473
|
source: "Bundle",
|
|
3446
3474
|
translation: ""
|
|
@@ -3978,6 +4006,8 @@ const it = {
|
|
|
3978
4006
|
libraryDialogTitle: libraryDialogTitle,
|
|
3979
4007
|
libraryDialogTitleInputPlaceholder: libraryDialogTitleInputPlaceholder,
|
|
3980
4008
|
libraryError: libraryError,
|
|
4009
|
+
libraryItemEditOverlayBack: libraryItemEditOverlayBack,
|
|
4010
|
+
libraryItemEditOverlayTitle: libraryItemEditOverlayTitle,
|
|
3981
4011
|
libraryPlaceBundleSelectLabel: libraryPlaceBundleSelectLabel,
|
|
3982
4012
|
libraryPlaceDialogLead: libraryPlaceDialogLead,
|
|
3983
4013
|
libraryPlaceDialogSubmit: libraryPlaceDialogSubmit,
|
|
@@ -339,6 +339,13 @@ export default defineBlokkliEditAdapter(
|
|
|
339
339
|
const url = typeof parts === "string" ? parts : "/" + parts.join("/");
|
|
340
340
|
return { url: prefix + url + `?paragraphsBlokkli=true` };
|
|
341
341
|
};
|
|
342
|
+
const getLibraryItemEditUrl = (uuid) => {
|
|
343
|
+
const url = buildFormUrl(
|
|
344
|
+
["blokkli", "library-item", uuid],
|
|
345
|
+
ctx.value.language
|
|
346
|
+
).url;
|
|
347
|
+
return `${url}&blokkliEditing=${uuid}&language=${ctx.value.language}`;
|
|
348
|
+
};
|
|
342
349
|
const formFrameBuilder = (e) => {
|
|
343
350
|
const entityType = ctx.value.entityType.toLowerCase();
|
|
344
351
|
if (e.id === "block:add") {
|
|
@@ -637,7 +644,8 @@ export default defineBlokkliEditAdapter(
|
|
|
637
644
|
addContentSearchItem,
|
|
638
645
|
clipboardMapBundle,
|
|
639
646
|
addBlockFromClipboardItem,
|
|
640
|
-
changeLanguage
|
|
647
|
+
changeLanguage,
|
|
648
|
+
getLibraryItemEditUrl
|
|
641
649
|
};
|
|
642
650
|
}
|
|
643
651
|
);
|
|
@@ -197,6 +197,10 @@ export interface BlokkliAdapter<T> {
|
|
|
197
197
|
* Add a reusable item.
|
|
198
198
|
*/
|
|
199
199
|
addLibraryItem?: (e: AddReusableItemEvent) => Promise<MutationResponseLike<T>>;
|
|
200
|
+
/**
|
|
201
|
+
* Build the URL to edit a library item.
|
|
202
|
+
*/
|
|
203
|
+
getLibraryItemEditUrl?: (uuid: string) => string;
|
|
200
204
|
/**
|
|
201
205
|
* Delete multiple items.
|
|
202
206
|
*/
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
:data-reusable-bundle="item.bundle"
|
|
8
8
|
:data-reusable-uuid="item.uuid"
|
|
9
9
|
:data-bk-library-label="libraryItem?.label"
|
|
10
|
+
:data-bk-library-item-uuid="libraryItem?.uuid"
|
|
10
11
|
data-blokkli-is-reusable="true"
|
|
11
12
|
:parent-type="parentType"
|
|
12
13
|
/>
|
|
@@ -23,6 +24,7 @@ import type { FieldListItem } from '#blokkli/types'
|
|
|
23
24
|
interface LibraryItem {
|
|
24
25
|
block?: FieldListItem
|
|
25
26
|
label?: string
|
|
27
|
+
uuid?: string
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const props = defineProps<{
|
|
@@ -31,9 +33,6 @@ const props = defineProps<{
|
|
|
31
33
|
|
|
32
34
|
const { index, options, parentType } = defineBlokkli({
|
|
33
35
|
bundle: 'from_library',
|
|
34
|
-
editor: {
|
|
35
|
-
disableEdit: true,
|
|
36
|
-
},
|
|
37
36
|
})
|
|
38
37
|
|
|
39
38
|
// Reusable items inherit the options from this wrapper paragraph.
|
|
@@ -19,7 +19,12 @@
|
|
|
19
19
|
</button>
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
|
-
<div
|
|
22
|
+
<div
|
|
23
|
+
class="bk-dialog-content"
|
|
24
|
+
:class="{
|
|
25
|
+
'bk-is-fullscreen': fullScreen,
|
|
26
|
+
}"
|
|
27
|
+
>
|
|
23
28
|
<div class="bk-dialog-content-inner">
|
|
24
29
|
<div v-if="lead" class="bk bk-dialog-lead">
|
|
25
30
|
{{ lead }}
|
|
@@ -67,6 +72,7 @@ const props = withDefaults(
|
|
|
67
72
|
isLoading?: boolean
|
|
68
73
|
hideButtons?: boolean
|
|
69
74
|
icon?: BlokkliIcon
|
|
75
|
+
fullScreen?: boolean
|
|
70
76
|
}>(),
|
|
71
77
|
{
|
|
72
78
|
width: 600,
|
|
@@ -82,6 +88,13 @@ const style = computed(() => {
|
|
|
82
88
|
return {}
|
|
83
89
|
}
|
|
84
90
|
|
|
91
|
+
if (props.fullScreen) {
|
|
92
|
+
return {
|
|
93
|
+
maxWidth: '100vw',
|
|
94
|
+
height: '100vh',
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
85
98
|
if (typeof props.width === 'number') {
|
|
86
99
|
return {
|
|
87
100
|
maxWidth: props.width + 'px',
|
|
@@ -158,15 +158,17 @@ function onPointerDown(e: PointerEvent) {
|
|
|
158
158
|
e.stopImmediatePropagation()
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
if (e.pointerType === 'touch') {
|
|
162
|
+
return onTouchStart(e)
|
|
163
|
+
}
|
|
164
|
+
|
|
161
165
|
// If we are already dragging, return.
|
|
162
166
|
// This might be the case if a dragging:start event was manually triggered,
|
|
163
167
|
// e.g. when selecting a draggable item using the keyboard.
|
|
164
168
|
if (selection.isDragging.value) {
|
|
165
169
|
return
|
|
166
170
|
}
|
|
167
|
-
|
|
168
|
-
return onTouchStart(e)
|
|
169
|
-
}
|
|
171
|
+
|
|
170
172
|
pointerDownTimestamp = Date.now()
|
|
171
173
|
const coords = { x: e.clientX, y: e.clientY }
|
|
172
174
|
|
|
@@ -241,10 +243,7 @@ function onPointerUp(e: PointerEvent) {
|
|
|
241
243
|
if (!block) {
|
|
242
244
|
return
|
|
243
245
|
}
|
|
244
|
-
eventBus.emit('item:
|
|
245
|
-
uuid: lastInteractedElement.uuid,
|
|
246
|
-
bundle: block.itemBundle,
|
|
247
|
-
})
|
|
246
|
+
eventBus.emit('item:doubleClick', block)
|
|
248
247
|
}
|
|
249
248
|
}
|
|
250
249
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<PluginItemAction
|
|
3
|
+
v-if="isEditing"
|
|
3
4
|
id="edit"
|
|
4
5
|
:title="$t('edit', 'Edit')"
|
|
5
|
-
:disabled="
|
|
6
|
+
:disabled="!canEdit"
|
|
6
7
|
meta
|
|
7
8
|
key-code="E"
|
|
8
9
|
icon="edit"
|
|
@@ -16,6 +17,7 @@ import { computed, useBlokkli, defineBlokkliFeature } from '#imports'
|
|
|
16
17
|
import type { DraggableExistingBlock } from '#blokkli/types'
|
|
17
18
|
import { PluginItemAction } from '#blokkli/plugins'
|
|
18
19
|
import { getDefinition } from '#blokkli/definitions'
|
|
20
|
+
import onBlokkliEvent from '#blokkli/helpers/composables/onBlokkliEvent'
|
|
19
21
|
|
|
20
22
|
defineBlokkliFeature({
|
|
21
23
|
id: 'edit',
|
|
@@ -25,23 +27,47 @@ defineBlokkliFeature({
|
|
|
25
27
|
requiredAdapterMethods: ['formFrameBuilder'],
|
|
26
28
|
})
|
|
27
29
|
|
|
28
|
-
const { eventBus, selection, state, $t } = useBlokkli()
|
|
30
|
+
const { eventBus, selection, state, $t, adapter } = useBlokkli()
|
|
29
31
|
|
|
30
|
-
const
|
|
31
|
-
if (state.editMode.value !== 'editing') {
|
|
32
|
-
return true
|
|
33
|
-
}
|
|
32
|
+
const block = computed(() => {
|
|
34
33
|
if (selection.blocks.value.length !== 1) {
|
|
35
|
-
return
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return selection.blocks.value[0]
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const isEditing = computed(() => state.editMode.value === 'editing')
|
|
41
|
+
|
|
42
|
+
const canEdit = computed(() => {
|
|
43
|
+
// Editing is only possible when a single block is selected.
|
|
44
|
+
if (!block.value) {
|
|
45
|
+
return false
|
|
36
46
|
}
|
|
37
47
|
|
|
38
|
-
const block = selection.blocks.value[0]
|
|
39
48
|
const definition = getDefinition(
|
|
40
|
-
block.itemBundle,
|
|
41
|
-
block.hostFieldListType,
|
|
42
|
-
block.parentBlockBundle,
|
|
49
|
+
block.value.itemBundle,
|
|
50
|
+
block.value.hostFieldListType,
|
|
51
|
+
block.value.parentBlockBundle,
|
|
43
52
|
)
|
|
44
|
-
|
|
53
|
+
|
|
54
|
+
// Editing is explicitly disabled via the definition.
|
|
55
|
+
if (definition?.editor?.disableEdit) {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// For reusable blocks, editing is only possible if the adapter implements
|
|
60
|
+
// the getLibraryItemEditUrl method.
|
|
61
|
+
if (block.value.libraryItemUuid) {
|
|
62
|
+
return (
|
|
63
|
+
!!adapter.getLibraryItemEditUrl &&
|
|
64
|
+
(state.editMode.value === 'editing' ||
|
|
65
|
+
state.editMode.value === 'translating') &&
|
|
66
|
+
!block.value.isNew
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return state.editMode.value === 'editing'
|
|
45
71
|
})
|
|
46
72
|
|
|
47
73
|
function onClick(items: DraggableExistingBlock[]) {
|
|
@@ -49,11 +75,34 @@ function onClick(items: DraggableExistingBlock[]) {
|
|
|
49
75
|
return
|
|
50
76
|
}
|
|
51
77
|
|
|
78
|
+
if (!canEdit.value) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const item = items[0]
|
|
83
|
+
|
|
84
|
+
// Because editing library items inside the current context is not (yet)
|
|
85
|
+
// supported, editing has to happen in a separate window where the host
|
|
86
|
+
// context is the library item entity.
|
|
87
|
+
if (item.libraryItemUuid && adapter.getLibraryItemEditUrl) {
|
|
88
|
+
const url = adapter.getLibraryItemEditUrl(item.libraryItemUuid)
|
|
89
|
+
eventBus.emit('library:edit-item', {
|
|
90
|
+
url,
|
|
91
|
+
label: item.editTitle,
|
|
92
|
+
uuid: item.libraryItemUuid,
|
|
93
|
+
})
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
52
97
|
eventBus.emit('item:edit', {
|
|
53
|
-
uuid:
|
|
54
|
-
bundle:
|
|
98
|
+
uuid: item.uuid,
|
|
99
|
+
bundle: item.itemBundle,
|
|
55
100
|
})
|
|
56
101
|
}
|
|
102
|
+
|
|
103
|
+
onBlokkliEvent('item:doubleClick', function (block) {
|
|
104
|
+
onClick([block])
|
|
105
|
+
})
|
|
57
106
|
</script>
|
|
58
107
|
|
|
59
108
|
<script lang="ts">
|
|
@@ -20,12 +20,13 @@ defineBlokkliFeature({
|
|
|
20
20
|
description: 'Provides a menu button to exit the editor without saving.',
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
const { $t } = useBlokkli()
|
|
23
|
+
const { $t, broadcast, context } = useBlokkli()
|
|
24
24
|
|
|
25
25
|
const route = useRoute()
|
|
26
26
|
|
|
27
27
|
function onClick() {
|
|
28
28
|
nextTick(() => {
|
|
29
|
+
broadcast.emit('closeEditor', { uuid: context.value.entityUuid })
|
|
29
30
|
window.location.href = route.path
|
|
30
31
|
})
|
|
31
32
|
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Teleport to="body">
|
|
3
|
+
<Loading v-if="isLoading" />
|
|
4
|
+
<Transition name="bk-library-edit-header">
|
|
5
|
+
<header v-show="isLoaded" class="bk bk-library-edit-overlay-header">
|
|
6
|
+
<h2>
|
|
7
|
+
<span>{{
|
|
8
|
+
$t('libraryItemEditOverlayTitle', 'Edit reusable block')
|
|
9
|
+
}}</span>
|
|
10
|
+
<span v-if="label"> {{ label }}</span>
|
|
11
|
+
</h2>
|
|
12
|
+
<button @click.prevent="closeOverlay">
|
|
13
|
+
<Icon name="arrow-left" />
|
|
14
|
+
<span>{{ $t('libraryItemEditOverlayBack', 'Back to page') }}</span>
|
|
15
|
+
</button>
|
|
16
|
+
</header>
|
|
17
|
+
</Transition>
|
|
18
|
+
<Transition
|
|
19
|
+
:css="false"
|
|
20
|
+
@enter="onEnter"
|
|
21
|
+
@after-enter="onAfter"
|
|
22
|
+
@enter-cancelled="onAfter"
|
|
23
|
+
@leave="onLeave"
|
|
24
|
+
@after-leave="onAfterLeave"
|
|
25
|
+
@leave-cancelled="onAfterLeave"
|
|
26
|
+
>
|
|
27
|
+
<div v-show="isLoaded" class="bk bk-library-edit-overlay">
|
|
28
|
+
<iframe
|
|
29
|
+
ref="iframe"
|
|
30
|
+
:src="url"
|
|
31
|
+
style="width: 100%; height: 100%"
|
|
32
|
+
@load="onLoad"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
</Transition>
|
|
36
|
+
</Teleport>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script lang="ts" setup>
|
|
40
|
+
import onBroadcastEvent from '#blokkli/helpers/composables/onBroadcastEvent'
|
|
41
|
+
import { ref, useBlokkli } from '#imports'
|
|
42
|
+
import { Icon } from '#blokkli/components'
|
|
43
|
+
import Loading from './../../../Loading/index.vue'
|
|
44
|
+
|
|
45
|
+
const props = defineProps<{
|
|
46
|
+
url: string
|
|
47
|
+
uuid: string
|
|
48
|
+
label?: string
|
|
49
|
+
}>()
|
|
50
|
+
|
|
51
|
+
const DURATION = 530
|
|
52
|
+
const emit = defineEmits(['submit', 'close'])
|
|
53
|
+
|
|
54
|
+
function getOriginatingElement(): HTMLElement | null {
|
|
55
|
+
const el = document.querySelector(
|
|
56
|
+
`[data-bk-library-item-uuid="${props.uuid}"]`,
|
|
57
|
+
)
|
|
58
|
+
if (el instanceof HTMLElement) {
|
|
59
|
+
return el
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// called one frame after the element is inserted.
|
|
66
|
+
// use this to start the entering animation.
|
|
67
|
+
function onEnter(el: Element, done: () => void) {
|
|
68
|
+
if (el instanceof HTMLElement) {
|
|
69
|
+
const originating = getOriginatingElement()
|
|
70
|
+
if (!originating) {
|
|
71
|
+
done()
|
|
72
|
+
isLoading.value = false
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const originatingRect = originating.getBoundingClientRect()
|
|
77
|
+
const overlayRect = el.getBoundingClientRect()
|
|
78
|
+
|
|
79
|
+
const offsetX =
|
|
80
|
+
originatingRect.x - overlayRect.x + originatingRect.width / 2
|
|
81
|
+
const offsetY =
|
|
82
|
+
originatingRect.y - overlayRect.y + originatingRect.height / 2
|
|
83
|
+
|
|
84
|
+
el.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(0, 0)`
|
|
85
|
+
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
el.style.transitionDuration = DURATION + 'ms'
|
|
88
|
+
el.style.transitionTimingFunction = 'cubic-bezier(0.56, 0.04, 0.25, 1)'
|
|
89
|
+
el.style.transitionProperty = 'transform'
|
|
90
|
+
el.style.transformOrigin = '0px 0px'
|
|
91
|
+
el.style.transform = 'translate(0px, 0px)'
|
|
92
|
+
}, 10)
|
|
93
|
+
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
done()
|
|
96
|
+
isLoading.value = false
|
|
97
|
+
}, DURATION)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// called when the enter transition has finished.
|
|
102
|
+
function onAfter(el: Element) {
|
|
103
|
+
if (el instanceof HTMLElement) {
|
|
104
|
+
el.style.transform = ''
|
|
105
|
+
el.style.transitionDuration = ''
|
|
106
|
+
el.style.opacity = ''
|
|
107
|
+
el.style.transitionProperty = ''
|
|
108
|
+
el.style.transitionTimingFunction = ''
|
|
109
|
+
el.style.transformOrigin = ''
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// called when the leave transition starts.
|
|
114
|
+
// use this to start the leaving animation.
|
|
115
|
+
function onLeave(el: Element, done: () => void) {
|
|
116
|
+
if (el instanceof HTMLElement) {
|
|
117
|
+
const originating = getOriginatingElement()
|
|
118
|
+
if (!originating) {
|
|
119
|
+
done()
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const originatingRect = originating.getBoundingClientRect()
|
|
124
|
+
const overlayRect = el.getBoundingClientRect()
|
|
125
|
+
|
|
126
|
+
const offsetX =
|
|
127
|
+
originatingRect.x - overlayRect.x + originatingRect.width / 2
|
|
128
|
+
const offsetY =
|
|
129
|
+
originatingRect.y - overlayRect.y + originatingRect.height / 2
|
|
130
|
+
|
|
131
|
+
el.style.transform = 'translate(0px, 0px)'
|
|
132
|
+
|
|
133
|
+
setTimeout(() => {
|
|
134
|
+
el.style.transitionDuration = DURATION + 'ms'
|
|
135
|
+
el.style.transitionTimingFunction = 'cubic-bezier(0.56, 0.04, 0.25, 1)'
|
|
136
|
+
el.style.transitionProperty = 'transform'
|
|
137
|
+
el.style.transformOrigin = '0px 0px'
|
|
138
|
+
el.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(0, 0)`
|
|
139
|
+
}, 10)
|
|
140
|
+
|
|
141
|
+
setTimeout(() => {
|
|
142
|
+
done()
|
|
143
|
+
}, DURATION)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function onAfterLeave(el: Element) {
|
|
148
|
+
onAfter(el)
|
|
149
|
+
if (hasPublished.value) {
|
|
150
|
+
emit('submit')
|
|
151
|
+
} else {
|
|
152
|
+
emit('close')
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const { $t } = useBlokkli()
|
|
157
|
+
|
|
158
|
+
const iframe = ref<HTMLIFrameElement | null>(null)
|
|
159
|
+
const isLoaded = ref(false)
|
|
160
|
+
const isLoading = ref(true)
|
|
161
|
+
const hasPublished = ref(false)
|
|
162
|
+
let timeout: any = null
|
|
163
|
+
|
|
164
|
+
function onLibraryItemPublished({ uuid }: { uuid: string }) {
|
|
165
|
+
if (props.uuid === uuid) {
|
|
166
|
+
hasPublished.value = true
|
|
167
|
+
isLoaded.value = false
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function onLoad() {
|
|
172
|
+
clearTimeout(timeout)
|
|
173
|
+
|
|
174
|
+
timeout = window.setTimeout(() => {
|
|
175
|
+
isLoaded.value = true
|
|
176
|
+
}, 3000)
|
|
177
|
+
if (!iframe.value) {
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
iframe.value.focus()
|
|
182
|
+
|
|
183
|
+
iframe.value.contentWindow?.focus()
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function closeOverlay() {
|
|
187
|
+
hasPublished.value = false
|
|
188
|
+
isLoaded.value = false
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function onLibraryItemClose({ uuid }: { uuid: string }) {
|
|
192
|
+
if (props.uuid === uuid) {
|
|
193
|
+
closeOverlay()
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function onEditorLoaded({ uuid }: { uuid: string }) {
|
|
198
|
+
if (props.uuid === uuid) {
|
|
199
|
+
isLoaded.value = true
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
onBroadcastEvent('published', onLibraryItemPublished)
|
|
204
|
+
onBroadcastEvent('closeEditor', onLibraryItemClose)
|
|
205
|
+
onBroadcastEvent('editorLoaded', onEditorLoaded)
|
|
206
|
+
</script>
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
</Teleport>
|
|
51
51
|
|
|
52
52
|
<Teleport to="body">
|
|
53
|
-
<transition name="bk-slide-
|
|
53
|
+
<transition name="bk-slide-up" :duration="200">
|
|
54
54
|
<LibraryDialog
|
|
55
55
|
v-if="placedAction && adapter.getLibraryItems"
|
|
56
56
|
:field="placedAction.field"
|
|
@@ -59,6 +59,12 @@
|
|
|
59
59
|
/>
|
|
60
60
|
</transition>
|
|
61
61
|
</Teleport>
|
|
62
|
+
<EditReusable
|
|
63
|
+
v-if="editingLibraryItem"
|
|
64
|
+
v-bind="editingLibraryItem"
|
|
65
|
+
@submit="onSubmitLibraryItem"
|
|
66
|
+
@close="cancelLibraryItemEdit"
|
|
67
|
+
/>
|
|
62
68
|
</template>
|
|
63
69
|
|
|
64
70
|
<script lang="ts" setup>
|
|
@@ -66,8 +72,10 @@ import { ref, computed, useBlokkli, defineBlokkliFeature } from '#imports'
|
|
|
66
72
|
import { PluginItemAction, PluginAddAction } from '#blokkli/plugins'
|
|
67
73
|
import ReusableDialog from './ReusableDialog/index.vue'
|
|
68
74
|
import LibraryDialog from './LibraryDialog/index.vue'
|
|
75
|
+
import EditReusable from './EditReusable/index.vue'
|
|
69
76
|
import { getDefinition } from '#blokkli/definitions'
|
|
70
|
-
import type { ActionPlacedEvent } from '#blokkli/types'
|
|
77
|
+
import type { ActionPlacedEvent, LibraryEditItemEvent } from '#blokkli/types'
|
|
78
|
+
import onBlokkliEvent from '#blokkli/helpers/composables/onBlokkliEvent'
|
|
71
79
|
|
|
72
80
|
const { adapter } = defineBlokkliFeature({
|
|
73
81
|
id: 'library',
|
|
@@ -175,6 +183,21 @@ const canMakeReusable = computed(
|
|
|
175
183
|
itemBundle?.value?.allowReusable &&
|
|
176
184
|
fromLibraryAllowedInList.value,
|
|
177
185
|
)
|
|
186
|
+
|
|
187
|
+
const editingLibraryItem = ref<LibraryEditItemEvent | null>(null)
|
|
188
|
+
|
|
189
|
+
onBlokkliEvent('library:edit-item', function (e) {
|
|
190
|
+
editingLibraryItem.value = e
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
function cancelLibraryItemEdit() {
|
|
194
|
+
editingLibraryItem.value = null
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function onSubmitLibraryItem() {
|
|
198
|
+
eventBus.emit('reloadState')
|
|
199
|
+
cancelLibraryItemEdit()
|
|
200
|
+
}
|
|
178
201
|
</script>
|
|
179
202
|
|
|
180
203
|
<script lang="ts">
|
|
@@ -44,7 +44,7 @@ const onSelect = (uuids: string[]) => {
|
|
|
44
44
|
let startTimeout: any = null
|
|
45
45
|
|
|
46
46
|
onBlokkliEvent('mouse:down', (e) => {
|
|
47
|
-
if (!enabled.value || e.type !== 'mouse') {
|
|
47
|
+
if (!enabled.value || e.type !== 'mouse' || selection.isDragging.value) {
|
|
48
48
|
return
|
|
49
49
|
}
|
|
50
50
|
if (keyboard.isPressingSpace.value || keyboard.isPressingControl.value) {
|
|
@@ -69,6 +69,7 @@ import OptionColor from './Color/index.vue'
|
|
|
69
69
|
import OptionRange from './Range/index.vue'
|
|
70
70
|
import OptionNumber from './Number/index.vue'
|
|
71
71
|
import type { BlockOptionDefinition } from '#blokkli/types/blokkOptions'
|
|
72
|
+
import { mapCheckboxTrue } from '#blokkli/helpers/runtimeHelpers'
|
|
72
73
|
|
|
73
74
|
const { state } = useBlokkli()
|
|
74
75
|
|
|
@@ -99,10 +100,7 @@ const validateValue = (
|
|
|
99
100
|
return v
|
|
100
101
|
}
|
|
101
102
|
} else if (props.option.type === 'checkbox') {
|
|
102
|
-
|
|
103
|
-
return v ? '1' : '0'
|
|
104
|
-
}
|
|
105
|
-
return v === '1' ? '1' : '0'
|
|
103
|
+
return mapCheckboxTrue(v)
|
|
106
104
|
} else if (props.option.type === 'checkboxes') {
|
|
107
105
|
const options = Object.keys(props.option.options || {})
|
|
108
106
|
const items = Array.isArray(v)
|
|
@@ -24,7 +24,7 @@ const { adapter } = defineBlokkliFeature({
|
|
|
24
24
|
'Provides a menu button to publish the changes of the current entity.',
|
|
25
25
|
})
|
|
26
26
|
|
|
27
|
-
const { state, $t, eventBus } = useBlokkli()
|
|
27
|
+
const { state, $t, eventBus, broadcast, context } = useBlokkli()
|
|
28
28
|
const { mutations, canEdit, mutateWithLoadingState } = state
|
|
29
29
|
|
|
30
30
|
const onClick = async () => {
|
|
@@ -39,7 +39,10 @@ const onClick = async () => {
|
|
|
39
39
|
if (validations.length) {
|
|
40
40
|
eventBus.emit('publish:failed')
|
|
41
41
|
}
|
|
42
|
+
return
|
|
42
43
|
}
|
|
44
|
+
|
|
45
|
+
broadcast.emit('published', { uuid: context.value.entityUuid })
|
|
43
46
|
}
|
|
44
47
|
</script>
|
|
45
48
|
|