@blokkli/editor 1.0.1 → 1.0.2
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 +1 -4
- package/dist/runtime/components/Edit/EditProvider.vue +1 -0
- package/dist/runtime/components/Edit/Features/Edit/index.vue +60 -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/Publish/index.vue +4 -1
- package/dist/runtime/components/Edit/Features/Translations/index.vue +26 -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/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.2";
|
|
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',
|
|
@@ -241,10 +241,7 @@ function onPointerUp(e: PointerEvent) {
|
|
|
241
241
|
if (!block) {
|
|
242
242
|
return
|
|
243
243
|
}
|
|
244
|
-
eventBus.emit('item:
|
|
245
|
-
uuid: lastInteractedElement.uuid,
|
|
246
|
-
bundle: block.itemBundle,
|
|
247
|
-
})
|
|
244
|
+
eventBus.emit('item:doubleClick', block)
|
|
248
245
|
}
|
|
249
246
|
}
|
|
250
247
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<PluginItemAction
|
|
3
3
|
id="edit"
|
|
4
4
|
:title="$t('edit', 'Edit')"
|
|
5
|
-
:disabled="
|
|
5
|
+
:disabled="!canEdit"
|
|
6
6
|
meta
|
|
7
7
|
key-code="E"
|
|
8
8
|
icon="edit"
|
|
@@ -16,6 +16,7 @@ import { computed, useBlokkli, defineBlokkliFeature } from '#imports'
|
|
|
16
16
|
import type { DraggableExistingBlock } from '#blokkli/types'
|
|
17
17
|
import { PluginItemAction } from '#blokkli/plugins'
|
|
18
18
|
import { getDefinition } from '#blokkli/definitions'
|
|
19
|
+
import onBlokkliEvent from '#blokkli/helpers/composables/onBlokkliEvent'
|
|
19
20
|
|
|
20
21
|
defineBlokkliFeature({
|
|
21
22
|
id: 'edit',
|
|
@@ -25,23 +26,45 @@ defineBlokkliFeature({
|
|
|
25
26
|
requiredAdapterMethods: ['formFrameBuilder'],
|
|
26
27
|
})
|
|
27
28
|
|
|
28
|
-
const { eventBus, selection, state, $t } = useBlokkli()
|
|
29
|
+
const { eventBus, selection, state, $t, adapter } = useBlokkli()
|
|
29
30
|
|
|
30
|
-
const
|
|
31
|
-
if (state.editMode.value !== 'editing') {
|
|
32
|
-
return true
|
|
33
|
-
}
|
|
31
|
+
const block = computed(() => {
|
|
34
32
|
if (selection.blocks.value.length !== 1) {
|
|
35
|
-
return
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return selection.blocks.value[0]
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const canEdit = computed(() => {
|
|
40
|
+
// Editing is only possible when a single block is selected.
|
|
41
|
+
if (!block.value) {
|
|
42
|
+
return false
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
const block = selection.blocks.value[0]
|
|
39
45
|
const definition = getDefinition(
|
|
40
|
-
block.itemBundle,
|
|
41
|
-
block.hostFieldListType,
|
|
42
|
-
block.parentBlockBundle,
|
|
46
|
+
block.value.itemBundle,
|
|
47
|
+
block.value.hostFieldListType,
|
|
48
|
+
block.value.parentBlockBundle,
|
|
43
49
|
)
|
|
44
|
-
|
|
50
|
+
|
|
51
|
+
// Editing is explicitly disabled via the definition.
|
|
52
|
+
if (definition?.editor?.disableEdit) {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// For reusable blocks, editing is only possible if the adapter implements
|
|
57
|
+
// the getLibraryItemEditUrl method.
|
|
58
|
+
if (block.value.libraryItemUuid) {
|
|
59
|
+
return (
|
|
60
|
+
!!adapter.getLibraryItemEditUrl &&
|
|
61
|
+
(state.editMode.value === 'editing' ||
|
|
62
|
+
state.editMode.value === 'translating') &&
|
|
63
|
+
!block.value.isNew
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return state.editMode.value === 'editing'
|
|
45
68
|
})
|
|
46
69
|
|
|
47
70
|
function onClick(items: DraggableExistingBlock[]) {
|
|
@@ -49,11 +72,34 @@ function onClick(items: DraggableExistingBlock[]) {
|
|
|
49
72
|
return
|
|
50
73
|
}
|
|
51
74
|
|
|
75
|
+
if (!canEdit.value) {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const item = items[0]
|
|
80
|
+
|
|
81
|
+
// Because editing library items inside the current context is not (yet)
|
|
82
|
+
// supported, editing has to happen in a separate window where the host
|
|
83
|
+
// context is the library item entity.
|
|
84
|
+
if (item.libraryItemUuid && adapter.getLibraryItemEditUrl) {
|
|
85
|
+
const url = adapter.getLibraryItemEditUrl(item.libraryItemUuid)
|
|
86
|
+
eventBus.emit('library:edit-item', {
|
|
87
|
+
url,
|
|
88
|
+
label: item.editTitle,
|
|
89
|
+
uuid: item.libraryItemUuid,
|
|
90
|
+
})
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
52
94
|
eventBus.emit('item:edit', {
|
|
53
|
-
uuid:
|
|
54
|
-
bundle:
|
|
95
|
+
uuid: item.uuid,
|
|
96
|
+
bundle: item.itemBundle,
|
|
55
97
|
})
|
|
56
98
|
}
|
|
99
|
+
|
|
100
|
+
onBlokkliEvent('item:doubleClick', function (block) {
|
|
101
|
+
onClick([block])
|
|
102
|
+
})
|
|
57
103
|
</script>
|
|
58
104
|
|
|
59
105
|
<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">
|
|
@@ -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
|
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
<PluginItemAction
|
|
73
73
|
v-if="editMode === 'translating'"
|
|
74
74
|
id="translate"
|
|
75
|
+
:disabled="!canTranslateBlock"
|
|
75
76
|
:title="$t('translationsItemAction', 'Translate')"
|
|
76
77
|
icon="translate"
|
|
77
78
|
@click="onTranslate"
|
|
@@ -98,6 +99,7 @@ import type {
|
|
|
98
99
|
Language,
|
|
99
100
|
} from '#blokkli/types'
|
|
100
101
|
import Banner from './Banner/index.vue'
|
|
102
|
+
import { getDefinition } from '#blokkli/definitions'
|
|
101
103
|
|
|
102
104
|
const { adapter } = defineBlokkliFeature({
|
|
103
105
|
id: 'translations',
|
|
@@ -107,7 +109,7 @@ const { adapter } = defineBlokkliFeature({
|
|
|
107
109
|
description: 'Adds support for block translations.',
|
|
108
110
|
})
|
|
109
111
|
|
|
110
|
-
const { eventBus, state, context, $t, ui } = useBlokkli()
|
|
112
|
+
const { eventBus, state, context, $t, ui, selection } = useBlokkli()
|
|
111
113
|
const { translation, editMode } = state
|
|
112
114
|
|
|
113
115
|
const isOpen = ref(false)
|
|
@@ -152,6 +154,29 @@ const items = computed<TranslationStateItem[]>(() => {
|
|
|
152
154
|
.filter(falsy)
|
|
153
155
|
})
|
|
154
156
|
|
|
157
|
+
const canTranslateBlock = computed(() => {
|
|
158
|
+
if (selection.blocks.value.length !== 1) {
|
|
159
|
+
return false
|
|
160
|
+
}
|
|
161
|
+
const block = selection.blocks.value[0]
|
|
162
|
+
|
|
163
|
+
if (block.libraryItemUuid) {
|
|
164
|
+
return false
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const definition = getDefinition(
|
|
168
|
+
block.itemBundle,
|
|
169
|
+
block.hostFieldListType,
|
|
170
|
+
block.parentBlockBundle,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
if (definition?.editor?.disableEdit) {
|
|
174
|
+
return false
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return true
|
|
178
|
+
})
|
|
179
|
+
|
|
155
180
|
function onClick(item: TranslationStateItem, event: Event) {
|
|
156
181
|
if (item.translation?.exists) {
|
|
157
182
|
return adapter.changeLanguage(item.translation)
|