Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/make spanner plugin #97

Merged
merged 5 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions packages/blocky-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ export * from "./block/basic";
export { ContentBlock } from "./block/contentBlock";
export { CustomBlock } from "./block/customBlock";
export { makeDefaultIdGenerator, type IdGenerator } from "./helper/idHelper";
export {
type SpannerFactory,
type SpannerInstance,
SpannerDelegate,
} from "./view/spannerDelegate";
export { type ToolbarFactory, type Toolbar } from "./view/toolbarDelegate";
export { FollowerWidget } from "./view/followerWidget";
export {
Expand All @@ -25,6 +20,7 @@ export {
PluginRegistry,
PluginContext,
} from "./registry/pluginRegistry";
export * from "./plugins/spannerPlugin";
export { BlockRegistry } from "./registry/blockRegistry";
export { type SpanStyle, SpanRegistry } from "./registry/spanRegistry";
export {
Expand Down
13 changes: 13 additions & 0 deletions packages/blocky-core/src/plugins/spannerPlugin/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { SpannerPlugin } from "./spannerPlugin";
import {
SpannerDelegate,
type SpannerFactory,
type SpannerInstance,
} from "./spannerDelegate";

export {
SpannerPlugin,
SpannerDelegate,
type SpannerFactory,
type SpannerInstance,
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it, vi } from "vitest";
import { SpannerDelegate, SpannerInstance } from "./spannerDelegate";
import { EditorController } from "./controller";
import { BlockDataElement } from "..";
import { EditorController } from "../../view/controller";
import { BlockDataElement, Editor } from "../..";

describe("SpannerDelegate", () => {
it("focusedNode", () => {
Expand All @@ -14,7 +14,8 @@ describe("SpannerDelegate", () => {

const mount = document.createElement("div");

const delegate = new SpannerDelegate(editorController, () => {
const editor = Editor.fromController(mount, editorController);
const delegate = new SpannerDelegate(editor, () => {
return spannerInstance;
});
delegate.mount(mount);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { type IDisposable } from "blocky-common/es";
import type { EditorController } from "@pkg/view/controller";
import type { BlockDataElement } from "@pkg/data";
import { UIDelegate } from "./uiDelegate";
import { UIDelegate } from "@pkg/view/uiDelegate";
import { fromEvent, takeUntil } from "rxjs";
import type { Editor } from "@pkg/view/editor";

export interface SpannerInstance extends IDisposable {
onFocusedNodeChanged?(focusedNode: BlockDataElement | undefined): void;
Expand Down Expand Up @@ -30,14 +31,7 @@ export class SpannerDelegate extends UIDelegate {
this.#instance?.onFocusedNodeChanged?.(v);
}

get width(): number {
return 28;
}

constructor(
private editorController: EditorController,
private factory: SpannerFactory
) {
constructor(public editor: Editor, private factory: SpannerFactory) {
super("blocky-editor-spanner-delegate blocky-cm-noselect");
// draggable
this.container.setAttribute("draggable", "true");
Expand All @@ -49,17 +43,14 @@ export class SpannerDelegate extends UIDelegate {
}

#handleDragStart() {
const editor = this.editorController.editor;
if (!editor) {
return;
}
editor.darggingNode = this.focusedNode;
this.editor.darggingNode = this.focusedNode;
}

override mount(parent: HTMLElement): void {
super.mount(parent);

this.#instance = this.factory(this.container, this.editorController, this);
const editorController = this.editor.controller;
this.#instance = this.factory(this.container, editorController, this);
if (this.#instance) {
this.disposables.push(this.#instance);
}
Expand Down
90 changes: 90 additions & 0 deletions packages/blocky-core/src/plugins/spannerPlugin/spannerPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { BlockDataElement, Editor, IPlugin, PluginContext } from "../..";
import { take, takeUntil, fromEvent } from "rxjs";
import { SpannerDelegate, SpannerFactory } from "./spannerDelegate";
import { type Position } from "blocky-common/es";

const defaultWidth = 48;

export interface SpannerPluginOptions {
factory: SpannerFactory;
width?: number;
mountPoint?: HTMLElement;
}

export class SpannerPlugin implements IPlugin {
deletage: SpannerDelegate | undefined;
name = "spanner";

constructor(readonly options: SpannerPluginOptions) {}

get container(): HTMLElement | undefined {
return this.options.mountPoint ?? this.deletage?.editor.container;
}

onInitialized(context: PluginContext): void {
const { editor, dispose$ } = context;
this.deletage = new SpannerDelegate(editor, this.options.factory);

const container = this.options.mountPoint ?? editor.container;
this.deletage.mount(container);

editor.placeSpannerAt$
.pipe(takeUntil(dispose$))
.subscribe(({ blockContainer, node }) => {
this.placeSpannerAt(editor, blockContainer, node);
});

fromEvent(container, "mouseleave")
.pipe(takeUntil(dispose$))
.subscribe(() => {
this.deletage?.hide();
});

dispose$.pipe(take(1)).subscribe(() => {
this.deletage?.dispose();
this.deletage = undefined;
});
}

protected placeSpannerAt(
editor: Editor,
blockContainer: HTMLElement,
node: BlockDataElement
) {
if (!this.deletage) {
return;
}
const block = editor.state.blocks.get(node.id);
if (!block) {
return;
}
let { x, y } = this.getRelativeOffsetByDom(blockContainer);
const offset = block.getSpannerOffset();
x += offset.x;
y += offset.y;
x -= this.width;
this.deletage.focusedNode = node;
this.deletage.show();
this.deletage.setPosition(x, y);
}

get width(): number {
return this.options.width ?? defaultWidth;
}

/**
* Get the element's relative position to the container of the editor.
*/
protected getRelativeOffsetByDom(element: HTMLElement): Position {
const container = this.container;
if (!container) {
return { x: 0, y: 0 };
}
const containerRect = container.getBoundingClientRect();
const blockRect = element.getBoundingClientRect();
return {
x: blockRect.x - containerRect.x,
y: blockRect.y - containerRect.y,
};
}
}
4 changes: 0 additions & 4 deletions packages/blocky-core/src/registry/pluginRegistry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,16 @@ describe("PluginRegistry", () => {
const plugin: IPlugin = {
name: "test",
onInitialized() {},
onDispose() {},
};
const onInitSpy = vi.spyOn(plugin, "onInitialized");
const disposeSpy = vi.spyOn(plugin, "onDispose");
const pluginRegistry = new PluginRegistry([plugin]);
const editorController = new EditorController("user");
const dom = document.createElement("div");
const editor = Editor.fromController(dom, editorController);
pluginRegistry.initAllPlugins(editor);

expect(onInitSpy).toBeCalledTimes(1);
expect(disposeSpy).toBeCalledTimes(0);

pluginRegistry.unload("test");
expect(disposeSpy).toBeCalledTimes(1);
});
});
3 changes: 0 additions & 3 deletions packages/blocky-core/src/registry/pluginRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
*/
onInitialized?(context: PluginContext): void;

onDispose?(context: PluginContext): void;

onPaste?(evt: BlockyPasteEvent): void;
}

Expand Down Expand Up @@ -81,7 +79,7 @@
this.plugins.set(pluginName, plugin);

for (const name of allowHookName) {
// @ts-ignore

Check warning on line 82 in packages/blocky-core/src/registry/pluginRegistry.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free
if (isFunction(plugin[name])) {
this.#hook[name].push(plugin);
}
Expand All @@ -99,7 +97,6 @@
if (context) {
context.dispose();
this.contexts.delete(name);
plugin.onDispose?.(context);
}
}

Expand Down
2 changes: 0 additions & 2 deletions packages/blocky-core/src/view/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { PluginRegistry, type IPlugin } from "@pkg/registry/pluginRegistry";
import { SpanRegistry } from "@pkg/registry/spanRegistry";
import { EmbedRegistry } from "@pkg/registry/embedRegistry";
import { HTMLConverter } from "@pkg/helper/htmlConverter";
import { type SpannerFactory } from "@pkg/view/spannerDelegate";
import { type ToolbarFactory } from "@pkg/view/toolbarDelegate";
import { type IdGenerator, makeDefaultIdGenerator } from "@pkg/helper/idHelper";
import { BlockPasteEvent, TryParsePastedDOMEvent } from "@pkg/block/basic";
Expand Down Expand Up @@ -89,7 +88,6 @@ export interface IEditorControllerOptions {
blockRegistry?: BlockRegistry;
embedRegistry?: EmbedRegistry;
idGenerator?: IdGenerator;
spannerFactory?: SpannerFactory;
toolbarFactory?: ToolbarFactory;

/**
Expand Down
Loading
Loading