From 506797b8a718f29b99d06375b140f6a4b7ac4657 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Thu, 24 Nov 2022 02:13:14 -0800 Subject: [PATCH] WIP --- .../src/components/ActionDispatcher.ts | 7 +- .../mindplot/src/components/CentralTopic.ts | 1 - packages/mindplot/src/components/Designer.ts | 11 ++- .../src/components/DesignerBuilder.ts | 3 +- .../src/components/DesignerOptionsBuilder.ts | 4 +- packages/mindplot/src/components/DragTopic.ts | 6 +- .../src/components/MultilineTextEditor.ts | 89 ++++++++++--------- .../src/components/PersistenceManager.ts | 2 +- .../mindplot/src/components/ScreenManager.ts | 2 +- packages/mindplot/src/components/Topic.ts | 48 +++++----- .../mindplot/src/components/WidgetManager.ts | 13 ++- .../src/components/commands/DeleteCommand.ts | 4 +- .../layout/ChildrenSorterStrategy.ts | 2 +- .../src/components/layout/LayoutManager.ts | 6 +- .../src/components/model/INodeModel.ts | 6 +- 15 files changed, 108 insertions(+), 96 deletions(-) diff --git a/packages/mindplot/src/components/ActionDispatcher.ts b/packages/mindplot/src/components/ActionDispatcher.ts index fc813521..2b8135a5 100644 --- a/packages/mindplot/src/components/ActionDispatcher.ts +++ b/packages/mindplot/src/components/ActionDispatcher.ts @@ -48,7 +48,12 @@ abstract class ActionDispatcher extends Events { abstract deleteEntities(topicsIds: number[], relIds: number[]): void; - abstract dragTopic(topicId: number, position: Point, order: number, parentTopic: Topic): void; + abstract dragTopic( + topicId: number, + position: Point, + order: number | null, + parentTopic: Topic | null, + ): void; abstract moveTopic(topicId: number, position: Point): void; diff --git a/packages/mindplot/src/components/CentralTopic.ts b/packages/mindplot/src/components/CentralTopic.ts index 85908a28..1fc61e92 100644 --- a/packages/mindplot/src/components/CentralTopic.ts +++ b/packages/mindplot/src/components/CentralTopic.ts @@ -53,7 +53,6 @@ class CentralTopic extends Topic { this.setPosition(zeroPoint); } - /** */ getShrinkConnector() { return null; } diff --git a/packages/mindplot/src/components/Designer.ts b/packages/mindplot/src/components/Designer.ts index 756d8fcf..3bfa32c7 100644 --- a/packages/mindplot/src/components/Designer.ts +++ b/packages/mindplot/src/components/Designer.ts @@ -87,7 +87,7 @@ class Designer extends Events { // Set up i18n location ... console.log(`Editor location: ${options.locale}`); - Messages.init(options.locale); + Messages.init(options.locale ? options.locale : 'en'); this._options = options; @@ -263,7 +263,10 @@ class Designer extends Events { } else { $assert(targetTopic, 'Could not find a topic to connect'); } - topic.connectTo(targetTopic, this._workspace); + + if (targetTopic) { + topic.connectTo(targetTopic, this._workspace); + } } topic.addEvent('ontblur', () => { @@ -521,7 +524,7 @@ class Designer extends Events { const parentTopic = topic.getOutgoingConnectedTopic(); const siblingModel = this._createSiblingModel(topic); - if (siblingModel) { + if (siblingModel && parentTopic) { // Hack: if parent is central topic, add node below not on opposite side. // This should be done in the layout if (parentTopic.getType() === 'CentralTopic') { @@ -724,7 +727,7 @@ class Designer extends Events { ); // Build relationship line .... - const result = new Relationship(sourceTopic, targetTopic, model); + const result = new Relationship(sourceTopic!, targetTopic!, model); const me = this; result.addEvent('ontblur', () => { diff --git a/packages/mindplot/src/components/DesignerBuilder.ts b/packages/mindplot/src/components/DesignerBuilder.ts index 4a7a3e20..cd289fca 100644 --- a/packages/mindplot/src/components/DesignerBuilder.ts +++ b/packages/mindplot/src/components/DesignerBuilder.ts @@ -37,8 +37,7 @@ export function buildDesigner(options: DesignerOptions): Designer { // Configure default persistence manager ... const persistence = options.persistenceManager; - $assert(persistence, 'persistence must be defined'); - PersistenceManager.init(persistence); + PersistenceManager.init(persistence!); // If not manager was specifed, use the readonly one. const widgetManager = options.widgetManager ? options.widgetManager : new ReadOnlyWidgetManager(); diff --git a/packages/mindplot/src/components/DesignerOptionsBuilder.ts b/packages/mindplot/src/components/DesignerOptionsBuilder.ts index 41fde211..f31305f8 100644 --- a/packages/mindplot/src/components/DesignerOptionsBuilder.ts +++ b/packages/mindplot/src/components/DesignerOptionsBuilder.ts @@ -24,7 +24,7 @@ export type DesignerOptions = { zoom: number; mode: EditorRenderMode; mapId?: string; - divContainer?: HTMLElement; + divContainer: HTMLElement; container: string; persistenceManager?: PersistenceManager; widgetManager?: WidgetManager; @@ -36,7 +36,7 @@ class OptionsBuilder { static buildOptions(options: DesignerOptions): DesignerOptions { $assert(options.persistenceManager, 'persistence must be defined'); - const defaultOptions: DesignerOptions = { + const defaultOptions = { mode: 'edition-owner', zoom: 0.85, saveOnLoad: true, diff --git a/packages/mindplot/src/components/DragTopic.ts b/packages/mindplot/src/components/DragTopic.ts index be51a848..859b60b3 100644 --- a/packages/mindplot/src/components/DragTopic.ts +++ b/packages/mindplot/src/components/DragTopic.ts @@ -108,8 +108,6 @@ class DragTopic { } connectTo(parent: Topic) { - $assert(parent, 'Parent connection node can not be null.'); - // Where it should be connected ? const predict = this._layoutManager.predict( parent.getId(), @@ -178,8 +176,8 @@ class DragTopic { const position = this.getPosition(); if (!this.isFreeLayoutOn()) { - let order = null; - let parent = null; + let order: number | null = null; + let parent: Topic | null = null; const isDragConnected = this.isConnected(); if (isDragConnected) { const targetTopic = this.getConnectedToTopic(); diff --git a/packages/mindplot/src/components/MultilineTextEditor.ts b/packages/mindplot/src/components/MultilineTextEditor.ts index 2dfc4540..e0b6c42f 100644 --- a/packages/mindplot/src/components/MultilineTextEditor.ts +++ b/packages/mindplot/src/components/MultilineTextEditor.ts @@ -23,9 +23,9 @@ import ActionDispatcher from './ActionDispatcher'; import Topic from './Topic'; class MultilineTextEditor extends Events { - private _topic: Topic; + private _topic: Topic | null; - private _containerElem: JQuery; + private _containerElem: JQuery | null; constructor() { super(); @@ -54,7 +54,7 @@ class MultilineTextEditor extends Events { private _registerEvents(containerElem: JQuery) { const textareaElem = this._getTextareaElem(); - textareaElem.on('keydown', (event) => { + textareaElem?.on('keydown', (event) => { switch (event.code) { case 'Escape': this.close(false); @@ -85,12 +85,12 @@ class MultilineTextEditor extends Events { event.stopPropagation(); }); - textareaElem.on('keypress', (event) => { + textareaElem?.on('keypress', (event) => { event.stopPropagation(); }); - textareaElem.on('keyup', (event) => { - const text = this._getTextareaElem().val(); + textareaElem?.on('keyup', (event) => { + const text = this._getTextareaElem()?.val(); this.fireEvent('input', [event, text]); this._adjustEditorSize(); }); @@ -117,22 +117,22 @@ class MultilineTextEditor extends Events { maxLineLength = Math.max(line.length, maxLineLength); }); - textElem.attr('cols', maxLineLength); - textElem.attr('rows', lines.length); + textElem?.attr('cols', maxLineLength); + textElem?.attr('rows', lines.length); - this._containerElem.css({ + this._containerElem?.css({ width: `${maxLineLength + 2}em`, - height: textElem.height(), + height: textElem?.height() || 0, }); } } isVisible(): boolean { - return $defined(this._containerElem) && this._containerElem.css('display') === 'block'; + return this._containerElem !== null && this._containerElem.css('display') === 'block'; } private _updateModel() { - if (this._topic.getText() !== this._getTextAreaText()) { + if (this._topic && this._topic.getText() !== this._getTextAreaText()) { const text = this._getTextAreaText(); const topicId = this._topic.getId(); @@ -167,36 +167,39 @@ class MultilineTextEditor extends Events { private _showEditor(defaultText: string) { const topic = this._topic; + if (topic && this._containerElem) { + // Hide topic text ... + topic.getTextShape().setVisibility(false); - // Hide topic text ... - topic.getTextShape().setVisibility(false); + // Set Editor Style + const nodeText = topic.getTextShape(); + const fontStyle = nodeText.getFontStyle(); + fontStyle.size = nodeText.getHtmlFontSize(); + fontStyle.color = nodeText.getColor(); + this._setStyle(fontStyle); - // Set Editor Style - const nodeText = topic.getTextShape(); - const fontStyle = nodeText.getFontStyle(); - fontStyle.size = nodeText.getHtmlFontSize(); - fontStyle.color = nodeText.getColor(); - this._setStyle(fontStyle); + // Set editor's initial size + // Position the editor and set the size... + const textShape = topic.getTextShape(); - // Set editor's initial size - // Position the editor and set the size... - const textShape = topic.getTextShape(); + this._containerElem.css('display', 'block'); - this._containerElem.css('display', 'block'); + let { top, left } = textShape.getNativePosition(); + // Adjust padding top position ... + top -= 4; + left -= 4; + this._containerElem.offset({ top, left }); - let { top, left } = textShape.getNativePosition(); - // Adjust padding top position ... - top -= 4; - left -= 4; - this._containerElem.offset({ top, left }); + // Set editor's initial text ... + const text = $defined(defaultText) ? defaultText : topic.getText(); + this._setText(text); - // Set editor's initial text ... - const text = $defined(defaultText) ? defaultText : topic.getText(); - this._setText(text); - - // Set the element focus and select the current text ... - const inputElem = this._getTextareaElem(); - this._positionCursor(inputElem, !$defined(defaultText)); + // Set the element focus and select the current text ... + const inputElem = this._getTextareaElem(); + if (inputElem) { + this._positionCursor(inputElem, !$defined(defaultText)); + } + } } private _setStyle(fontStyle) { @@ -223,22 +226,22 @@ class MultilineTextEditor extends Events { fontWeight: fontStyle.weight, color: fontStyle.color, }; - inputField.css(style); - this._containerElem.css(style); + inputField?.css(style); + this._containerElem?.css(style); } private _setText(text: string): void { const textareaElem = this._getTextareaElem(); - textareaElem.val(text); + textareaElem?.val(text); this._adjustEditorSize(); } private _getTextAreaText(): string { - return this._getTextareaElem().val() as string; + return this._getTextareaElem()?.val() as string; } - private _getTextareaElem(): JQuery { - return this._containerElem.find('textarea'); + private _getTextareaElem(): JQuery | null { + return this._containerElem ? this._containerElem.find('textarea') : null; } private _positionCursor(textareaElem: JQuery, selectText: boolean) { @@ -259,7 +262,7 @@ class MultilineTextEditor extends Events { } // Remove it form the screen ... - this._containerElem.remove(); + this._containerElem?.remove(); this._containerElem = null; } diff --git a/packages/mindplot/src/components/PersistenceManager.ts b/packages/mindplot/src/components/PersistenceManager.ts index ead8e31b..886f7557 100644 --- a/packages/mindplot/src/components/PersistenceManager.ts +++ b/packages/mindplot/src/components/PersistenceManager.ts @@ -54,7 +54,7 @@ abstract class PersistenceManager { protected getCSRFToken(): string | null { const meta = document.head.querySelector('meta[name="_csrf"]'); - let result = null; + let result: string | null = null; if (meta) { result = meta.getAttribute('content'); } diff --git a/packages/mindplot/src/components/ScreenManager.ts b/packages/mindplot/src/components/ScreenManager.ts index 18b0a94d..0b5b5323 100644 --- a/packages/mindplot/src/components/ScreenManager.ts +++ b/packages/mindplot/src/components/ScreenManager.ts @@ -85,7 +85,7 @@ class ScreenManager { } } - fireEvent(type: string, event: UIEvent = null) { + fireEvent(type: string, event?: UIEvent): void { if (type === 'click') { this._clickEvents.forEach((listener) => { listener(type, event); diff --git a/packages/mindplot/src/components/Topic.ts b/packages/mindplot/src/components/Topic.ts index e09befde..ed1e6e0f 100644 --- a/packages/mindplot/src/components/Topic.ts +++ b/packages/mindplot/src/components/Topic.ts @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import $ from 'jquery'; import { $assert, $defined } from '@wisemapping/core-js'; import { Rect, Image, Line, Text, Group, ElementClass, Point } from '@wisemapping/web2d'; @@ -147,7 +146,7 @@ abstract class Topic extends NodeGraph { // Move connector to front const connector = this.getShrinkConnector(); - if ($defined(connector)) { + if (connector) { connector.moveToFront(); } } @@ -508,7 +507,7 @@ abstract class Topic extends NodeGraph { } } - private _setText(text: string, updateModel?: boolean) { + private _setText(text: string | null, updateModel?: boolean) { const textShape = this.getTextShape(); textShape.setText(text == null ? TopicStyle.defaultText(this) : text); @@ -520,7 +519,7 @@ abstract class Topic extends NodeGraph { setText(text: string) { // Avoid empty nodes ... - if (!text || $.trim(text).length === 0) { + if (!text || text.trim().length === 0) { this._setText(null, true); } else { this._setText(text, true); @@ -531,11 +530,8 @@ abstract class Topic extends NodeGraph { getText(): string { const model = this.getModel(); - let result = model.getText(); - if (!$defined(result)) { - result = TopicStyle.defaultText(this); - } - return result; + const text = model.getText(); + return text || TopicStyle.defaultText(this); } setBackgroundColor(color: string): void { @@ -622,7 +618,7 @@ abstract class Topic extends NodeGraph { } const shrinkConnector = this.getShrinkConnector(); - if ($defined(shrinkConnector)) { + if (shrinkConnector) { shrinkConnector.addToWorkspace(group); } @@ -706,7 +702,7 @@ abstract class Topic extends NodeGraph { EventBus.instance.fireEvent('childShrinked', model); } - getShrinkConnector(): ShirinkConnector | undefined { + getShrinkConnector(): ShirinkConnector | null { let result = this._connector; if (this._connector == null) { this._connector = new ShirinkConnector(this); @@ -849,10 +845,10 @@ abstract class Topic extends NodeGraph { .map((node) => node.getOutgoingLine()); } - getOutgoingConnectedTopic(): Topic { + getOutgoingConnectedTopic(): Topic | null { let result = null; const line = this.getOutgoingLine(); - if ($defined(line)) { + if (line) { result = line.getTargetTopic(); } return result; @@ -875,7 +871,7 @@ abstract class Topic extends NodeGraph { setBranchVisibility(value: boolean): void { let current: Topic = this; - let parent: Topic = this; + let parent: Topic | null = this; while (parent != null && !parent.isCentralTopic()) { current = parent; parent = current.getParent(); @@ -905,7 +901,7 @@ abstract class Topic extends NodeGraph { this._relationships.forEach((r) => r.moveToBack()); const connector = this.getShrinkConnector(); - if ($defined(connector)) { + if (connector) { connector.moveToBack(); } @@ -916,7 +912,7 @@ abstract class Topic extends NodeGraph { moveToFront(): void { this.get2DElement().moveToFront(); const connector = this.getShrinkConnector(); - if ($defined(connector)) { + if (connector) { connector.moveToFront(); } // Update relationship lines @@ -951,7 +947,7 @@ abstract class Topic extends NodeGraph { if (this.getIncomingLines().length > 0) { const connector = this.getShrinkConnector(); - if ($defined(connector)) { + if (connector) { connector.setVisibility(value, fade); } } @@ -970,7 +966,7 @@ abstract class Topic extends NodeGraph { elem.setOpacity(opacity); const connector = this.getShrinkConnector(); - if ($defined(connector)) { + if (connector) { connector.setOpacity(opacity); } const textShape = this.getTextShape(); @@ -1132,7 +1128,7 @@ abstract class Topic extends NodeGraph { // Display connection node... const connector = targetTopic.getShrinkConnector(); - if ($defined(connector)) { + if (connector) { connector.setVisibility(true); } @@ -1190,9 +1186,10 @@ abstract class Topic extends NodeGraph { EventBus.instance.fireEvent('topicAdded', this.getModel()); } - if (this.getModel().isConnected()) { + const outgoingTopic = this.getOutgoingConnectedTopic(); + if (this.getModel().isConnected() && outgoingTopic) { EventBus.instance.fireEvent('topicConnected', { - parentNode: this.getOutgoingConnectedTopic().getModel(), + parentNode: outgoingTopic.getModel(), childNode: this.getModel(), }); } @@ -1212,7 +1209,7 @@ abstract class Topic extends NodeGraph { // Is the node already connected ? const targetTopic = this.getOutgoingConnectedTopic(); - if ($defined(targetTopic)) { + if (targetTopic) { result.connectTo(targetTopic); result.setVisibility(false); } @@ -1265,19 +1262,18 @@ abstract class Topic extends NodeGraph { } private _flatten2DElements(topic: Topic): (Topic | Relationship)[] { - let result = []; - + const result: (Topic | Relationship)[] = []; const children = topic.getChildren(); children.forEach((child) => { result.push(child); result.push(child.getOutgoingLine()); const relationships = child.getRelationships(); - result = result.concat(relationships); + result.push(...relationships); if (!child.areChildrenShrunken()) { const innerChilds = this._flatten2DElements(child); - result = result.concat(innerChilds); + result.push(...innerChilds); } }); return result; diff --git a/packages/mindplot/src/components/WidgetManager.ts b/packages/mindplot/src/components/WidgetManager.ts index fa2cd0cc..a713f3e9 100644 --- a/packages/mindplot/src/components/WidgetManager.ts +++ b/packages/mindplot/src/components/WidgetManager.ts @@ -18,7 +18,12 @@ abstract class WidgetManager { return this._instance; } - private createTooltip(mindmapElement, title: string, linkModel: LinkModel, noteModel: NoteModel) { + private createTooltip( + mindmapElement, + title: string, + linkModel?: LinkModel, + noteModel?: NoteModel, + ) { const webcomponentShadowRoot = $($('#mindmap-comp')[0].shadowRoot); let tooltip = webcomponentShadowRoot.find('#mindplot-svg-tooltip'); if (!tooltip.length) { @@ -97,7 +102,11 @@ abstract class WidgetManager { abstract showEditorForLink(topic: Topic, linkModel: LinkModel, linkIcon: LinkIcon): void; - abstract showEditorForNote(topic: Topic, noteModel: NoteModel, noteIcon: NoteIcon): void; + abstract showEditorForNote( + topic: Topic, + noteModel: NoteModel | null, + noteIcon: NoteIcon | null, + ): void; } export default WidgetManager; diff --git a/packages/mindplot/src/components/commands/DeleteCommand.ts b/packages/mindplot/src/components/commands/DeleteCommand.ts index 76ef0723..775107f7 100644 --- a/packages/mindplot/src/components/commands/DeleteCommand.ts +++ b/packages/mindplot/src/components/commands/DeleteCommand.ts @@ -137,10 +137,10 @@ class DeleteCommand extends Command { this._deletedRelModel = []; } - private _filterChildren(topicIds: number[], commandContext: CommandContext) { + private _filterChildren(topicIds: number[], commandContext: CommandContext): Topic[] { const topics = commandContext.findTopics(topicIds); - const result = []; + const result: Topic[] = []; topics.forEach((topic: Topic) => { let parent = topic.getParent(); let found = false; diff --git a/packages/mindplot/src/components/layout/ChildrenSorterStrategy.ts b/packages/mindplot/src/components/layout/ChildrenSorterStrategy.ts index 85396b4c..e07fd91c 100644 --- a/packages/mindplot/src/components/layout/ChildrenSorterStrategy.ts +++ b/packages/mindplot/src/components/layout/ChildrenSorterStrategy.ts @@ -28,7 +28,7 @@ abstract class ChildrenSorterStrategy { abstract detach(treeSet: RootedTreeSet, node: Node): void; - abstract predict(treeSet: RootedTreeSet, parent, node: Node, position: PositionType); + abstract predict(treeSet: RootedTreeSet, parent, node: Node | null, position: PositionType); abstract verify(treeSet: RootedTreeSet, node: Node); diff --git a/packages/mindplot/src/components/layout/LayoutManager.ts b/packages/mindplot/src/components/layout/LayoutManager.ts index 310d4f61..dcbe9e67 100644 --- a/packages/mindplot/src/components/layout/LayoutManager.ts +++ b/packages/mindplot/src/components/layout/LayoutManager.ts @@ -128,8 +128,8 @@ class LayoutManager extends Events { predict( parentId: number, - nodeId: number, - position: PositionType, + nodeId: number | null, + position: PositionType | null, ): { order: number; position: PositionType } { $assert($defined(parentId), 'parentId can not be null'); @@ -194,7 +194,7 @@ class LayoutManager extends Events { if (node.hasOrderChanged() || node.hasPositionChanged()) { // Find or create a event ... const id = node.getId(); - let event: ChangeEvent = this._events.find((e) => e.getId() === id); + let event: ChangeEvent | undefined = this._events.find((e) => e.getId() === id); if (!event) { event = new ChangeEvent(id); } diff --git a/packages/mindplot/src/components/model/INodeModel.ts b/packages/mindplot/src/components/model/INodeModel.ts index 61b470c6..44c7b405 100644 --- a/packages/mindplot/src/components/model/INodeModel.ts +++ b/packages/mindplot/src/components/model/INodeModel.ts @@ -66,11 +66,11 @@ abstract class INodeModel { this.putProperty('type', type); } - setText(text: string): void { + setText(text: string | null): void { this.putProperty('text', text); } - getText(): string | undefined { + getText(): string | null { return this.getProperty('text') as string; } @@ -290,7 +290,7 @@ abstract class INodeModel { abstract getProperty(key: string): number | string | boolean; - abstract putProperty(key: string, value: number | string | boolean): void; + abstract putProperty(key: string, value: number | string | boolean | null): void; abstract setParent(parent: INodeModel): void;