/** * Media editor - file upload, URL entry, media library browser, and save UI * * Reads (via globals): * SFE.Context - .activeEditor (r/w), .activeMode (r/w), * .draftEditState, .actionBar, .buttonManager * SFE.PositionManager - .positionFloatingElements * SFE.FocusManager - .createFocusManager * SFE.Api - .apiCall * SFE.MediaHelper - (MediaHelper global) * SFE.MediaLibraryCache - (mediaLibraryCache global) * SFE.OverlayManager * SFE.LifecycleHelpers - .createFadeHandler, .setupDraftPreviewLifecycle * SFE.handleInlineSave - set by SaveManager * SFE.closeDraftPreview - set by DraftManager * SFE.ManagerData - .iconLibraryUrl, .mediaLibraryUrl, .restBase, * .restUrl, .nonce, .postId * * Exposes: SFE.MediaEditor { startMediaEditing, startSchemaComponentEditing } */ (function() { 'use strict'; window.MWP = window.MWP || {}; window.MWP.SFE = window.MWP.SFE || {}; const SFE = window.MWP.SFE; SFE.ManagerData = SFE.ManagerData || {}; function showToolbar(toolbar) { if (!toolbar) return; if (toolbar._mwpSwitchHideTimeout) { clearTimeout(toolbar._mwpSwitchHideTimeout); delete toolbar._mwpSwitchHideTimeout; } toolbar.classList.remove('mwp-sfe-closing'); toolbar.style.display = ''; } function ensureToolbarContainer(editorState) { if (!editorState) return null; let toolbarContainer = editorState.toolbarContainer || null; if (!toolbarContainer) { toolbarContainer = document.createElement('div'); toolbarContainer.className = 'mwp-sfe-inline-toolbar mwp-sfe-inline-editor'; toolbarContainer.setAttribute('data-mwp-sfe-control', 'true'); toolbarContainer.style.pointerEvents = 'auto'; toolbarContainer.style.display = 'none'; document.body.appendChild(toolbarContainer); editorState.toolbarContainer = toolbarContainer; } return toolbarContainer; } function bindInlineEditButtons(editorState) { const actionsContainer = editorState?.actionsContainer || null; if (!actionsContainer) return; if (actionsContainer._saveBtn) { actionsContainer._saveBtn.addEventListener('click', (event) => { event.preventDefault(); event.stopImmediatePropagation(); SFE.handleInlineSave(editorState); }); } if (actionsContainer._cancelBtn) { actionsContainer._cancelBtn.addEventListener('click', (event) => { event.preventDefault(); event.stopImmediatePropagation(); SFE.closeInPlaceEditor(editorState, true); }); } } function restoreInlineEditButtons(editorState) { const ctx = SFE.Context; const actionBar = ctx?.actionBar; const buttonManager = ctx?.buttonManager; const actionsContainer = editorState?.actionsContainer || null; if (!actionBar || !buttonManager || !actionsContainer) return; actionBar.updateState({ bar: actionsContainer, element: editorState.element, state: 'edit', content: buttonManager.getEditButtons(), }); bindInlineEditButtons(editorState); } function cloneAttributeChanges(attributeChanges) { return attributeChanges && typeof attributeChanges === 'object' ? { ...attributeChanges } : {}; } function createMediaToolbarHost(config) { const { editorState, component, toolbarContainer, formats, getMediaElement, setMediaElement, reposition, serializeState, applySerializedState, showMediaReplaceUI, } = config; const historyApi = typeof editorState?.getSessionHistoryApi === 'function' ? editorState.getSessionHistoryApi('media') : null; const host = { element: getMediaElement(), formats: Array.isArray(formats) ? formats : [], options: { ...(component?.editorOptions && typeof component.editorOptions === 'object' ? component.editorOptions : {}), toolbarContainer, blockRootElement: editorState?.element || null, }, attributeChanges: editorState.attributeChanges && typeof editorState.attributeChanges === 'object' ? editorState.attributeChanges : (editorState.attributeChanges = {}), toolbarManager: null, attachToolbarManager(manager) { this.toolbarManager = manager; }, detachToolbarManager(manager) { if (this.toolbarManager === manager) { this.toolbarManager = null; } }, isSelectionInEditor() { return false; }, getCurrentListItem() { return null; }, getParentList() { return null; }, canIndentListItem() { return false; }, canOutdentListItem() { return false; }, canUndo() { return !!historyApi?.canUndo?.(); }, canRedo() { return !!historyApi?.canRedo?.(); }, updateToolbarState() { if (this.toolbarManager && typeof this.toolbarManager.updateToolbarState === 'function') { this.toolbarManager.updateToolbarState(); } }, updateUndoRedoButtons() { if (this.toolbarManager && typeof this.toolbarManager.updateUndoRedoButtons === 'function') { this.toolbarManager.updateUndoRedoButtons(); } }, saveToHistory() { historyApi?.saveToHistory?.(); }, undo() { historyApi?.undo?.(); }, redo() { historyApi?.redo?.(); }, setElement(element) { this.element = element; setMediaElement(element); }, showMediaReplaceUI() { if (typeof showMediaReplaceUI === 'function') { showMediaReplaceUI(); } }, getBlockRootElement() { return editorState?.element || null; }, scheduleFloatingElementsPositionAfterLayout() { requestAnimationFrame(() => { requestAnimationFrame(() => { reposition(); }); }); } }; return SFE.SchemaEditorHost.attachHostContract(host); } // ─── Pure / stateless helpers ───────────────────────────────────────────── /** * Reposition the action bar once a media element has finished loading, or * immediately when it is already in a ready state. * Handles both (.complete) and