mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat(plugin): migrate plugin runner to rxjs
This commit is contained in:
@@ -9,30 +9,35 @@ import {
|
||||
import { Clip } from './clip';
|
||||
import assert from 'assert';
|
||||
import ClipboardParse from './clipboard-parse';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
class ClipboardPopulator {
|
||||
private editor: Editor;
|
||||
private hooks: PluginHooks;
|
||||
private selection_manager: SelectionManager;
|
||||
private clipboard: any;
|
||||
private clipboard_parse: ClipboardParse;
|
||||
private _editor: Editor;
|
||||
private _hooks: PluginHooks;
|
||||
private _selectionManager: SelectionManager;
|
||||
private _clipboardParse: ClipboardParse;
|
||||
private _sub = new Subscription();
|
||||
|
||||
constructor(
|
||||
editor: Editor,
|
||||
hooks: PluginHooks,
|
||||
selectionManager: SelectionManager,
|
||||
clipboard: any
|
||||
selectionManager: SelectionManager
|
||||
) {
|
||||
this.editor = editor;
|
||||
this.hooks = hooks;
|
||||
this.selection_manager = selectionManager;
|
||||
this.clipboard = clipboard;
|
||||
this.clipboard_parse = new ClipboardParse(editor);
|
||||
hooks.addHook(HookType.BEFORE_COPY, this.populate_app_clipboard, this);
|
||||
hooks.addHook(HookType.BEFORE_CUT, this.populate_app_clipboard, this);
|
||||
this._editor = editor;
|
||||
this._hooks = hooks;
|
||||
this._selectionManager = selectionManager;
|
||||
this._clipboardParse = new ClipboardParse(editor);
|
||||
this._sub.add(
|
||||
hooks
|
||||
.get(HookType.BEFORE_COPY)
|
||||
.subscribe(this._populateAppClipboard)
|
||||
);
|
||||
this._sub.add(
|
||||
hooks.get(HookType.BEFORE_CUT).subscribe(this._populateAppClipboard)
|
||||
);
|
||||
}
|
||||
|
||||
private async populate_app_clipboard(e: ClipboardEvent) {
|
||||
private _populateAppClipboard = async (e: ClipboardEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const clips = await this.getClips();
|
||||
@@ -58,7 +63,8 @@ class ClipboardPopulator {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private copy_to_cliboard_from_pc(clips: any[]) {
|
||||
let success = false;
|
||||
const tempElem = document.createElement('textarea');
|
||||
@@ -91,8 +97,8 @@ class ClipboardPopulator {
|
||||
}
|
||||
|
||||
private async get_clip_block_info(selBlock: SelectBlock) {
|
||||
const block = await this.editor.getBlockById(selBlock.blockId);
|
||||
const block_view = this.editor.getView(block.type);
|
||||
const block = await this._editor.getBlockById(selBlock.blockId);
|
||||
const block_view = this._editor.getView(block.type);
|
||||
assert(block_view);
|
||||
const block_info: ClipBlockInfo = {
|
||||
type: block.type,
|
||||
@@ -112,7 +118,8 @@ class ClipboardPopulator {
|
||||
|
||||
private async get_inner_clip(): Promise<InnerClipInfo> {
|
||||
const clips: ClipBlockInfo[] = [];
|
||||
const select_info: SelectInfo = await this.selection_manager.getSelectInfo();
|
||||
const select_info: SelectInfo =
|
||||
await this._selectionManager.getSelectInfo();
|
||||
for (let i = 0; i < select_info.blocks.length; i++) {
|
||||
const sel_block = select_info.blocks[i];
|
||||
const clip_block_info = await this.get_clip_block_info(sel_block);
|
||||
@@ -136,7 +143,7 @@ class ClipboardPopulator {
|
||||
)
|
||||
);
|
||||
|
||||
const html_clip = await this.clipboard_parse.generateHtml();
|
||||
const html_clip = await this._clipboardParse.generateHtml();
|
||||
html_clip &&
|
||||
clips.push(new Clip(OFFICE_CLIPBOARD_MIMETYPE.HTML, html_clip));
|
||||
|
||||
@@ -144,12 +151,8 @@ class ClipboardPopulator {
|
||||
}
|
||||
|
||||
disposeInternal() {
|
||||
this.hooks.removeHook(
|
||||
HookType.BEFORE_COPY,
|
||||
this.populate_app_clipboard
|
||||
);
|
||||
this.hooks.removeHook(HookType.BEFORE_CUT, this.populate_app_clipboard);
|
||||
this.hooks = null;
|
||||
this._sub.unsubscribe();
|
||||
this._hooks = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,8 +186,7 @@ export class Editor implements Virgo {
|
||||
this.clipboard_populator = new ClipboardPopulator(
|
||||
this,
|
||||
this.hooks,
|
||||
this.selectionManager,
|
||||
this.clipboard
|
||||
this.selectionManager
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +1,37 @@
|
||||
import {
|
||||
HooksRunner,
|
||||
PluginHooks,
|
||||
HookType,
|
||||
HookBaseArgs,
|
||||
BlockDomInfo,
|
||||
AnyFunction,
|
||||
AnyThisType,
|
||||
} from '../types';
|
||||
|
||||
interface PluginHookInfo {
|
||||
thisObj?: AnyThisType;
|
||||
callback: AnyFunction;
|
||||
once: boolean;
|
||||
}
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { HooksRunner, HookType, BlockDomInfo, PluginHooks } from '../types';
|
||||
|
||||
export class Hooks implements HooksRunner, PluginHooks {
|
||||
private _hooksMap: Map<string, PluginHookInfo[]> = new Map();
|
||||
private _subject: Record<string, Subject<unknown>> = {};
|
||||
private _observable: Record<string, Observable<unknown>> = {};
|
||||
|
||||
dispose() {
|
||||
this._hooksMap.clear();
|
||||
this._subject = {};
|
||||
}
|
||||
|
||||
private _runHook(key: HookType, ...params: unknown[]): void {
|
||||
const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
|
||||
hookInfos.forEach(hookInfo => {
|
||||
if (hookInfo.once) {
|
||||
this.removeHook(key, hookInfo.callback);
|
||||
}
|
||||
let isStoppedPropagation = false;
|
||||
const hookOption: HookBaseArgs = {
|
||||
stopImmediatePropagation: () => {
|
||||
isStoppedPropagation = true;
|
||||
},
|
||||
};
|
||||
hookInfo.callback.call(
|
||||
hookInfo.thisObj || this,
|
||||
...params,
|
||||
hookOption
|
||||
);
|
||||
return isStoppedPropagation;
|
||||
});
|
||||
if (this._subject[key] == null) {
|
||||
this._subject[key] = new Subject();
|
||||
this._observable[key] = this._subject[key].asObservable();
|
||||
}
|
||||
let payload: unknown = params;
|
||||
|
||||
if (params.length === 0) {
|
||||
payload = undefined;
|
||||
}
|
||||
if (params.length === 1) {
|
||||
payload = params[0];
|
||||
}
|
||||
this._subject[key].next(payload);
|
||||
}
|
||||
|
||||
private _hasHook(key: HookType, callback: AnyFunction): boolean {
|
||||
const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
|
||||
for (let i = hookInfos.length - 1; i >= 0; i--) {
|
||||
if (hookInfos[i].callback === callback) {
|
||||
return true;
|
||||
}
|
||||
public get<K extends keyof HooksRunner>(key: K) {
|
||||
if (this._subject[key] == null) {
|
||||
this._subject[key] = new Subject();
|
||||
this._observable[key] = this._subject[key].asObservable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 执行多次
|
||||
public addHook(
|
||||
key: HookType,
|
||||
callback: AnyFunction,
|
||||
thisObj?: AnyThisType,
|
||||
once?: boolean
|
||||
): void {
|
||||
if (this._hasHook(key, callback)) {
|
||||
throw new Error('Duplicate registration of the same class');
|
||||
}
|
||||
if (!this._hooksMap.has(key)) {
|
||||
this._hooksMap.set(key, []);
|
||||
}
|
||||
const hookInfos: PluginHookInfo[] = this._hooksMap.get(key);
|
||||
hookInfos.push({ callback, thisObj, once });
|
||||
}
|
||||
|
||||
// 执行一次
|
||||
public addOnceHook(
|
||||
key: HookType,
|
||||
callback: AnyFunction,
|
||||
thisObj?: AnyThisType
|
||||
): void {
|
||||
this.addHook(key, callback, thisObj, true);
|
||||
}
|
||||
|
||||
// 移除
|
||||
public removeHook(key: HookType, callback: AnyFunction): void {
|
||||
const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
|
||||
for (let i = hookInfos.length - 1; i >= 0; i--) {
|
||||
if (hookInfos[i].callback === callback) {
|
||||
hookInfos.splice(i, 1);
|
||||
}
|
||||
}
|
||||
return this._observable[key] as any;
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import EventEmitter from 'eventemitter3';
|
||||
|
||||
import { domToRect, Rect } from '@toeverything/utils';
|
||||
import type { Editor as Block_editor } from '../editor';
|
||||
import type { Editor as BlockEditor } from '../editor';
|
||||
|
||||
import { AsyncBlock } from '../block';
|
||||
|
||||
@@ -9,7 +9,7 @@ type VerticalTypes = 'up' | 'down' | null;
|
||||
type HorizontalTypes = 'left' | 'right' | null;
|
||||
|
||||
export class ScrollManager {
|
||||
private _editor: Block_editor;
|
||||
private _editor: BlockEditor;
|
||||
private _animationFrame: null | number = null;
|
||||
private _eventName = 'scrolling';
|
||||
private _currentMoveDirection: [HorizontalTypes, VerticalTypes] = [
|
||||
@@ -20,9 +20,8 @@ export class ScrollManager {
|
||||
private _scrollMoveOffset = 8;
|
||||
private _scrollingEvent = new EventEmitter();
|
||||
|
||||
constructor(editor: Block_editor) {
|
||||
constructor(editor: BlockEditor) {
|
||||
this._editor = editor;
|
||||
console.log('scrollmanager constructor', this._editor.ui_container);
|
||||
}
|
||||
|
||||
private _updateScrollInfo(left: number, top: number) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import type { BlockHelper } from './block/block-helper';
|
||||
import type { BlockCommands } from './commands/block-commands';
|
||||
import type { DragDropManager } from './drag-drop';
|
||||
import { MouseManager } from './mouse';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
// import { BrowserClipboard } from './clipboard/browser-clipboard';
|
||||
|
||||
@@ -176,10 +177,6 @@ export enum HookType {
|
||||
BEFORE_CUT = 'beforeCut',
|
||||
}
|
||||
|
||||
export interface HookBaseArgs {
|
||||
stopImmediatePropagation: () => void;
|
||||
}
|
||||
|
||||
export interface BlockDomInfo {
|
||||
blockId: string;
|
||||
dom: HTMLElement;
|
||||
@@ -227,25 +224,16 @@ export interface HooksRunner {
|
||||
beforeCut: (e: ClipboardEvent) => void;
|
||||
}
|
||||
|
||||
export type AnyFunction = (...args: any[]) => any;
|
||||
export type AnyThisType = ThisParameterType<any>;
|
||||
export type PayloadType<T extends Array<any>> = T extends []
|
||||
? void
|
||||
: T extends [infer U]
|
||||
? U
|
||||
: T;
|
||||
|
||||
// hook管理,在editor、plugin中使用
|
||||
export interface PluginHooks {
|
||||
// 执行多次
|
||||
addHook: (
|
||||
key: HookType,
|
||||
callback: AnyFunction,
|
||||
thisObj?: AnyThisType,
|
||||
once?: boolean
|
||||
) => void;
|
||||
// 执行一次
|
||||
addOnceHook: (
|
||||
key: HookType,
|
||||
callback: AnyFunction,
|
||||
thisObj?: AnyThisType
|
||||
) => void;
|
||||
// 移除
|
||||
removeHook: (key: HookType, callback: AnyFunction) => void;
|
||||
get<K extends keyof HooksRunner>(
|
||||
key: K
|
||||
): Observable<PayloadType<Parameters<HooksRunner[K]>>>;
|
||||
}
|
||||
|
||||
export * from './drag-drop/types';
|
||||
|
||||
Reference in New Issue
Block a user