import type { Editor, EditorControllerProps } from '~/types/editor'; import { executeScript } from '~/utils/execute-scripts'; import { isScriptContent } from '~/utils/html-parse'; export class EditorController implements Editor { private props: EditorControllerProps; constructor(props: EditorControllerProps) { this.props = props; } setContent(newHTML: string) { const pageElement = this.props.getContentElement(); if (!pageElement) { return; } pageElement.innerHTML = newHTML; } replaceWith(query: string, newHTML: string, sort?: number) { const pageElement = this.props.getContentElement(); if (!pageElement) { return; } const targetElement = pageElement.querySelector(query); if (!targetElement) { return; } targetElement.outerHTML = newHTML; if (sort === undefined) { return; } const parent = targetElement.parentElement; if (!parent) { return; } const children = Array.from(parent.children); const index = children.indexOf(targetElement); if (index === -1) { return; } if (sort !== index) { parent.insertBefore(targetElement, children[sort]); } } /** * 在指定节点下追加 HTML * @param query 查询条件,待添加元素的父节点 ID。 * @param newHTML 新 HTML * @param sort 排序位置,从 0 开始表示应该处于第一位,2 表示应该处于第二位,以此类推。不填写则表示默认或者不变 */ append(query: string, newHTML: string, sort?: number) { const pageElement = this.props.getContentElement(); if (!pageElement) { return; } const targetElement = pageElement.querySelector(query); const parent = targetElement || pageElement; const tempDiv = document.createElement('div'); tempDiv.innerHTML = newHTML; const newElement = tempDiv.firstElementChild as HTMLElement; if (!newElement) { return; } if (sort === undefined) { parent.appendChild(newElement); } else { parent.insertBefore(newElement, parent.children[sort]); } } appendContent(query: string, newHTML: string, sort?: number) { const pageElement = this.props.getContentElement(); if (!pageElement) { return; } const tempDiv = document.createElement('div'); tempDiv.innerHTML = newHTML; const newElement = tempDiv.firstElementChild as HTMLElement; if (!newElement) { return; } const id = newElement.id; const targetElement = pageElement.querySelector(`#${id}`); if (targetElement) { this.replaceWith(`#${id}`, newHTML, sort); if (isScriptContent(newHTML)) { this.refresh(); } return; } this.append(query, newHTML, sort); const element = pageElement.querySelector(`#${id}`); if (element instanceof HTMLScriptElement) { executeScript(element); const frameRef = this.props.getIframeElement(); const event = new Event('DOMContentLoaded', { bubbles: true, cancelable: true, }); frameRef?.contentDocument?.dispatchEvent(event); } } updateContent(query: string, newHTML: string, sort?: number) { const pageElement = this.props.getContentElement(); if (!pageElement) { return; } this.replaceWith(query, newHTML, sort); if (isScriptContent(newHTML)) { this.refresh(); } } deleteContent(query: string) { const pageElement = this.props.getContentElement(); if (!pageElement) { return; } const targetElement = pageElement.querySelector(query); if (targetElement) { targetElement.remove(); } if (targetElement instanceof HTMLScriptElement) { this.refresh(); } } getContent(query?: string): string { const pageElement = this.props.getContentElement(); if (!pageElement) { return ''; } if (query) { const targetElement = pageElement.querySelector(query); return targetElement ? targetElement.innerHTML : ''; } return pageElement.innerHTML; } scrollToElement(query: string) { const pageElement = this.props.getContentElement(); if (!pageElement) { return; } const targetElement = pageElement.querySelector(query); if (targetElement) { targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } refresh() { const iframeElement = this.props.getIframeElement(); if (!iframeElement) { return; } iframeElement.contentWindow?.location.reload(); } }