From 315bfbb26412aa0bdd4346b0fa65b6b915a5e7a1 Mon Sep 17 00:00:00 2001 From: pubuzhixing8 Date: Wed, 9 Jun 2021 14:31:04 +0800 Subject: [PATCH] refactor(view): refactor block-card logic and api --- .../components/editable/editable.component.ts | 29 +-------- packages/src/plugins/angular-editor.ts | 65 ++++++++++--------- packages/src/utils/block-card.ts | 34 ++++++++++ packages/src/utils/index.ts | 3 +- 4 files changed, 71 insertions(+), 60 deletions(-) create mode 100644 packages/src/utils/block-card.ts diff --git a/packages/src/components/editable/editable.component.ts b/packages/src/components/editable/editable.component.ts index f1d32ed2..51f0b4bc 100644 --- a/packages/src/components/editable/editable.component.ts +++ b/packages/src/components/editable/editable.component.ts @@ -43,8 +43,8 @@ import { SlateStringTemplateComponent } from '../string/template.component'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { SlateChildrenContext, SlateViewContext } from '../../view/context'; import { ViewType } from '../../types/view'; -import { isDecoratorRangeListEqual } from '../../utils'; import { HistoryEditor } from 'slate-history'; +import { isDecoratorRangeListEqual } from '../../utils'; const timeDebug = Debug('slate-time'); // COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event @@ -548,14 +548,6 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy { if (data instanceof DataTransfer) { AngularEditor.insertData(editor, data); } else if (typeof data === 'string') { - // block card - const window = AngularEditor.getWindow(editor) - const domSelection = window.getSelection(); - const isBlockCard = AngularEditor.hasCardTarget(domSelection.anchorNode) || - AngularEditor.hasCardTarget(domSelection.focusNode); - if (isBlockCard) { - return; - } Editor.insertText(editor, data); } break; @@ -664,24 +656,12 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy { private onDOMCompositionStart(event: CompositionEvent) { const { selection } = this.editor; - const domSelection = window.getSelection(); - const cardTargetAttr = AngularEditor.getCardTargetAttribute(domSelection.anchorNode); - const cardTarget = domSelection.anchorNode; - if (selection) { // solve the problem of cross node Chinese input if (Range.isExpanded(selection)) { Editor.deleteFragment(this.editor); this.forceFlush(); } - // 当光标是块级光标时,输入中文前需要强制移动选区 - if (cardTargetAttr) { - const cardEntry = AngularEditor.toSlateCardEntry(this.editor, cardTarget); - const isCardLeft = AngularEditor.isCardLeftByTargetAttr(cardTargetAttr); - const point = isCardLeft ? Editor.before(this.editor, cardEntry[1]) : Editor.after(this.editor, cardEntry[1]); - Transforms.select(this.editor, point); - this.forceFlush(); - } } if (hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionStart)) { this.isComposing = true; @@ -1068,13 +1048,6 @@ export class SlateEditableComponent implements OnInit, OnChanges, OnDestroy { if (!Range.isCollapsed(this.editor.selection)) { Editor.deleteFragment(this.editor); } - // block card - const domSelection = window.getSelection(); - const isBlockCard = AngularEditor.hasCardTarget(domSelection.anchorNode) || - AngularEditor.hasCardTarget(domSelection.focusNode); - if (isBlockCard) { - return; - } // just handle Non-IME input if (!this.isComposing) { Editor.insertText(this.editor, text); diff --git a/packages/src/plugins/angular-editor.ts b/packages/src/plugins/angular-editor.ts index 85e6052c..a3d29518 100644 --- a/packages/src/plugins/angular-editor.ts +++ b/packages/src/plugins/angular-editor.ts @@ -27,6 +27,7 @@ import { NodeEntry } from 'slate'; import { SlateError } from '../types/error'; import { Key } from '../utils/key'; import { IS_CHROME } from '../utils/environment'; +import { FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, getCardTargetAttribute, isCardCenterByTargetAttr, isCardLeftByTargetAttr, isCardRightByTargetAttr } from '../utils/block-card'; /** * A React and DOM-specific version of the `Editor` interface. @@ -303,9 +304,9 @@ export const AngularEditor = { let domPoint: DOMPoint | undefined; // block card - const cardTargetAttr = AngularEditor.getCardTargetAttribute(el); + const cardTargetAttr = getCardTargetAttribute(el); if (cardTargetAttr) { - if (point.offset === -1) { + if (point.offset === FAKE_LEFT_BLOCK_CARD_OFFSET) { const cursorNode = AngularEditor.getCardCursorNode(editor, node, { direction: 'left' }); return [cursorNode, 1]; } else { @@ -487,14 +488,14 @@ export const AngularEditor = { let offset = 0; // block card - const cardTargetAttr = AngularEditor.getCardTargetAttribute(domNode); + const cardTargetAttr = getCardTargetAttribute(domNode); if (cardTargetAttr) { const domSelection = window.getSelection(); const isBackward = editor.selection && Range.isBackward(editor.selection); const blockCardEntry = AngularEditor.toSlateCardEntry(editor, domNode) || AngularEditor.toSlateCardEntry(editor, nearestNode); const [, blockPath] = blockCardEntry; if (domSelection.isCollapsed) { - if (AngularEditor.isCardLeftByTargetAttr(cardTargetAttr)) { + if (isCardLeftByTargetAttr(cardTargetAttr)) { return { path: blockPath, offset: -1 }; } else { @@ -503,7 +504,7 @@ export const AngularEditor = { } // forward // and to the end of previous node - if (AngularEditor.isCardLeftByTargetAttr(cardTargetAttr) && !isBackward) { + if (isCardLeftByTargetAttr(cardTargetAttr) && !isBackward) { const endPath = blockPath[blockPath.length - 1] <= 0 ? blockPath @@ -512,21 +513,21 @@ export const AngularEditor = { } // to the of current node if ( - (AngularEditor.isCardCenterByTargetAttr(cardTargetAttr) || - AngularEditor.isCardRightByTargetAttr(cardTargetAttr)) && + (isCardCenterByTargetAttr(cardTargetAttr) || + isCardRightByTargetAttr(cardTargetAttr)) && !isBackward ) { return Editor.end(editor, blockPath); } // backward // and to the start of next node - if (AngularEditor.isCardRightByTargetAttr(cardTargetAttr) && isBackward) { + if (isCardRightByTargetAttr(cardTargetAttr) && isBackward) { return Editor.start(editor, Path.next(blockPath)); } // and to the start of current node if ( - (AngularEditor.isCardCenterByTargetAttr(cardTargetAttr) || - AngularEditor.isCardLeftByTargetAttr(cardTargetAttr)) && + (isCardCenterByTargetAttr(cardTargetAttr) || + isCardLeftByTargetAttr(cardTargetAttr)) && isBackward ) { return Editor.start(editor, blockPath); @@ -652,12 +653,12 @@ export const AngularEditor = { return Element.isElement(node) && !editor.isInline(node) && Editor.hasInlines(editor, node); }, - hasCardTarget(node: DOMNode) { - return node && (node.parentElement.hasAttribute('card-target') || (node instanceof HTMLElement && node.hasAttribute('card-target'))); + isBlockCardLeftCursor(editor: AngularEditor) { + return editor.selection.anchor.offset === FAKE_LEFT_BLOCK_CARD_OFFSET && editor.selection.focus.offset === FAKE_LEFT_BLOCK_CARD_OFFSET; }, - getCardTargetAttribute(node: DOMNode) { - return node.parentElement.attributes['card-target'] || (node instanceof HTMLElement && node.attributes['card-target']); + isBlockCardRightCursor(editor: AngularEditor) { + return editor.selection.anchor.offset === FAKE_RIGHT_BLOCK_CARD_OFFSET && editor.selection.focus.offset === FAKE_RIGHT_BLOCK_CARD_OFFSET; }, getCardCursorNode(editor: AngularEditor, blockCardNode: Node, options: { @@ -670,23 +671,6 @@ export const AngularEditor = { : cardCenter.nextElementSibling; }, - isCardLeft(node: DOMNode) { - const cardTarget = AngularEditor.getCardTargetAttribute(node); - return cardTarget && cardTarget.nodeValue === 'card-left'; - }, - - isCardLeftByTargetAttr(targetAttr: any) { - return targetAttr && targetAttr.nodeValue === 'card-left'; - }, - - isCardRightByTargetAttr(targetAttr: any) { - return targetAttr && targetAttr.nodeValue === 'card-right'; - }, - - isCardCenterByTargetAttr(targetAttr: any) { - return targetAttr && targetAttr.nodeValue === 'card-center'; - }, - toSlateCardEntry(editor: AngularEditor, node: DOMNode): NodeEntry { const element = node.parentElement .closest('.slate-block-card')?.querySelector('[card-target="card-center"]') @@ -696,6 +680,12 @@ export const AngularEditor = { return [slateNode, path]; }, + /** + * move native selection to card-left or card-right + * @param editor + * @param blockCardNode + * @param options + */ moveBlockCard(editor: AngularEditor, blockCardNode: Node, options: { direction: 'left' | 'right' }) { @@ -705,6 +695,19 @@ export const AngularEditor = { domSelection.setBaseAndExtent(cursorNode, 1, cursorNode, 1); }, + /** + * move slate selection to card-left or card-right + * @param editor + * @param path + * @param options + */ + moveBlockCardCursor(editor: AngularEditor, path: Path, options: { + direction: 'left' | 'right' + }) { + const cursor = { path, offset: options.direction === 'left' ? FAKE_LEFT_BLOCK_CARD_OFFSET : FAKE_RIGHT_BLOCK_CARD_OFFSET }; + Transforms.select(editor, { anchor: cursor, focus: cursor }); + }, + hasRange(editor: AngularEditor, range: Range): boolean { const { anchor, focus } = range; return ( diff --git a/packages/src/utils/block-card.ts b/packages/src/utils/block-card.ts new file mode 100644 index 00000000..4595cd55 --- /dev/null +++ b/packages/src/utils/block-card.ts @@ -0,0 +1,34 @@ +import { DOMNode, DOMSelection } from "./dom"; + +export const FAKE_LEFT_BLOCK_CARD_OFFSET = -1; + +export const FAKE_RIGHT_BLOCK_CARD_OFFSET = -2; + +export function hasBlockCardWithNode(node: DOMNode) { + return node && (node.parentElement.hasAttribute('card-target') || (node instanceof HTMLElement && node.hasAttribute('card-target'))); +} + +export function hasBlockCard(selection: DOMSelection) { + return hasBlockCardWithNode(selection?.anchorNode) || hasBlockCardWithNode(selection?.focusNode); +} + +export function getCardTargetAttribute(node: DOMNode) { + return node.parentElement.attributes['card-target'] || (node instanceof HTMLElement && node.attributes['card-target']); +} + +export function isCardLeft(node: DOMNode) { + const cardTarget = getCardTargetAttribute(node); + return cardTarget && cardTarget.nodeValue === 'card-left'; +} + +export function isCardLeftByTargetAttr(targetAttr: any) { + return targetAttr && targetAttr.nodeValue === 'card-left'; +} + +export function isCardRightByTargetAttr(targetAttr: any) { + return targetAttr && targetAttr.nodeValue === 'card-right'; +} + +export function isCardCenterByTargetAttr(targetAttr: any) { + return targetAttr && targetAttr.nodeValue === 'card-center'; +} diff --git a/packages/src/utils/index.ts b/packages/src/utils/index.ts index db22853b..bdcf2722 100644 --- a/packages/src/utils/index.ts +++ b/packages/src/utils/index.ts @@ -4,4 +4,5 @@ export * from './dom'; export * from './view'; export * from './environment'; export * from './key'; -export * from './range-list'; \ No newline at end of file +export * from './range-list'; +export * from './block-card'; \ No newline at end of file