Migrate TopicFatory to typescript.

This commit is contained in:
Paulo Gustavo Veiga 2023-01-02 17:43:16 -08:00
parent 887c799fc9
commit a8b093b43f
23 changed files with 110 additions and 130 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 98 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: 99 KiB

After

Width:  |  Height:  |  Size: 99 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: 61 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View File

@ -856,10 +856,8 @@ class Designer extends Events {
addIconType(type: 'image' | 'emoji', iconType: string): void {
const topicsIds = this.getModel().filterTopicsIds();
const featureType: FeatureType = type === 'emoji' ? 'eicon' : 'icon';
const featureType: FeatureType = (
type === 'emoji' ? TopicFeatureFactory.EmojiIcon.id : TopicFeatureFactory.SvgIcon.id
) as FeatureType;
if (topicsIds.length > 0) {
this._actionDispatcher.addFeatureToTopic(topicsIds[0], featureType, {
id: iconType,

View File

@ -26,8 +26,6 @@ import Topic from './Topic';
import ActionDispatcher from './ActionDispatcher';
class EmojiCharIcon implements Icon {
private char: string;
private element: ElementClass;
private group: IconGroup;

View File

@ -1,11 +1,12 @@
import { Point, ElementClass } from '@wisemapping/web2d';
import { Point, ElementClass, Group } from '@wisemapping/web2d';
import IconGroup from './IconGroup';
import FeatureModel from './model/FeatureModel';
import SizeType from './SizeType';
interface Icon {
getElement(): ElementClass;
setGroup(group: IconGroup);
setGroup(group: IconGroup): Group;
getGroup(): IconGroup;
@ -13,11 +14,11 @@ interface Icon {
getPosition(): Point;
addEvent(type: string, fnc): void;
addEvent(type: string, fnc: () => void): void;
remove(): void;
getModel();
getModel(): FeatureModel;
}
export default Icon;

View File

@ -22,6 +22,7 @@ import IconGroupRemoveTip from './IconGroupRemoveTip';
import ImageIcon from './ImageIcon';
import SizeType from './SizeType';
import FeatureModel from './model/FeatureModel';
import Icon from './Icon';
const ORDER_BY_TYPE = new Map<string, number>();
ORDER_BY_TYPE.set('icon', 0);
@ -29,7 +30,7 @@ ORDER_BY_TYPE.set('note', 1);
ORDER_BY_TYPE.set('link', 2);
class IconGroup {
private _icons: ImageIcon[];
private _icons: Icon[];
private _group: Group;
@ -84,7 +85,7 @@ class IconGroup {
this._resize(this._icons.length);
}
addIcon(icon: ImageIcon, remove: boolean) {
addIcon(icon: Icon, remove: boolean): void {
$defined(icon, 'icon is not defined');
// Order could have change, need to re-add all.
@ -114,8 +115,8 @@ class IconGroup {
}
}
private _findIconFromModel(iconModel: FeatureModel) {
let result: ImageIcon | null = null;
private _findIconFromModel(iconModel: FeatureModel): Icon {
let result: Icon | null = null;
this._icons.forEach((icon) => {
const elModel = icon.getModel();
@ -140,7 +141,7 @@ class IconGroup {
this._removeIcon(icon);
}
private _removeIcon(icon: ImageIcon) {
private _removeIcon(icon: Icon) {
$assert(icon, 'icon can not be null');
this._removeTip.close(0);
@ -179,7 +180,7 @@ class IconGroup {
this._group.setCoordSize(iconsLength * iconSize, iconSize);
}
private _positionIcon(icon: ImageIcon, order: number) {
private _positionIcon(icon: Icon, order: number) {
const iconSize = ImageIcon.SIZE + IconGroup.ICON_PADDING * 2;
icon
.getElement()

View File

@ -23,9 +23,9 @@ import FeatureModel from './model/FeatureModel';
import Icon from './Icon';
abstract class ImageIcon implements Icon {
protected _image: Image;
private _image: Image;
protected _group: IconGroup;
private _group: IconGroup;
constructor(url: string) {
$assert(url, 'image url can not be null');

View File

@ -43,7 +43,7 @@ class LinkIcon extends ImageIcon {
}
private _registerEvents() {
this._image.setCursor('pointer');
this.getElement().setCursor('pointer');
const manager = WidgetManager.getInstance();
manager.createTooltipForLink(this._topic, this._linksModel as LinkModel, this);

View File

@ -42,7 +42,7 @@ class NoteIcon extends ImageIcon {
}
private _registerEvents(): void {
this._image.setCursor('pointer');
this.getElement().setCursor('pointer');
const manager = WidgetManager.getInstance();
manager.createTooltipForNote(this._topic, this._linksModel as NoteModel, this);

View File

@ -19,6 +19,8 @@ import { $assert } from '@wisemapping/core-js';
import ImageIcon from './ImageIcon';
import ActionDispatcher from './ActionDispatcher';
import iconFamily from './model/SvgIconFamily.json';
import Topic from './Topic';
import SvgIconModel from './model/SvgIconModel';
function importAll(r) {
const images = {};
@ -28,10 +30,16 @@ function importAll(r) {
return images;
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const images = importAll(require.context('../../assets/icons', false, /\.(png|svg)$/));
class SvgImageIcon extends ImageIcon {
constructor(topic, iconModel, readOnly) {
private _topicId: number;
private _featureModel: SvgIconModel;
constructor(topic: Topic, iconModel: SvgIconModel, readOnly: boolean) {
$assert(iconModel, 'iconModel can not be null');
$assert(topic, 'topic can not be null');
@ -52,13 +60,13 @@ class SvgImageIcon extends ImageIcon {
const newIconType = SvgImageIcon._getNextFamilyIconId(iconTypeClick);
iconModel.setIconType(newIconType);
me._image.setHref(SvgImageIcon.getImageUrl(newIconType));
me.getElement().setHref(SvgImageIcon.getImageUrl(newIconType));
});
this._image.setCursor('pointer');
this.getElement().setCursor('pointer');
}
}
static getImageUrl(iconId) {
static getImageUrl(iconId: string) {
let result = images[`${iconId}.svg`];
if (!result) {
result = images[`${iconId}.png`];
@ -70,11 +78,11 @@ class SvgImageIcon extends ImageIcon {
return this._featureModel;
}
static _getNextFamilyIconId(iconId) {
private static _getNextFamilyIconId(iconId: string): string {
const familyIcons = SvgImageIcon._getFamilyIcons(iconId);
$assert(familyIcons !== null, `Family Icon not found: ${iconId}`);
let result = null;
let result: string | null = null;
for (let i = 0; i < familyIcons.length && result == null; i++) {
if (familyIcons[i] === iconId) {
// Is last one?
@ -87,28 +95,18 @@ class SvgImageIcon extends ImageIcon {
}
}
if (!result) {
throw new Error(`Could not find iconId ${iconId}`);
}
return result;
}
static _getNextUnicode(iconId) {
let result = null;
for (let i = 0; i < iconFamily.length; i++) {
const family = iconFamily[i];
const iconFamilyId = iconId.substr(0, iconId.indexOf('_'));
if (family.id === iconFamilyId) {
result = family.icons;
break;
}
}
return result;
}
static _getFamilyIcons(iconId) {
private static _getFamilyIcons(iconId: string): string[] {
$assert(iconId != null, 'id must not be null');
$assert(iconId.indexOf('_') !== -1, `Invalid icon id (it must contain '_'). Id: ${iconId}`);
let result = null;
let result: string[] | null = null;
for (let i = 0; i < iconFamily.length; i++) {
const family = iconFamily[i];
const iconFamilyId = iconId.substr(0, iconId.indexOf('_'));
@ -118,6 +116,11 @@ class SvgImageIcon extends ImageIcon {
break;
}
}
if (!result) {
throw new Error(`Could not find icon id ${iconId}`);
}
return result;
}

View File

@ -39,11 +39,11 @@ import NoteModel from './model/NoteModel';
import LinkModel from './model/LinkModel';
import SizeType from './SizeType';
import FeatureModel from './model/FeatureModel';
import ImageIcon from './ImageIcon';
import PositionType from './PositionType';
import LineTopicShape from './widget/LineTopicShape';
import ImageTopicShape from './widget/ImageTopicShape';
import ColorUtil from './render/ColorUtil';
import Icon from './Icon';
const ICON_SCALING_FACTOR = 1.3;
@ -305,20 +305,19 @@ abstract class Topic extends NodeGraph {
// Load topic features ...
const model = this.getModel();
const featuresModel = model.getFeatures();
featuresModel.forEach((f) => {
const icon = TopicFeatureFactory.createIcon(this, f, this.isReadOnly());
const type = f.getType();
const addRemoveAction =
type === TopicFeatureFactory.SvgIcon.id || type === TopicFeatureFactory.EmojiIcon.id;
const addRemoveAction = type === 'eicon' || type === 'icon';
result.addIcon(icon, addRemoveAction && !this.isReadOnly());
});
return result;
}
addFeature(featureModel: FeatureModel): ImageIcon {
addFeature(featureModel: FeatureModel): Icon {
const iconGroup = this.getOrBuildIconGroup();
this.closeEditors();
@ -326,10 +325,8 @@ abstract class Topic extends NodeGraph {
const model = this.getModel();
model.addFeature(featureModel);
const result: ImageIcon = TopicFeatureFactory.createIcon(this, featureModel, this.isReadOnly());
const isIcon =
featureModel.getType() === TopicFeatureFactory.SvgIcon.id ||
featureModel.getType() === TopicFeatureFactory.EmojiIcon.id;
const result: Icon = TopicFeatureFactory.createIcon(this, featureModel, this.isReadOnly());
const isIcon = featureModel.getType() === 'icon' || featureModel.getType() === 'eicon';
iconGroup.addIcon(result, isIcon && !this.isReadOnly());
this.redraw();
@ -697,7 +694,7 @@ abstract class Topic extends NodeGraph {
getNoteValue(): string {
const model = this.getModel();
const notes = model.findFeatureByType(TopicFeatureFactory.Note.id);
const notes = model.findFeatureByType('note');
let result;
if (notes.length > 0) {
result = (notes[0] as NoteModel).getText();
@ -710,7 +707,7 @@ abstract class Topic extends NodeGraph {
const topicId = this.getId();
const model = this.getModel();
const dispatcher = ActionDispatcher.getInstance();
const notes = model.findFeatureByType(TopicFeatureFactory.Note.id);
const notes = model.findFeatureByType('note');
if (!$defined(value) && notes.length > 0) {
const featureId = notes[0].getId();
@ -720,7 +717,7 @@ abstract class Topic extends NodeGraph {
text: value,
});
} else {
dispatcher.addFeatureToTopic(topicId, TopicFeatureFactory.Note.id, {
dispatcher.addFeatureToTopic(topicId, 'note', {
text: value,
});
}
@ -729,7 +726,7 @@ abstract class Topic extends NodeGraph {
getLinkValue(): string {
const model = this.getModel();
// @param {mindplot.model.LinkModel[]} links
const links = model.findFeatureByType(TopicFeatureFactory.Link.id);
const links = model.findFeatureByType('link');
let result;
if (links.length > 0) {
result = (links[0] as LinkModel).getUrl();
@ -742,7 +739,7 @@ abstract class Topic extends NodeGraph {
const topicId = this.getId();
const model = this.getModel();
const dispatcher = ActionDispatcher.getInstance();
const links = model.findFeatureByType(TopicFeatureFactory.Link.id);
const links = model.findFeatureByType('link');
if (!$defined(value)) {
const featureId = links[0].getId();
@ -752,7 +749,7 @@ abstract class Topic extends NodeGraph {
url: value,
});
} else {
dispatcher.addFeatureToTopic(topicId, TopicFeatureFactory.Link.id, {
dispatcher.addFeatureToTopic(topicId, 'link', {
url: value,
});
}

View File

@ -1,75 +0,0 @@
/*
* Copyright [2021] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import EmojiCharIcon from './EmojiCharIcon';
import SvgImageIcon from './SvgImageIcon';
import LinkIcon from './LinkIcon';
import NoteIcon from './NoteIcon';
const TopicFeatureFactory = {
/** the icon object */
SvgIcon: {
id: 'icon',
icon: SvgImageIcon,
},
EmojiIcon: {
id: 'eicon',
icon: EmojiCharIcon,
},
/** the link object */
Link: {
id: 'link',
icon: LinkIcon,
},
/** the note object */
Note: {
id: 'note',
icon: NoteIcon,
},
createIcon(topic, model, readOnly) {
$assert(topic, 'topic can not be null');
$assert(model, 'model can not be null');
const { icon: Icon } = TopicFeatureFactory._featuresMetadataById.filter(
(elem) => elem.id === model.getType(),
)[0];
// Temporal catch to idenfify bug. Please, remove.
let result;
try {
result = new Icon(topic, model, readOnly);
} catch (e) {
throw new Error(`${e} - ${JSON.stringify(model)}`);
}
return result;
},
};
TopicFeatureFactory._featuresMetadataById = [
TopicFeatureFactory.SvgIcon,
TopicFeatureFactory.EmojiIcon,
TopicFeatureFactory.Link,
TopicFeatureFactory.Note,
];
export default TopicFeatureFactory;

View File

@ -0,0 +1,57 @@
/*
* Copyright [2021] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import EmojiCharIcon from './EmojiCharIcon';
import SvgImageIcon from './SvgImageIcon';
import LinkIcon from './LinkIcon';
import NoteIcon from './NoteIcon';
import FeatureModel from './model/FeatureModel';
import Topic from './Topic';
import SvgIconModel from './model/SvgIconModel';
import LinkModel from './model/LinkModel';
import NoteModel from './model/NoteModel';
import Icon from './Icon';
import EmojiIconModel from './model/EmojiIconModel';
class TopicFeatureFactory {
static createIcon(topic: Topic, model: FeatureModel, readOnly: boolean): Icon {
let result: Icon;
const featureType = model.getType();
switch (featureType) {
case 'icon':
result = new SvgImageIcon(topic, model as SvgIconModel, readOnly);
break;
case 'eicon':
result = new EmojiCharIcon(topic, model as EmojiIconModel, readOnly);
break;
case 'link':
result = new LinkIcon(topic, model as LinkModel, readOnly);
break;
case 'note':
result = new NoteIcon(topic, model as NoteModel, readOnly);
break;
default: {
const exhaustiveCheck: never = featureType;
throw new Error(`Unhandled feature type case: ${exhaustiveCheck}`);
}
}
return result;
}
}
export default TopicFeatureFactory;