Files
upage-git/app/.client/components/editor/EditorController.tsx

172 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { executeScript } from '~/.client/utils/execute-scripts';
import { isScriptContent } from '~/.client/utils/html-parse';
import type { Editor, EditorControllerProps } from '~/types/editor';
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();
}
}