Skip to content

Commit

Permalink
Enable strict mode on "roosterjs-editor-plugins" - Phase 1 (#1289)
Browse files Browse the repository at this point in the history
* Strict AutoFormat & ContextMenu

* Strict CustomReplace

* CutPasteListChain plugin

* Allow nullish dom attribute value

* Strict HyperLink

* Strict Watermark

* Use individual tsconfigs

* Check this.editor at start of onPluginEvent
  • Loading branch information
ianeli1 authored Oct 12, 2022
1 parent e81200f commit fa2b0f1
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 97 deletions.
2 changes: 1 addition & 1 deletion packages/roosterjs-editor-core/lib/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ export default class Editor implements IEditor {
* @param name Name of the attribute
* @param value Value of the attribute
*/
public setEditorDomAttribute(name: string, value: string) {
public setEditorDomAttribute(name: string, value: string | null) {
if (value === null) {
this.getCore().contentDiv.removeAttribute(name);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ const specialCharacters = /[`!@#$%^&*()_+\=\[\]{};':"\\|,.<>\/?~]/;
* Automatically transform -- into hyphen, if typed between two words.
*/
export default class AutoFormat implements EditorPlugin {
private editor: IEditor;
private lastKeyTyped: string;
private editor: IEditor | null = null;
private lastKeyTyped: string | null = null;

/**
* Get a friendly name of this plugin
Expand Down Expand Up @@ -43,6 +43,9 @@ export default class AutoFormat implements EditorPlugin {
* @param event PluginEvent object
*/
onPluginEvent(event: PluginEvent) {
if (!this.editor) {
return;
}
if (
event.eventType === PluginEventType.ContentChanged ||
event.eventType === PluginEventType.MouseDown ||
Expand All @@ -65,26 +68,29 @@ export default class AutoFormat implements EditorPlugin {
keyTyped !== '-'
) {
const searcher = this.editor.getContentSearcherOfCursor(event);
const textBeforeCursor = searcher.getSubStringBefore(3);
const dashes = searcher.getSubStringBefore(2);
const isPrecededByADash = textBeforeCursor[0] === '-';
const isPrecededByASpace = textBeforeCursor[0] === ' ';
const textBeforeCursor = searcher?.getSubStringBefore(3);
const dashes = searcher?.getSubStringBefore(2);
const isPrecededByADash = textBeforeCursor?.[0] === '-';
const isPrecededByASpace = textBeforeCursor?.[0] === ' ';
if (
isPrecededByADash ||
isPrecededByASpace ||
specialCharacters.test(textBeforeCursor[0]) ||
(typeof textBeforeCursor === 'string' &&
specialCharacters.test(textBeforeCursor[0])) ||
dashes !== '--'
) {
return;
}

const textRange = searcher.getRangeFromText(dashes, true /* exactMatch */);
const textRange = searcher?.getRangeFromText(dashes, true /* exactMatch */);
const nodeHyphen = document.createTextNode('—');
this.editor.addUndoSnapshot(
() => {
textRange.deleteContents();
textRange.insertNode(nodeHyphen);
this.editor.select(nodeHyphen, PositionType.End);
if (textRange) {
textRange.deleteContents();
textRange.insertNode(nodeHyphen);
this.editor!.select(nodeHyphen, PositionType.End);
}
},
ChangeSource.Format /*changeSource*/,
true /*canUndoByBackspace*/,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"strict": true
},
"extends": "../../../../tsconfig.json",
"include": ["./**/*.ts"],
"references": [{ "path": "../../../../roosterjs-editor-types/tsconfig.child.json" }]
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ export interface ContextMenuOptions<T> {
* An editor plugin that support showing a context menu using render() function from options parameter
*/
export default class ContextMenu<T> implements EditorPlugin {
private container: HTMLElement;
private editor: IEditor;
private isMenuShowing: boolean;
private container: HTMLElement | null = null;
private editor: IEditor | null = null;
private isMenuShowing: boolean = false;

/**
* Create a new instance of ContextMenu class
Expand Down Expand Up @@ -68,7 +68,7 @@ export default class ContextMenu<T> implements EditorPlugin {
dispose() {
this.onDismiss();

if (this.container) {
if (this.container?.parentNode) {
this.container.parentNode.removeChild(this.container);
this.container = null;
}
Expand All @@ -89,22 +89,24 @@ export default class ContextMenu<T> implements EditorPlugin {
rawEvent.preventDefault();
}

this.initContainer(rawEvent.pageX, rawEvent.pageY);
this.options.render(this.container, items as T[], this.onDismiss);
this.isMenuShowing = true;
if (this.initContainer(rawEvent.pageX, rawEvent.pageY)) {
this.options.render(this.container!, items as T[], this.onDismiss);
this.isMenuShowing = true;
}
}
}

private initContainer(x: number, y: number) {
if (!this.container) {
if (!this.container && this.editor) {
this.container = createElement(
KnownCreateElementDataIndex.ContextMenuWrapper,
this.editor.getDocument()
) as HTMLElement;
this.editor.getDocument().body.appendChild(this.container);
}
this.container.style.left = x + 'px';
this.container.style.top = y + 'px';
this.container?.style.setProperty('left', x + 'px');
this.container?.style.setProperty('top', y + 'px');
return !!this.container;
}

private onDismiss = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"strict": true
},
"extends": "../../../../tsconfig.json",
"include": ["./**/*.ts"],
"references": [
{ "path": "../../../../roosterjs-editor-dom/tsconfig.child.json" },
{ "path": "../../../../roosterjs-editor-types/tsconfig.child.json" }
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ const defaultReplacements: CustomReplacement[] = [
* content edit feature
*/
export default class CustomReplacePlugin implements EditorPlugin {
private longestReplacementLength: number;
private editor: IEditor;
private replacements: CustomReplacement[];
private replacementEndCharacters: Set<string>;
private longestReplacementLength: number | null = null;
private editor: IEditor | null = null;
private replacements: CustomReplacement[] | null = null;
private replacementEndCharacters: Set<string> | null = null;

/**
* Create instance of CustomReplace plugin
Expand Down Expand Up @@ -86,33 +86,29 @@ export default class CustomReplacePlugin implements EditorPlugin {
* @param event PluginEvent object
*/
public onPluginEvent(event: PluginEvent) {
if (event.eventType != PluginEventType.Input || this.editor.isInIME()) {
if (event.eventType != PluginEventType.Input || !this.editor || this.editor.isInIME()) {
return;
}

// Exit early on input events that do not insert a replacement's final character.
if (!event.rawEvent.data || !this.replacementEndCharacters.has(event.rawEvent.data)) {
if (!event.rawEvent.data || !this.replacementEndCharacters?.has(event.rawEvent.data)) {
return;
}

// Get the matching replacement
const range = this.editor.getSelectionRange();
if (range == null) {
const searcher = this.editor.getContentSearcherOfCursor(event);
if (!searcher || this.longestReplacementLength == null) {
return;
}

const searcher = this.editor.getContentSearcherOfCursor(event);
const stringToSearch = searcher.getSubStringBefore(this.longestReplacementLength);
const sourceEditor = this.editor;

const replacement = this.getMatchingReplacement(stringToSearch);
if (replacement == null) {
return;
}

if (
replacement.shouldReplace &&
!replacement.shouldReplace(replacement, searcher.getWordBefore(), sourceEditor)
!replacement ||
(replacement.shouldReplace &&
searcher &&
!replacement.shouldReplace(replacement, searcher.getWordBefore(), this.editor))
) {
return;
}
Expand All @@ -130,19 +126,21 @@ export default class CustomReplacePlugin implements EditorPlugin {
parsingSpan.childNodes.length == 1 ? parsingSpan.childNodes[0] : parsingSpan;

// Switch the node for the selection range
this.editor.addUndoSnapshot(
() => {
matchingRange.deleteContents();
matchingRange.insertNode(nodeToInsert);
this.editor.select(nodeToInsert, PositionType.End);
},
null /*changeSource*/,
true /*canUndoByBackspace*/
);
if (matchingRange) {
this.editor.addUndoSnapshot(
() => {
matchingRange.deleteContents();
matchingRange.insertNode(nodeToInsert);
this.editor?.select(nodeToInsert, PositionType.End);
},
undefined /*changeSource*/,
true /*canUndoByBackspace*/
);
}
}

private getMatchingReplacement(stringToSearch: string): CustomReplacement | null {
if (stringToSearch.length == 0) {
if (stringToSearch.length == 0 || !this.replacements) {
return null;
}
const originalStringToSearch = stringToSearch.replace(/\s/g, ' ');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"strict": true
},
"extends": "../../../../tsconfig.json",
"include": ["./**/*.ts"],
"references": [{ "path": "../../../../roosterjs-editor-types/tsconfig.child.json" }]
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import type { CompatibleChangeSource } from 'roosterjs-editor-types/lib/compatib
* Maintain list numbers of list chain when content is modified by cut/paste/drag&drop
*/
export default class CutPasteListChain implements EditorPlugin {
private chains: VListChain[];
private expectedChangeSource: ChangeSource | CompatibleChangeSource;
private editor: IEditor;
private disposer: () => void;
private chains: VListChain[] | null = null;
private expectedChangeSource: ChangeSource | CompatibleChangeSource | null = null;
private editor: IEditor | null = null;
private disposer: (() => void) | null = null;

/**
* Get a friendly name of this plugin
Expand Down Expand Up @@ -60,7 +60,12 @@ export default class CutPasteListChain implements EditorPlugin {
break;

case PluginEventType.ContentChanged:
if (this.chains?.length > 0 && this.expectedChangeSource == event.source) {
if (
this.chains &&
this.chains.length > 0 &&
this.expectedChangeSource == event.source &&
this.editor
) {
commitListChains(this.editor, this.chains);
this.chains = null;
this.expectedChangeSource = null;
Expand All @@ -74,7 +79,10 @@ export default class CutPasteListChain implements EditorPlugin {
};

private cacheListChains(source: ChangeSource) {
this.chains = VListChain.createListChains(this.editor.getSelectedRegions());
this.expectedChangeSource = source;
const selectedRegions = this.editor?.getSelectedRegions();
if (selectedRegions) {
this.chains = VListChain.createListChains(selectedRegions);
this.expectedChangeSource = source;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"strict": true
},
"extends": "../../../../tsconfig.json",
"include": ["./**/*.ts"],
"references": [
{ "path": "../../../../roosterjs-editor-types/tsconfig.child.json" },
{ "path": "../../../../roosterjs-editor-api/tsconfig.child.json" }
]
}
Loading

0 comments on commit fa2b0f1

Please sign in to comment.