Fix editor selection text.

This commit is contained in:
Paulo Gustavo Veiga 2023-01-01 19:54:16 -08:00
parent 7977fcee42
commit bd2f404934
29 changed files with 141 additions and 83 deletions

View File

@ -16,6 +16,7 @@ context('Render all sample maps', () => {
'sample4',
'sample5',
'sample6',
'connection-style',
'sample8',
'welcome',
].forEach((mapId) => {

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

@ -88,13 +88,33 @@ const KeyboardShorcutsHelp = (): ReactElement => {
<td>
<FormattedMessage
id="shortcut-help-pane.edit-topic-key"
defaultMessage="Just start typing"
defaultMessage="F2 or Double Click"
/>
</td>
<td>
<FormattedMessage
id="shortcut-help-pane.edit-topic-key"
defaultMessage="Just start typing"
defaultMessage="F2 or Double Click"
/>
</td>
</tr>
<tr>
<td>
<FormattedMessage
id="shortcut-help-pane.overwrite-edit-topic"
defaultMessage="Overwrite topic text"
/>
</td>
<td>
<FormattedMessage
id="shortcut-help-pane.overwrite-edit-topic-key"
defaultMessage="Type on a selected topic"
/>
</td>
<td>
<FormattedMessage
id="shortcut-help-pane.overwrite-edit-topic-key"
defaultMessage="Type on a selected topic"
/>
</td>
</tr>

View File

@ -42,6 +42,7 @@
<li><a href="/viewmode.html?id=huge">Huge</a></li>
<li><a href="/viewmode.html?id=icon-sample">Icon Sample</a></li>
<li><a href="/viewmode.html?id=emoji">UTF-8 Emoji</a></li>
<li><a href="/viewmode.html?id=connection-style">Connection Style</a></li>
</ul>
<p><span class="section">Editor Mode:</span>Example on how mindplot can be used for mindmap edition. Browser local storage is used for persistance.</p>
<ul>

View File

@ -0,0 +1 @@
<map name="1434422" version="tango"><topic central="true" text="Connection Style" id="1" connColor="#ffff00"><topic position="168,0" order="0" text="Main Change Color" id="2" connColor="#00ff00"><topic position="305,-144" order="0" id="5"/><topic position="305,112" order="3" id="14"/><topic position="305,144" order="4" id="15"/><topic position="279,-96" order="1" text="Circle" shape="elipse" id="27" connStyle="1"><topic position="375,-112" order="0" shape="elipse" id="28"/><topic position="375,-80" order="1" shape="elipse" id="29"/></topic><topic position="277,16" order="2" text="Rect" shape="rectangle" id="6" connStyle="2"><topic position="370,-16" order="0" id="7"><topic position="492,-48" order="0" id="34"/><topic position="492,-16" order="1" id="35"/><topic position="492,16" order="2" id="36"/></topic><topic position="370,48" order="1" id="8"/><topic position="370,80" order="2" id="9"/></topic></topic><topic position="-168,-48" order="1" text="Central Topic Color" id="19"><topic position="-305,-128" order="0" id="20"/><topic position="-305,-96" order="1" id="21"/><topic position="-305,-64" order="2" id="22"/><topic position="-305,0" order="3" id="23" connStyle="2" connColor="#ff00ff"><topic position="-427,-32" order="0" id="24"/><topic position="-427,0" order="1" id="25"/><topic position="-427,32" order="2" id="26"/></topic></topic><topic position="-161,96" order="3" text="Subtopic change" id="4" connColor="#f1a327"><topic position="-292,64" order="0" id="16"/><topic position="-292,96" order="1" id="17"/><topic position="-292,128" order="2" id="18"/></topic></topic><relationship srcTopicId="26" destTopicId="15" lineType="0" srcCtrlPoint="-20,194" destCtrlPoint="-134,68" endArrow="true" startArrow="false"/></map>

View File

@ -33,12 +33,12 @@ class EditorComponent extends Events {
this._topic = topic;
// Create editor ui
this._containerElem = EditorComponent._buildEditor();
this._containerElem = EditorComponent.buildEditor();
$('body').append(this._containerElem);
this._registerEvents(this._containerElem);
this.registerEvents(this._containerElem);
}
private static _buildEditor() {
private static buildEditor() {
const result = $('<div></div>').attr('id', 'textContainer').css({
display: 'none',
zIndex: '8',
@ -58,8 +58,8 @@ class EditorComponent extends Events {
return result;
}
private _registerEvents(containerElem: JQuery): void {
const textareaElem = this._getTextareaElem();
private registerEvents(containerElem: JQuery): void {
const textareaElem = this.getTextareaElem();
textareaElem.on('keydown', (event) => {
switch (event.code) {
case 'Escape':
@ -68,7 +68,7 @@ class EditorComponent extends Events {
case 'Enter': {
if (event.metaKey || event.ctrlKey) {
// Add return ...
const text = this._getTextAreaText();
const text = this.getTextAreaText();
const cursorPosition = text.length;
const head = text.substring(0, cursorPosition);
let tail = '';
@ -96,9 +96,9 @@ class EditorComponent extends Events {
});
textareaElem.on('keyup', (event) => {
const text = this._getTextareaElem().val();
const text = this.getTextareaElem().val();
this.fireEvent('input', [event, text]);
this._adjustEditorSize();
this.adjustEditorSize();
});
// If the user clicks on the input, all event must be ignored ...
@ -113,10 +113,10 @@ class EditorComponent extends Events {
});
}
private _adjustEditorSize() {
const textElem = this._getTextareaElem();
private adjustEditorSize() {
const textElem = this.getTextareaElem();
const lines = this._getTextAreaText().split('\n');
const lines = this.getTextAreaText().split('\n');
let maxLineLength = 1;
lines.forEach((line: string) => {
maxLineLength = Math.max(line.length, maxLineLength);
@ -131,9 +131,9 @@ class EditorComponent extends Events {
});
}
private _updateModel() {
if (this._topic && this._topic.getText() !== this._getTextAreaText()) {
const text = this._getTextAreaText();
private updateModel() {
if (this._topic && this._topic.getText() !== this.getTextAreaText()) {
const text = this.getTextAreaText();
const topicId = this._topic.getId();
const actionDispatcher = ActionDispatcher.getInstance();
@ -147,7 +147,7 @@ class EditorComponent extends Events {
}
}
show(defaultText: string) {
show(textOverwrite?: string) {
const topic = this._topic;
// Hide topic text ...
@ -158,12 +158,11 @@ class EditorComponent extends Events {
const fontStyle = nodeText.getFontStyle();
fontStyle.size = nodeText.getHtmlFontSize();
fontStyle.color = nodeText.getColor();
this._setStyle(fontStyle);
this.setStyle(fontStyle);
// Set editor's initial size
// Position the editor and set the size...
const textShape = topic.getTextShape();
this._containerElem.css('display', 'block');
let { top, left } = textShape.getNativePosition();
@ -172,25 +171,26 @@ class EditorComponent extends Events {
left -= 4;
this._containerElem.offset({ top, left });
// Set editor's initial text ...
const text = defaultText || topic.getText();
this._setText(text);
// Set editor's initial text. If the text has not been specifed, it will be empty
const modelText = topic.getModel().getText();
const text = textOverwrite || modelText || '';
this.setText(text);
// Set the element focus and select the current text ...
const inputElem = this._getTextareaElem();
const inputElem = this.getTextareaElem();
if (inputElem) {
this._positionCursor(inputElem, !$defined(defaultText));
this.positionCursor(inputElem, textOverwrite === undefined);
}
}
private _setStyle(fontStyle: {
private setStyle(fontStyle: {
fontFamily: string;
style: string;
weight: string;
size: number;
color: string;
}) {
const inputField = this._getTextareaElem();
const inputField = this.getTextareaElem();
// allowed param reassign to avoid risks of existing code relying in this side-effect
/* eslint-disable no-param-reassign */
if (!$defined(fontStyle.fontFamily)) {
@ -217,23 +217,23 @@ class EditorComponent extends Events {
this._containerElem.css(style);
}
private _setText(text: string): void {
const textareaElem = this._getTextareaElem();
private setText(text: string): void {
const textareaElem = this.getTextareaElem();
textareaElem.val(text);
this._adjustEditorSize();
this.adjustEditorSize();
}
private _getTextAreaText(): string {
return this._getTextareaElem().val() as string;
private getTextAreaText(): string {
return this.getTextareaElem().val() as string;
}
private _getTextareaElem(): JQuery<HTMLTextAreaElement> {
private getTextareaElem(): JQuery<HTMLTextAreaElement> {
return this._containerElem.find('textarea');
}
private _positionCursor(textareaElem: JQuery<HTMLTextAreaElement>, selectText: boolean) {
private positionCursor(textareaElem: JQuery<HTMLTextAreaElement>, selectText: boolean) {
textareaElem.focus();
const { length } = this._getTextAreaText();
const { length } = this.getTextAreaText();
if (selectText) {
// Mark text as selected ...
textareaElem[0].setSelectionRange(0, length);
@ -244,7 +244,7 @@ class EditorComponent extends Events {
close(update: boolean): void {
if (update) {
this._updateModel();
this.updateModel();
}
// Remove it form the screen ...
this._containerElem.remove();
@ -268,7 +268,7 @@ class MultitTextEditor {
return this.component !== null;
}
show(topic: Topic, defaultText: string): void {
show(topic: Topic, textOverwrite?: string): void {
// Is it active ?
if (this.component) {
console.error('Editor was already displayed. Please, clouse it');
@ -276,7 +276,7 @@ class MultitTextEditor {
}
// Create a new instance
this.component = new EditorComponent(topic);
this.component.show(defaultText);
this.component.show(textOverwrite);
}
close(update: boolean): void {

View File

@ -1,3 +1,4 @@
/* eslint-disable no-bitwise */
/*
* Copyright [2021] [wisemapping]
*
@ -31,9 +32,6 @@ class ShirinkConnector {
const ellipse = new Elipse(TopicConfig.INNER_RECT_ATTRIBUTES);
this._ellipse = ellipse;
const color = topic.getConnectionColor();
ellipse.setFill(color);
ellipse.setSize(TopicConfig.CONNECTOR_WIDTH, TopicConfig.CONNECTOR_WIDTH);
ellipse.addEvent('click', (event: Event) => {
const model = topic.getModel();
@ -79,6 +77,38 @@ class ShirinkConnector {
this._isShrink = isShrink;
}
setColor(color: string) {
this._ellipse.setStroke('1', 'solid', color);
this._ellipse.setFill(this.lightenColor(color, 100));
}
private lightenColor(col: string, amt: number): string {
let usePound = false;
if (col[0] === '#') {
col = col.slice(1);
usePound = true;
}
const num = parseInt(col, 16);
let r = (num >> 16) + amt;
if (r > 255) r = 255;
else if (r < 0) r = 0;
let b = ((num >> 8) & 0x00ff) + amt;
if (b > 255) b = 255;
else if (b < 0) b = 0;
let g = (num & 0x0000ff) + amt;
if (g > 255) g = 255;
else if (g < 0) g = 0;
return (usePound ? '#' : '') + (g | (b << 8) | (r << 16)).toString(16);
}
setVisibility(value: boolean, fade = 0): void {
this._ellipse.setVisibility(value, fade);
}
@ -87,11 +117,7 @@ class ShirinkConnector {
this._ellipse.setOpacity(opacity);
}
setFill(color: string): void {
this._ellipse.setFill(color);
}
setAttribute(name: string, value) {
setAttribute(name: string, value: string) {
this._ellipse.setAttribute(name, value);
}

View File

@ -570,11 +570,6 @@ abstract class Topic extends NodeGraph {
const innerShape = this.getInnerShape();
innerShape.setFill(color);
const connector = this.getShrinkConnector();
if (connector) {
connector.setFill(color);
}
if ($defined(updateModel) && updateModel) {
const model = this.getModel();
model.setBackgroundColor(color);
@ -584,15 +579,17 @@ abstract class Topic extends NodeGraph {
getBackgroundColor(): string {
const model = this.getModel();
let result = model.getBackgroundColor();
if (!$defined(result)) {
if (!result) {
result = TopicStyle.defaultBackgroundColor(this);
}
return result;
}
/** */
setBorderColor(color: string): void {
this._setBorderColor(color, true);
// @todo: review this ...
this.getChildren().forEach((t) => t.redraw());
}
private _setBorderColor(color: string, updateModel: boolean): void {
@ -613,8 +610,22 @@ abstract class Topic extends NodeGraph {
getBorderColor(): string {
const model = this.getModel();
let result = model.getBorderColor();
if (!$defined(result)) {
result = TopicStyle.defaultBorderColor(this);
// If the the style is a line, the color is alward the connection one.
if (this.getShapeType() === 'line') {
result = this.getConnectionColor();
}
if (result === undefined) {
const parent = this.getParent();
if (parent) {
result = parent.getBorderColor();
}
}
// If border color has not been defined, use the connection color for the border ...
if (!result) {
result = this.getConnectionColor();
}
return result;
}
@ -753,9 +764,7 @@ abstract class Topic extends NodeGraph {
}
showTextEditor(text: string) {
this._getTopicEventDispatcher().show(this, {
text,
});
this._getTopicEventDispatcher().show(this, text);
}
getNoteValue(): string {
@ -1276,7 +1285,7 @@ abstract class Topic extends NodeGraph {
const connColorChanged = color !== this.getParent()!.getConnectionColor();
if (connColorChanged) {
this._outgoingLine.redraw();
this._connector.setFill(color);
this.getChildren().forEach((t) => t.redraw());
result = true;
}
@ -1316,12 +1325,14 @@ abstract class Topic extends NodeGraph {
textShape.setPosition(padding + iconGroupWith + textIconSpacing, yPosition);
// Has color changed ?
if (this.getShapeType() === 'line') {
const color = this.getConnectionColor();
this.getInnerShape().setStroke(1, 'solid', color);
const borderColor = this.getBorderColor();
this.getInnerShape().setStroke(1, 'solid', borderColor);
// Force the repaint in case that the main topic color has changed.
if (this.getParent() && this.getParent()?.isCentralTopic()) {
if (this.getParent()) {
this._connector.setColor(borderColor);
if (this.getParent()?.isCentralTopic()) {
this._outgoingLine?.redraw();
}
}

View File

@ -15,7 +15,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import Events from './Events';
import Topic from './Topic';
import MultitTextEditor from './MultilineTextEditor';
@ -43,13 +42,11 @@ class TopicEventDispatcher extends Events {
}
}
show(topic: Topic, options?): void {
this.process(TopicEvent.EDIT, topic, options);
show(topic: Topic, textOverwrite?: string): void {
this.process(TopicEvent.EDIT, topic, textOverwrite);
}
process(eventType: string, topic: Topic, options?): void {
$assert(eventType, 'eventType can not be null');
process(eventType: string, topic: Topic, textOverwrite?: string): void {
// Close all previous open editor ....
const editor = MultitTextEditor.getInstance();
if (editor.isActive()) {
@ -59,7 +56,7 @@ class TopicEventDispatcher extends Events {
// Open the new editor ...
const model = topic.getModel();
if (model.getShapeType() !== 'image' && !this._readOnly && eventType === TopicEvent.EDIT) {
editor.show(topic, options ? options.text : '');
editor.show(topic, textOverwrite);
} else {
this.fireEvent(eventType, { model, readOnly: this._readOnly });
}

View File

@ -145,7 +145,10 @@ class FreemindExporter extends Exporter {
const wiseShape: TopicShapeType = mindmapTopic.getShapeType();
if (wiseShape && wiseShape !== 'line') {
freemindNode.setBackgorundColor(this.rgbToHex(mindmapTopic.getBackgroundColor()));
const color = mindmapTopic.getBackgroundColor();
if (color) {
freemindNode.setBackgorundColor(this.rgbToHex(color));
}
}
if (wiseShape) {
@ -242,7 +245,10 @@ class FreemindExporter extends Exporter {
private addEdgeNode(freemainMap: FreeminNode, mindmapTopic: INodeModel): void {
if (mindmapTopic.getBorderColor()) {
const edgeNode: Edge = this.objectFactory.createEdge();
edgeNode.setColor(this.rgbToHex(mindmapTopic.getBorderColor()));
const color = mindmapTopic.getBorderColor();
if (color) {
edgeNode.setColor(this.rgbToHex(color));
}
freemainMap.setArrowlinkOrCloudOrEdge(edgeNode);
}
}

View File

@ -193,7 +193,7 @@ abstract class INodeModel {
return this.getProperty('fontSize') as number;
}
getBorderColor(): string {
getBorderColor(): string | undefined {
return this.getProperty('borderColor') as string;
}
@ -201,11 +201,11 @@ abstract class INodeModel {
this.putProperty('borderColor', color);
}
getBackgroundColor(): string {
getBackgroundColor(): string | undefined {
return this.getProperty('backgroundColor') as string;
}
setBackgroundColor(color: string) {
setBackgroundColor(color: string): void {
this.putProperty('backgroundColor', color);
}

View File

@ -169,11 +169,6 @@ class NodeModel extends INodeModel {
this.setShapeType(shape);
}
const borderColor = value.getBorderColor();
if (borderColor) {
this.setBorderColor(borderColor);
}
const backgroundColor = value.getBackgroundColor();
if (backgroundColor) {
this.setBackgroundColor(backgroundColor);

View File

@ -108,12 +108,12 @@ class XMLSerializerBeta implements XMLMindmapSerializer {
}
const bgColor = topic.getBackgroundColor();
if ($defined(bgColor)) {
if (bgColor) {
parentTopic.setAttribute('bgColor', bgColor);
}
const brColor = topic.getBorderColor();
if ($defined(brColor)) {
if (brColor) {
parentTopic.setAttribute('brColor', brColor);
}

View File

@ -143,7 +143,7 @@ class XMLSerializerTango implements XMLMindmapSerializer {
}
const bgColor = topic.getBackgroundColor();
if ($defined(bgColor)) {
if (bgColor) {
parentTopic.setAttribute('bgColor', bgColor);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB