@blokkli/editor 2.0.0-alpha.36 → 2.0.0-alpha.37
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/global/types/blockOptions.d.ts +4 -3
- package/dist/module.d.mts +2 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +71 -4
- package/dist/modules/agent/index.d.mts +1 -1
- package/dist/modules/agent/index.mjs +236 -6
- package/dist/modules/agent/runtime/app/composables/agentProvider.js +31 -14
- package/dist/modules/agent/runtime/app/composables/defineBlokkliAgentTool.d.ts +2 -20
- package/dist/modules/agent/runtime/app/composables/defineBlokkliAgentTool.js +0 -3
- package/dist/modules/agent/runtime/app/features/agent/Panel/Conversation/Item/Assistant/index.vue +2 -2
- package/dist/modules/agent/runtime/app/features/agent/Panel/Conversation/Item/User/index.vue +1 -2
- package/dist/modules/agent/runtime/app/features/agent/Panel/DebugGallery/index.vue +1 -2
- package/dist/modules/agent/runtime/app/features/agent/Panel/Input/Actions/index.d.vue.ts +1 -0
- package/dist/modules/agent/runtime/app/features/agent/Panel/Input/Actions/index.vue +66 -59
- package/dist/modules/agent/runtime/app/features/agent/Panel/Input/Actions/index.vue.d.ts +1 -0
- package/dist/modules/agent/runtime/app/features/agent/Panel/Input/index.vue +10 -12
- package/dist/modules/agent/runtime/app/features/agent/Panel/Welcome/de.md +2 -2
- package/dist/modules/agent/runtime/app/features/agent/Panel/Welcome/en.md +2 -2
- package/dist/modules/agent/runtime/app/features/agent/Panel/index.vue +1 -5
- package/dist/modules/agent/runtime/app/features/agent/index.vue +89 -37
- package/dist/modules/agent/runtime/app/helpers/index.d.ts +16 -19
- package/dist/modules/agent/runtime/app/helpers/index.js +22 -46
- package/dist/modules/agent/runtime/app/helpers/pageStructure.js +1 -1
- package/dist/modules/agent/runtime/app/tools/add_content_search_paragraph/index.js +5 -9
- package/dist/modules/agent/runtime/app/tools/add_fragment/index.js +2 -6
- package/dist/modules/agent/runtime/app/tools/add_media_paragraph/index.js +2 -6
- package/dist/modules/agent/runtime/app/tools/add_paragraphs/index.js +2 -3
- package/dist/modules/agent/runtime/app/tools/add_reusable_paragraph/index.js +2 -6
- package/dist/modules/agent/runtime/app/tools/add_template/index.js +2 -6
- package/dist/modules/agent/runtime/app/tools/analyze_content/index.d.ts +2 -0
- package/dist/modules/agent/runtime/app/tools/analyze_content/index.js +120 -0
- package/dist/modules/agent/runtime/app/tools/check_readability/index.d.ts +2 -0
- package/dist/modules/agent/runtime/app/tools/check_readability/index.js +57 -0
- package/dist/modules/agent/runtime/app/tools/duplicate_paragraphs/index.js +2 -6
- package/dist/modules/agent/runtime/app/tools/get_all_page_content/index.js +1 -1
- package/dist/modules/agent/runtime/app/tools/get_bundle_info/index.js +2 -1
- package/dist/modules/agent/runtime/app/tools/get_content_fields/index.js +1 -1
- package/dist/modules/agent/runtime/app/tools/get_paragraph_context/index.js +2 -5
- package/dist/modules/agent/runtime/app/tools/get_paragraph_options/index.js +2 -1
- package/dist/modules/agent/runtime/app/tools/get_selected_paragraphs/index.js +2 -3
- package/dist/modules/agent/runtime/app/tools/helpers.d.ts +53 -0
- package/dist/modules/agent/runtime/app/tools/helpers.js +187 -0
- package/dist/modules/agent/runtime/app/tools/move_paragraphs/index.js +2 -6
- package/dist/modules/agent/runtime/app/tools/schemas.d.ts +0 -52
- package/dist/modules/agent/runtime/app/tools/schemas.js +0 -187
- package/dist/modules/agent/runtime/app/tools/search_content/index.js +40 -47
- package/dist/modules/agent/runtime/app/tools/set_paragraph_options/index.js +2 -5
- package/dist/modules/agent/runtime/app/types/index.d.ts +0 -61
- package/dist/modules/agent/runtime/server/Session.d.ts +25 -6
- package/dist/modules/agent/runtime/server/Session.js +109 -30
- package/dist/modules/agent/runtime/server/SessionManager.d.ts +3 -0
- package/dist/modules/agent/runtime/server/SessionManager.js +4 -1
- package/dist/modules/agent/runtime/server/agent.js +3 -2
- package/dist/modules/agent/runtime/server/default-skills/fixReadability.d.ts +2 -0
- package/dist/modules/agent/runtime/server/default-skills/fixReadability.js +69 -0
- package/dist/modules/agent/runtime/server/default-system-prompts/page-context.js +28 -0
- package/dist/modules/agent/runtime/server/server-tools/index.d.ts +10 -2
- package/dist/modules/agent/runtime/server/server-tools/index.js +1 -1
- package/dist/modules/agent/runtime/server/server-tools/load_tools/index.js +1 -1
- package/dist/modules/agent/runtime/shared/types.d.ts +46 -11
- package/dist/modules/agent/runtime/shared/types.js +22 -10
- package/dist/modules/charts/index.d.mts +1 -1
- package/dist/modules/charts/index.mjs +21 -7
- package/dist/modules/charts/runtime/blokkli/skills/charts.js +6 -6
- package/dist/modules/charts/runtime/blokkli/tools/chart_schemas.d.ts +25 -2
- package/dist/modules/charts/runtime/blokkli/tools/chart_schemas.js +39 -1
- package/dist/modules/charts/runtime/blokkli/tools/create_chart/index.js +24 -17
- package/dist/modules/charts/runtime/blokkli/tools/get_chart_data/index.js +11 -19
- package/dist/modules/charts/runtime/blokkli/tools/get_chart_type_options/index.js +2 -4
- package/dist/modules/charts/runtime/blokkli/tools/update_chart/index.js +8 -20
- package/dist/modules/charts/runtime/chartTypes/area.d.ts +6 -1
- package/dist/modules/charts/runtime/chartTypes/bar.d.ts +7 -1
- package/dist/modules/charts/runtime/chartTypes/define.d.ts +1 -1
- package/dist/modules/charts/runtime/chartTypes/donut.d.ts +5 -1
- package/dist/modules/charts/runtime/chartTypes/heatmap.d.ts +3 -1
- package/dist/modules/charts/runtime/chartTypes/index.d.ts +18 -0
- package/dist/modules/charts/runtime/chartTypes/line.d.ts +6 -1
- package/dist/modules/charts/runtime/chartTypes/pie.d.ts +4 -1
- package/dist/modules/charts/runtime/chartTypes/radar.d.ts +6 -1
- package/dist/modules/charts/runtime/chartTypes/radialBar.d.ts +5 -1
- package/dist/modules/charts/runtime/chartTypes/shared.d.ts +20 -5
- package/dist/modules/charts/runtime/chartTypes/types.d.ts +6 -6
- package/dist/modules/charts/runtime/components/ChartRenderer/index.d.vue.ts +145 -2
- package/dist/modules/charts/runtime/components/ChartRenderer/index.vue +2 -2
- package/dist/modules/charts/runtime/components/ChartRenderer/index.vue.d.ts +145 -2
- package/dist/modules/charts/runtime/components/index.d.ts +1 -0
- package/dist/modules/charts/runtime/components/index.js +1 -0
- package/dist/modules/charts/runtime/features/charts/Editor/ChartTypeOptions/index.d.vue.ts +3 -2
- package/dist/modules/charts/runtime/features/charts/Editor/ChartTypeOptions/index.vue.d.ts +3 -2
- package/dist/modules/charts/runtime/features/charts/Editor/CsvImport/index.vue +1 -2
- package/dist/modules/charts/runtime/features/charts/Editor/FootnoteEditor/index.vue +1 -1
- package/dist/modules/charts/runtime/features/charts/Editor/Preview/index.d.vue.ts +2 -0
- package/dist/modules/charts/runtime/features/charts/Editor/Preview/index.vue +35 -13
- package/dist/modules/charts/runtime/features/charts/Editor/Preview/index.vue.d.ts +2 -0
- package/dist/modules/charts/runtime/features/charts/Editor/index.d.vue.ts +1 -0
- package/dist/modules/charts/runtime/features/charts/Editor/index.vue +9 -3
- package/dist/modules/charts/runtime/features/charts/Editor/index.vue.d.ts +1 -0
- package/dist/modules/charts/runtime/features/charts/Editor/useChartEditorState.js +1 -1
- package/dist/modules/charts/runtime/features/charts/index.vue +6 -6
- package/dist/modules/charts/runtime/helpers/index.d.ts +25 -0
- package/dist/modules/charts/runtime/helpers/index.js +63 -0
- package/dist/modules/charts/runtime/types.d.ts +10 -28
- package/dist/modules/charts/runtime/types.js +0 -64
- package/dist/modules/drupal/index.d.mts +1 -1
- package/dist/modules/drupal/runtime/adapter/index.d.ts +3 -1
- package/dist/modules/drupal/runtime/adapter/index.js +4 -4
- package/dist/modules/table-of-contents/index.d.mts +1 -1
- package/dist/runtime/components/BlokkliItem.vue +1 -1
- package/dist/runtime/composables/defineBlokkli.js +1 -1
- package/dist/runtime/editor/components/AnimationCanvas/index.vue +13 -7
- package/dist/runtime/editor/components/Banner/index.d.vue.ts +1 -0
- package/dist/runtime/editor/components/Banner/index.vue +1 -1
- package/dist/runtime/editor/components/Banner/index.vue.d.ts +1 -0
- package/dist/runtime/editor/components/DropdownItem/index.d.vue.ts +1 -0
- package/dist/runtime/editor/components/DropdownItem/index.vue +3 -2
- package/dist/runtime/editor/components/DropdownItem/index.vue.d.ts +1 -0
- package/dist/runtime/editor/components/EditProvider.vue +7 -4
- package/dist/runtime/editor/components/FlexTextarea/index.d.vue.ts +5 -1
- package/dist/runtime/editor/components/FlexTextarea/index.vue +24 -101
- package/dist/runtime/editor/components/FlexTextarea/index.vue.d.ts +5 -1
- package/dist/runtime/editor/components/NestedEditorOverlay/index.vue +28 -9
- package/dist/runtime/editor/components/Popup/index.d.vue.ts +30 -0
- package/dist/runtime/editor/components/Popup/index.vue +82 -0
- package/dist/runtime/editor/components/Popup/index.vue.d.ts +30 -0
- package/dist/runtime/editor/components/Resizable/index.vue +4 -1
- package/dist/runtime/editor/components/Toolbar/index.vue +107 -6
- package/dist/runtime/editor/components/index.d.ts +4 -3
- package/dist/runtime/editor/components/index.js +6 -4
- package/dist/runtime/editor/composables/defineDropAreas.js +3 -3
- package/dist/runtime/editor/composables/defineDropHandler.d.ts +3 -0
- package/dist/runtime/editor/composables/defineDropHandler.js +10 -0
- package/dist/runtime/editor/composables/index.d.ts +1 -0
- package/dist/runtime/editor/composables/index.js +1 -0
- package/dist/runtime/editor/css/output.css +1 -1
- package/dist/runtime/editor/events/index.d.ts +9 -0
- package/dist/runtime/editor/features/add-list/index.vue +58 -1
- package/dist/runtime/editor/features/analyze/Main.d.vue.ts +3 -2
- package/dist/runtime/editor/features/analyze/Main.vue +28 -44
- package/dist/runtime/editor/features/analyze/Main.vue.d.ts +3 -2
- package/dist/runtime/editor/features/analyze/analyzers/readability.js +65 -0
- package/dist/runtime/editor/features/analyze/analyzers/types.d.ts +19 -0
- package/dist/runtime/editor/features/analyze/index.vue +18 -15
- package/dist/runtime/editor/features/clipboard/DropElement/Video.d.vue.ts +8 -0
- package/dist/runtime/editor/features/clipboard/{List/Item → DropElement}/Video.vue +1 -5
- package/dist/runtime/editor/features/clipboard/DropElement/Video.vue.d.ts +8 -0
- package/dist/runtime/editor/features/clipboard/DropElement/helpers.d.ts +1 -0
- package/dist/runtime/editor/features/clipboard/DropElement/helpers.js +14 -0
- package/dist/runtime/editor/features/clipboard/DropElement/index.d.vue.ts +16 -0
- package/dist/runtime/editor/features/clipboard/DropElement/index.vue +97 -0
- package/dist/runtime/editor/features/clipboard/DropElement/index.vue.d.ts +16 -0
- package/dist/runtime/editor/features/clipboard/helpers.d.ts +15 -0
- package/dist/runtime/editor/features/clipboard/helpers.js +62 -0
- package/dist/runtime/editor/features/clipboard/index.vue +585 -337
- package/dist/runtime/editor/features/clipboard/types.d.ts +14 -2
- package/dist/runtime/editor/features/dragging-overlay/DragItems/index.vue +17 -5
- package/dist/runtime/editor/features/dragging-overlay/Renderer/index.vue +2 -2
- package/dist/runtime/editor/features/dragging-overlay/index.vue +125 -219
- package/dist/runtime/editor/features/editable-field/Overlay/Plaintext/index.vue +4 -4
- package/dist/runtime/editor/features/editable-field/Overlay/index.vue +6 -0
- package/dist/runtime/editor/features/library/index.vue +14 -0
- package/dist/runtime/editor/features/media-library/index.vue +32 -1
- package/dist/runtime/editor/features/options/Form/ComplexType/index.d.vue.ts +11 -0
- package/dist/runtime/editor/features/options/Form/ComplexType/index.vue +36 -0
- package/dist/runtime/editor/features/options/Form/ComplexType/index.vue.d.ts +11 -0
- package/dist/runtime/editor/features/options/Form/Item.d.vue.ts +3 -2
- package/dist/runtime/editor/features/options/Form/Item.vue +10 -2
- package/dist/runtime/editor/features/options/Form/Item.vue.d.ts +3 -2
- package/dist/runtime/editor/features/options/Form/index.vue +5 -0
- package/dist/runtime/editor/features/search/index.vue +25 -1
- package/dist/runtime/editor/features/structure/index.vue +25 -1
- package/dist/runtime/editor/features/tour/index.vue +22 -12
- package/dist/runtime/editor/helpers/clipboardData/index.d.ts +11 -0
- package/dist/runtime/editor/helpers/clipboardData/index.js +157 -0
- package/dist/runtime/editor/helpers/options/index.js +5 -0
- package/dist/runtime/editor/icons/svg/stars.svg +5 -1
- package/dist/runtime/editor/plugins/Sidebar/Detached/index.d.vue.ts +1 -1
- package/dist/runtime/editor/plugins/Sidebar/Detached/index.vue.d.ts +1 -1
- package/dist/runtime/editor/plugins/Sidebar/index.d.vue.ts +14 -3
- package/dist/runtime/editor/plugins/Sidebar/index.vue +4 -2
- package/dist/runtime/editor/plugins/Sidebar/index.vue.d.ts +14 -3
- package/dist/runtime/editor/providers/analyze.d.ts +43 -0
- package/dist/runtime/editor/providers/analyze.js +78 -0
- package/dist/runtime/editor/providers/animation.d.ts +4 -0
- package/dist/runtime/editor/providers/animation.js +6 -0
- package/dist/runtime/editor/providers/dragdrop.d.ts +55 -0
- package/dist/runtime/editor/providers/dragdrop.js +37 -0
- package/dist/runtime/editor/providers/storage.js +15 -0
- package/dist/runtime/editor/providers/ui.d.ts +6 -0
- package/dist/runtime/editor/providers/ui.js +19 -0
- package/dist/runtime/editor/translations/de.json +73 -61
- package/dist/runtime/editor/translations/fr.json +67 -55
- package/dist/runtime/editor/translations/gsw_CH.json +71 -59
- package/dist/runtime/editor/translations/it.json +67 -55
- package/dist/runtime/editor/types/app.d.ts +4 -2
- package/dist/runtime/editor/types/draggable.d.ts +1 -0
- package/dist/runtime/editor/types/ui.d.ts +1 -1
- package/dist/runtime/helpers/injections.d.ts +1 -1
- package/dist/runtime/types/blockOptions.d.ts +2 -1
- package/dist/runtime/types/definitions.d.ts +4 -0
- package/dist/shared/{editor.CWQIFIEQ.d.mts → editor.BdBm1Z7C.d.mts} +12 -0
- package/dist/types.d.mts +1 -1
- package/package.json +5 -3
- package/dist/modules/charts/runtime/components/Fragment/BlokkliChart.d.vue.ts +0 -3
- package/dist/modules/charts/runtime/components/Fragment/BlokkliChart.vue +0 -29
- package/dist/modules/charts/runtime/components/Fragment/BlokkliChart.vue.d.ts +0 -3
- package/dist/runtime/editor/features/clipboard/List/Item/File.d.vue.ts +0 -4
- package/dist/runtime/editor/features/clipboard/List/Item/File.vue +0 -60
- package/dist/runtime/editor/features/clipboard/List/Item/File.vue.d.ts +0 -4
- package/dist/runtime/editor/features/clipboard/List/Item/Video.d.vue.ts +0 -4
- package/dist/runtime/editor/features/clipboard/List/Item/Video.vue.d.ts +0 -4
- package/dist/runtime/editor/features/clipboard/List/index.d.vue.ts +0 -11
- package/dist/runtime/editor/features/clipboard/List/index.vue +0 -72
- package/dist/runtime/editor/features/clipboard/List/index.vue.d.ts +0 -11
- package/dist/runtime/editor/features/tour/Popup/index.d.vue.ts +0 -9
- package/dist/runtime/editor/features/tour/Popup/index.vue +0 -34
- package/dist/runtime/editor/features/tour/Popup/index.vue.d.ts +0 -9
- package/dist/runtime/editor/providers/dropArea.d.ts +0 -48
- package/dist/runtime/editor/providers/dropArea.js +0 -22
|
@@ -1,68 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
$t(
|
|
9
|
-
'clipboardTourText',
|
|
10
|
-
'Drag and drop content pasted from your clipboard into the page to create a matching block.'
|
|
11
|
-
)
|
|
12
|
-
"
|
|
13
|
-
edit-only
|
|
14
|
-
icon="bk_mdi_content_paste"
|
|
15
|
-
weight="-30"
|
|
16
|
-
>
|
|
17
|
-
<div class="bk bk-clipboard bk-control">
|
|
18
|
-
<div
|
|
19
|
-
v-if="!pastedItems.length"
|
|
20
|
-
class="bk-clipboard-info bk-sidebar-padding"
|
|
21
|
-
>
|
|
22
|
-
<h4>{{ $t("clipboardEmpty", "No items in the clipboard") }}</h4>
|
|
23
|
-
<div
|
|
24
|
-
v-if="!ui.isMobile.value"
|
|
25
|
-
v-html="
|
|
26
|
-
$t(
|
|
27
|
-
'clipboardExplanation',
|
|
28
|
-
`<p>
|
|
29
|
-
Use Ctrl-V on the page to paste content. These
|
|
30
|
-
will then be displayed here.
|
|
31
|
-
</p>
|
|
32
|
-
<p>
|
|
33
|
-
Use Ctrl-F to search for existing content and paste it into
|
|
34
|
-
the clipboard.
|
|
35
|
-
</p>`
|
|
36
|
-
)
|
|
37
|
-
"
|
|
38
|
-
/>
|
|
39
|
-
</div>
|
|
40
|
-
<ClipboardList
|
|
41
|
-
v-if="pastedItems.length"
|
|
42
|
-
:items="pastedItems"
|
|
43
|
-
@remove="remove"
|
|
2
|
+
<Teleport :to="ui.mainLayoutElement.value">
|
|
3
|
+
<div class="bk-clipboard-drop-element-wrapper">
|
|
4
|
+
<DropElement
|
|
5
|
+
ref="dropElementRef"
|
|
6
|
+
:bundles="directDropBundles"
|
|
7
|
+
:items="dropItems"
|
|
44
8
|
/>
|
|
45
|
-
<div class="bk-clipboard-form bk-sidebar-padding">
|
|
46
|
-
<div class="bk-clipboard-input">
|
|
47
|
-
<input
|
|
48
|
-
type="text"
|
|
49
|
-
class="bk-form-input"
|
|
50
|
-
:placeholder="
|
|
51
|
-
$t('clipboardPastePlaceholder', 'Paste text or media here')
|
|
52
|
-
"
|
|
53
|
-
@paste.stop.prevent="onManualPaste"
|
|
54
|
-
@keydown.stop
|
|
55
|
-
/>
|
|
56
|
-
</div>
|
|
57
|
-
<div class="bk-clipboard-upload">
|
|
58
|
-
<input type="file" @change="onFileInput" />
|
|
59
|
-
<div class="bk-button bk-is-primary">
|
|
60
|
-
<Icon name="bk_mdi_upload" />
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
9
|
</div>
|
|
65
|
-
</
|
|
10
|
+
</Teleport>
|
|
66
11
|
</template>
|
|
67
12
|
|
|
68
13
|
<script setup>
|
|
@@ -75,38 +20,200 @@ import {
|
|
|
75
20
|
computed,
|
|
76
21
|
useTemplateRef
|
|
77
22
|
} from "#imports";
|
|
78
|
-
import { PluginSidebar } from "#blokkli/editor/plugins";
|
|
79
|
-
import ClipboardList from "./List/index.vue";
|
|
80
23
|
import { falsy, getFieldKey } from "#blokkli/helpers";
|
|
81
24
|
import { generateUUID } from "#blokkli/editor/helpers/uuid";
|
|
82
|
-
import { Icon } from "#blokkli/editor/components";
|
|
83
25
|
import getVideoId from "get-video-id";
|
|
26
|
+
import DropElement, {} from "./DropElement/index.vue";
|
|
84
27
|
import { emitMessage } from "#blokkli/editor/events";
|
|
85
28
|
import { fragmentBlockBundle, itemEntityType } from "#blokkli-build/config";
|
|
86
29
|
import {
|
|
30
|
+
defineDropHandler,
|
|
87
31
|
defineItemDropdownAction,
|
|
88
32
|
defineShortcut,
|
|
89
33
|
onBlokkliEvent
|
|
90
34
|
} from "#blokkli/editor/composables";
|
|
91
|
-
|
|
35
|
+
import { buildMapBundleEvent, sanitizeHtml } from "./helpers";
|
|
36
|
+
const { logger } = defineBlokkliFeature({
|
|
92
37
|
id: "clipboard",
|
|
93
38
|
label: "Clipboard",
|
|
94
39
|
icon: "bk_mdi_content_paste",
|
|
95
40
|
description: "Provides clipboard integration to copy/paste existing blocks or paste supported clipboard content like text or images.",
|
|
96
|
-
settings: {
|
|
97
|
-
openSidebarOnPaste: {
|
|
98
|
-
type: "checkbox",
|
|
99
|
-
default: true,
|
|
100
|
-
label: "Open sidebar when pasting",
|
|
101
|
-
description: "Automatically opens the sidebar when pasting content from the clipboard.",
|
|
102
|
-
group: "behavior"
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
41
|
screenshot: "feature-clipboard.jpg"
|
|
106
42
|
});
|
|
107
|
-
const {
|
|
108
|
-
|
|
43
|
+
const {
|
|
44
|
+
selection,
|
|
45
|
+
$t,
|
|
46
|
+
adapter,
|
|
47
|
+
state,
|
|
48
|
+
ui,
|
|
49
|
+
types,
|
|
50
|
+
keyboard,
|
|
51
|
+
blocks,
|
|
52
|
+
fields,
|
|
53
|
+
eventBus,
|
|
54
|
+
animation
|
|
55
|
+
} = useBlokkli();
|
|
109
56
|
const selectionClipboard = ref([]);
|
|
57
|
+
const isDirectDrop = ref(false);
|
|
58
|
+
const directDropBundles = ref([]);
|
|
59
|
+
const dropItems = ref([]);
|
|
60
|
+
const dropElementRef = useTemplateRef("dropElementRef");
|
|
61
|
+
let dragCounter = 0;
|
|
62
|
+
let nativeDropItem = null;
|
|
63
|
+
function positionDropElement(x, y) {
|
|
64
|
+
const el = dropElementRef.value?.$el;
|
|
65
|
+
const wrapper = el?.parentElement;
|
|
66
|
+
if (wrapper && el) {
|
|
67
|
+
const w = el.offsetWidth;
|
|
68
|
+
const h = el.offsetHeight;
|
|
69
|
+
wrapper.style.left = x - w / 2 + "px";
|
|
70
|
+
wrapper.style.top = y - h / 2 + "px";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function normalizeBundles(result) {
|
|
74
|
+
if (!result) return null;
|
|
75
|
+
return Array.isArray(result) ? result : [result];
|
|
76
|
+
}
|
|
77
|
+
function startClipboardDrag(item, bundles, allItems) {
|
|
78
|
+
if (!adapter.clipboardMapBundle || !adapter.addBlockFromClipboardItem || state.editMode.value !== "editing" || !dropElementRef.value) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const itemBundles = bundles || [item.itemBundle];
|
|
82
|
+
if (!itemBundles.length) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const items = allItems || [item];
|
|
86
|
+
directDropBundles.value = itemBundles;
|
|
87
|
+
dropItems.value = items.map((v) => ({
|
|
88
|
+
type: v.type,
|
|
89
|
+
data: v.data,
|
|
90
|
+
fileName: "fileName" in v ? v.fileName : void 0,
|
|
91
|
+
fileSize: "fileSize" in v ? v.fileSize : void 0,
|
|
92
|
+
videoId: "videoId" in v ? v.videoId : void 0,
|
|
93
|
+
videoService: "videoService" in v ? v.videoService : void 0
|
|
94
|
+
}));
|
|
95
|
+
const coords = animation.getMouseCoords();
|
|
96
|
+
positionDropElement(coords.x, coords.y);
|
|
97
|
+
const el = dropElementRef.value.$el;
|
|
98
|
+
nativeDropItem = {
|
|
99
|
+
itemType: "native_drop",
|
|
100
|
+
itemBundles,
|
|
101
|
+
dataTransfer: null,
|
|
102
|
+
clipboardItems: allItems || [item],
|
|
103
|
+
element: () => el
|
|
104
|
+
};
|
|
105
|
+
isDirectDrop.value = true;
|
|
106
|
+
eventBus.emit("dragging:start", {
|
|
107
|
+
items: [nativeDropItem],
|
|
108
|
+
coords,
|
|
109
|
+
mode: "mouse"
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function tryStartDirectDrop(e) {
|
|
113
|
+
if (!adapter.clipboardMapBundle || !adapter.addBlockFromClipboardItem || state.editMode.value !== "editing" || !dropElementRef.value) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const mapEvent = buildMapBundleEvent(e);
|
|
117
|
+
if (!mapEvent) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
const bundles = normalizeBundles(adapter.clipboardMapBundle(mapEvent));
|
|
121
|
+
if (!bundles) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
const itemType = mapEvent.type === "plaintext" ? "text" : mapEvent.type;
|
|
125
|
+
const fileCount = mapEvent.fileCount || 1;
|
|
126
|
+
directDropBundles.value = bundles;
|
|
127
|
+
dropItems.value = Array.from({ length: fileCount }, () => ({
|
|
128
|
+
type: itemType,
|
|
129
|
+
fileName: mapEvent.fileName
|
|
130
|
+
}));
|
|
131
|
+
positionDropElement(e.clientX, e.clientY);
|
|
132
|
+
const el = dropElementRef.value.$el;
|
|
133
|
+
nativeDropItem = {
|
|
134
|
+
itemType: "native_drop",
|
|
135
|
+
itemBundles: bundles,
|
|
136
|
+
dataTransfer: null,
|
|
137
|
+
element: () => el
|
|
138
|
+
};
|
|
139
|
+
isDirectDrop.value = true;
|
|
140
|
+
eventBus.emit("dragging:start", {
|
|
141
|
+
items: [nativeDropItem],
|
|
142
|
+
coords: { x: e.clientX, y: e.clientY },
|
|
143
|
+
mode: "mouse"
|
|
144
|
+
});
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
function resetDrag() {
|
|
148
|
+
dragCounter = 0;
|
|
149
|
+
isDragFromInput = false;
|
|
150
|
+
if (isDirectDrop.value) {
|
|
151
|
+
eventBus.emit("dragging:end");
|
|
152
|
+
isDirectDrop.value = false;
|
|
153
|
+
nativeDropItem = null;
|
|
154
|
+
directDropBundles.value = [];
|
|
155
|
+
dropItems.value = [];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
let isDragFromInput = false;
|
|
159
|
+
function onDragStart(e) {
|
|
160
|
+
const target = e.target;
|
|
161
|
+
if (target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement || target instanceof HTMLElement && target.isContentEditable) {
|
|
162
|
+
isDragFromInput = true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function onDragEnter(e) {
|
|
166
|
+
if (isDragFromInput) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
dragCounter++;
|
|
170
|
+
if (dragCounter === 1) {
|
|
171
|
+
tryStartDirectDrop(e);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function onDragLeave() {
|
|
175
|
+
if (isDragFromInput) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
dragCounter--;
|
|
179
|
+
if (dragCounter <= 0) {
|
|
180
|
+
resetDrag();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function onDragOver(e) {
|
|
184
|
+
e.preventDefault();
|
|
185
|
+
if (isDirectDrop.value) {
|
|
186
|
+
eventBus.emit("dragging:move", { x: e.clientX, y: e.clientY });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function onNativeDrop(e) {
|
|
190
|
+
e.preventDefault();
|
|
191
|
+
if (isDragFromInput) {
|
|
192
|
+
isDragFromInput = false;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (isDirectDrop.value && nativeDropItem && e.dataTransfer) {
|
|
196
|
+
nativeDropItem.dataTransfer = e.dataTransfer;
|
|
197
|
+
eventBus.emit("mouse:up", {
|
|
198
|
+
type: "mouse",
|
|
199
|
+
x: e.clientX,
|
|
200
|
+
y: e.clientY,
|
|
201
|
+
distance: 100,
|
|
202
|
+
duration: 1e3
|
|
203
|
+
});
|
|
204
|
+
eventBus.emit("dragging:end");
|
|
205
|
+
dragCounter = 0;
|
|
206
|
+
isDirectDrop.value = false;
|
|
207
|
+
nativeDropItem = null;
|
|
208
|
+
directDropBundles.value = [];
|
|
209
|
+
dropItems.value = [];
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
resetDrag();
|
|
213
|
+
if (e.dataTransfer) {
|
|
214
|
+
onDropFallback(e.dataTransfer);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
110
217
|
const itemDropdownItems = computed(() => {
|
|
111
218
|
return [
|
|
112
219
|
{
|
|
@@ -134,160 +241,125 @@ function onSelectDropdownItem(item) {
|
|
|
134
241
|
handleSelectionPaste(selectionClipboard.value);
|
|
135
242
|
}
|
|
136
243
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
additional: "asdfasdfasdf",
|
|
151
|
-
fileName: "my-little-document.pdf",
|
|
152
|
-
fileSize: 26624,
|
|
153
|
-
fileType: "application/pdf"
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
type: "file",
|
|
157
|
-
id: generateUUID(),
|
|
158
|
-
itemBundle: "image",
|
|
159
|
-
data: "asdfasdf",
|
|
160
|
-
additional: "asdfasdfasdf",
|
|
161
|
-
fileName: "my-little-document.pdf",
|
|
162
|
-
fileSize: 36623,
|
|
163
|
-
fileType: "application/pdf"
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
type: "video",
|
|
167
|
-
id: generateUUID(),
|
|
168
|
-
itemBundle: "video",
|
|
169
|
-
data: "https://vimeo.com/53520224",
|
|
170
|
-
videoService: "vimeo",
|
|
171
|
-
videoId: "53520224"
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
type: "video",
|
|
175
|
-
id: generateUUID(),
|
|
176
|
-
itemBundle: "video",
|
|
177
|
-
data: "https://www.youtube.com/watch?v=zsvYVVRAk0c",
|
|
178
|
-
videoService: "youtube",
|
|
179
|
-
videoId: "zsvYVVRAk0c"
|
|
180
|
-
}
|
|
181
|
-
];
|
|
182
|
-
const pastedItems = ref([]);
|
|
183
|
-
const onFileInput = (e) => {
|
|
184
|
-
e.preventDefault();
|
|
185
|
-
if (e.target instanceof HTMLInputElement) {
|
|
186
|
-
const files = e.target.files;
|
|
187
|
-
if (files) {
|
|
188
|
-
handleFiles(files);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
function removeAllAttrs(element) {
|
|
193
|
-
for (let i = element.attributes.length; i-- > 0; ) {
|
|
194
|
-
const attribute = element.attributes[i];
|
|
195
|
-
if (!ALLOWED_HTML_ATTRIBUTES.includes(attribute.name)) {
|
|
196
|
-
element.removeAttributeNode(attribute);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
244
|
+
function readFileAsDataURL(file) {
|
|
245
|
+
return new Promise((resolve, reject) => {
|
|
246
|
+
const fr = new FileReader();
|
|
247
|
+
fr.onload = () => {
|
|
248
|
+
if (typeof fr.result === "string") {
|
|
249
|
+
resolve(fr.result);
|
|
250
|
+
} else {
|
|
251
|
+
reject(new Error("FileReader result is not a string"));
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
fr.onerror = () => reject(fr.error);
|
|
255
|
+
fr.readAsDataURL(file);
|
|
256
|
+
});
|
|
199
257
|
}
|
|
200
|
-
function
|
|
201
|
-
if (
|
|
202
|
-
el.remove();
|
|
258
|
+
async function handleFiles(data) {
|
|
259
|
+
if (!FileReader || !adapter.clipboardMapBundle) {
|
|
203
260
|
return;
|
|
204
261
|
}
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
const child = children[i];
|
|
208
|
-
removeAllAttrs(child);
|
|
209
|
-
if (child.children.length) {
|
|
210
|
-
removeAttributes(child);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
const onManualPaste = (e) => {
|
|
215
|
-
onPaste(e, true);
|
|
216
|
-
};
|
|
217
|
-
function handleFiles(data) {
|
|
218
|
-
if (!FileReader) {
|
|
262
|
+
const files = data instanceof DataTransfer ? [...data.files] : [...data];
|
|
263
|
+
if (!files.length) {
|
|
219
264
|
return;
|
|
220
265
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
if (typeof fr.result !== "string") {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
const type = file.type.startsWith("image/") ? "image" : "file";
|
|
232
|
-
const itemBundle = adapter.clipboardMapBundle({
|
|
266
|
+
let commonBundles = null;
|
|
267
|
+
for (const file of files) {
|
|
268
|
+
const type = file.type.startsWith("image/") ? "image" : "file";
|
|
269
|
+
const fileBundles = normalizeBundles(
|
|
270
|
+
adapter.clipboardMapBundle({
|
|
233
271
|
type,
|
|
234
272
|
fileType: file.type,
|
|
235
273
|
fileSize: file.size
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
showClipboardSidebar();
|
|
251
|
-
};
|
|
252
|
-
fr.readAsDataURL(file);
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
function onDrop(e) {
|
|
256
|
-
e.preventDefault();
|
|
257
|
-
if (e.dataTransfer?.files.length) {
|
|
258
|
-
handleFiles(e.dataTransfer);
|
|
274
|
+
})
|
|
275
|
+
);
|
|
276
|
+
if (!fileBundles) {
|
|
277
|
+
emitPasteError(
|
|
278
|
+
$t("clipboardUnsupportedFileType", "This file type is not supported.")
|
|
279
|
+
);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (commonBundles === null) {
|
|
283
|
+
commonBundles = fileBundles;
|
|
284
|
+
} else {
|
|
285
|
+
commonBundles = commonBundles.filter((b) => fileBundles.includes(b));
|
|
286
|
+
}
|
|
259
287
|
}
|
|
288
|
+
if (!commonBundles || !commonBundles.length) {
|
|
289
|
+
emitPasteError(
|
|
290
|
+
$t("clipboardNoCommonBundle", "No common block type for these files.")
|
|
291
|
+
);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
let results;
|
|
295
|
+
try {
|
|
296
|
+
results = await Promise.all(files.map(readFileAsDataURL));
|
|
297
|
+
} catch {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const items = [];
|
|
301
|
+
for (let i = 0; i < files.length; i++) {
|
|
302
|
+
const file = files[i];
|
|
303
|
+
const result = results[i];
|
|
304
|
+
const type = file.type.startsWith("image/") ? "image" : "file";
|
|
305
|
+
items.push({
|
|
306
|
+
type,
|
|
307
|
+
itemBundle: commonBundles[0],
|
|
308
|
+
id: generateUUID(),
|
|
309
|
+
data: result,
|
|
310
|
+
additional: file.name,
|
|
311
|
+
fileSize: file.size,
|
|
312
|
+
fileType: file.type,
|
|
313
|
+
fileName: file.name
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
startClipboardDrag(items[0], commonBundles, items);
|
|
260
317
|
}
|
|
261
|
-
function
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
318
|
+
function onDropFallback(data) {
|
|
319
|
+
if (data.files.length) {
|
|
320
|
+
handleFiles(data);
|
|
321
|
+
} else {
|
|
322
|
+
const text = data.getData("text/html") || data.getData("text/plain") || data.getData("text");
|
|
323
|
+
if (text) {
|
|
324
|
+
handlePastedText(text);
|
|
325
|
+
}
|
|
267
326
|
}
|
|
268
|
-
}
|
|
327
|
+
}
|
|
269
328
|
function emitPasteError(message) {
|
|
270
329
|
const prefix = $t("clipboardPasteError", "Failed to paste:");
|
|
271
330
|
emitMessage(`${prefix} ${message}`, "error");
|
|
272
331
|
}
|
|
332
|
+
function startCopyDrag(existingBlocks) {
|
|
333
|
+
const items = existingBlocks.map((block) => ({
|
|
334
|
+
itemType: "existing",
|
|
335
|
+
block,
|
|
336
|
+
isCopy: true
|
|
337
|
+
}));
|
|
338
|
+
const coords = animation.getMouseCoords();
|
|
339
|
+
eventBus.emit("dragging:start", {
|
|
340
|
+
items,
|
|
341
|
+
coords,
|
|
342
|
+
mode: "mouse"
|
|
343
|
+
});
|
|
344
|
+
}
|
|
273
345
|
const handleSelectionPaste = (pastedUuids) => {
|
|
274
346
|
if (!adapter.pasteExistingBlocks) {
|
|
275
347
|
return;
|
|
276
348
|
}
|
|
277
|
-
if (
|
|
278
|
-
emitPasteError(
|
|
279
|
-
$t(
|
|
280
|
-
"clipboardPasteErrorOneField",
|
|
281
|
-
"Pasting is only possible into one field at a time."
|
|
282
|
-
)
|
|
283
|
-
);
|
|
349
|
+
if (!pastedUuids.length) {
|
|
284
350
|
return;
|
|
285
351
|
}
|
|
286
|
-
|
|
352
|
+
const existingBlocks = pastedUuids.map((uuid) => blocks.getBlock(uuid)).filter((block2) => !!block2);
|
|
353
|
+
if (!existingBlocks.length) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (selection.uuids.value.length !== 1) {
|
|
357
|
+
startCopyDrag(existingBlocks);
|
|
287
358
|
return;
|
|
288
359
|
}
|
|
289
360
|
const block = selection.items.value[0];
|
|
290
361
|
if (!block) {
|
|
362
|
+
startCopyDrag(existingBlocks);
|
|
291
363
|
return;
|
|
292
364
|
}
|
|
293
365
|
let targetField = null;
|
|
@@ -295,11 +367,10 @@ const handleSelectionPaste = (pastedUuids) => {
|
|
|
295
367
|
let targetFieldKey = null;
|
|
296
368
|
let preceedingUuid = null;
|
|
297
369
|
if (!keyboard.isPressingShift.value) {
|
|
298
|
-
const pastedBundles =
|
|
299
|
-
const pastedFragments =
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
return block2.fragment.name;
|
|
370
|
+
const pastedBundles = existingBlocks.map((b) => b.bundle).filter((bundle) => !!bundle);
|
|
371
|
+
const pastedFragments = existingBlocks.map((b) => {
|
|
372
|
+
if (b.bundle === fragmentBlockBundle && b.fragment?.name) {
|
|
373
|
+
return b.fragment.name;
|
|
303
374
|
}
|
|
304
375
|
return null;
|
|
305
376
|
}).filter(falsy);
|
|
@@ -342,83 +413,40 @@ const handleSelectionPaste = (pastedUuids) => {
|
|
|
342
413
|
}
|
|
343
414
|
if (!targetField || !targetFieldElement || !targetFieldKey) {
|
|
344
415
|
const field = state.getMutatedField(block.host.uuid, block.host.fieldName);
|
|
345
|
-
if (
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
};
|
|
357
|
-
targetFieldElement = fieldElement;
|
|
358
|
-
targetFieldKey = getFieldKey(field.entityUuid, field.name);
|
|
359
|
-
preceedingUuid = selection.uuids.value[0] ?? null;
|
|
360
|
-
}
|
|
361
|
-
const pastedBlocks = [];
|
|
362
|
-
const notAllowedBundles = [];
|
|
363
|
-
const notAllowedFragments = [];
|
|
364
|
-
for (let i = 0; i < pastedUuids.length; i++) {
|
|
365
|
-
const uuid = pastedUuids[i];
|
|
366
|
-
if (!uuid) {
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
const block2 = blocks.getBlock(uuid);
|
|
370
|
-
if (!block2) {
|
|
371
|
-
continue;
|
|
372
|
-
}
|
|
373
|
-
const isAllowed = targetFieldElement.allowedBundles.includes(block2.bundle);
|
|
374
|
-
if (!isAllowed) {
|
|
375
|
-
notAllowedBundles.push(block2.bundle);
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
if (block2.bundle === fragmentBlockBundle && block2.fragment?.name && targetFieldElement.allowedFragments.length > 0) {
|
|
379
|
-
const fragmentAllowed = targetFieldElement.allowedFragments.includes(
|
|
380
|
-
block2.fragment.name
|
|
381
|
-
);
|
|
382
|
-
if (!fragmentAllowed) {
|
|
383
|
-
notAllowedFragments.push(block2.fragment.name);
|
|
384
|
-
continue;
|
|
416
|
+
if (field) {
|
|
417
|
+
const fieldElement = fields.find(field.entityUuid, field.name);
|
|
418
|
+
if (fieldElement) {
|
|
419
|
+
targetField = {
|
|
420
|
+
entityType: field.entityType,
|
|
421
|
+
entityUuid: field.entityUuid,
|
|
422
|
+
name: field.name
|
|
423
|
+
};
|
|
424
|
+
targetFieldElement = fieldElement;
|
|
425
|
+
targetFieldKey = getFieldKey(field.entityUuid, field.name);
|
|
426
|
+
preceedingUuid = selection.uuids.value[0] ?? null;
|
|
385
427
|
}
|
|
386
428
|
}
|
|
387
|
-
pastedBlocks.push(block2);
|
|
388
429
|
}
|
|
389
|
-
if (!
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
"Fragments (@types) are not allowed here."
|
|
397
|
-
);
|
|
398
|
-
emitPasteError(message2.replace("@types", notAllowedFragments.join(", ")));
|
|
399
|
-
return;
|
|
430
|
+
if (!targetField || !targetFieldElement || !targetFieldKey) {
|
|
431
|
+
startCopyDrag(existingBlocks);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const pastedBlocks = existingBlocks.filter((b) => {
|
|
435
|
+
if (!targetFieldElement.allowedBundles.includes(b.bundle)) {
|
|
436
|
+
return false;
|
|
400
437
|
}
|
|
401
|
-
|
|
402
|
-
return
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
)
|
|
408
|
-
"clipboardPasteErrorAllowedBundlesMultiple",
|
|
409
|
-
"Block types (@types) are not allowed here."
|
|
410
|
-
);
|
|
411
|
-
emitPasteError(message.replace("@types", blockTypes.join(", ")));
|
|
438
|
+
if (b.bundle === fragmentBlockBundle && b.fragment?.name && targetFieldElement.allowedFragments.length > 0) {
|
|
439
|
+
return targetFieldElement.allowedFragments.includes(b.fragment.name);
|
|
440
|
+
}
|
|
441
|
+
return true;
|
|
442
|
+
});
|
|
443
|
+
if (!pastedBlocks.length) {
|
|
444
|
+
startCopyDrag(existingBlocks);
|
|
412
445
|
return;
|
|
413
446
|
}
|
|
414
447
|
const count = state.getFieldBlockCount(targetFieldKey);
|
|
415
448
|
if (targetFieldElement.cardinality !== -1 && count + pastedBlocks.length > targetFieldElement.cardinality) {
|
|
416
|
-
|
|
417
|
-
$t(
|
|
418
|
-
"clipboardPasteErrorCardinality",
|
|
419
|
-
"This field only allows up to @count blocks."
|
|
420
|
-
).replace("@count", targetFieldElement.cardinality.toString())
|
|
421
|
-
);
|
|
449
|
+
startCopyDrag(existingBlocks);
|
|
422
450
|
return;
|
|
423
451
|
}
|
|
424
452
|
state.mutateWithLoadingState(
|
|
@@ -433,23 +461,26 @@ const handleSelectionPaste = (pastedUuids) => {
|
|
|
433
461
|
})
|
|
434
462
|
);
|
|
435
463
|
};
|
|
436
|
-
function onPaste(e
|
|
464
|
+
function onPaste(e) {
|
|
437
465
|
logger.log("Paste Event", e);
|
|
438
466
|
if (state.editMode.value !== "editing") {
|
|
439
467
|
return;
|
|
440
468
|
}
|
|
441
|
-
if (
|
|
469
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
|
|
442
470
|
return;
|
|
443
471
|
}
|
|
444
472
|
e.stopPropagation();
|
|
445
473
|
e.preventDefault();
|
|
446
|
-
if (state.isLoading.value) {
|
|
474
|
+
if (state.isLoading.value || selection.isDragging.value) {
|
|
447
475
|
return;
|
|
448
476
|
}
|
|
449
477
|
const clipboardData = e.clipboardData;
|
|
450
478
|
if (!clipboardData) {
|
|
451
479
|
return;
|
|
452
480
|
}
|
|
481
|
+
if (clipboardData.files.length) {
|
|
482
|
+
return handleFiles(clipboardData);
|
|
483
|
+
}
|
|
453
484
|
const pastedData = clipboardData.getData("text/html") || clipboardData.getData("text/plain") || clipboardData.getData("text");
|
|
454
485
|
if (pastedData) {
|
|
455
486
|
if (pastedData.startsWith("{")) {
|
|
@@ -464,9 +495,6 @@ function onPaste(e, fromInput) {
|
|
|
464
495
|
}
|
|
465
496
|
handlePastedText(pastedData);
|
|
466
497
|
}
|
|
467
|
-
if (clipboardData.files.length) {
|
|
468
|
-
return handleFiles(clipboardData);
|
|
469
|
-
}
|
|
470
498
|
}
|
|
471
499
|
const handlePastedText = (text) => {
|
|
472
500
|
if (!adapter.clipboardMapBundle) {
|
|
@@ -474,50 +502,279 @@ const handlePastedText = (text) => {
|
|
|
474
502
|
}
|
|
475
503
|
const video = getVideoId(text);
|
|
476
504
|
if (video.id && video.service) {
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
505
|
+
const itemBundles = normalizeBundles(
|
|
506
|
+
adapter.clipboardMapBundle({
|
|
507
|
+
type: "video",
|
|
508
|
+
videoService: video.service,
|
|
509
|
+
videoId: video.id
|
|
510
|
+
})
|
|
511
|
+
);
|
|
512
|
+
if (!itemBundles) {
|
|
483
513
|
return;
|
|
484
514
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
515
|
+
startClipboardDrag(
|
|
516
|
+
{
|
|
517
|
+
type: "video",
|
|
518
|
+
id: generateUUID(),
|
|
519
|
+
itemBundle: itemBundles[0],
|
|
520
|
+
data: text,
|
|
521
|
+
videoService: video.service,
|
|
522
|
+
videoId: video.id
|
|
523
|
+
},
|
|
524
|
+
itemBundles
|
|
525
|
+
);
|
|
494
526
|
return;
|
|
495
527
|
}
|
|
496
528
|
const div = document.createElement("div");
|
|
497
529
|
div.innerHTML = text.replace(/ |<br>/g, "");
|
|
498
|
-
|
|
530
|
+
sanitizeHtml(div);
|
|
499
531
|
if (div.textContent) {
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
532
|
+
const itemBundles = normalizeBundles(
|
|
533
|
+
adapter.clipboardMapBundle({
|
|
534
|
+
type: "plaintext",
|
|
535
|
+
text: div.innerHTML
|
|
536
|
+
})
|
|
537
|
+
);
|
|
538
|
+
if (!itemBundles) {
|
|
505
539
|
return;
|
|
506
540
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
541
|
+
startClipboardDrag(
|
|
542
|
+
{
|
|
543
|
+
type: "text",
|
|
544
|
+
id: generateUUID(),
|
|
545
|
+
itemBundle: itemBundles[0],
|
|
546
|
+
data: div.innerHTML
|
|
547
|
+
},
|
|
548
|
+
itemBundles
|
|
549
|
+
);
|
|
514
550
|
}
|
|
515
551
|
};
|
|
516
|
-
function
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
552
|
+
function extractBareUrl(text) {
|
|
553
|
+
const trimmed = text.trim();
|
|
554
|
+
try {
|
|
555
|
+
const url = new URL(trimmed);
|
|
556
|
+
if (url.protocol === "http:" || url.protocol === "https:") {
|
|
557
|
+
return trimmed;
|
|
558
|
+
}
|
|
559
|
+
} catch {
|
|
560
|
+
}
|
|
561
|
+
return null;
|
|
520
562
|
}
|
|
563
|
+
defineDropHandler("native_drop", {
|
|
564
|
+
resolveBundles({ items, field }) {
|
|
565
|
+
const item = items[0];
|
|
566
|
+
if (!adapter.addBlockFromClipboardItem) {
|
|
567
|
+
return [];
|
|
568
|
+
}
|
|
569
|
+
if (item.clipboardItems?.length) {
|
|
570
|
+
return field.allowedBundles.filter((b) => item.itemBundles.includes(b));
|
|
571
|
+
}
|
|
572
|
+
if (!item.dataTransfer) {
|
|
573
|
+
return field.allowedBundles.filter((b) => item.itemBundles.includes(b));
|
|
574
|
+
}
|
|
575
|
+
const dt = item.dataTransfer;
|
|
576
|
+
if (dt.files.length > 0) {
|
|
577
|
+
if (!adapter.clipboardMapBundle) {
|
|
578
|
+
return field.allowedBundles.filter((b) => item.itemBundles.includes(b));
|
|
579
|
+
}
|
|
580
|
+
const files = [...dt.files];
|
|
581
|
+
let possibleBundles = null;
|
|
582
|
+
for (const file of files) {
|
|
583
|
+
const type = file.type.startsWith("image/") ? "image" : "file";
|
|
584
|
+
const mapped = normalizeBundles(
|
|
585
|
+
adapter.clipboardMapBundle({
|
|
586
|
+
type,
|
|
587
|
+
fileType: file.type,
|
|
588
|
+
fileSize: file.size
|
|
589
|
+
})
|
|
590
|
+
);
|
|
591
|
+
if (!mapped) {
|
|
592
|
+
return [];
|
|
593
|
+
}
|
|
594
|
+
if (possibleBundles === null) {
|
|
595
|
+
possibleBundles = mapped;
|
|
596
|
+
} else {
|
|
597
|
+
possibleBundles = possibleBundles.filter((b) => mapped.includes(b));
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return (possibleBundles || []).filter(
|
|
601
|
+
(b) => field.allowedBundles.includes(b)
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
const text = dt.getData("text/html") || dt.getData("text/plain") || dt.getData("text");
|
|
605
|
+
if (!text) {
|
|
606
|
+
return [];
|
|
607
|
+
}
|
|
608
|
+
if (adapter.clipboardMapBundle) {
|
|
609
|
+
const video = getVideoId(text);
|
|
610
|
+
if (video.id && video.service) {
|
|
611
|
+
const mapped2 = normalizeBundles(
|
|
612
|
+
adapter.clipboardMapBundle({
|
|
613
|
+
type: "video",
|
|
614
|
+
videoService: video.service,
|
|
615
|
+
videoId: video.id
|
|
616
|
+
})
|
|
617
|
+
);
|
|
618
|
+
if (mapped2?.length) {
|
|
619
|
+
item.clipboardItems = [
|
|
620
|
+
{
|
|
621
|
+
type: "video",
|
|
622
|
+
id: generateUUID(),
|
|
623
|
+
itemBundle: mapped2[0],
|
|
624
|
+
data: text,
|
|
625
|
+
videoService: video.service,
|
|
626
|
+
videoId: video.id
|
|
627
|
+
}
|
|
628
|
+
];
|
|
629
|
+
return mapped2.filter((b) => field.allowedBundles.includes(b));
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const bareUrl = extractBareUrl(text);
|
|
633
|
+
if (bareUrl) {
|
|
634
|
+
const mapped2 = normalizeBundles(
|
|
635
|
+
adapter.clipboardMapBundle({ type: "link", url: bareUrl })
|
|
636
|
+
);
|
|
637
|
+
if (mapped2?.length) {
|
|
638
|
+
item.clipboardItems = [
|
|
639
|
+
{
|
|
640
|
+
type: "text",
|
|
641
|
+
id: generateUUID(),
|
|
642
|
+
itemBundle: mapped2[0],
|
|
643
|
+
data: bareUrl
|
|
644
|
+
}
|
|
645
|
+
];
|
|
646
|
+
return mapped2.filter((b) => field.allowedBundles.includes(b));
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
const mapped = normalizeBundles(
|
|
650
|
+
adapter.clipboardMapBundle({ type: "plaintext", text })
|
|
651
|
+
);
|
|
652
|
+
if (mapped?.length) {
|
|
653
|
+
item.clipboardItems = [
|
|
654
|
+
{
|
|
655
|
+
type: "text",
|
|
656
|
+
id: generateUUID(),
|
|
657
|
+
itemBundle: mapped[0],
|
|
658
|
+
data: text
|
|
659
|
+
}
|
|
660
|
+
];
|
|
661
|
+
return mapped.filter((b) => field.allowedBundles.includes(b));
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
item.clipboardItems = [
|
|
665
|
+
{
|
|
666
|
+
type: "text",
|
|
667
|
+
id: generateUUID(),
|
|
668
|
+
itemBundle: item.itemBundles[0],
|
|
669
|
+
data: text
|
|
670
|
+
}
|
|
671
|
+
];
|
|
672
|
+
return field.allowedBundles.filter((b) => item.itemBundles.includes(b));
|
|
673
|
+
},
|
|
674
|
+
async execute({ items, host, afterUuid, bundle }) {
|
|
675
|
+
if (!adapter.addBlockFromClipboardItem) {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
const item = items[0];
|
|
679
|
+
if (item.clipboardItems?.length) {
|
|
680
|
+
await state.mutateWithLoadingState(async () => {
|
|
681
|
+
let lastResult;
|
|
682
|
+
for (const clipItem of item.clipboardItems) {
|
|
683
|
+
lastResult = await adapter.addBlockFromClipboardItem({
|
|
684
|
+
item: clipItem,
|
|
685
|
+
blockBundle: bundle,
|
|
686
|
+
host,
|
|
687
|
+
afterUuid
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
return lastResult;
|
|
691
|
+
});
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
if (!item.dataTransfer) {
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const dt = item.dataTransfer;
|
|
698
|
+
if (dt.files.length > 0) {
|
|
699
|
+
const files = [...dt.files];
|
|
700
|
+
if (adapter.clipboardMapBundle) {
|
|
701
|
+
for (const file of files) {
|
|
702
|
+
const type = file.type.startsWith("image/") ? "image" : "file";
|
|
703
|
+
const mapped = adapter.clipboardMapBundle({
|
|
704
|
+
type,
|
|
705
|
+
fileType: file.type,
|
|
706
|
+
fileSize: file.size
|
|
707
|
+
});
|
|
708
|
+
if (!mapped) {
|
|
709
|
+
emitMessage("This file type or size is not supported.", "error");
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
let results;
|
|
715
|
+
try {
|
|
716
|
+
results = await Promise.all(files.map(readFileAsDataURL));
|
|
717
|
+
} catch {
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const clipboardItems = files.map((file, i) => {
|
|
721
|
+
const type = file.type.startsWith("image/") ? "image" : "file";
|
|
722
|
+
return {
|
|
723
|
+
type,
|
|
724
|
+
id: generateUUID(),
|
|
725
|
+
itemBundle: bundle,
|
|
726
|
+
data: results[i],
|
|
727
|
+
additional: file.name,
|
|
728
|
+
fileName: file.name,
|
|
729
|
+
fileSize: file.size,
|
|
730
|
+
fileType: file.type
|
|
731
|
+
};
|
|
732
|
+
});
|
|
733
|
+
await state.mutateWithLoadingState(async () => {
|
|
734
|
+
let lastResult;
|
|
735
|
+
for (const clipItem of clipboardItems) {
|
|
736
|
+
lastResult = await adapter.addBlockFromClipboardItem({
|
|
737
|
+
item: clipItem,
|
|
738
|
+
blockBundle: bundle,
|
|
739
|
+
host,
|
|
740
|
+
afterUuid
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
return lastResult;
|
|
744
|
+
});
|
|
745
|
+
} else {
|
|
746
|
+
const text = dt.getData("text/html") || dt.getData("text/plain") || dt.getData("text");
|
|
747
|
+
if (!text) {
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
const clipboardItem = {
|
|
751
|
+
type: "text",
|
|
752
|
+
id: generateUUID(),
|
|
753
|
+
itemBundle: bundle,
|
|
754
|
+
data: text
|
|
755
|
+
};
|
|
756
|
+
await state.mutateWithLoadingState(
|
|
757
|
+
() => adapter.addBlockFromClipboardItem({
|
|
758
|
+
item: clipboardItem,
|
|
759
|
+
blockBundle: bundle,
|
|
760
|
+
host,
|
|
761
|
+
afterUuid
|
|
762
|
+
})
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
defineDropHandler("clipboard", {
|
|
768
|
+
async execute({ items, host, afterUuid }) {
|
|
769
|
+
const item = items[0];
|
|
770
|
+
eventBus.emit("drop:clipboardItem", {
|
|
771
|
+
id: item.clipboardId,
|
|
772
|
+
host,
|
|
773
|
+
blockBundle: item.itemBundle,
|
|
774
|
+
afterUuid
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
});
|
|
521
778
|
function setClipboard(text) {
|
|
522
779
|
const type = "text/plain";
|
|
523
780
|
const blob = new Blob([text], { type });
|
|
@@ -574,32 +831,23 @@ defineItemDropdownAction(() => {
|
|
|
574
831
|
}));
|
|
575
832
|
}
|
|
576
833
|
});
|
|
577
|
-
onBlokkliEvent("drop:clipboardItem", async (data) => {
|
|
578
|
-
const item = pastedItems.value.find((v) => v.id === data.id);
|
|
579
|
-
if (!item) {
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
if (adapter.addBlockFromClipboardItem) {
|
|
583
|
-
await state.mutateWithLoadingState(
|
|
584
|
-
() => adapter.addBlockFromClipboardItem({
|
|
585
|
-
afterUuid: data.afterUuid,
|
|
586
|
-
item,
|
|
587
|
-
blockBundle: data.blockBundle,
|
|
588
|
-
host: data.host
|
|
589
|
-
})
|
|
590
|
-
);
|
|
591
|
-
pastedItems.value = pastedItems.value.filter((v) => v.id !== item.id);
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
834
|
onMounted(() => {
|
|
595
835
|
document.addEventListener("paste", onPaste);
|
|
596
|
-
document.
|
|
836
|
+
document.addEventListener("dragstart", onDragStart);
|
|
837
|
+
document.addEventListener("dragenter", onDragEnter);
|
|
838
|
+
document.addEventListener("dragleave", onDragLeave);
|
|
839
|
+
document.addEventListener("dragend", resetDrag);
|
|
597
840
|
document.addEventListener("dragover", onDragOver);
|
|
841
|
+
document.addEventListener("drop", onNativeDrop);
|
|
598
842
|
});
|
|
599
843
|
onUnmounted(() => {
|
|
600
844
|
document.removeEventListener("paste", onPaste);
|
|
601
|
-
document.
|
|
845
|
+
document.removeEventListener("dragstart", onDragStart);
|
|
846
|
+
document.removeEventListener("dragenter", onDragEnter);
|
|
847
|
+
document.removeEventListener("dragleave", onDragLeave);
|
|
848
|
+
document.removeEventListener("dragend", resetDrag);
|
|
602
849
|
document.removeEventListener("dragover", onDragOver);
|
|
850
|
+
document.removeEventListener("drop", onNativeDrop);
|
|
603
851
|
});
|
|
604
852
|
</script>
|
|
605
853
|
|