@alpaca-editor/core 1.0.0 → 1.0.3764-editor-mono
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/client-components/api.js +6 -0
- package/dist/client-components/index.js +36 -0
- package/dist/components/ActionButton.js +9 -0
- package/dist/components/Error.js +28 -0
- package/dist/config/config.js +654 -0
- package/dist/config/types.js +2 -0
- package/dist/editor/ComponentInfo.js +31 -0
- package/dist/editor/ConfirmationDialog.js +32 -0
- package/dist/editor/ContentTree.js +406 -0
- package/dist/editor/ContextMenu.js +117 -0
- package/dist/editor/Editor.js +55 -0
- package/dist/editor/EditorWarning.js +13 -0
- package/dist/editor/EditorWarnings.js +24 -0
- package/dist/editor/FieldEditorPopup.js +24 -0
- package/dist/editor/FieldHistory.js +40 -0
- package/dist/editor/FieldList.js +63 -0
- package/dist/editor/FieldListField.js +164 -0
- package/dist/editor/FieldListFieldWithFallbacks.js +114 -0
- package/dist/editor/FloatingToolbar.js +92 -0
- package/dist/editor/ImageEditor.js +55 -0
- package/dist/editor/InsertMenu.js +164 -0
- package/dist/editor/ItemInfo.js +30 -0
- package/dist/editor/LinkEditorDialog.js +89 -0
- package/dist/editor/MainLayout.js +46 -0
- package/dist/editor/NewEditorClient.js +9 -0
- package/dist/editor/PictureCropper.js +332 -0
- package/dist/editor/PictureEditor.js +104 -0
- package/dist/editor/PictureEditorDialog.js +194 -0
- package/dist/editor/ScrollingContentTree.js +30 -0
- package/dist/editor/Terminal.js +109 -0
- package/dist/editor/Titlebar.js +11 -0
- package/dist/editor/ai/AiPopup.js +25 -0
- package/dist/editor/ai/AiResponseMessage.js +24 -0
- package/dist/editor/ai/AiTerminal.js +241 -0
- package/dist/editor/ai/AiToolCall.js +18 -0
- package/dist/editor/ai/EditorAiTerminal.js +9 -0
- package/dist/editor/ai/editorAiContext.js +14 -0
- package/dist/editor/client/DialogContext.js +29 -0
- package/dist/editor/client/EditorClient.js +1336 -0
- package/dist/editor/client/GenericDialog.js +27 -0
- package/dist/editor/client/editContext.js +59 -0
- package/dist/editor/client/helpers.js +31 -0
- package/dist/editor/client/itemsRepository.js +255 -0
- package/dist/editor/client/operations.js +398 -0
- package/dist/editor/client/pageModelBuilder.js +129 -0
- package/dist/editor/commands/commands.js +2 -0
- package/dist/editor/commands/componentCommands.js +277 -0
- package/dist/editor/commands/createVersionCommand.js +26 -0
- package/dist/editor/commands/deleteVersionCommand.js +55 -0
- package/dist/editor/commands/itemCommands.js +134 -0
- package/dist/editor/commands/localizeItem/LocalizeItemDialog.js +94 -0
- package/dist/editor/commands/undo.js +32 -0
- package/dist/editor/component-designer/ComponentDesigner.js +58 -0
- package/dist/editor/component-designer/ComponentDesignerAiTerminal.js +9 -0
- package/dist/editor/component-designer/ComponentDesignerMenu.js +67 -0
- package/dist/editor/component-designer/ComponentEditor.js +59 -0
- package/dist/editor/component-designer/ComponentRenderingCodeEditor.js +16 -0
- package/dist/editor/component-designer/ComponentRenderingEditor.js +71 -0
- package/dist/editor/component-designer/ComponentsDropdown.js +22 -0
- package/dist/editor/component-designer/PlaceholdersEditor.js +70 -0
- package/dist/editor/component-designer/RenderingsDropdown.js +25 -0
- package/dist/editor/component-designer/TemplateEditor.js +144 -0
- package/dist/editor/component-designer/aiContext.js +18 -0
- package/dist/editor/componentTreeHelper.js +97 -0
- package/dist/editor/control-center/ControlCenterMenu.js +59 -0
- package/dist/editor/control-center/IndexOverview.js +27 -0
- package/dist/editor/control-center/IndexSettings.js +106 -0
- package/dist/editor/control-center/Status.js +7 -0
- package/dist/editor/editor-warnings/ItemLocked.js +40 -0
- package/dist/editor/editor-warnings/NoLanguageWriteAccess.js +16 -0
- package/dist/editor/editor-warnings/NoWorkflowWriteAccess.js +16 -0
- package/dist/editor/editor-warnings/NoWriteAccess.js +14 -0
- package/dist/editor/editor-warnings/ValidationErrors.js +27 -0
- package/dist/editor/field-types/AttachmentEditor.js +7 -0
- package/dist/editor/field-types/CheckboxEditor.js +32 -0
- package/dist/editor/field-types/DropLinkEditor.js +51 -0
- package/dist/editor/field-types/DropListEditor.js +58 -0
- package/dist/editor/field-types/ImageFieldEditor.js +36 -0
- package/dist/editor/field-types/InternalLinkFieldEditor.js +64 -0
- package/dist/editor/field-types/LinkFieldEditor.js +58 -0
- package/dist/editor/field-types/MultiLineText.js +35 -0
- package/dist/editor/field-types/PictureFieldEditor.js +59 -0
- package/dist/editor/field-types/RawEditor.js +33 -0
- package/dist/editor/field-types/ReactQuill.js +366 -0
- package/dist/editor/field-types/RichTextEditor.js +46 -0
- package/dist/editor/field-types/RichTextEditorComponent.js +72 -0
- package/dist/editor/field-types/SingleLineText.js +92 -0
- package/dist/editor/field-types/TreeListEditor.js +137 -0
- package/dist/editor/fieldTypes.js +2 -0
- package/dist/editor/media-selector/AiImageSearch.js +110 -0
- package/dist/editor/media-selector/AiImageSearchPrompt.js +58 -0
- package/dist/editor/media-selector/MediaSelector.js +11 -0
- package/dist/editor/media-selector/Preview.js +9 -0
- package/dist/editor/media-selector/Thumbnails.js +11 -0
- package/dist/editor/media-selector/TreeSelector.js +171 -0
- package/dist/editor/media-selector/UploadZone.js +80 -0
- package/dist/editor/menubar/ActionsMenu.js +33 -0
- package/dist/editor/menubar/ActiveUsers.js +13 -0
- package/dist/editor/menubar/ApproveAndPublish.js +13 -0
- package/dist/editor/menubar/BrowseHistory.js +14 -0
- package/dist/editor/menubar/ItemLanguageVersion.js +36 -0
- package/dist/editor/menubar/LanguageSelector.js +33 -0
- package/dist/editor/menubar/Menu.js +65 -0
- package/dist/editor/menubar/NavButtons.js +43 -0
- package/dist/editor/menubar/PageSelector.js +50 -0
- package/dist/editor/menubar/PageViewerControls.js +37 -0
- package/dist/editor/menubar/Separator.js +8 -0
- package/dist/editor/menubar/SiteInfo.js +26 -0
- package/dist/editor/menubar/User.js +18 -0
- package/dist/editor/menubar/VersionSelector.js +49 -0
- package/dist/editor/page-editor-chrome/CommentHighlighting.js +214 -0
- package/dist/editor/page-editor-chrome/CommentHighlightings.js +17 -0
- package/dist/editor/page-editor-chrome/FieldActionIndicator.js +27 -0
- package/dist/editor/page-editor-chrome/FieldActionIndicators.js +15 -0
- package/dist/editor/page-editor-chrome/FieldEditedIndicator.js +27 -0
- package/dist/editor/page-editor-chrome/FieldEditedIndicators.js +15 -0
- package/dist/editor/page-editor-chrome/FrameMenu.js +178 -0
- package/dist/editor/page-editor-chrome/FrameMenus.js +24 -0
- package/dist/editor/page-editor-chrome/InlineEditor.js +101 -0
- package/dist/editor/page-editor-chrome/LockedFieldIndicator.js +35 -0
- package/dist/editor/page-editor-chrome/NoLayout.js +21 -0
- package/dist/editor/page-editor-chrome/PageEditorChrome.js +65 -0
- package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +109 -0
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +82 -0
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +147 -0
- package/dist/editor/page-viewer/DeviceToolbar.js +21 -0
- package/dist/editor/page-viewer/EditorForm.js +130 -0
- package/dist/editor/page-viewer/MiniMap.js +257 -0
- package/dist/editor/page-viewer/PageViewer.js +64 -0
- package/dist/editor/page-viewer/PageViewerFrame.js +696 -0
- package/dist/editor/page-viewer/pageViewContext.js +117 -0
- package/dist/editor/pageModel.js +2 -0
- package/dist/editor/picture-shared.js +28 -0
- package/dist/editor/reviews/Comment.js +112 -0
- package/dist/editor/reviews/Comments.js +24 -0
- package/dist/editor/reviews/PreviewInfo.js +13 -0
- package/dist/editor/reviews/Reviews.js +165 -0
- package/dist/editor/reviews/reviewCommands.js +44 -0
- package/dist/editor/reviews/useReviews.js +48 -0
- package/dist/editor/services/aiService.js +99 -0
- package/dist/editor/services/componentDesignerService.js +79 -0
- package/dist/editor/services/contentService.js +104 -0
- package/dist/editor/services/editService.js +322 -0
- package/dist/editor/services/indexService.js +25 -0
- package/dist/editor/services/reviewsService.js +43 -0
- package/dist/editor/services/serviceHelper.js +67 -0
- package/dist/editor/services/systemService.js +7 -0
- package/dist/editor/services/translationService.js +15 -0
- package/dist/editor/services-server/api.js +119 -0
- package/dist/editor/services-server/graphQL.js +56 -0
- package/dist/editor/sidebar/ComponentPalette.js +55 -0
- package/dist/editor/sidebar/ComponentTree.js +362 -0
- package/dist/editor/sidebar/Debug.js +60 -0
- package/dist/editor/sidebar/DictionaryEditor.js +160 -0
- package/dist/editor/sidebar/EditHistory.js +74 -0
- package/dist/editor/sidebar/GraphQL.js +115 -0
- package/dist/editor/sidebar/Insert.js +24 -0
- package/dist/editor/sidebar/MainContentTree.js +52 -0
- package/dist/editor/sidebar/Performance.js +34 -0
- package/dist/editor/sidebar/Sessions.js +31 -0
- package/dist/editor/sidebar/Sidebar.js +15 -0
- package/dist/editor/sidebar/SidebarView.js +76 -0
- package/dist/editor/sidebar/Translations.js +160 -0
- package/dist/editor/sidebar/Validation.js +52 -0
- package/dist/editor/sidebar/ViewSelector.js +15 -0
- package/dist/editor/sidebar/Workbox.js +80 -0
- package/dist/editor/ui/CenteredMessage.js +7 -0
- package/dist/editor/ui/CopyToClipboardButton.js +17 -0
- package/dist/editor/ui/DialogButtons.js +7 -0
- package/dist/editor/ui/Icons.js +75 -0
- package/dist/editor/ui/ItemNameDialog.js +45 -0
- package/dist/editor/ui/ItemNameDialogNew.js +61 -0
- package/dist/editor/ui/ItemSearch.js +93 -0
- package/dist/editor/ui/PerfectTree.js +223 -0
- package/dist/editor/ui/Section.js +12 -0
- package/dist/editor/ui/SimpleIconButton.js +11 -0
- package/dist/editor/ui/SimpleMenu.js +9 -0
- package/dist/editor/ui/SimpleTable.js +11 -0
- package/dist/editor/ui/SimpleTabs.js +21 -0
- package/dist/editor/ui/SimpleToolbar.js +7 -0
- package/dist/editor/ui/Spinner.js +7 -0
- package/dist/editor/ui/Splitter.js +187 -0
- package/dist/editor/ui/StackedPanels.js +69 -0
- package/dist/editor/ui/Toolbar.js +7 -0
- package/dist/editor/utils/id-helper.js +7 -0
- package/dist/editor/utils/insertOptions.js +45 -0
- package/dist/editor/utils/itemutils.js +25 -0
- package/dist/editor/utils/useMemoDebug.js +20 -0
- package/dist/editor/utils.js +328 -0
- package/dist/editor/views/CompareView.js +147 -0
- package/dist/editor/views/EditView.js +17 -0
- package/dist/editor/views/ItemEditor.js +24 -0
- package/dist/editor/views/SingleEditView.js +25 -0
- package/dist/index.js +22 -0
- package/dist/page-wizard/PageWizard.js +62 -0
- package/dist/page-wizard/SelectWizard.js +43 -0
- package/dist/page-wizard/WizardSteps.js +71 -0
- package/dist/page-wizard/service.js +26 -0
- package/dist/page-wizard/startPageWizardCommand.js +23 -0
- package/dist/page-wizard/steps/BuildPageStep.js +138 -0
- package/dist/page-wizard/steps/CollectStep.js +124 -0
- package/dist/page-wizard/steps/ComponentTypesSelector.js +211 -0
- package/dist/page-wizard/steps/Components.js +94 -0
- package/dist/page-wizard/steps/CreatePage.js +142 -0
- package/dist/page-wizard/steps/CreatePageAndLayoutStep.js +230 -0
- package/dist/page-wizard/steps/EditButton.js +7 -0
- package/dist/page-wizard/steps/FieldEditor.js +30 -0
- package/dist/page-wizard/steps/Generate.js +11 -0
- package/dist/page-wizard/steps/ImagesStep.js +159 -0
- package/dist/page-wizard/steps/LayoutStep.js +120 -0
- package/dist/page-wizard/steps/SelectStep.js +150 -0
- package/dist/page-wizard/steps/schema.js +140 -0
- package/dist/page-wizard/steps/usePageCreator.js +194 -0
- package/dist/splash-screen/NewPage.js +131 -0
- package/dist/splash-screen/SectionHeadline.js +9 -0
- package/dist/splash-screen/SplashScreen.js +81 -0
- package/dist/tour/Tour.js +321 -0
- package/dist/tour/default-tour.js +231 -0
- package/dist/tour/preview-tour.js +93 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types.js +2 -0
- package/package.json +1 -1
- package/src/editor/sidebar/ComponentTree.tsx +512 -512
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PageViewerFrame = PageViewerFrame;
|
|
7
|
+
exports.injectEditorCSS = injectEditorCSS;
|
|
8
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
|
+
const react_1 = require("react");
|
|
10
|
+
const MiniMap_1 = require("./MiniMap");
|
|
11
|
+
const editContext_1 = require("../client/editContext");
|
|
12
|
+
const use_debounce_1 = require("use-debounce");
|
|
13
|
+
const PageEditorChrome_1 = require("../page-editor-chrome/PageEditorChrome");
|
|
14
|
+
const morphdom_1 = __importDefault(require("morphdom"));
|
|
15
|
+
const react_uuid_1 = __importDefault(require("react-uuid"));
|
|
16
|
+
const utils_1 = require("../utils");
|
|
17
|
+
const componentTreeHelper_1 = require("../componentTreeHelper");
|
|
18
|
+
const ContextMenu_1 = require("../ContextMenu");
|
|
19
|
+
const editService_1 = require("../services/editService");
|
|
20
|
+
const navigation_1 = require("next/navigation");
|
|
21
|
+
const EditorWarnings_1 = require("../EditorWarnings");
|
|
22
|
+
const NoLayout_1 = require("../page-editor-chrome/NoLayout");
|
|
23
|
+
const Spinner_1 = require("../ui/Spinner");
|
|
24
|
+
const DeviceToolbar_1 = require("./DeviceToolbar");
|
|
25
|
+
function PageViewerFrame({ mode, pageViewContext, }) {
|
|
26
|
+
const editContext = (0, editContext_1.useEditContext)();
|
|
27
|
+
const pathname = (0, navigation_1.usePathname)();
|
|
28
|
+
const pageViewContextRef = (0, react_1.useRef)(undefined);
|
|
29
|
+
if (!editContext || !pageViewContext)
|
|
30
|
+
return null;
|
|
31
|
+
(0, react_1.useEffect)(() => {
|
|
32
|
+
pageViewContextRef.current = pageViewContext;
|
|
33
|
+
}, [pageViewContext]);
|
|
34
|
+
const editContextRef = (0, editContext_1.useEditContextRef)();
|
|
35
|
+
const iframeRef = pageViewContext.editorIframeRef;
|
|
36
|
+
const [showSpinner, setShowSpinner] = (0, react_1.useState)(false);
|
|
37
|
+
const [scroll, setScroll] = (0, react_1.useState)(0);
|
|
38
|
+
const [showMiniMap, setShowMiniMap] = (0, react_1.useState)(false);
|
|
39
|
+
const zoom = pageViewContext.zoom;
|
|
40
|
+
const blockBlurEventRef = (0, react_1.useRef)(0);
|
|
41
|
+
const [currentItemDescriptor, setCurrentItemDescriptor] = (0, react_1.useState)(undefined);
|
|
42
|
+
const pageItemDescriptor = pageViewContext.pageItemDescriptor;
|
|
43
|
+
(0, react_1.useEffect)(() => {
|
|
44
|
+
//Workaround for iframeref updates not propagating to usePageViewContext
|
|
45
|
+
pageViewContext.setWorkaround((x) => !x);
|
|
46
|
+
}, [iframeRef.current]);
|
|
47
|
+
const updateMiniMapVisibility = (0, use_debounce_1.useDebouncedCallback)(() => {
|
|
48
|
+
if (!iframeRef.current)
|
|
49
|
+
return;
|
|
50
|
+
const iframe = iframeRef.current;
|
|
51
|
+
const doc = iframe.contentDocument;
|
|
52
|
+
if (!doc?.documentElement)
|
|
53
|
+
return;
|
|
54
|
+
const scrollContainer = doc.scrollingElement || doc.body;
|
|
55
|
+
if (!scrollContainer)
|
|
56
|
+
return;
|
|
57
|
+
const contentHeight = scrollContainer.scrollHeight;
|
|
58
|
+
const clientHeight = iframe.clientHeight;
|
|
59
|
+
const upperThreshold = clientHeight + 100; // show minimap if content exceeds this height
|
|
60
|
+
const lowerThreshold = clientHeight; // hide minimap if content falls below this
|
|
61
|
+
if (showMiniMap) {
|
|
62
|
+
if (contentHeight <= lowerThreshold) {
|
|
63
|
+
setShowMiniMap(false);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
if (contentHeight > upperThreshold) {
|
|
68
|
+
setShowMiniMap(true);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}, 100);
|
|
72
|
+
updateMiniMapVisibility();
|
|
73
|
+
function buildPageModel(iframeDocument) {
|
|
74
|
+
if (!iframeDocument ||
|
|
75
|
+
!editContextRef.current ||
|
|
76
|
+
!pageViewContextRef.current)
|
|
77
|
+
return;
|
|
78
|
+
const pageItemDescriptor = pageViewContextRef.current?.pageItemDescriptor;
|
|
79
|
+
if (!pageItemDescriptor)
|
|
80
|
+
return;
|
|
81
|
+
const pageItem = {
|
|
82
|
+
...pageItemDescriptor,
|
|
83
|
+
renderedFieldIds: [],
|
|
84
|
+
};
|
|
85
|
+
const start = performance.now();
|
|
86
|
+
const treeWalker = iframeDocument.createTreeWalker(iframeDocument.documentElement, // Root node to start traversal
|
|
87
|
+
NodeFilter.SHOW_ELEMENT, // Only show element nodes
|
|
88
|
+
null);
|
|
89
|
+
const root = {
|
|
90
|
+
placeholders: [],
|
|
91
|
+
id: "page",
|
|
92
|
+
type: "Page",
|
|
93
|
+
typeId: "",
|
|
94
|
+
name: "Page",
|
|
95
|
+
items: [pageItem],
|
|
96
|
+
datasourceItem: pageItem,
|
|
97
|
+
renderedDictionaryKeys: [],
|
|
98
|
+
editorFields: {},
|
|
99
|
+
};
|
|
100
|
+
let currentComponent = root;
|
|
101
|
+
let currentPlaceholder;
|
|
102
|
+
while (treeWalker.nextNode()) {
|
|
103
|
+
const node = treeWalker.currentNode;
|
|
104
|
+
if (node.nodeType !== Node.ELEMENT_NODE)
|
|
105
|
+
continue;
|
|
106
|
+
const element = node;
|
|
107
|
+
if (currentComponent && element.hasAttribute("data-fieldid")) {
|
|
108
|
+
const fieldId = element.getAttribute("data-fieldid");
|
|
109
|
+
const language = element.getAttribute("data-language") ||
|
|
110
|
+
currentComponent.datasourceItem?.language ||
|
|
111
|
+
pageItem.language;
|
|
112
|
+
const version = element.hasAttribute("data-version")
|
|
113
|
+
? parseInt(element.getAttribute("data-version"))
|
|
114
|
+
: currentComponent.datasourceItem?.version || pageItem.version;
|
|
115
|
+
const itemId = element.getAttribute("data-itemid") ||
|
|
116
|
+
currentComponent.datasourceItem?.id;
|
|
117
|
+
if (!itemId)
|
|
118
|
+
continue;
|
|
119
|
+
let renderedItem = currentComponent.items.find((x) => x.id === itemId && x.language === language && x.version === version);
|
|
120
|
+
if (!renderedItem) {
|
|
121
|
+
renderedItem = {
|
|
122
|
+
id: itemId,
|
|
123
|
+
language,
|
|
124
|
+
version,
|
|
125
|
+
renderedFieldIds: [],
|
|
126
|
+
};
|
|
127
|
+
currentComponent.items.push(renderedItem);
|
|
128
|
+
}
|
|
129
|
+
if (renderedItem.renderedFieldIds.indexOf(fieldId) === -1) {
|
|
130
|
+
renderedItem.renderedFieldIds.push(fieldId);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (element.tagName === "SCRIPT") {
|
|
134
|
+
const placeholderStartId = element.getAttribute("data-placeholder-start");
|
|
135
|
+
const placeholderEndId = element.getAttribute("data-placeholder-end");
|
|
136
|
+
const componentStartId = element.getAttribute("data-component-start");
|
|
137
|
+
const componentEndId = element.getAttribute("data-component-end");
|
|
138
|
+
const dictionaryKeyStart = element.getAttribute("data-dictionary-key-start");
|
|
139
|
+
const editorGroup = element.getAttribute("data-editor-group");
|
|
140
|
+
if (currentComponent && editorGroup) {
|
|
141
|
+
let group = currentComponent.editorFields[editorGroup];
|
|
142
|
+
if (!group) {
|
|
143
|
+
group = {
|
|
144
|
+
addFields: [],
|
|
145
|
+
removeFields: [],
|
|
146
|
+
};
|
|
147
|
+
currentComponent.editorFields[editorGroup] = group;
|
|
148
|
+
}
|
|
149
|
+
const addFields = element.getAttribute("data-add-fields")?.split(",");
|
|
150
|
+
const removeFields = element
|
|
151
|
+
.getAttribute("data-remove-fields")
|
|
152
|
+
?.split(",");
|
|
153
|
+
group.addFields = [...group.addFields, ...(addFields || [])];
|
|
154
|
+
group.removeFields = [...group.removeFields, ...(removeFields || [])];
|
|
155
|
+
}
|
|
156
|
+
if (dictionaryKeyStart) {
|
|
157
|
+
if (!currentComponent) {
|
|
158
|
+
console.error("Dictionary key without component:", dictionaryKeyStart);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
currentComponent.renderedDictionaryKeys.push(dictionaryKeyStart);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (placeholderStartId) {
|
|
165
|
+
if (!currentComponent) {
|
|
166
|
+
console.error("Placeholder start without component:", placeholderStartId, "Current placeholder", currentPlaceholder);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
currentPlaceholder = currentComponent.placeholders.find((x) => x.key === placeholderStartId);
|
|
170
|
+
if (!currentPlaceholder) {
|
|
171
|
+
currentPlaceholder = {
|
|
172
|
+
key: placeholderStartId,
|
|
173
|
+
name: placeholderStartId.indexOf(currentComponent.id + "_") === 0
|
|
174
|
+
? placeholderStartId.substring(currentComponent.id.length + 1)
|
|
175
|
+
: placeholderStartId,
|
|
176
|
+
description: "",
|
|
177
|
+
components: [],
|
|
178
|
+
parentComponent: currentComponent,
|
|
179
|
+
};
|
|
180
|
+
currentComponent.placeholders.push(currentPlaceholder);
|
|
181
|
+
}
|
|
182
|
+
currentComponent = undefined;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (placeholderEndId) {
|
|
186
|
+
currentComponent = currentPlaceholder?.parentComponent;
|
|
187
|
+
if (currentPlaceholder?.key !== placeholderEndId) {
|
|
188
|
+
console.error("Placeholder end does not match start", currentPlaceholder, placeholderEndId);
|
|
189
|
+
}
|
|
190
|
+
currentPlaceholder = undefined;
|
|
191
|
+
}
|
|
192
|
+
if (componentStartId) {
|
|
193
|
+
if (!currentPlaceholder) {
|
|
194
|
+
if (!currentComponent) {
|
|
195
|
+
console.error("Component start without parent component:", componentStartId);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
currentPlaceholder = {
|
|
199
|
+
key: "implicit_" + componentStartId,
|
|
200
|
+
name: "no-placeholder",
|
|
201
|
+
description: "",
|
|
202
|
+
components: [],
|
|
203
|
+
parentComponent: currentComponent,
|
|
204
|
+
};
|
|
205
|
+
if (!currentComponent) {
|
|
206
|
+
console.error("Component start without placeholder or parent component");
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
currentComponent.placeholders.push(currentPlaceholder);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (currentPlaceholder) {
|
|
213
|
+
const language = element.getAttribute("data-language") || pageItem.language;
|
|
214
|
+
const version = element.hasAttribute("data-version")
|
|
215
|
+
? parseInt(element.getAttribute("data-version"))
|
|
216
|
+
: pageItem.version;
|
|
217
|
+
const itemId = element.getAttribute("data-itemid");
|
|
218
|
+
const datasourceItem = itemId
|
|
219
|
+
? {
|
|
220
|
+
id: itemId,
|
|
221
|
+
language,
|
|
222
|
+
version,
|
|
223
|
+
renderedFieldIds: [],
|
|
224
|
+
}
|
|
225
|
+
: undefined;
|
|
226
|
+
const layoutId = element.getAttribute("data-layoutid");
|
|
227
|
+
currentComponent = currentPlaceholder.components.find((x) => x.id === componentStartId);
|
|
228
|
+
if (!currentComponent) {
|
|
229
|
+
currentComponent = {
|
|
230
|
+
id: componentStartId,
|
|
231
|
+
name: "",
|
|
232
|
+
type: element.getAttribute("data-type") || "",
|
|
233
|
+
typeId: element.getAttribute("data-typeid") || "",
|
|
234
|
+
items: datasourceItem ? [datasourceItem] : [],
|
|
235
|
+
placeholders: [],
|
|
236
|
+
parentPlaceholder: currentPlaceholder,
|
|
237
|
+
renderedDictionaryKeys: [],
|
|
238
|
+
datasourceItem,
|
|
239
|
+
layoutId: layoutId || undefined,
|
|
240
|
+
editorFields: {},
|
|
241
|
+
};
|
|
242
|
+
currentPlaceholder.components.push(currentComponent);
|
|
243
|
+
}
|
|
244
|
+
currentPlaceholder = undefined;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (componentEndId) {
|
|
248
|
+
if (!currentComponent || currentComponent.id !== componentEndId) {
|
|
249
|
+
console.error("Component end does not match start", currentComponent, componentEndId);
|
|
250
|
+
// Placeholder closed implicitly
|
|
251
|
+
if (currentPlaceholder?.parentComponent.id === componentEndId) {
|
|
252
|
+
currentComponent = currentPlaceholder.parentComponent;
|
|
253
|
+
currentPlaceholder = undefined;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
currentPlaceholder = currentComponent?.parentPlaceholder;
|
|
257
|
+
if (currentPlaceholder?.key.startsWith("implicit_")) {
|
|
258
|
+
currentComponent = currentPlaceholder.parentComponent;
|
|
259
|
+
}
|
|
260
|
+
else
|
|
261
|
+
currentComponent = undefined;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const page = {
|
|
266
|
+
rootComponent: root,
|
|
267
|
+
item: pageItem,
|
|
268
|
+
editRevision: editContextRef.current?.revision ?? "",
|
|
269
|
+
};
|
|
270
|
+
const time = performance.now() - start;
|
|
271
|
+
console.log("PAGE MODEL SKELETON", page, time);
|
|
272
|
+
pageViewContextRef.current?.setPageSkeleton(page);
|
|
273
|
+
}
|
|
274
|
+
const buildPageModelThrottled = (0, use_debounce_1.useThrottledCallback)(buildPageModel, 1000);
|
|
275
|
+
const [iframeSrc, setIframeSrc] = (0, react_1.useState)();
|
|
276
|
+
(0, react_1.useEffect)(() => {
|
|
277
|
+
const isHeadless = pageViewContext.isHeadless;
|
|
278
|
+
if (!pageItemDescriptor || isHeadless === undefined)
|
|
279
|
+
return;
|
|
280
|
+
let renderUrl;
|
|
281
|
+
if (!isHeadless) {
|
|
282
|
+
// Sitecore MVC rendering
|
|
283
|
+
renderUrl = new URL(window.location.href);
|
|
284
|
+
renderUrl.pathname = "/";
|
|
285
|
+
renderUrl.searchParams.set("sc_itemid", pageItemDescriptor.id);
|
|
286
|
+
renderUrl.searchParams.set("sc_lang", pageItemDescriptor.language);
|
|
287
|
+
renderUrl.searchParams.set("sc_version", pageItemDescriptor.version.toString());
|
|
288
|
+
renderUrl.searchParams.set("sc_mode", editContext.previewMode ? "preview" : "edit");
|
|
289
|
+
renderUrl.searchParams.set("alpaca_editor", "1");
|
|
290
|
+
renderUrl.searchParams.set("sc_database", "master");
|
|
291
|
+
//renderUrl.searchParams.set(
|
|
292
|
+
// "sc_site",
|
|
293
|
+
// editContext.site?.name || "website"
|
|
294
|
+
// );
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
// Headless rendering
|
|
298
|
+
console.log("Headless rendering", pageItemDescriptor);
|
|
299
|
+
renderUrl = new URL(window.location.href);
|
|
300
|
+
if (editContext.configuration.services.renderService.path)
|
|
301
|
+
renderUrl.pathname =
|
|
302
|
+
editContext.configuration.services.renderService.path;
|
|
303
|
+
renderUrl.searchParams.set("itemid", pageItemDescriptor.id);
|
|
304
|
+
renderUrl.searchParams.set("lang", pageItemDescriptor.language);
|
|
305
|
+
renderUrl.searchParams.set("version", pageItemDescriptor.version.toString());
|
|
306
|
+
renderUrl.searchParams.set("site", editContext.pageView.site?.name || "website");
|
|
307
|
+
renderUrl.searchParams.set("mode", editContext.previewMode ? "preview" : "edit");
|
|
308
|
+
}
|
|
309
|
+
renderUrl.searchParams.set("edit_rev", editContext.revision ?? (0, react_uuid_1.default)());
|
|
310
|
+
if (iframeRef.current?.contentWindow?.requestRefresh) {
|
|
311
|
+
console.log("Integration - requesting refresh");
|
|
312
|
+
iframeRef.current?.contentWindow.requestRefresh(renderUrl.toString());
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
setShowSpinner(true);
|
|
316
|
+
console.log("No integration - reloading frame");
|
|
317
|
+
if (isHeadless) {
|
|
318
|
+
console.log("Setting iframe src", renderUrl.toString());
|
|
319
|
+
setIframeSrc(renderUrl.toString());
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
const initialLoad = currentItemDescriptor?.id !== pageItemDescriptor.id ||
|
|
323
|
+
currentItemDescriptor?.language !== pageItemDescriptor.language ||
|
|
324
|
+
currentItemDescriptor?.version !== pageItemDescriptor.version;
|
|
325
|
+
loadContent(renderUrl.toString(), initialLoad);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
setCurrentItemDescriptor(pageItemDescriptor);
|
|
329
|
+
}, [
|
|
330
|
+
pathname,
|
|
331
|
+
editContext.revision,
|
|
332
|
+
pageItemDescriptor,
|
|
333
|
+
pageViewContext.isHeadless,
|
|
334
|
+
editContext.previewMode,
|
|
335
|
+
]);
|
|
336
|
+
(0, react_1.useEffect)(() => {
|
|
337
|
+
if (editContext.focusedField) {
|
|
338
|
+
if (editContext.selection.length > 0 &&
|
|
339
|
+
editContext.focusedField.item.id !== editContext.selection[0])
|
|
340
|
+
return;
|
|
341
|
+
const fieldElement = (0, utils_1.findFieldElement)(iframeRef.current, editContext.focusedField);
|
|
342
|
+
if (fieldElement) {
|
|
343
|
+
const rect = (0, utils_1.getAbsolutePosition)(fieldElement, iframeRef.current);
|
|
344
|
+
const scrollTop = iframeRef.current?.contentWindow?.scrollY || 0;
|
|
345
|
+
const iframeHeight = iframeRef.current?.getBoundingClientRect().height;
|
|
346
|
+
const isInViewport = rect.y >= scrollTop && rect.y <= scrollTop + (iframeHeight || 0);
|
|
347
|
+
if (!isInViewport) {
|
|
348
|
+
iframeRef.current?.contentWindow?.scrollTo({
|
|
349
|
+
top: rect.y,
|
|
350
|
+
behavior: "smooth",
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
if (editContext.selection.length > 0) {
|
|
357
|
+
const lastSelectedComponent = (0, componentTreeHelper_1.getComponentById)(editContext.selection[editContext.selection.length - 1], pageViewContextRef.current.page);
|
|
358
|
+
if (lastSelectedComponent) {
|
|
359
|
+
editContext.setScrollIntoView(lastSelectedComponent.id);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}, [editContext.focusedField, editContext.selection]);
|
|
364
|
+
const loadContent = async (href, initialLoad) => {
|
|
365
|
+
console.log("Loading content:", href);
|
|
366
|
+
const start = performance.now();
|
|
367
|
+
if (!href)
|
|
368
|
+
return;
|
|
369
|
+
const content = await fetch(href);
|
|
370
|
+
const text = await content.text();
|
|
371
|
+
console.log("Content loaded in " + (performance.now() - start) + " ms");
|
|
372
|
+
const doc = iframeRef.current?.contentDocument;
|
|
373
|
+
if (doc) {
|
|
374
|
+
if (initialLoad) {
|
|
375
|
+
doc.open();
|
|
376
|
+
doc.write(text);
|
|
377
|
+
doc.close();
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
const parser = new DOMParser();
|
|
381
|
+
const newDoc = parser.parseFromString(text, "text/html");
|
|
382
|
+
(0, morphdom_1.default)(doc.documentElement, newDoc.documentElement);
|
|
383
|
+
setShowSpinner(false);
|
|
384
|
+
}
|
|
385
|
+
if (mode === "edit" && !editContext.previewMode)
|
|
386
|
+
injectEditorCSS(doc);
|
|
387
|
+
buildPageModel(doc);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
(0, react_1.useEffect)(() => {
|
|
391
|
+
if (!editContext.scrollIntoView ||
|
|
392
|
+
!iframeRef.current?.contentDocument?.documentElement)
|
|
393
|
+
return;
|
|
394
|
+
const rect = (0, utils_1.findComponentRect)(iframeRef.current, editContext.scrollIntoView, true);
|
|
395
|
+
if (!rect)
|
|
396
|
+
return;
|
|
397
|
+
// Check if element is already in viewport
|
|
398
|
+
const iframeHeight = iframeRef.current.getBoundingClientRect().height;
|
|
399
|
+
const scrollTop = iframeRef.current?.contentWindow?.scrollY || 0;
|
|
400
|
+
const elementTop = rect.rect.y;
|
|
401
|
+
const isInViewport = elementTop >= scrollTop && elementTop <= scrollTop + iframeHeight;
|
|
402
|
+
// If already in viewport, no need to scroll
|
|
403
|
+
if (isInViewport) {
|
|
404
|
+
editContext.setScrollIntoView(undefined);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const scrollPosition = rect.rect.y - iframeHeight / 2 + rect.rect.height / 2;
|
|
408
|
+
iframeRef.current?.contentWindow?.scrollTo({
|
|
409
|
+
top: scrollPosition,
|
|
410
|
+
behavior: "smooth",
|
|
411
|
+
});
|
|
412
|
+
editContext.setScrollIntoView(undefined);
|
|
413
|
+
}, [editContext.scrollIntoView, pageViewContext.page]);
|
|
414
|
+
(0, react_1.useEffect)(() => {
|
|
415
|
+
const handleMessage = (message) => {
|
|
416
|
+
if (message.data.type === "editor-exitFullscreen") {
|
|
417
|
+
editContext.pageView.setFullscreen(false);
|
|
418
|
+
}
|
|
419
|
+
if (message.data.type === "editor-timings") {
|
|
420
|
+
editContext.setTimings(message.data.timings);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
window.addEventListener("message", handleMessage);
|
|
424
|
+
return () => {
|
|
425
|
+
window.removeEventListener("message", handleMessage);
|
|
426
|
+
};
|
|
427
|
+
}, []);
|
|
428
|
+
const selecionChangeHandler = (0, use_debounce_1.useThrottledCallback)(() => {
|
|
429
|
+
const sel = iframeRef.current?.contentDocument?.getSelection();
|
|
430
|
+
if (sel && sel.rangeCount > 0) {
|
|
431
|
+
// Find the field element containing the selection
|
|
432
|
+
const fieldElement = (0, utils_1.findClosestFieldElement)(sel.anchorNode);
|
|
433
|
+
if (!fieldElement)
|
|
434
|
+
return;
|
|
435
|
+
const fieldId = fieldElement.getAttribute("data-fieldid");
|
|
436
|
+
if (!fieldId)
|
|
437
|
+
return;
|
|
438
|
+
const range = sel.getRangeAt(0);
|
|
439
|
+
editContextRef.current?.setFocusedField({
|
|
440
|
+
fieldId: fieldId,
|
|
441
|
+
item: {
|
|
442
|
+
id: fieldElement.getAttribute("data-itemid") || "",
|
|
443
|
+
language: fieldElement.getAttribute("data-language") || "",
|
|
444
|
+
version: parseInt(fieldElement.getAttribute("data-version") || "0"),
|
|
445
|
+
},
|
|
446
|
+
}, true);
|
|
447
|
+
// Compute the global offsets relative to the field element.
|
|
448
|
+
const globalStartOffset = getGlobalTextOffset(fieldElement, range.startContainer, range.startOffset);
|
|
449
|
+
const globalEndOffset = getGlobalTextOffset(fieldElement, range.endContainer, range.endOffset);
|
|
450
|
+
editContextRef.current?.setSelectedRange({
|
|
451
|
+
fieldId: fieldId,
|
|
452
|
+
startOffset: globalStartOffset,
|
|
453
|
+
endOffset: globalEndOffset,
|
|
454
|
+
text: range.toString(),
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
}, 100);
|
|
458
|
+
(0, react_1.useEffect)(() => {
|
|
459
|
+
const iframe = iframeRef.current;
|
|
460
|
+
if (!iframe)
|
|
461
|
+
return;
|
|
462
|
+
const handleIframeMouseDown = async (event) => {
|
|
463
|
+
const target = event.target;
|
|
464
|
+
if (editContextRef.current?.isRefreshing)
|
|
465
|
+
return;
|
|
466
|
+
const componentId = (0, utils_1.findParentComponentId)(target);
|
|
467
|
+
editContextRef.current?.setCurrentOverlay(undefined);
|
|
468
|
+
if (componentId) {
|
|
469
|
+
if (event.ctrlKey) {
|
|
470
|
+
const currentSelection = editContextRef.current?.selection || [];
|
|
471
|
+
if (currentSelection.indexOf(componentId) === -1)
|
|
472
|
+
editContextRef.current?.select([...currentSelection, componentId]);
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
editContextRef.current?.select([componentId]);
|
|
476
|
+
}
|
|
477
|
+
// if (mode !== "edit") {
|
|
478
|
+
//editContextRef.current?.setScrollIntoView(componentId);
|
|
479
|
+
//}
|
|
480
|
+
}
|
|
481
|
+
else
|
|
482
|
+
editContextRef.current?.select([]);
|
|
483
|
+
if (mode === "edit" &&
|
|
484
|
+
pageViewContextRef.current?.page?.item.canWriteItem) {
|
|
485
|
+
const fieldElement = (0, utils_1.findParentWithAttribute)(target, "data-fieldid");
|
|
486
|
+
if (fieldElement?.hasAttribute("data-itemid")) {
|
|
487
|
+
const hasLock = await editContextRef.current?.setFocusedField((0, utils_1.getFieldDescriptorFromElement)(fieldElement), true);
|
|
488
|
+
blockBlurEventRef.current = Date.now() + 500;
|
|
489
|
+
if (hasLock) {
|
|
490
|
+
editContextRef.current?.setInlineEditingFieldElement(fieldElement);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
//Forward events so primereact overlays can close
|
|
495
|
+
const clickEvent = new MouseEvent("click", {
|
|
496
|
+
view: window,
|
|
497
|
+
bubbles: true,
|
|
498
|
+
cancelable: true,
|
|
499
|
+
clientX: event.clientX,
|
|
500
|
+
clientY: event.clientY,
|
|
501
|
+
});
|
|
502
|
+
document.dispatchEvent(clickEvent);
|
|
503
|
+
};
|
|
504
|
+
const handleIframeClick = async (event) => {
|
|
505
|
+
const target = event.target;
|
|
506
|
+
// Check if the click target is a link (anchor tag)
|
|
507
|
+
const anchor = target.tagName.toLowerCase() === "a" ? target : target.closest("a");
|
|
508
|
+
if (anchor) {
|
|
509
|
+
const href = anchor.href;
|
|
510
|
+
// Block only navigation links, allow anchor links and javascript links
|
|
511
|
+
if (href && !href.startsWith("#") && !href.startsWith("javascript:")) {
|
|
512
|
+
event.preventDefault();
|
|
513
|
+
console.log("Navigation link blocked:", href);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
const handleContextMenu = async (event) => {
|
|
518
|
+
if (editContextRef.current?.isRefreshing)
|
|
519
|
+
return;
|
|
520
|
+
const target = event.target;
|
|
521
|
+
if (!target)
|
|
522
|
+
return;
|
|
523
|
+
if (event.ctrlKey)
|
|
524
|
+
return;
|
|
525
|
+
event.preventDefault();
|
|
526
|
+
event.stopPropagation();
|
|
527
|
+
const componentId = (0, utils_1.findNearestComponentId)(target);
|
|
528
|
+
if (componentId) {
|
|
529
|
+
if (!editContextRef.current?.selection.includes(componentId)) {
|
|
530
|
+
console.log("Selecting component CONTEXT MENU", componentId);
|
|
531
|
+
editContextRef.current.select([componentId]);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const fieldElement = (0, utils_1.findParentWithAttribute)(target, "data-fieldid");
|
|
535
|
+
const selectedComponents = editContextRef.current?.selection
|
|
536
|
+
.map((id) => (0, componentTreeHelper_1.getComponentById)(id, pageViewContextRef.current.page))
|
|
537
|
+
.filter((x) => x);
|
|
538
|
+
const iframeRect = iframe.getBoundingClientRect();
|
|
539
|
+
const adjustedEvent = new MouseEvent("contextmenu", {
|
|
540
|
+
bubbles: true,
|
|
541
|
+
cancelable: true,
|
|
542
|
+
shiftKey: event.shiftKey,
|
|
543
|
+
altKey: event.altKey,
|
|
544
|
+
ctrlKey: event.ctrlKey,
|
|
545
|
+
view: window,
|
|
546
|
+
clientX: event.clientX + iframeRect.x,
|
|
547
|
+
clientY: event.clientY + iframeRect.y,
|
|
548
|
+
});
|
|
549
|
+
const field = fieldElement
|
|
550
|
+
? (0, utils_1.getFieldDescriptorFromElement)(fieldElement)
|
|
551
|
+
: undefined;
|
|
552
|
+
const fieldButtons = field ? await (0, editService_1.loadFieldButtons)(field) : [];
|
|
553
|
+
if ((0, ContextMenu_1.showComponentContextMenu)(selectedComponents, editContextRef.current, field, fieldButtons)(adjustedEvent)) {
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
const handleLoad = () => {
|
|
557
|
+
setShowSpinner(false);
|
|
558
|
+
const iframeDocument = iframe.contentDocument || iframe.contentWindow?.document;
|
|
559
|
+
if (iframeDocument) {
|
|
560
|
+
iframeDocument.documentElement.addEventListener("mousedown", handleIframeMouseDown);
|
|
561
|
+
iframeDocument.documentElement.addEventListener("click", handleIframeClick);
|
|
562
|
+
iframe.contentWindow?.addEventListener("contextmenu", handleContextMenu, true);
|
|
563
|
+
const scrollContainer = iframe.contentWindow?.document.scrollingElement ||
|
|
564
|
+
iframe.contentWindow?.document.body;
|
|
565
|
+
scrollContainer?.addEventListener("scroll", () => {
|
|
566
|
+
const scrollTop = scrollContainer.scrollTop || 0;
|
|
567
|
+
scrollHandler(scrollTop);
|
|
568
|
+
});
|
|
569
|
+
iframe.contentWindow?.addEventListener("scroll", () => {
|
|
570
|
+
const scrollTop = scrollContainer?.scrollTop || 0;
|
|
571
|
+
scrollHandler(scrollTop);
|
|
572
|
+
});
|
|
573
|
+
iframeDocument.addEventListener("selectionchange", selecionChangeHandler);
|
|
574
|
+
iframeDocument.addEventListener("keydown", (event) => {
|
|
575
|
+
editContextRef.current?.handleKeyDown(event);
|
|
576
|
+
});
|
|
577
|
+
iframeDocument.documentElement?.addEventListener("blur", () => {
|
|
578
|
+
// Block blur event if it was triggered by clicking on a field
|
|
579
|
+
if (blockBlurEventRef.current < Date.now()) {
|
|
580
|
+
//editContext.setFocusedField(undefined, false);
|
|
581
|
+
editContext.setInlineEditingFieldElement(undefined);
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
blockBlurEventRef.current = 0;
|
|
585
|
+
}
|
|
586
|
+
}, true);
|
|
587
|
+
const observer = new MutationObserver((records) => {
|
|
588
|
+
// Ignore all text field edits
|
|
589
|
+
if (records.some((x) => !(x &&
|
|
590
|
+
"getAttribute" in x.target &&
|
|
591
|
+
x.target.getAttribute("data-fieldid") &&
|
|
592
|
+
x.target.getAttribute("data-itemid")))) {
|
|
593
|
+
buildPageModelThrottled(iframeDocument);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
observer.observe(iframeDocument, {
|
|
597
|
+
childList: true, // observe direct children changes
|
|
598
|
+
subtree: true, // observe all descendants changes
|
|
599
|
+
characterData: false, // observe text changes
|
|
600
|
+
//attributes: true, // observe attribute changes (like style or class)
|
|
601
|
+
});
|
|
602
|
+
buildPageModel(iframeDocument);
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
if (iframe) {
|
|
606
|
+
iframe.addEventListener("load", handleLoad);
|
|
607
|
+
}
|
|
608
|
+
// Cleanup function
|
|
609
|
+
return () => {
|
|
610
|
+
if (iframe) {
|
|
611
|
+
iframe.removeEventListener("load", handleLoad);
|
|
612
|
+
const iframeDocument = iframe.contentDocument || iframe.contentWindow?.document;
|
|
613
|
+
if (iframeDocument) {
|
|
614
|
+
iframeDocument.documentElement.removeEventListener("click", handleIframeMouseDown);
|
|
615
|
+
iframeDocument.documentElement.removeEventListener("contextmenu", handleContextMenu);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
}, [iframeRef.current]);
|
|
620
|
+
(0, react_1.useEffect)(() => {
|
|
621
|
+
iframeRef.current?.contentWindow?.postMessage({ type: "componentsSelected", componentIds: editContext.selection }, "*");
|
|
622
|
+
}, [editContext.selection]);
|
|
623
|
+
const updateScrollPosition = (e) => {
|
|
624
|
+
setScroll(e);
|
|
625
|
+
if (mode === "edit")
|
|
626
|
+
pageViewContextRef.current?.setScroll(e);
|
|
627
|
+
};
|
|
628
|
+
(0, react_1.useEffect)(() => {
|
|
629
|
+
if (!iframeRef.current)
|
|
630
|
+
return;
|
|
631
|
+
const body = iframeRef.current.contentWindow?.document.documentElement;
|
|
632
|
+
if (!body)
|
|
633
|
+
return;
|
|
634
|
+
body.style.transform = `scale(${zoom})`;
|
|
635
|
+
body.style.transformOrigin = "top center";
|
|
636
|
+
body.style.overflow = "auto";
|
|
637
|
+
//body.style.height = `${body.scrollHeight / zoom}px`;
|
|
638
|
+
}, [zoom]);
|
|
639
|
+
const scrollHandler = (0, use_debounce_1.useThrottledCallback)(updateScrollPosition, 100);
|
|
640
|
+
if (pageViewContext.page?.item && !pageViewContext.page?.item.hasLayout) {
|
|
641
|
+
return (0, jsx_runtime_1.jsx)(NoLayout_1.NoLayout, {});
|
|
642
|
+
}
|
|
643
|
+
const deviceHeight = pageViewContext.device === "desktop" || !pageViewContext.deviceHeight
|
|
644
|
+
? "100%"
|
|
645
|
+
: pageViewContext.deviceHeight || 640;
|
|
646
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "relative flex h-full w-full flex-col items-center bg-slate-100 select-none", children: [!editContext.pageView.fullscreen && ((0, jsx_runtime_1.jsx)(EditorWarnings_1.EditorWarnings, { item: pageViewContext.page?.item })), pageViewContext.device !== "desktop" && ((0, jsx_runtime_1.jsx)(DeviceToolbar_1.DeviceToolbar, { pageViewContext: pageViewContext, configuration: editContext.configuration })), (0, jsx_runtime_1.jsxs)("div", { className: "relative flex flex-1 select-none", style: {
|
|
647
|
+
width: pageViewContext.device === "desktop" ||
|
|
648
|
+
pageViewContext.device === "Responsive"
|
|
649
|
+
? "100%"
|
|
650
|
+
: (pageViewContext.deviceWidth || 640) +
|
|
651
|
+
editContext.configuration.outline.width +
|
|
652
|
+
"px",
|
|
653
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative h-full w-full", children: [(0, jsx_runtime_1.jsx)("iframe", { ref: iframeRef, className: "page-iframe h-full w-full bg-white", style: { height: deviceHeight }, src: iframeSrc, "data-testid": "pageEditoriframe" }), iframeRef.current && ((0, jsx_runtime_1.jsx)(PageEditorChrome_1.PageEditorChrome, { iframe: iframeRef.current, mode: mode || "edit", pageViewContext: pageViewContext })), pageViewContext.deviceHeight && pageViewContext.device && ((0, jsx_runtime_1.jsx)("div", { className: "relative z-40 h-full w-full bg-slate-100" }))] }), !editContext.pageView.fullscreen && showMiniMap && ((0, jsx_runtime_1.jsx)(MiniMap_1.MiniMap, { mode: mode, scroll: scroll, mainViewIframeRef: iframeRef, pageViewContext: pageViewContext, deviceHeight: pageViewContext.device === "Desktop"
|
|
654
|
+
? undefined
|
|
655
|
+
: pageViewContext.deviceHeight })), showSpinner && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute top-0 left-0 h-full w-full bg-slate-100/50" }), (0, jsx_runtime_1.jsx)("div", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform", children: (0, jsx_runtime_1.jsx)(Spinner_1.Spinner, {}) })] }))] })] }));
|
|
656
|
+
}
|
|
657
|
+
function injectEditorCSS(iframeDocument) {
|
|
658
|
+
if (!iframeDocument)
|
|
659
|
+
return;
|
|
660
|
+
const style = iframeDocument.createElement("style");
|
|
661
|
+
style.textContent = `[contentEditable]:empty:before {
|
|
662
|
+
content: attr(placeholder);
|
|
663
|
+
opacity: 0.6;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
[contenteditable] {
|
|
667
|
+
outline: 0px solid transparent;
|
|
668
|
+
}
|
|
669
|
+
`;
|
|
670
|
+
if (iframeDocument && iframeDocument.head) {
|
|
671
|
+
iframeDocument.head.appendChild(style);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Calculates the global offset of a given target node and its local offset,
|
|
676
|
+
* relative to the container's complete text content.
|
|
677
|
+
*
|
|
678
|
+
* @param container - The container element that holds the text nodes.
|
|
679
|
+
* @param targetNode - The text node where the selection starts or ends.
|
|
680
|
+
* @param localOffset - The offset within the target text node.
|
|
681
|
+
* @returns The computed global offset.
|
|
682
|
+
*/
|
|
683
|
+
function getGlobalTextOffset(container, targetNode, localOffset) {
|
|
684
|
+
let globalOffset = 0;
|
|
685
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, null);
|
|
686
|
+
while (walker.nextNode()) {
|
|
687
|
+
const currentNode = walker.currentNode;
|
|
688
|
+
// If we've reached the target node, add the local offset and return.
|
|
689
|
+
if (currentNode === targetNode) {
|
|
690
|
+
return globalOffset + localOffset;
|
|
691
|
+
}
|
|
692
|
+
// Otherwise, add the length of this text node.
|
|
693
|
+
globalOffset += (currentNode.textContent || "").length;
|
|
694
|
+
}
|
|
695
|
+
return globalOffset;
|
|
696
|
+
}
|