From 60aa5616a6b9ead09e8047b053c567fff52ece70 Mon Sep 17 00:00:00 2001 From: Jiuqing Song Date: Wed, 13 Mar 2019 15:01:03 -0700 Subject: [PATCH] Fix some perf issue and some other changes (#272) * 45000 * 7.2.6 --- package.json | 2 +- .../lib/format/getFormatState.ts | 104 ++++++++++++++---- packages/roosterjs-editor-api/lib/index.ts | 7 +- .../lib/editor/createEditorCore.ts | 17 +-- packages/roosterjs-editor-types/lib/index.ts | 14 ++- .../lib/interface/FormatState.ts | 90 +++++++++------ tools/dts.js | 2 +- 7 files changed, 166 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 840f986eb51..0d89c339c9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "roosterjs", - "version": "7.2.5", + "version": "7.2.6", "description": "Framework-independent javascript editor", "repository": { "type": "git", diff --git a/packages/roosterjs-editor-api/lib/format/getFormatState.ts b/packages/roosterjs-editor-api/lib/format/getFormatState.ts index 977503688f1..0054cc2336e 100644 --- a/packages/roosterjs-editor-api/lib/format/getFormatState.ts +++ b/packages/roosterjs-editor-api/lib/format/getFormatState.ts @@ -1,37 +1,59 @@ import { cacheGetElementAtCursor, Editor } from 'roosterjs-editor-core'; -import { DocumentCommand, FormatState, PluginEvent, QueryScope } from 'roosterjs-editor-types'; import { getComputedStyles, getTagOfNode, Position } from 'roosterjs-editor-dom'; +import { + DocumentCommand, + ElementBasedFormatState, + FormatState, + PendableFormatState, + PluginEvent, + QueryScope, + StyleBasedFormatState, +} from 'roosterjs-editor-types'; + +type PendableFormatNames = keyof PendableFormatState; + +const PendableFormatCommandMap: { [key in PendableFormatNames]: DocumentCommand } = { + isBold: DocumentCommand.Bold, + isItalic: DocumentCommand.Italic, + isUnderline: DocumentCommand.Underline, + isStrikeThrough: DocumentCommand.StrikeThrough, + isSubscript: DocumentCommand.Subscript, + isSuperscript: DocumentCommand.Superscript, +}; /** - * Get format state at cursor - * A format state is a collection of all format related states, e.g., - * bold, italic, underline, font name, font size, etc. - * @param editor The editor - * @param (Optional) The plugin event, it stores the event cached data for looking up. + * Get Pendable Format State at cursor. + * @param document The HTML Document to get format state from + * @returns A PendableFormatState object which contains the values of pendable format states + */ +export function getPendableFormatState(document: Document): PendableFormatState { + let keys = Object.keys(PendableFormatCommandMap) as PendableFormatNames[]; + + return keys.reduce( + (state, key) => { + state[key] = document.queryCommandState(PendableFormatCommandMap[key]); + return state; + }, + {} + ); +} + +/** + * Get element based Format State at cursor + * @param editor The editor instance + * @param event (Optional) The plugin event, it stores the event cached data for looking up. * In this function the event cache is used to get list state and header level. If not passed, * it will query the node within selection to get the info - * @returns The format state at cursor + * @returns An ElementBasedFormatState object */ -export default function getFormatState(editor: Editor, event?: PluginEvent): FormatState { - let range = editor.getSelectionRange(); - let node = range && Position.getStart(range).normalize().node; - let styles = node ? getComputedStyles(node) : []; +export function getElementBasedFormatState( + editor: Editor, + event?: PluginEvent +): ElementBasedFormatState { let listTag = getTagOfNode(cacheGetElementAtCursor(editor, event, 'OL,UL')); let headerTag = getTagOfNode(cacheGetElementAtCursor(editor, event, 'H1,H2,H3,H4,H5,H6')); - let document = editor.getDocument(); - return { - fontName: styles[0], - fontSize: styles[1], - textColor: styles[2], - backgroundColor: styles[3], - - isBold: document.queryCommandState(DocumentCommand.Bold), - isItalic: document.queryCommandState(DocumentCommand.Italic), - isUnderline: document.queryCommandState(DocumentCommand.Underline), - isStrikeThrough: document.queryCommandState(DocumentCommand.StrikeThrough), - isSubscript: document.queryCommandState(DocumentCommand.Subscript), - isSuperscript: document.queryCommandState(DocumentCommand.Superscript), + return { isBullet: listTag == 'UL', isNumbering: listTag == 'OL', headerLevel: (headerTag && parseInt(headerTag[1])) || 0, @@ -39,7 +61,41 @@ export default function getFormatState(editor: Editor, event?: PluginEvent): For canUnlink: !!editor.queryElements('a[href]', QueryScope.OnSelection)[0], canAddImageAltText: !!editor.queryElements('img', QueryScope.OnSelection)[0], isBlockQuote: !!editor.queryElements('blockquote', QueryScope.OnSelection)[0], + }; +} +/** + * Get style based Format State at cursor + * @param editor The editor instance + * @returns A StyleBasedFormatState object + */ +export function getStyleBasedFormatState(editor: Editor): StyleBasedFormatState { + let range = editor.getSelectionRange(); + let node = range && Position.getStart(range).normalize().node; + let styles = node ? getComputedStyles(node) : []; + return { + fontName: styles[0], + fontSize: styles[1], + textColor: styles[2], + backgroundColor: styles[3], + }; +} + +/** + * Get format state at cursor + * A format state is a collection of all format related states, e.g., + * bold, italic, underline, font name, font size, etc. + * @param editor The editor instance + * @param event (Optional) The plugin event, it stores the event cached data for looking up. + * In this function the event cache is used to get list state and header level. If not passed, + * it will query the node within selection to get the info + * @returns The format state at cursor + */ +export default function getFormatState(editor: Editor, event?: PluginEvent): FormatState { + return { + ...getPendableFormatState(editor.getDocument()), + ...getElementBasedFormatState(editor, event), + ...getStyleBasedFormatState(editor), canUndo: editor.canUndo(), canRedo: editor.canRedo(), }; diff --git a/packages/roosterjs-editor-api/lib/index.ts b/packages/roosterjs-editor-api/lib/index.ts index cda4d3115cb..e68d8481c16 100644 --- a/packages/roosterjs-editor-api/lib/index.ts +++ b/packages/roosterjs-editor-api/lib/index.ts @@ -7,7 +7,12 @@ export { } from './format/clearBlockFormat'; export { default as clearFormat } from './format/clearFormat'; export { default as createLink } from './format/createLink'; -export { default as getFormatState } from './format/getFormatState'; +export { + default as getFormatState, + getPendableFormatState, + getElementBasedFormatState, + getStyleBasedFormatState, +} from './format/getFormatState'; export { default as insertImage } from './format/insertImage'; export { default as insertTable } from './table/insertTable'; export { default as editTable } from './table/editTable'; diff --git a/packages/roosterjs-editor-core/lib/editor/createEditorCore.ts b/packages/roosterjs-editor-core/lib/editor/createEditorCore.ts index d4224ca2489..2c8dadecd0c 100644 --- a/packages/roosterjs-editor-core/lib/editor/createEditorCore.ts +++ b/packages/roosterjs-editor-core/lib/editor/createEditorCore.ts @@ -64,15 +64,16 @@ function calcDefaultFormat(node: Node, baseFormat: DefaultFormat): DefaultFormat } baseFormat = baseFormat || {}; - let styles = getComputedStyles(node); + let { fontFamily, fontSize, textColor, backgroundColor, bold, italic, underline } = baseFormat; + let currentStyles = fontFamily && fontSize && textColor ? null : getComputedStyles(node); return { - fontFamily: baseFormat.fontFamily || styles[0], - fontSize: baseFormat.fontSize || styles[1], - textColor: baseFormat.textColor || styles[2], - backgroundColor: baseFormat.backgroundColor || '', - bold: baseFormat.bold, - italic: baseFormat.italic, - underline: baseFormat.underline, + fontFamily: fontFamily || currentStyles[0], + fontSize: fontSize || currentStyles[1], + textColor: textColor || currentStyles[2], + backgroundColor: backgroundColor || '', + bold: bold, + italic: italic, + underline: underline, }; } diff --git a/packages/roosterjs-editor-types/lib/index.ts b/packages/roosterjs-editor-types/lib/index.ts index a681297b863..36779fd9fdb 100644 --- a/packages/roosterjs-editor-types/lib/index.ts +++ b/packages/roosterjs-editor-types/lib/index.ts @@ -43,9 +43,19 @@ export { default as BlockElement } from './interface/BlockElement'; export { default as ClipboardData } from './interface/ClipboardData'; export { default as ClipboardItems } from './interface/ClipboardItems'; export { default as DefaultFormat } from './interface/DefaultFormat'; -export { default as FormatState } from './interface/FormatState'; +export { + default as FormatState, + PendableFormatState, + ElementBasedFormatState, + StyleBasedFormatState, +} from './interface/FormatState'; export { default as InlineElement } from './interface/InlineElement'; -export { default as InsertOption, InsertOptionBase, InsertOptionBasic, InsertOptionRange } from './interface/InsertOption'; +export { + default as InsertOption, + InsertOptionBase, + InsertOptionBasic, + InsertOptionRange, +} from './interface/InsertOption'; export { default as LinkData } from './interface/LinkData'; export { default as NodePosition } from './interface/NodePosition'; export { default as Rect } from './interface/Rect'; diff --git a/packages/roosterjs-editor-types/lib/interface/FormatState.ts b/packages/roosterjs-editor-types/lib/interface/FormatState.ts index eefbfd736ec..790e7579f42 100644 --- a/packages/roosterjs-editor-types/lib/interface/FormatState.ts +++ b/packages/roosterjs-editor-types/lib/interface/FormatState.ts @@ -1,17 +1,11 @@ /** - * The format state + * Format states that can have pending state. + * + * e.g., When using execCommand('bold') target to a collapsed selection, browser will enter bold state, + * but there isn't a <B> tag until user type something, or the state will be rollback if selection + * is changed. */ -export default interface FormatState { - /** - * Font name - */ - fontName?: string; - - /** - * Font size - */ - fontSize?: string; - +export interface PendableFormatState { /** * Whether the text is bolded */ @@ -28,15 +22,25 @@ export default interface FormatState { isUnderline?: boolean; /** - * Background color + * Whether the text has strike through line */ - backgroundColor?: string; + isStrikeThrough?: boolean; /** - * Text color + * Whether the text is in subscript mode */ - textColor?: string; + isSubscript?: boolean; + /** + * Whether the text is in superscript mode + */ + isSuperscript?: boolean; +} + +/** + * Format state represented by DOM element + */ +export interface ElementBasedFormatState { /** * Whether the text is in bullet mode */ @@ -48,47 +52,67 @@ export default interface FormatState { isNumbering?: boolean; /** - * Whether the text has strike through line + * Whether the text is in block quote */ - isStrikeThrough?: boolean; + isBlockQuote?: boolean; /** - * Whether the text is in block quote + * Whether unlink command can be called to the text */ - isBlockQuote?: boolean; + canUnlink?: boolean; /** - * Whether the text is in subscript mode + * Whether add image alt text command can be called to the text */ - isSubscript?: boolean; + canAddImageAltText?: boolean; /** - * Whether the text is in superscript mode + * Header level (0-6, 0 means no header) */ - isSuperscript?: boolean; + headerLevel?: number; +} +/** + * Format states represented by CSS style + */ +export interface StyleBasedFormatState { /** - * Whether unlink command can be called to the text + * Font name */ - canUnlink?: boolean; + fontName?: string; /** - * Whether add image alt text command can be called to the text + * Font size */ - canAddImageAltText?: boolean; + fontSize?: string; + + /** + * Background color + */ + backgroundColor?: string; + + /** + * Text color + */ + textColor?: string; +} +/** + * The format state + */ +export default interface FormatState + extends PendableFormatState, + ElementBasedFormatState, + StyleBasedFormatState { /** + * @deprecated Use editor.canUndo() instead * Whether the content can be undone */ canUndo?: boolean; /** + * @deprecated Use editor.canRedo() instead * Whether the content ca nbe redone */ canRedo?: boolean; - - /** - * Header level (0-6, 0 means no header) - */ - headerLevel?: number; } diff --git a/tools/dts.js b/tools/dts.js index 5fbc8990df9..b5ac54fd3fa 100644 --- a/tools/dts.js +++ b/tools/dts.js @@ -8,7 +8,7 @@ var singleLineComment = /\/\/[^\n]*\n/g; var multiLineComment = /(^\/\*(\*(?!\/)|[^*])*\*\/\s*)/m; // 1. [export ][default |declare ](class|interface) [ extends| implements ] {...} -var regClassInterface = /(\/\*(\*(?!\/)|[^*])*\*\/\s*)?(export\s+)?(default\s+|declare\s+)?(interface|class)\s+([a-zA-Z0-9_]+(\s*<[^>]+>)?)((\s+extends|\s+implements)(\s+[0-9a-zA-Z_\.]+(\s*<[^>]+>)?))?\s*{/g; +var regClassInterface = /(\/\*(\*(?!\/)|[^*])*\*\/\s*)?(export\s+)?(default\s+|declare\s+)?(interface|class)\s+([a-zA-Z0-9_]+(\s*<[^>]+>)?)((\s+extends|\s+implements)(\s[0-9a-zA-Z_\.\s,]+(\s*<[^>]+>)?))?\s*{/g; // 2. [export ][default |declare ]function (...)[: ]; var regFunction = /(\/\*(\*(?!\/)|[^*])*\*\/\s*)?(export\s+)?(default\s+|declare\s+)?function\s+([a-zA-Z0-9_]+(\s*<[^>]+>)?)\s*(\([^;]+;)/g; // 3. [export ][default |declare ]const enum {...}