Skip to content

Commit

Permalink
refactor: add types to scroll page (#141)
Browse files Browse the repository at this point in the history
* refactor: add types to TreeNode

* refactor: add Nullable type

* refactor: add types to scrollPage
  • Loading branch information
Jocs authored Nov 19, 2023
1 parent 6ba740e commit b80ae9a
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 70 deletions.
20 changes: 19 additions & 1 deletion lib/block/base/content/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import diff from "fast-diff";

// const debug = logger('block.content:')

abstract class Content extends TreeNode {
class Content extends TreeNode {
public _text: string;
public isComposed: boolean;

Expand Down Expand Up @@ -117,6 +117,24 @@ abstract class Content extends TreeNode {
// Do nothing.
}

/**
* check this is a Content block?
* @param this
* @returns boolean
*/
isContent() {
return true;
}

/**
* check this is a Parent block?
* @param this
* @returns boolean
*/
isParent() {
return false;
}

deleteHandler(event: Event): void {
const { start, end } = this.getCursor()!;
const { text } = this;
Expand Down
2 changes: 1 addition & 1 deletion lib/block/base/format/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface Format
deleteHandler,
converter
)
abstract class Format extends Content {
class Format extends Content {
static blockName = "format";

checkCursorInTokenType(text: string, offset: number, type: Token["type"]): Token | null {
Expand Down
27 changes: 23 additions & 4 deletions lib/block/base/parent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import { CLASS_NAMES } from "@muya/config";
import Muya from "@muya/index";
import { operateClassName } from "@muya/utils/dom";
import logger from "@muya/utils/logger";
import { TState } from "../../state/types";
import Content from "./content/index";

const debug = logger("parent:");

abstract class Parent extends TreeNode {
class Parent extends TreeNode {
// Used to store icon, checkbox(span) etc. these blocks are not in children properties in json state.
public attachments: LinkedList<Parent> = new LinkedList();
public children: LinkedList<TreeNode> = new LinkedList();
Expand Down Expand Up @@ -49,7 +48,23 @@ abstract class Parent extends TreeNode {
super(muya);
}

abstract getState(): TState;
/**
* check this is a Content block?
* @param this
* @returns boolean
*/
isContent() {
return false;
}

/**
* check this is a Parent block?
* @param this
* @returns boolean
*/
isParent() {
return true;
}

getJsonPath() {
const { path } = this;
Expand Down Expand Up @@ -168,7 +183,11 @@ abstract class Parent extends TreeNode {
return block;
}

insertBefore(newNode: Parent, refNode: Parent | null = null, source = "user") {
insertBefore(
newNode: Parent,
refNode: Parent | null = null,
source = "user"
) {
newNode.parent = this;
this.children.insertBefore(newNode, refNode);
this.domNode!.insertBefore(
Expand Down
25 changes: 1 addition & 24 deletions lib/block/base/treeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import type { TState } from "@muya/state/types";
import { Nullable } from "@muya/types";
import { createDomNode } from "@muya/utils/dom";
import type { Attributes, Datasets } from "@muya/utils/types";
import type { Path } from "../types";
import Content from "./content";
import Parent from "./parent";

Expand All @@ -15,17 +14,14 @@ interface IConstructor<T> {
new (muya: Muya): T;
}

abstract class TreeNode extends LinkedNode<TreeNode> {
class TreeNode extends LinkedNode<TreeNode> {
public parent: Nullable<Parent> = null;
public domNode: Nullable<HTMLElement> = null;
public tagName: string = "";
public classList: string[] = [];
public attributes: Attributes = {};
public datasets: Datasets = {};

abstract get path(): Path;
abstract get isContainerBlock(): boolean;

static blockName = "tree.node";

get static(): IConstructor<TreeNode> {
Expand Down Expand Up @@ -69,25 +65,6 @@ abstract class TreeNode extends LinkedNode<TreeNode> {
super();
}

/**
* check this is a Content block?
* @param this
* @returns boolean
*/
isContent(this: unknown): this is Content {
return typeof (this as Content).text === "string";
}


/**
* check this is a Parent block?
* @param this
* @returns boolean
*/
isParent(this: unknown): this is Parent {
return this instanceof Parent;
}

/**
* create domNode
*/
Expand Down
3 changes: 2 additions & 1 deletion lib/block/commonMark/codeBlock/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Parent from "@muya/block/base/parent";
import ScrollPage from "@muya/block/scrollPage";
import I18n from "@muya/i18n";
import Muya from "@muya/index";
import { Nullable } from "@muya/types";
import logger from "@muya/utils/logger";
import { h, toHTML } from "@muya/utils/snabbdom";
import { ICodeBlockState, TState } from "../../../state/types";
Expand Down Expand Up @@ -39,7 +40,7 @@ const renderCopyButton = (i18n: I18n) => {
};

class Code extends Parent {
public parent: CodeBlock | null = null;
public parent: Nullable<CodeBlock> = null;

static blockName = "code";

Expand Down
92 changes: 53 additions & 39 deletions lib/block/scrollPage/index.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,44 @@
import Parent from "@muya/block/base/parent";
import { BLOCK_DOM_PROPERTY } from "@muya/config";
import Muya from "@muya/index";
import { Nullable } from "@muya/types";
import { isMouseEvent } from "@muya/utils";
import logger from "@muya/utils/logger";
import { TState } from "../../state/types";
import Content from "../base/content";
import TreeNode from "../base/treeNode";
import { Path } from "../types";

const debug = logger("scrollpage:");

interface IBlurFocus {
blur: Nullable<Content>;
focus: Nullable<Content>;
}

class ScrollPage extends Parent {
public blurFocus: {
blur: any;
focus: any;
};
private blurFocus: IBlurFocus = { blur: null, focus: null };

static blockName = "scrollpage";

static blocks = new Map();
static registeredBlocks = new Map();

static register(Block) {
static register(Block: Parent | Content) {
const { blockName } = Block;
this.blocks.set(blockName, Block);
this.registeredBlocks.set(blockName, Block);
}

static loadBlock(blockName) {
const block = this.blocks.get(blockName);
static loadBlock(blockName: string) {
const block = this.registeredBlocks.get(blockName);

if (!block) {
debug.warn(`block:${blockName} is not existed.`);
}

return block;
}

static create(muya, state) {
static create(muya: Muya, state: TState[]) {
const scrollPage = new ScrollPage(muya);

scrollPage.append(
Expand All @@ -38,7 +47,7 @@ class ScrollPage extends Parent {
})
);

scrollPage.parent.domNode.appendChild(scrollPage.domNode);
scrollPage.parent!.domNode!.appendChild(scrollPage.domNode!);

return scrollPage;
}
Expand All @@ -47,31 +56,31 @@ class ScrollPage extends Parent {
return [];
}

constructor(muya) {
constructor(muya: Muya) {
super(muya);
this.parent = muya;
// muya is not extends Parent, but it is the parent of scrollPage.
this.parent = muya as unknown as Parent;
this.tagName = "div";
this.classList = ["mu-container"];
this.blurFocus = {
blur: null,
focus: null,
};

this.createDomNode();
this.listenDomEvent();
}

getState(): TState {
getState() {
debug.warn("You can never call `getState` in scrollPage");
return;

return {} as TState;
}

listenDomEvent() {
private listenDomEvent() {
const { eventCenter } = this.muya;
const { domNode } = this;

eventCenter.attachDOMEvent(domNode!, "click", this.clickHandler.bind(this));
}

updateState(state) {
updateState(state: TState[]) {
const { muya } = this;
// Empty scrollPage dom
this.empty();
Expand All @@ -86,46 +95,46 @@ class ScrollPage extends Parent {
* Find the content block by the path
* @param {array} path
*/
queryBlock(path) {
queryBlock(path: Path) {
if (path.length === 0) {
return this;
}

const p = path.shift();
const block = this.find(p);
const p = path.shift() as number;
const block = this.find(p) as Parent;

return block && path.length ? (block as any).queryBlock(path) : block;
return block && path.length ? block.queryBlock(path) : block;
}

updateRefLinkAndImage(label) {
updateRefLinkAndImage(label: string) {
const REG = new RegExp(`\\[${label}\\](?!:)`);

this.breadthFirstTraverse((node) => {
this.breadthFirstTraverse((node: TreeNode) => {
if (node.isContent() && REG.test(node.text)) {
node.update();
}
});
}

handleBlurFromContent(block) {
handleBlurFromContent(block: Content) {
this.blurFocus.blur = block;
requestAnimationFrame(this.updateActiveStatus);
}

handleFocusFromContent(block) {
handleFocusFromContent(block: Content) {
this.blurFocus.focus = block;
requestAnimationFrame(this.updateActiveStatus);
}

updateActiveStatus = () => {
private updateActiveStatus = () => {
const { blur, focus } = this.blurFocus;

if (!blur && !focus) {
if (blur == null && focus == null) {
return;
}

let needBlurBlocks = [];
let needFocusBlocks = [];
let needBlurBlocks: Parent[] = [];
let needFocusBlocks: Parent[] = [];
let block;

if (blur && focus) {
Expand Down Expand Up @@ -159,15 +168,20 @@ class ScrollPage extends Parent {
};
};

// Create a new paragraph if the blank area in editor
clickHandler(event) {
const { target } = event;
// Create a new paragraph if click the blank area in editor.
private clickHandler(event: Event) {
if (!isMouseEvent(event)) {
return;
}

const target = event.target as HTMLElement;

if (target && target[BLOCK_DOM_PROPERTY] === this) {
const lastChild = this.lastChild;
const lastContentBlock = (lastChild as any).lastContentInDescendant();
const lastChild = this.lastChild as Parent;
const lastContentBlock = lastChild.lastContentInDescendant();
const { clientY } = event;
const lastChildDom = lastChild.domNode;
const { bottom } = lastChildDom.getBoundingClientRect();
const { bottom } = lastChildDom!.getBoundingClientRect();
if (clientY > bottom) {
if (
lastChild.blockName === "paragraph" &&
Expand Down

0 comments on commit b80ae9a

Please sign in to comment.