128 lines
3.0 KiB
TypeScript
128 lines
3.0 KiB
TypeScript
/**
|
|
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
import { Emitter } from '@flowgram.ai/free-layout-editor';
|
|
|
|
import { CommentEditorEventParams } from './type';
|
|
import { CommentEditorDefaultValue, CommentEditorEvent } from './constant';
|
|
|
|
export class CommentEditorModel {
|
|
private innerValue: string = CommentEditorDefaultValue;
|
|
|
|
private emitter: Emitter<CommentEditorEventParams> = new Emitter();
|
|
|
|
private editor: HTMLTextAreaElement;
|
|
|
|
/** 注册事件 */
|
|
public on = this.emitter.event;
|
|
|
|
/** 获取当前值 */
|
|
public get value(): string {
|
|
return this.innerValue;
|
|
}
|
|
|
|
/** 外部设置模型值 */
|
|
public setValue(value: string = CommentEditorDefaultValue): void {
|
|
if (!this.initialized) {
|
|
return;
|
|
}
|
|
if (value === this.innerValue) {
|
|
return;
|
|
}
|
|
this.innerValue = value;
|
|
this.syncEditorValue();
|
|
this.emitter.fire({
|
|
type: CommentEditorEvent.Change,
|
|
value: this.innerValue,
|
|
});
|
|
}
|
|
|
|
/** 外部设置模型值 */
|
|
public setInitValue(value: string = CommentEditorDefaultValue): void {
|
|
if (!this.initialized) {
|
|
return;
|
|
}
|
|
if (value === this.innerValue) {
|
|
return;
|
|
}
|
|
this.innerValue = value;
|
|
this.syncEditorValue();
|
|
this.emitter.fire({
|
|
type: CommentEditorEvent.Init,
|
|
value: this.innerValue,
|
|
});
|
|
}
|
|
|
|
public set element(el: HTMLTextAreaElement) {
|
|
if (this.initialized) {
|
|
return;
|
|
}
|
|
this.editor = el;
|
|
}
|
|
|
|
/** 获取编辑器 DOM 节点 */
|
|
public get element(): HTMLTextAreaElement {
|
|
return this.editor;
|
|
}
|
|
|
|
/** 编辑器聚焦/失焦 */
|
|
public setFocus(focused: boolean): void {
|
|
if (!this.initialized) {
|
|
return;
|
|
}
|
|
if (focused && !this.focused) {
|
|
this.editor.focus();
|
|
} else if (!focused && this.focused) {
|
|
this.editor.blur();
|
|
this.deselect();
|
|
this.emitter.fire({
|
|
type: CommentEditorEvent.Blur,
|
|
});
|
|
}
|
|
}
|
|
|
|
/** 选择末尾 */
|
|
public selectEnd(): void {
|
|
if (!this.initialized) {
|
|
return;
|
|
}
|
|
// 获取文本长度
|
|
const length = this.editor.value.length;
|
|
// 将选择范围设置为文本末尾(开始位置和结束位置都是文本长度)
|
|
this.editor.setSelectionRange(length, length);
|
|
}
|
|
|
|
/** 获取聚焦状态 */
|
|
public get focused(): boolean {
|
|
return document.activeElement === this.editor;
|
|
}
|
|
|
|
/** 取消选择文本 */
|
|
private deselect(): void {
|
|
const selection: Selection | null = window.getSelection();
|
|
|
|
// 清除所有选择区域
|
|
if (selection) {
|
|
selection.removeAllRanges();
|
|
}
|
|
}
|
|
|
|
/** 是否初始化 */
|
|
private get initialized(): boolean {
|
|
return Boolean(this.editor);
|
|
}
|
|
|
|
/**
|
|
* 同步编辑器实例内容
|
|
* > **NOTICE:** *为确保不影响性能,应仅在外部值变更导致编辑器值与模型值不一致时调用*
|
|
*/
|
|
private syncEditorValue(): void {
|
|
if (!this.initialized) {
|
|
return;
|
|
}
|
|
this.editor.value = this.innerValue;
|
|
}
|
|
}
|