mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-12-03 10:54:58 +01:00
Add string validation
This commit is contained in:
parent
1cf42269b7
commit
0194407c7c
@ -1,7 +1,7 @@
|
||||
version: '3'
|
||||
services:
|
||||
e2e:
|
||||
image: cypress/included:12.3.0
|
||||
image: cypress/included:12.2.0
|
||||
container_name: wisemapping-integration-tests
|
||||
entrypoint: '/bin/sh -c "yarn install && yarn build && yarn test:integration"'
|
||||
working_dir: /e2e
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"baseUrl": "."
|
||||
"module": "ES6",
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
"src/**/*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": false,
|
||||
@ -13,8 +13,8 @@
|
||||
"target": "es6",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"strictNullChecks": false,
|
||||
"declaration": true,
|
||||
"rootDirs": [
|
||||
"src",
|
||||
],
|
||||
|
@ -35,8 +35,6 @@ class ConnectionLine {
|
||||
|
||||
protected _sourceTopic: Topic;
|
||||
|
||||
protected _lineType: LineType;
|
||||
|
||||
protected _line: Line;
|
||||
|
||||
private _type: LineType;
|
||||
@ -50,7 +48,7 @@ class ConnectionLine {
|
||||
this._sourceTopic = sourceNode;
|
||||
this._type = type;
|
||||
this._line = this.createLine(type);
|
||||
this.updateColor();
|
||||
this._color = this.updateColor();
|
||||
}
|
||||
|
||||
private _getCtrlPoints(sourceNode: Topic, targetNode: Topic) {
|
||||
@ -64,7 +62,6 @@ class ConnectionLine {
|
||||
}
|
||||
|
||||
protected createLine(lineType: LineType): ConnectionLine {
|
||||
this._lineType = lineType;
|
||||
let line: ConnectionLine;
|
||||
switch (lineType) {
|
||||
case LineType.POLYLINE_MIDDLE:
|
||||
@ -88,7 +85,7 @@ class ConnectionLine {
|
||||
return line;
|
||||
}
|
||||
|
||||
private updateColor(): void {
|
||||
private updateColor(): string {
|
||||
// In case that the main topic has changed the color, overwrite the main topic definiton.
|
||||
let color = this._targetTopic.getConnectionColor();
|
||||
if (this._targetTopic.isCentralTopic()) {
|
||||
@ -96,7 +93,7 @@ class ConnectionLine {
|
||||
}
|
||||
|
||||
this._color = color;
|
||||
switch (this._lineType) {
|
||||
switch (this._type) {
|
||||
case LineType.POLYLINE_MIDDLE:
|
||||
this._line.setStroke(1, 'solid', color, 1);
|
||||
break;
|
||||
@ -112,8 +109,9 @@ class ConnectionLine {
|
||||
this._line.setFill(color, 1);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unexpected line type. ${this._lineType}`);
|
||||
throw new Error(`Unexpected line type. ${this._type}`);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
setVisibility(value: boolean, fade = 0): void {
|
||||
@ -207,7 +205,7 @@ class ConnectionLine {
|
||||
}
|
||||
|
||||
getLineType(): number {
|
||||
return this._lineType;
|
||||
return this._type;
|
||||
}
|
||||
|
||||
getLine(): Line {
|
||||
|
@ -58,7 +58,7 @@ import { TopicShapeType } from './model/INodeModel';
|
||||
import { LineType } from './ConnectionLine';
|
||||
|
||||
class Designer extends Events {
|
||||
private _mindmap: Mindmap;
|
||||
private _mindmap: Mindmap | null;
|
||||
|
||||
private _options: DesignerOptions;
|
||||
|
||||
@ -70,13 +70,13 @@ class Designer extends Events {
|
||||
|
||||
_eventBussDispatcher: EventBusDispatcher;
|
||||
|
||||
private _dragManager: DragManager;
|
||||
private _dragManager!: DragManager;
|
||||
|
||||
private _relPivot: RelationshipPivot;
|
||||
|
||||
private _clipboard: NodeModel[];
|
||||
|
||||
private _cleanScreen: () => void;
|
||||
private _cleanScreen!: () => void;
|
||||
|
||||
constructor(options: DesignerOptions, divElement: JQuery) {
|
||||
super();
|
||||
@ -133,6 +133,7 @@ class Designer extends Events {
|
||||
|
||||
// Hack: There are static reference to designer variable. Needs to be reviewed.
|
||||
globalThis.designer = this;
|
||||
this._mindmap = null;
|
||||
}
|
||||
|
||||
private _registerWheelEvents(): void {
|
||||
@ -539,7 +540,6 @@ class Designer extends Events {
|
||||
}
|
||||
|
||||
loadMap(mindmap: Mindmap): Promise<void> {
|
||||
$assert(mindmap, 'mindmapModel can not be null');
|
||||
this._mindmap = mindmap;
|
||||
|
||||
this._workspace.enableQueueRender(true);
|
||||
@ -587,7 +587,7 @@ class Designer extends Events {
|
||||
}
|
||||
|
||||
getMindmap(): Mindmap {
|
||||
return this._mindmap;
|
||||
return this._mindmap!;
|
||||
}
|
||||
|
||||
undo(): void {
|
||||
|
@ -16,7 +16,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Text, Group, ElementClass, Point } from '@wisemapping/web2d';
|
||||
import { $assert } from '@wisemapping/core-js';
|
||||
|
||||
import Icon from './Icon';
|
||||
import IconGroup from './IconGroup';
|
||||
@ -28,17 +27,15 @@ import ActionDispatcher from './ActionDispatcher';
|
||||
class EmojiCharIcon implements Icon {
|
||||
private element: ElementClass;
|
||||
|
||||
private group: IconGroup;
|
||||
private _group: IconGroup | null;
|
||||
|
||||
private iconModel: SvgIconModel;
|
||||
private _iconModel: SvgIconModel;
|
||||
|
||||
private topic: Topic;
|
||||
private _topic: Topic;
|
||||
|
||||
constructor(topic: Topic, iconModel: SvgIconModel, readOnly: boolean) {
|
||||
$assert(iconModel, 'iconModel can not be null');
|
||||
$assert(topic, 'topic can not be null');
|
||||
this.iconModel = iconModel;
|
||||
this.topic = topic;
|
||||
this._iconModel = iconModel;
|
||||
this._topic = topic;
|
||||
|
||||
this.element = new Group({
|
||||
width: 90,
|
||||
@ -57,6 +54,7 @@ class EmojiCharIcon implements Icon {
|
||||
if (!readOnly) {
|
||||
this.element.setCursor('pointer');
|
||||
}
|
||||
this._group = null;
|
||||
}
|
||||
|
||||
getElement(): ElementClass {
|
||||
@ -64,19 +62,19 @@ class EmojiCharIcon implements Icon {
|
||||
}
|
||||
|
||||
setGroup(group: IconGroup) {
|
||||
this.group = group;
|
||||
this._group = group;
|
||||
}
|
||||
|
||||
getGroup(): IconGroup {
|
||||
return this.group;
|
||||
return this._group!;
|
||||
}
|
||||
|
||||
getSize(): SizeType {
|
||||
return this.group.getSize();
|
||||
return this._group!.getSize();
|
||||
}
|
||||
|
||||
getPosition(): Point {
|
||||
return this.group.getPosition();
|
||||
return this._group!.getPosition();
|
||||
}
|
||||
|
||||
addEvent(type: string, fnc: (e: object) => void): void {
|
||||
@ -85,12 +83,12 @@ class EmojiCharIcon implements Icon {
|
||||
|
||||
remove() {
|
||||
const actionDispatcher = ActionDispatcher.getInstance();
|
||||
const featureId = this.iconModel.getId();
|
||||
actionDispatcher.removeFeatureFromTopic(this.topic.getId(), featureId);
|
||||
const featureId = this._iconModel.getId();
|
||||
actionDispatcher.removeFeatureFromTopic(this._topic.getId(), featureId);
|
||||
}
|
||||
|
||||
getModel(): SvgIconModel {
|
||||
return this.iconModel;
|
||||
return this._iconModel;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ interface Icon {
|
||||
|
||||
setGroup(group: IconGroup): Group;
|
||||
|
||||
getGroup(): IconGroup;
|
||||
getGroup(): IconGroup | null;
|
||||
|
||||
getSize(): SizeType;
|
||||
|
||||
|
@ -36,14 +36,11 @@ class IconGroup {
|
||||
|
||||
private _removeTip: IconGroupRemoveTip;
|
||||
|
||||
private _iconSize: SizeType;
|
||||
private _iconSize: SizeType | null;
|
||||
|
||||
private _topicId: number;
|
||||
|
||||
constructor(topicId: number, iconSize: number) {
|
||||
$assert($defined(topicId), 'topicId can not be null');
|
||||
$assert($defined(iconSize), 'iconSize can not be null');
|
||||
|
||||
this._topicId = topicId;
|
||||
this._icons = [];
|
||||
this._group = new Group({
|
||||
@ -57,6 +54,7 @@ class IconGroup {
|
||||
this._removeTip = new IconGroupRemoveTip(this._group);
|
||||
this.seIconSize(iconSize, iconSize);
|
||||
this._registerListeners();
|
||||
this._iconSize = null;
|
||||
}
|
||||
|
||||
setPosition(x: number, y: number): void {
|
||||
@ -142,8 +140,6 @@ class IconGroup {
|
||||
}
|
||||
|
||||
private _removeIcon(icon: Icon) {
|
||||
$assert(icon, 'icon can not be null');
|
||||
|
||||
this._removeTip.close(0);
|
||||
this._group.removeChild(icon.getElement());
|
||||
|
||||
@ -174,10 +170,12 @@ class IconGroup {
|
||||
}
|
||||
|
||||
private _resize(iconsLength: number) {
|
||||
this._group.setSize(iconsLength * this._iconSize.width, this._iconSize.height);
|
||||
if (this._iconSize) {
|
||||
this._group.setSize(iconsLength * this._iconSize.width, this._iconSize.height);
|
||||
|
||||
const iconSize = ImageIcon.SIZE + IconGroup.ICON_PADDING * 2;
|
||||
this._group.setCoordSize(iconsLength * iconSize, iconSize);
|
||||
const iconSize = ImageIcon.SIZE + IconGroup.ICON_PADDING * 2;
|
||||
this._group.setCoordSize(iconsLength * iconSize, iconSize);
|
||||
}
|
||||
}
|
||||
|
||||
private _positionIcon(icon: Icon, order: number) {
|
||||
|
@ -14,6 +14,7 @@ class IconGroupRemoveTip {
|
||||
constructor(group: Group) {
|
||||
$assert(group, 'group can not be null');
|
||||
this._group = group;
|
||||
this._activeIcon = null;
|
||||
}
|
||||
|
||||
show(topicId: number, icon: ImageIcon) {
|
||||
|
@ -25,13 +25,14 @@ import Icon from './Icon';
|
||||
abstract class ImageIcon implements Icon {
|
||||
private _image: Image;
|
||||
|
||||
private _group: IconGroup;
|
||||
private _group: IconGroup | null;
|
||||
|
||||
constructor(url: string) {
|
||||
$assert(url, 'image url can not be null');
|
||||
this._image = new Image();
|
||||
this._image.setHref(url);
|
||||
this._image.setSize(ImageIcon.SIZE, ImageIcon.SIZE);
|
||||
this._group = null;
|
||||
}
|
||||
|
||||
getElement(): ElementClass {
|
||||
@ -42,7 +43,7 @@ abstract class ImageIcon implements Icon {
|
||||
this._group = group;
|
||||
}
|
||||
|
||||
getGroup(): IconGroup {
|
||||
getGroup(): IconGroup | null {
|
||||
return this._group;
|
||||
}
|
||||
|
||||
|
@ -43,9 +43,9 @@ export type MindplotWebComponentInterface = {
|
||||
class MindplotWebComponent extends HTMLElement {
|
||||
private _shadowRoot: ShadowRoot;
|
||||
|
||||
private _designer: Designer;
|
||||
private _designer: Designer | null;
|
||||
|
||||
private saveRequired: boolean;
|
||||
private _saveRequired: boolean;
|
||||
|
||||
private _isLoaded: boolean;
|
||||
|
||||
@ -62,12 +62,15 @@ class MindplotWebComponent extends HTMLElement {
|
||||
wrapper.setAttribute('id', 'mindplot');
|
||||
|
||||
this._shadowRoot.appendChild(wrapper);
|
||||
this._isLoaded = false;
|
||||
this._saveRequired = false;
|
||||
this._designer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the designer
|
||||
*/
|
||||
getDesigner(): Designer {
|
||||
getDesigner(): Designer | null {
|
||||
return this._designer;
|
||||
}
|
||||
|
||||
@ -124,24 +127,24 @@ class MindplotWebComponent extends HTMLElement {
|
||||
}
|
||||
|
||||
setSaveRequired(value: boolean) {
|
||||
this.saveRequired = value;
|
||||
this._saveRequired = value;
|
||||
}
|
||||
|
||||
getSaveRequired() {
|
||||
return this.saveRequired;
|
||||
return this._saveRequired;
|
||||
}
|
||||
|
||||
loadMap(id: string): Promise<void> {
|
||||
const instance = PersistenceManager.getInstance();
|
||||
return instance.load(id).then((mindmap) => this._designer.loadMap(mindmap));
|
||||
return instance.load(id).then((mindmap) => this._designer!.loadMap(mindmap));
|
||||
}
|
||||
|
||||
save(saveHistory: boolean) {
|
||||
if (!saveHistory && !this.getSaveRequired()) return;
|
||||
console.log('Saving...');
|
||||
// Load map content ...
|
||||
const mindmap = this._designer.getMindmap();
|
||||
const mindmapProp = this._designer.getMindmapProperties();
|
||||
const mindmap = this._designer!.getMindmap();
|
||||
const mindmapProp = this._designer!.getMindmapProperties();
|
||||
|
||||
// Display save message ..
|
||||
if (saveHistory) {
|
||||
@ -166,7 +169,7 @@ class MindplotWebComponent extends HTMLElement {
|
||||
}
|
||||
|
||||
unlockMap() {
|
||||
const mindmap = this._designer.getMindmap();
|
||||
const mindmap = this._designer!.getMindmap();
|
||||
const persistenceManager = PersistenceManager.getInstance();
|
||||
|
||||
// If the map could not be loaded, partial map load could happen.
|
||||
|
@ -256,31 +256,35 @@ class MultitTextEditor {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance: MultitTextEditor = new MultitTextEditor();
|
||||
|
||||
private component: EditorComponent | null;
|
||||
private _component: EditorComponent | null;
|
||||
|
||||
constructor() {
|
||||
this._component = null;
|
||||
}
|
||||
|
||||
static getInstance(): MultitTextEditor {
|
||||
return MultitTextEditor.instance;
|
||||
}
|
||||
|
||||
isActive(): boolean {
|
||||
return this.component !== null;
|
||||
return this._component !== null;
|
||||
}
|
||||
|
||||
show(topic: Topic, textOverwrite?: string): void {
|
||||
// Is it active ?
|
||||
if (this.component) {
|
||||
if (this._component) {
|
||||
console.error('Editor was already displayed. Please, clouse it');
|
||||
this.component.close(false);
|
||||
this._component.close(false);
|
||||
}
|
||||
// Create a new instance
|
||||
this.component = new EditorComponent(topic);
|
||||
this.component.show(textOverwrite);
|
||||
this._component = new EditorComponent(topic);
|
||||
this._component.show(textOverwrite);
|
||||
}
|
||||
|
||||
close(update: boolean): void {
|
||||
if (this.component) {
|
||||
this.component.close(update);
|
||||
this.component = null;
|
||||
if (this._component) {
|
||||
this._component.close(update);
|
||||
this._component = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ abstract class NodeGraph {
|
||||
|
||||
this._options = options;
|
||||
this._mouseEvents = true;
|
||||
this.setModel(nodeModel);
|
||||
this._model = nodeModel;
|
||||
this._onFocus = false;
|
||||
this._size = { width: 50, height: 20 };
|
||||
}
|
||||
@ -70,7 +70,6 @@ abstract class NodeGraph {
|
||||
}
|
||||
|
||||
get2DElement(): ElementClass {
|
||||
$assert(this._elem2d, 'NodeGraph has not been initialized properly');
|
||||
return this._elem2d;
|
||||
}
|
||||
|
||||
@ -118,7 +117,7 @@ abstract class NodeGraph {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
setModel(model: NodeModel) {
|
||||
setModel(model: NodeModel): void {
|
||||
$assert(model, 'Model can not be null');
|
||||
this._model = model;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ class ControlPivotLine {
|
||||
|
||||
private _pivotType: PivotType;
|
||||
|
||||
private _workspace: Workspace;
|
||||
private _workspace: Workspace | null;
|
||||
|
||||
private _relationship: Relationship;
|
||||
|
||||
@ -93,6 +93,9 @@ class ControlPivotLine {
|
||||
this._mouseMoveHandler = (e: MouseEvent) => this.mouseMoveHandler(e);
|
||||
this._mouseUpHandler = () => this.mouseUpHandler();
|
||||
this._mouseDownHandler = (event: MouseEvent) => this.mouseDownHandler(event);
|
||||
|
||||
this._isVisible = false;
|
||||
this._workspace = null;
|
||||
}
|
||||
|
||||
private mouseDownHandler(event: MouseEvent) {
|
||||
@ -153,7 +156,7 @@ class ControlPivotLine {
|
||||
}
|
||||
|
||||
private mouseMoveHandler(event: MouseEvent) {
|
||||
const screen = this._workspace.getScreenManager();
|
||||
const screen = this._workspace!.getScreenManager();
|
||||
const mousePosition = screen.getWorkspaceMousePosition(event);
|
||||
|
||||
// Update relatioship position ...
|
||||
@ -213,8 +216,6 @@ class RelationshipControlPoints {
|
||||
|
||||
private _relationship: Relationship;
|
||||
|
||||
private _relationshipLinePositions: [PositionType, PositionType];
|
||||
|
||||
constructor(relationship: Relationship) {
|
||||
this._relationship = relationship;
|
||||
const startControlLine = new ControlPivotLine(
|
||||
@ -278,10 +279,6 @@ class RelationshipControlPoints {
|
||||
getControlPointPosition(pivotType: PivotType): PositionType {
|
||||
return this._pivotLines[pivotType].getPosition();
|
||||
}
|
||||
|
||||
getRelationshipPosition(index: number): PositionType {
|
||||
return { ...this._relationshipLinePositions[index] };
|
||||
}
|
||||
}
|
||||
|
||||
export default RelationshipControlPoints;
|
||||
|
@ -32,7 +32,7 @@ class RelationshipPivot {
|
||||
|
||||
private _onClickEvent: (event: MouseEvent) => void;
|
||||
|
||||
private _onTopicClick: (event: MouseEvent) => void;
|
||||
private _onTopicClick: (event: MouseEvent, targetTopic: Topic) => void;
|
||||
|
||||
private _sourceTopic: Topic | null;
|
||||
|
||||
@ -49,6 +49,7 @@ class RelationshipPivot {
|
||||
this._mouseMoveEvent = this.mouseMoveHandler.bind(this);
|
||||
this._onClickEvent = this.cleanOnMouseClick.bind(this);
|
||||
this._onTopicClick = this._connectOnFocus.bind(this);
|
||||
this._sourceTopic = null;
|
||||
}
|
||||
|
||||
start(sourceTopic: Topic, targetPos: Point) {
|
||||
@ -156,7 +157,7 @@ class RelationshipPivot {
|
||||
return Shape.calculateRelationShipPointCoordinates(sourceTopic, point);
|
||||
}
|
||||
|
||||
private _connectOnFocus(event: string, targetTopic: Topic): void {
|
||||
private _connectOnFocus(event: MouseEvent, targetTopic: Topic): void {
|
||||
const sourceTopic = this._sourceTopic;
|
||||
const mindmap = this._designer.getMindmap();
|
||||
|
||||
|
@ -39,6 +39,7 @@ class RESTPersistenceManager extends PersistenceManager {
|
||||
this.documentUrl = options.documentUrl;
|
||||
this.revertUrl = options.revertUrl;
|
||||
this.lockUrl = options.lockUrl;
|
||||
this.onSave = false;
|
||||
}
|
||||
|
||||
saveMapXml(mapId: string, mapXml: Document, pref: string, saveHistory: boolean, events): void {
|
||||
|
@ -52,6 +52,7 @@ class ScreenManager {
|
||||
event.preventDefault();
|
||||
},
|
||||
);
|
||||
this._scale = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,7 +66,6 @@ class ScreenManager {
|
||||
}
|
||||
|
||||
setScale(scale: number) {
|
||||
$assert(scale, 'Screen scale can not be null');
|
||||
this._scale = scale;
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,6 @@ class StandaloneActionDispatcher extends ActionDispatcher {
|
||||
this.execute(command);
|
||||
}
|
||||
|
||||
/** */
|
||||
changeBackgroundColorToTopic(topicsIds: number[], color: string | undefined) {
|
||||
const commandFunc = (topic: Topic, value: string | undefined) => {
|
||||
const result = topic.getBackgroundColor();
|
||||
|
@ -67,11 +67,11 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
private _text: Text | null;
|
||||
|
||||
private _iconsGroup: IconGroup;
|
||||
private _iconsGroup!: IconGroup;
|
||||
|
||||
private _connector: ShirinkConnector;
|
||||
private _connector!: ShirinkConnector;
|
||||
|
||||
private _outgoingLine: ConnectionLine | null;
|
||||
private _outgoingLine!: ConnectionLine | null;
|
||||
|
||||
constructor(model: NodeModel, options: NodeOption) {
|
||||
super(model, options);
|
||||
@ -83,7 +83,7 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
// Position a topic ....
|
||||
const pos = model.getPosition();
|
||||
if (pos != null && this.isCentralTopic()) {
|
||||
if (pos && this.isCentralTopic()) {
|
||||
this.setPosition(pos);
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
protected redrawShapeType() {
|
||||
const oldInnerShape = this.getInnerShape();
|
||||
if (oldInnerShape != null) {
|
||||
if (oldInnerShape) {
|
||||
this._removeInnerShape();
|
||||
|
||||
// Create a new one ...
|
||||
@ -208,7 +208,7 @@ abstract class Topic extends NodeGraph {
|
||||
}
|
||||
|
||||
getInnerShape(): ElementClass {
|
||||
if (!$defined(this._innerShape)) {
|
||||
if (!this._innerShape) {
|
||||
// Create inner box.
|
||||
this._innerShape = this._buildShape(TopicConfig.INNER_RECT_ATTRIBUTES, this.getShapeType());
|
||||
|
||||
@ -285,16 +285,17 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
private getOrBuildIconGroup(): Group {
|
||||
if (!this._iconsGroup) {
|
||||
this._iconsGroup = this._buildIconGroup();
|
||||
const iconGroup = this._buildIconGroup();
|
||||
const group = this.get2DElement();
|
||||
|
||||
group.append(this._iconsGroup.getNativeElement());
|
||||
this._iconsGroup.moveToFront();
|
||||
group.append(iconGroup.getNativeElement());
|
||||
iconGroup.moveToFront();
|
||||
this._iconsGroup = iconGroup;
|
||||
}
|
||||
return this._iconsGroup;
|
||||
}
|
||||
|
||||
private getIconGroup(): IconGroup {
|
||||
private getIconGroup(): IconGroup | null {
|
||||
return this._iconsGroup;
|
||||
}
|
||||
|
||||
@ -351,7 +352,7 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
// Removing the icon from UI
|
||||
const iconGroup = this.getIconGroup();
|
||||
if ($defined(iconGroup)) {
|
||||
if (iconGroup) {
|
||||
iconGroup.removeIconByModel(featureModel);
|
||||
}
|
||||
this.redraw();
|
||||
@ -837,7 +838,7 @@ abstract class Topic extends NodeGraph {
|
||||
setBranchVisibility(value: boolean): void {
|
||||
let current: Topic = this;
|
||||
let parent: Topic | null = this;
|
||||
while (parent != null && !parent.isCentralTopic()) {
|
||||
while (parent && !parent.isCentralTopic()) {
|
||||
current = parent;
|
||||
parent = current.getParent();
|
||||
}
|
||||
@ -896,8 +897,8 @@ abstract class Topic extends NodeGraph {
|
||||
const sourceParent = sourceTopic.getModel().getParent();
|
||||
relationship.setVisibility(
|
||||
value &&
|
||||
(targetParent == null || !targetParent.areChildrenShrunken()) &&
|
||||
(sourceParent == null || !sourceParent.areChildrenShrunken()),
|
||||
(!targetParent || !targetParent.areChildrenShrunken()) &&
|
||||
(!sourceParent || !sourceParent.areChildrenShrunken()),
|
||||
fade,
|
||||
);
|
||||
});
|
||||
@ -1242,7 +1243,7 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
// Force the repaint in case that the main topic color has changed.
|
||||
if (this.getParent()) {
|
||||
this._connector.setColor(borderColor);
|
||||
this._connector!.setColor(borderColor);
|
||||
|
||||
if (this.getParent()?.isCentralTopic()) {
|
||||
this._outgoingLine?.redraw();
|
||||
|
@ -33,7 +33,7 @@ class Workspace {
|
||||
|
||||
private _eventsEnabled: boolean;
|
||||
|
||||
private _visibleAreaSize: SizeType;
|
||||
private _visibleAreaSize!: SizeType;
|
||||
|
||||
private _renderQueue: Element2D[];
|
||||
|
||||
@ -61,8 +61,9 @@ class Workspace {
|
||||
workspace.addItAsChildTo(divContainer);
|
||||
|
||||
this.setZoom(zoom, true);
|
||||
|
||||
this._renderQueue = [];
|
||||
this._eventsEnabled = false;
|
||||
this._queueRenderEnabled = false;
|
||||
}
|
||||
|
||||
private _adjustWorkspace(): void {
|
||||
@ -163,11 +164,11 @@ class Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
addEvent(type: string, listener: (event: Event) => void): void {
|
||||
addEvent(type: string, listener: (event: MouseEvent) => void): void {
|
||||
this._workspace.addEvent(type, listener);
|
||||
}
|
||||
|
||||
removeEvent(type: string, listener: (event: Event) => void): void {
|
||||
removeEvent(type: string, listener: (event: MouseEvent) => void): void {
|
||||
$assert(type, 'type can not be null');
|
||||
$assert(listener, 'listener can not be null');
|
||||
this._workspace.removeEvent(type, listener);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import { $assert } from '@wisemapping/core-js';
|
||||
import Point from '@wisemapping/web2d';
|
||||
import Command from '../Command';
|
||||
import CommandContext from '../CommandContext';
|
||||
@ -30,18 +30,10 @@ class DragTopicCommand extends Command {
|
||||
|
||||
private _order: number;
|
||||
|
||||
/**
|
||||
* @classdesc This command class handles do/undo of dragging a topic to a new position.
|
||||
* @constructs
|
||||
*/
|
||||
constructor(topicId: number, position: Point, order: number, parentTopic: Topic) {
|
||||
$assert(topicId, 'topicId must be defined');
|
||||
super();
|
||||
|
||||
this._topicsId = topicId;
|
||||
if ($defined(parentTopic)) {
|
||||
this._parentId = parentTopic.getId();
|
||||
}
|
||||
this._parentId = parentTopic ? parentTopic.getId() : null;
|
||||
|
||||
this._position = position;
|
||||
this._order = order;
|
||||
@ -59,7 +51,7 @@ class DragTopicCommand extends Command {
|
||||
const origPosition = topic.getPosition();
|
||||
|
||||
// Disconnect topic ..
|
||||
if ($defined(origParentTopic)) {
|
||||
if (origParentTopic) {
|
||||
commandContext.disconnect(topic);
|
||||
}
|
||||
|
||||
|
@ -15,37 +15,28 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import Command from '../Command';
|
||||
import CommandContext from '../CommandContext';
|
||||
import Topic from '../Topic';
|
||||
|
||||
type CommandTypes = string | object | boolean | number | undefined;
|
||||
|
||||
class GenericFunctionCommand extends Command {
|
||||
private _value: CommandTypes;
|
||||
class GenericFunctionCommand<T> extends Command {
|
||||
private _value: T;
|
||||
|
||||
private _topicsIds: number[];
|
||||
|
||||
private _commandFunc: (topic: Topic, value: CommandTypes) => CommandTypes;
|
||||
private _commandFunc: (topic: Topic, value: T) => T;
|
||||
|
||||
private _oldValues: CommandTypes[];
|
||||
private _oldValues: T[];
|
||||
|
||||
private _applied: boolean;
|
||||
|
||||
constructor(
|
||||
commandFunc: (topic: Topic, value: CommandTypes) => CommandTypes,
|
||||
topicsIds: number[],
|
||||
value: CommandTypes,
|
||||
) {
|
||||
$assert(commandFunc, 'commandFunc must be defined');
|
||||
$assert($defined(topicsIds), 'topicsIds must be defined');
|
||||
|
||||
constructor(commandFunc: (topic: Topic, value: T) => T, topicsIds: number[], value: T) {
|
||||
super();
|
||||
this._value = value;
|
||||
this._topicsIds = topicsIds;
|
||||
this._commandFunc = commandFunc;
|
||||
this._oldValues = [];
|
||||
this._applied = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,7 @@ class RemoveFeatureFromTopicCommand extends Command {
|
||||
|
||||
private _featureId: number;
|
||||
|
||||
private _oldFeature: FeatureModel;
|
||||
private _oldFeature: FeatureModel | null;
|
||||
|
||||
/**
|
||||
* @classdesc This command handles do/undo of removing a feature from a topic, e.g. an icon or
|
||||
@ -38,6 +38,7 @@ class RemoveFeatureFromTopicCommand extends Command {
|
||||
super();
|
||||
this._topicId = topicId;
|
||||
this._featureId = featureId;
|
||||
this._oldFeature = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,7 +57,7 @@ class RemoveFeatureFromTopicCommand extends Command {
|
||||
*/
|
||||
undoExecute(commandContext: CommandContext) {
|
||||
const topic = commandContext.findTopics([this._topicId])[0];
|
||||
topic.addFeature(this._oldFeature);
|
||||
topic.addFeature(this._oldFeature!);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,11 @@ import Font from './freemind/Font';
|
||||
class FreemindExporter extends Exporter {
|
||||
private mindmap: Mindmap;
|
||||
|
||||
private nodeMap: Map<number, FreeminNode>;
|
||||
private nodeMap!: Map<number, FreeminNode>;
|
||||
|
||||
private version: VersionNumber = FreemindConstant.SUPPORTED_FREEMIND_VERSION;
|
||||
|
||||
private objectFactory: ObjectFactory;
|
||||
private objectFactory!: ObjectFactory;
|
||||
|
||||
private static wisweToFreeFontSize: Map<number, number> = new Map<number, number>();
|
||||
|
||||
|
@ -1,43 +1,43 @@
|
||||
export default class Arrowlink {
|
||||
protected COLOR: string;
|
||||
protected COLOR: string | undefined;
|
||||
|
||||
protected DESTINATION: string;
|
||||
protected DESTINATION: string | undefined;
|
||||
|
||||
protected ENDARROW: string;
|
||||
protected ENDARROW: string | undefined;
|
||||
|
||||
protected ENDINCLINATION: string;
|
||||
protected ENDINCLINATION: string | undefined;
|
||||
|
||||
protected ID: string;
|
||||
protected ID: string | undefined;
|
||||
|
||||
protected STARTARROW: string;
|
||||
protected STARTARROW: string | undefined;
|
||||
|
||||
protected STARTINCLINATION: string;
|
||||
protected STARTINCLINATION: string | undefined;
|
||||
|
||||
getColor(): string {
|
||||
getColor(): string | undefined {
|
||||
return this.COLOR;
|
||||
}
|
||||
|
||||
getDestination(): string {
|
||||
getDestination(): string | undefined {
|
||||
return this.DESTINATION;
|
||||
}
|
||||
|
||||
getEndarrow(): string {
|
||||
getEndarrow(): string | undefined {
|
||||
return this.ENDARROW;
|
||||
}
|
||||
|
||||
getEndInclination(): string {
|
||||
getEndInclination(): string | undefined {
|
||||
return this.ENDINCLINATION;
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
getId(): string | undefined {
|
||||
return this.ID;
|
||||
}
|
||||
|
||||
getStartarrow(): string {
|
||||
getStartarrow(): string | undefined {
|
||||
return this.STARTARROW;
|
||||
}
|
||||
|
||||
getStartinclination(): string {
|
||||
getStartinclination(): string | undefined {
|
||||
return this.STARTINCLINATION;
|
||||
}
|
||||
|
||||
@ -72,8 +72,12 @@ export default class Arrowlink {
|
||||
toXml(document: Document): HTMLElement {
|
||||
const arrowlinkElem = document.createElement('arrowlink');
|
||||
|
||||
arrowlinkElem.setAttribute('DESTINATION', this.DESTINATION);
|
||||
arrowlinkElem.setAttribute('STARTARROW', this.STARTARROW);
|
||||
if (this.DESTINATION) {
|
||||
arrowlinkElem.setAttribute('DESTINATION', this.DESTINATION);
|
||||
}
|
||||
if (this.STARTARROW) {
|
||||
arrowlinkElem.setAttribute('STARTARROW', this.STARTARROW);
|
||||
}
|
||||
|
||||
if (this.COLOR) {
|
||||
arrowlinkElem.setAttribute('COLOR', this.COLOR);
|
||||
|
@ -1,7 +1,7 @@
|
||||
export default class Cloud {
|
||||
protected COLOR: string;
|
||||
protected COLOR: string | undefined;
|
||||
|
||||
getColor(): string {
|
||||
getColor(): string | undefined {
|
||||
return this.COLOR;
|
||||
}
|
||||
|
||||
@ -12,8 +12,9 @@ export default class Cloud {
|
||||
toXml(document: Document): HTMLElement {
|
||||
// Set node attributes
|
||||
const cloudElem = document.createElement('cloud');
|
||||
|
||||
cloudElem.setAttribute('COLOR', this.COLOR);
|
||||
if (this.COLOR) {
|
||||
cloudElem.setAttribute('COLOR', this.COLOR);
|
||||
}
|
||||
|
||||
return cloudElem;
|
||||
}
|
||||
|
@ -1,19 +1,36 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
export default class Edge {
|
||||
protected COLOR: string;
|
||||
protected COLOR: string | undefined;
|
||||
|
||||
protected STYLE: string;
|
||||
protected STYLE: string | undefined;
|
||||
|
||||
protected WIDTH: string;
|
||||
protected WIDTH: string | undefined;
|
||||
|
||||
getColor(): string {
|
||||
getColor(): string | undefined {
|
||||
return this.COLOR;
|
||||
}
|
||||
|
||||
getStyle(): string {
|
||||
getStyle(): string | undefined {
|
||||
return this.STYLE;
|
||||
}
|
||||
|
||||
getWidth(): string {
|
||||
getWidth(): string | undefined {
|
||||
return this.WIDTH;
|
||||
}
|
||||
|
||||
@ -32,10 +49,15 @@ export default class Edge {
|
||||
toXml(document: Document): HTMLElement {
|
||||
// Set node attributes
|
||||
const edgeElem = document.createElement('edge');
|
||||
|
||||
edgeElem.setAttribute('COLOR', this.COLOR);
|
||||
if (this.STYLE) edgeElem.setAttribute('STYLE', this.STYLE);
|
||||
if (this.WIDTH) edgeElem.setAttribute('WIDTH', this.WIDTH);
|
||||
if (this.COLOR) {
|
||||
edgeElem.setAttribute('COLOR', this.COLOR);
|
||||
}
|
||||
if (this.STYLE) {
|
||||
edgeElem.setAttribute('STYLE', this.STYLE);
|
||||
}
|
||||
if (this.WIDTH) {
|
||||
edgeElem.setAttribute('WIDTH', this.WIDTH);
|
||||
}
|
||||
|
||||
return edgeElem;
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
export default class Font {
|
||||
protected BOLD?: string;
|
||||
protected BOLD: string | undefined;
|
||||
|
||||
protected ITALIC?: string;
|
||||
protected ITALIC: string | undefined;
|
||||
|
||||
protected NAME?: string;
|
||||
protected NAME: string | undefined;
|
||||
|
||||
protected SIZE: string;
|
||||
protected SIZE: string | undefined;
|
||||
|
||||
getBold(): string | undefined {
|
||||
return this.BOLD;
|
||||
@ -19,7 +19,7 @@ export default class Font {
|
||||
return this.NAME;
|
||||
}
|
||||
|
||||
getSize(): string {
|
||||
getSize(): string | undefined {
|
||||
return this.SIZE;
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
import Parameters from './Parameters';
|
||||
|
||||
export default class Hook {
|
||||
protected PARAMETERS: Parameters;
|
||||
protected PARAMETERS: Parameters | undefined;
|
||||
|
||||
protected TEXT: string;
|
||||
protected TEXT: string | undefined;
|
||||
|
||||
protected NAME: string;
|
||||
protected NAME: string | undefined;
|
||||
|
||||
getParameters(): Parameters {
|
||||
getParameters(): Parameters | undefined {
|
||||
return this.PARAMETERS;
|
||||
}
|
||||
|
||||
getText(): string {
|
||||
getText(): string | undefined {
|
||||
return this.TEXT;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
getName(): string | undefined {
|
||||
return this.NAME;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
export default class Icon {
|
||||
protected BUILTIN: string;
|
||||
protected BUILTIN: string | undefined;
|
||||
|
||||
getBuiltin(): string {
|
||||
getBuiltin(): string | undefined {
|
||||
return this.BUILTIN;
|
||||
}
|
||||
|
||||
@ -12,8 +12,9 @@ export default class Icon {
|
||||
toXml(document: Document): HTMLElement {
|
||||
// Set node attributes
|
||||
const iconElem = document.createElement('icon');
|
||||
|
||||
iconElem.setAttribute('BUILTIN', this.BUILTIN);
|
||||
if (this.BUILTIN) {
|
||||
iconElem.setAttribute('BUILTIN', this.BUILTIN);
|
||||
}
|
||||
|
||||
return iconElem;
|
||||
}
|
||||
|
@ -8,15 +8,15 @@ import Node, { Choise } from './Node';
|
||||
import Richcontent from './Richcontent';
|
||||
|
||||
export default class Freemap {
|
||||
protected node: Node;
|
||||
protected node: Node | undefined;
|
||||
|
||||
protected version: string;
|
||||
protected version: string | undefined;
|
||||
|
||||
getNode(): Node {
|
||||
getNode(): Node | undefined {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
getVersion(): string {
|
||||
getVersion(): string | undefined {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ export default class Freemap {
|
||||
document.appendChild(mapElem);
|
||||
|
||||
// Create main node
|
||||
const mainNode: Node = this.node;
|
||||
const mainNode: Node = this.node!;
|
||||
mainNode.setCentralTopic(true);
|
||||
const mainNodeElem = mainNode.toXml(document);
|
||||
mapElem.appendChild(mainNodeElem);
|
||||
|
@ -7,43 +7,43 @@ import Icon from './Icon';
|
||||
import Richcontent from './Richcontent';
|
||||
|
||||
class Node {
|
||||
protected arrowlinkOrCloudOrEdge: Array<
|
||||
Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | this
|
||||
>;
|
||||
protected arrowlinkOrCloudOrEdge:
|
||||
| Array<Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | this>
|
||||
| undefined;
|
||||
|
||||
protected BACKGROUND_COLOR: string;
|
||||
protected BACKGROUND_COLOR: string | undefined;
|
||||
|
||||
protected COLOR: string;
|
||||
protected COLOR: string | undefined;
|
||||
|
||||
protected FOLDED: string;
|
||||
protected FOLDED: string | undefined;
|
||||
|
||||
protected ID: string;
|
||||
protected ID: string | undefined;
|
||||
|
||||
protected LINK: string;
|
||||
protected LINK: string | undefined;
|
||||
|
||||
protected POSITION: string;
|
||||
protected POSITION: string | undefined;
|
||||
|
||||
protected STYLE: string;
|
||||
protected STYLE: string | undefined;
|
||||
|
||||
protected TEXT: string;
|
||||
protected TEXT: string | undefined;
|
||||
|
||||
protected CREATED: string;
|
||||
protected CREATED: string | undefined;
|
||||
|
||||
protected MODIFIED: string;
|
||||
protected MODIFIED: string | undefined;
|
||||
|
||||
protected HGAP: string;
|
||||
protected HGAP: string | undefined;
|
||||
|
||||
protected VGAP: string;
|
||||
protected VGAP: string | undefined;
|
||||
|
||||
protected WCOORDS: string;
|
||||
protected WCOORDS: string | undefined;
|
||||
|
||||
protected WORDER: string;
|
||||
protected WORDER: string | undefined;
|
||||
|
||||
protected VSHIFT: string;
|
||||
protected VSHIFT: string | undefined;
|
||||
|
||||
protected ENCRYPTED_CONTENT: string;
|
||||
protected ENCRYPTED_CONTENT: string | undefined;
|
||||
|
||||
private centralTopic: boolean;
|
||||
private centralTopic = false;
|
||||
|
||||
getArrowlinkOrCloudOrEdge(): Array<
|
||||
/* eslint-disable */
|
||||
@ -57,67 +57,67 @@ class Node {
|
||||
return this.arrowlinkOrCloudOrEdge;
|
||||
}
|
||||
|
||||
getBackgroundColor(): string {
|
||||
getBackgroundColor(): string | undefined {
|
||||
return this.BACKGROUND_COLOR;
|
||||
}
|
||||
|
||||
getColor(): string {
|
||||
getColor(): string | undefined {
|
||||
return this.COLOR;
|
||||
}
|
||||
|
||||
getFolded(): string {
|
||||
getFolded(): string | undefined {
|
||||
return this.FOLDED;
|
||||
}
|
||||
|
||||
getId(): string | null {
|
||||
getId(): string | undefined {
|
||||
return this.ID;
|
||||
}
|
||||
|
||||
getLink(): string {
|
||||
getLink(): string | undefined {
|
||||
return this.LINK;
|
||||
}
|
||||
|
||||
getPosition(): string {
|
||||
getPosition(): string | undefined {
|
||||
return this.POSITION;
|
||||
}
|
||||
|
||||
getStyle(): string {
|
||||
getStyle(): string | undefined {
|
||||
return this.STYLE;
|
||||
}
|
||||
|
||||
getText(): string {
|
||||
getText(): string | undefined {
|
||||
return this.TEXT;
|
||||
}
|
||||
|
||||
getCreated(): string {
|
||||
getCreated(): string | undefined {
|
||||
return this.CREATED;
|
||||
}
|
||||
|
||||
getModified(): string {
|
||||
getModified(): string | undefined {
|
||||
return this.MODIFIED;
|
||||
}
|
||||
|
||||
getHgap(): string {
|
||||
getHgap(): string | undefined {
|
||||
return this.HGAP;
|
||||
}
|
||||
|
||||
getVgap(): string {
|
||||
getVgap(): string | undefined {
|
||||
return this.VGAP;
|
||||
}
|
||||
|
||||
getWcoords(): string {
|
||||
getWcoords(): string | undefined {
|
||||
return this.WCOORDS;
|
||||
}
|
||||
|
||||
getWorder(): string {
|
||||
getWorder(): string | undefined {
|
||||
return this.WORDER;
|
||||
}
|
||||
|
||||
getVshift(): string {
|
||||
getVshift(): string | undefined {
|
||||
return this.VSHIFT;
|
||||
}
|
||||
|
||||
getEncryptedContent(): string {
|
||||
getEncryptedContent(): string | undefined {
|
||||
return this.ENCRYPTED_CONTENT;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
export default class Parameters {
|
||||
protected REMINDUSERAT: number;
|
||||
protected REMINDUSERAT: number | undefined;
|
||||
|
||||
getReminduserat(): number {
|
||||
getReminduserat(): number | undefined {
|
||||
return this.REMINDUSERAT;
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
export default class Richcontent {
|
||||
protected html: string;
|
||||
protected html: string | undefined;
|
||||
|
||||
protected type: string;
|
||||
protected type: string | undefined;
|
||||
|
||||
getHtml(): string {
|
||||
getHtml(): string | undefined {
|
||||
return this.html;
|
||||
}
|
||||
|
||||
getType(): string {
|
||||
getType(): string | undefined {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@ -22,9 +22,9 @@ export default class Richcontent {
|
||||
toXml(document: Document): HTMLElement {
|
||||
// Set node attributes
|
||||
const richcontentElem = document.createElement('richcontent');
|
||||
|
||||
richcontentElem.setAttribute('TYPE', this.type);
|
||||
|
||||
if (this.type) {
|
||||
richcontentElem.setAttribute('TYPE', this.type);
|
||||
}
|
||||
if (this.html) {
|
||||
const htmlElement: DocumentFragment = document
|
||||
.createRange()
|
||||
|
@ -6,7 +6,6 @@ import NodeModel from '../model/NodeModel';
|
||||
import FreemindConstant from '../export/freemind/FreemindConstant';
|
||||
import FreemindMap from '../export/freemind/Map';
|
||||
import FreemindNode, { Choise } from '../export/freemind/Node';
|
||||
import FreemindFont from '../export/freemind/Font';
|
||||
import FreemindEdge from '../export/freemind/Edge';
|
||||
import FreemindIcon from '../export/freemind/Icon';
|
||||
import FreemindHook from '../export/freemind/Hook';
|
||||
@ -21,15 +20,15 @@ import XMLSerializerFactory from '../persistence/XMLSerializerFactory';
|
||||
import { TopicShapeType } from '../model/INodeModel';
|
||||
|
||||
export default class FreemindImporter extends Importer {
|
||||
private mindmap: Mindmap;
|
||||
private mindmap!: Mindmap;
|
||||
|
||||
private freemindInput: string;
|
||||
|
||||
private freemindMap: FreemindMap;
|
||||
private freemindMap!: FreemindMap;
|
||||
|
||||
private nodesmap: Map<string, NodeModel>;
|
||||
private nodesmap!: Map<string, NodeModel>;
|
||||
|
||||
private relationship: Array<RelationshipModel>;
|
||||
private relationship!: Array<RelationshipModel>;
|
||||
|
||||
private idDefault = 0;
|
||||
|
||||
@ -47,7 +46,7 @@ export default class FreemindImporter extends Importer {
|
||||
const freemindDoc = parser.parseFromString(this.freemindInput, 'application/xml');
|
||||
this.freemindMap = new FreemindMap().loadFromDom(freemindDoc);
|
||||
|
||||
const version: string = this.freemindMap.getVersion();
|
||||
const version: string | undefined = this.freemindMap.getVersion();
|
||||
|
||||
if (!version || version.startsWith('freeplane')) {
|
||||
throw new Error(
|
||||
@ -60,10 +59,10 @@ export default class FreemindImporter extends Importer {
|
||||
}
|
||||
}
|
||||
|
||||
const freeNode: FreemindNode = this.freemindMap.getNode();
|
||||
const freeNode = this.freemindMap.getNode()!;
|
||||
this.mindmap.setVersion(FreemindConstant.CODE_VERSION);
|
||||
|
||||
const wiseTopicId = this.getIdNode(this.freemindMap.getNode());
|
||||
const wiseTopicId = this.getIdNode(freeNode);
|
||||
const wiseTopic = this.mindmap.createNode('CentralTopic');
|
||||
wiseTopic.setPosition(0, 0);
|
||||
wiseTopic.setId(wiseTopicId);
|
||||
@ -158,7 +157,7 @@ export default class FreemindImporter extends Importer {
|
||||
wiseTopic: NodeModel,
|
||||
centralTopic: boolean,
|
||||
): void {
|
||||
const text: string = freeNode.getText();
|
||||
const text = freeNode.getText();
|
||||
if (text) {
|
||||
if (!centralTopic && text.length > 100) {
|
||||
wiseTopic.setText(text.replace(/([^\n]{1,100})\s/g, '$1\n'));
|
||||
@ -167,7 +166,7 @@ export default class FreemindImporter extends Importer {
|
||||
}
|
||||
}
|
||||
|
||||
const bgColor: string = freeNode.getBackgroundColor();
|
||||
const bgColor = freeNode.getBackgroundColor();
|
||||
if (bgColor) {
|
||||
wiseTopic.setBackgroundColor(bgColor);
|
||||
}
|
||||
@ -186,7 +185,7 @@ export default class FreemindImporter extends Importer {
|
||||
// }
|
||||
|
||||
// Is there any link...
|
||||
const url: string = freeNode.getLink();
|
||||
const url = freeNode.getLink();
|
||||
if (url) {
|
||||
const link: FeatureModel = FeatureModelFactory.createModel('link', { url });
|
||||
wiseTopic.addFeature(link);
|
||||
@ -214,7 +213,7 @@ export default class FreemindImporter extends Importer {
|
||||
const wiseChild = mindmap.createNode('MainTopic', wiseId);
|
||||
|
||||
const id = child.getId();
|
||||
if (id !== null) {
|
||||
if (id !== undefined) {
|
||||
this.nodesmap.set(id, wiseChild);
|
||||
}
|
||||
|
||||
@ -269,13 +268,15 @@ export default class FreemindImporter extends Importer {
|
||||
|
||||
if (child instanceof FreemindIcon) {
|
||||
const freeIcon: FreemindIcon = child as FreemindIcon;
|
||||
const iconId: string = freeIcon.getBuiltin();
|
||||
const wiseIconId = FreemindIconConverter.toWiseId(iconId);
|
||||
if (wiseIconId) {
|
||||
const mindmapIcon: FeatureModel = FeatureModelFactory.createModel('icon', {
|
||||
id: wiseIconId,
|
||||
});
|
||||
currentWiseTopic.addFeature(mindmapIcon);
|
||||
const iconId = freeIcon.getBuiltin();
|
||||
if (iconId) {
|
||||
const wiseIconId = FreemindIconConverter.toWiseId(iconId);
|
||||
if (wiseIconId) {
|
||||
const mindmapIcon: FeatureModel = FeatureModelFactory.createModel('icon', {
|
||||
id: wiseIconId,
|
||||
});
|
||||
currentWiseTopic.addFeature(mindmapIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,7 +284,7 @@ export default class FreemindImporter extends Importer {
|
||||
const hook: FreemindHook = child as FreemindHook;
|
||||
const mindmapNote: NoteModel = new NoteModel({ text: '' });
|
||||
|
||||
let textNote: string = hook.getText();
|
||||
let textNote = hook.getText();
|
||||
if (!textNote) {
|
||||
textNote = FreemindConstant.EMPTY_NOTE;
|
||||
mindmapNote.setText(textNote);
|
||||
@ -294,27 +295,28 @@ export default class FreemindImporter extends Importer {
|
||||
if (child instanceof FreemindRichcontent) {
|
||||
const type = child.getType();
|
||||
const html = child.getHtml();
|
||||
const text = this.html2Text(html);
|
||||
if (html) {
|
||||
const text = this.html2Text(html);
|
||||
switch (type) {
|
||||
case 'NOTE': {
|
||||
const noteModel: FeatureModel = FeatureModelFactory.createModel('note', {
|
||||
text: text || FreemindConstant.EMPTY_NOTE,
|
||||
});
|
||||
currentWiseTopic.addFeature(noteModel);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'NOTE': {
|
||||
const noteModel: FeatureModel = FeatureModelFactory.createModel('note', {
|
||||
text: text || FreemindConstant.EMPTY_NOTE,
|
||||
});
|
||||
currentWiseTopic.addFeature(noteModel);
|
||||
break;
|
||||
}
|
||||
case 'NODE': {
|
||||
currentWiseTopic.setText(text);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'NODE': {
|
||||
currentWiseTopic.setText(text);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
const noteModel: FeatureModel = FeatureModelFactory.createModel('note', {
|
||||
text: text || FreemindConstant.EMPTY_NOTE,
|
||||
});
|
||||
currentWiseTopic.addFeature(noteModel);
|
||||
default: {
|
||||
const noteModel: FeatureModel = FeatureModelFactory.createModel('note', {
|
||||
text: text || FreemindConstant.EMPTY_NOTE,
|
||||
});
|
||||
currentWiseTopic.addFeature(noteModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -322,28 +324,28 @@ export default class FreemindImporter extends Importer {
|
||||
if (child instanceof FreemindArrowLink) {
|
||||
const arrow: FreemindArrowLink = child as FreemindArrowLink;
|
||||
const relationship: RelationshipModel = new RelationshipModel(0, 0);
|
||||
const destId: string = arrow.getDestination();
|
||||
const destId = arrow.getDestination();
|
||||
|
||||
relationship.setSrcCtrlPoint(destId);
|
||||
relationship.setDestCtrlPoint(freeParent.getId());
|
||||
const endinclination: string = arrow.getEndInclination();
|
||||
const endinclination = arrow.getEndInclination();
|
||||
if (endinclination) {
|
||||
const inclination: Array<string> = endinclination.split(';');
|
||||
relationship.setDestCtrlPoint(`${inclination[0]},${inclination[1]}`);
|
||||
}
|
||||
|
||||
const startinclination: string = arrow.getStartinclination();
|
||||
const startinclination = arrow.getStartinclination();
|
||||
if (startinclination) {
|
||||
const inclination: Array<string> = startinclination.split(';');
|
||||
relationship.setSrcCtrlPoint(`${inclination[0]},${inclination[1]}`);
|
||||
}
|
||||
|
||||
const endarrow: string = arrow.getEndarrow();
|
||||
const endarrow = arrow.getEndarrow();
|
||||
if (endarrow) {
|
||||
relationship.setEndArrow(endarrow.toLowerCase() !== 'none');
|
||||
}
|
||||
|
||||
const startarrow: string = arrow.getStartarrow();
|
||||
const startarrow = arrow.getStartarrow();
|
||||
if (startarrow) {
|
||||
relationship.setStartArrow(startarrow.toLowerCase() !== 'none');
|
||||
}
|
||||
@ -375,7 +377,7 @@ export default class FreemindImporter extends Importer {
|
||||
|
||||
private getChildrenCountSameSide(freeChilden: Array<Choise>, freeChild: FreemindNode): number {
|
||||
let result = 0;
|
||||
let childSide: string = freeChild.getPosition();
|
||||
let childSide = freeChild.getPosition();
|
||||
|
||||
if (!childSide) {
|
||||
childSide = FreemindConstant.POSITION_RIGHT;
|
||||
@ -410,55 +412,54 @@ export default class FreemindImporter extends Importer {
|
||||
return result;
|
||||
}
|
||||
|
||||
private generateFontStyle(node: FreemindNode, font: FreemindFont | undefined): string {
|
||||
const fontStyle: Array<string> = [];
|
||||
// private generateFontStyle(node: FreemindNode, font: FreemindFont | undefined): string {
|
||||
// const fontStyle: Array<string> = [];
|
||||
|
||||
// Font family
|
||||
if (font) {
|
||||
const name = font.getName();
|
||||
if (name) {
|
||||
fontStyle.push(name);
|
||||
}
|
||||
}
|
||||
fontStyle.push(';');
|
||||
// // Font family
|
||||
// if (font) {
|
||||
// const name = font.getName();
|
||||
// if (name) {
|
||||
// fontStyle.push(name);
|
||||
// }
|
||||
// }
|
||||
// fontStyle.push(';');
|
||||
|
||||
// Font Size
|
||||
if (font) {
|
||||
const fontSize: number =
|
||||
!font.getSize() || parseInt(font.getSize(), 10) < 8
|
||||
? FreemindConstant.FONT_SIZE_NORMAL
|
||||
: parseInt(font.getSize(), 10);
|
||||
let wiseFontSize: number = FreemindConstant.FONT_SIZE_SMALL;
|
||||
if (fontSize >= 24) {
|
||||
wiseFontSize = FreemindConstant.FONT_SIZE_HUGE;
|
||||
}
|
||||
if (fontSize >= 16) {
|
||||
wiseFontSize = FreemindConstant.FONT_SIZE_LARGE;
|
||||
}
|
||||
if (fontSize >= 8) {
|
||||
wiseFontSize = FreemindConstant.FONT_SIZE_NORMAL;
|
||||
}
|
||||
fontStyle.push(wiseFontSize.toString());
|
||||
}
|
||||
fontStyle.push(';');
|
||||
// // Font Size
|
||||
// if (font) {
|
||||
// const size = font.getSize();
|
||||
// const fontSize: number =
|
||||
// !size || parseInt(size, 10) < 8 ? FreemindConstant.FONT_SIZE_NORMAL : parseInt(size, 10);
|
||||
// let wiseFontSize: number = FreemindConstant.FONT_SIZE_SMALL;
|
||||
// if (fontSize >= 24) {
|
||||
// wiseFontSize = FreemindConstant.FONT_SIZE_HUGE;
|
||||
// }
|
||||
// if (fontSize >= 16) {
|
||||
// wiseFontSize = FreemindConstant.FONT_SIZE_LARGE;
|
||||
// }
|
||||
// if (fontSize >= 8) {
|
||||
// wiseFontSize = FreemindConstant.FONT_SIZE_NORMAL;
|
||||
// }
|
||||
// fontStyle.push(wiseFontSize.toString());
|
||||
// }
|
||||
// fontStyle.push(';');
|
||||
|
||||
// Font Color
|
||||
const color: string = node.getColor();
|
||||
if (color && color !== '') {
|
||||
fontStyle.push(color);
|
||||
}
|
||||
fontStyle.push(';');
|
||||
// // Font Color
|
||||
// const color = node.getColor();
|
||||
// if (color && color !== '') {
|
||||
// fontStyle.push(color);
|
||||
// }
|
||||
// fontStyle.push(';');
|
||||
|
||||
// Font Italic
|
||||
if (font) {
|
||||
const hasItalic = Boolean(font.getItalic());
|
||||
fontStyle.push(hasItalic ? FreemindConstant.ITALIC : '');
|
||||
}
|
||||
fontStyle.push(';');
|
||||
// // Font Italic
|
||||
// if (font) {
|
||||
// const hasItalic = Boolean(font.getItalic());
|
||||
// fontStyle.push(hasItalic ? FreemindConstant.ITALIC : '');
|
||||
// }
|
||||
// fontStyle.push(';');
|
||||
|
||||
const result: string = fontStyle.join('');
|
||||
return result;
|
||||
}
|
||||
// const result: string = fontStyle.join('');
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private convertPosition(
|
||||
wiseParent: NodeModel,
|
||||
@ -471,7 +472,7 @@ export default class FreemindImporter extends Importer {
|
||||
FreemindConstant.CENTRAL_TO_TOPIC_DISTANCE +
|
||||
(depth - 1) * FreemindConstant.TOPIC_TO_TOPIC_DISTANCE;
|
||||
if (depth === 1) {
|
||||
const side: string = freeChild.getPosition();
|
||||
const side = freeChild.getPosition();
|
||||
x *= side && FreemindConstant.POSITION_LEFT === side ? -1 : 1;
|
||||
} else {
|
||||
const position = wiseParent.getPosition();
|
||||
|
@ -1,12 +1,9 @@
|
||||
import Mindmap from '../model/Mindmap';
|
||||
import XMLSerializerFactory from '../persistence/XMLSerializerFactory';
|
||||
import Importer from './Importer';
|
||||
|
||||
export default class WisemappingImporter extends Importer {
|
||||
private wisemappingInput: string;
|
||||
|
||||
private mindmap: Mindmap;
|
||||
|
||||
constructor(map: string) {
|
||||
super();
|
||||
this.wisemappingInput = map;
|
||||
@ -17,11 +14,11 @@ export default class WisemappingImporter extends Importer {
|
||||
const wiseDoc = parser.parseFromString(this.wisemappingInput, 'application/xml');
|
||||
|
||||
const serialize = XMLSerializerFactory.createInstanceFromDocument(wiseDoc);
|
||||
this.mindmap = serialize.loadFromDom(wiseDoc, nameMap);
|
||||
const mindmap = serialize.loadFromDom(wiseDoc, nameMap);
|
||||
|
||||
this.mindmap.setDescription(description);
|
||||
mindmap.setDescription(description);
|
||||
|
||||
const mindmapToXml = serialize.toXML(this.mindmap);
|
||||
const mindmapToXml = serialize.toXML(mindmap);
|
||||
|
||||
const xmlStr = new XMLSerializer().serializeToString(mindmapToXml);
|
||||
return Promise.resolve(xmlStr);
|
||||
|
@ -22,10 +22,11 @@ import EventBus from './EventBus';
|
||||
import LayoutManager from './LayoutManager';
|
||||
|
||||
class EventBusDispatcher {
|
||||
private _layoutManager: LayoutManager;
|
||||
private _layoutManager: LayoutManager | null;
|
||||
|
||||
constructor() {
|
||||
this.registerBusEvents();
|
||||
this._layoutManager = null;
|
||||
}
|
||||
|
||||
setLayoutManager(layoutManager: LayoutManager) {
|
||||
@ -44,19 +45,19 @@ class EventBusDispatcher {
|
||||
}
|
||||
|
||||
private _topicResizeEvent(args: { node: Topic; size: SizeType }) {
|
||||
this._layoutManager.updateNodeSize(args.node.getId(), args.size);
|
||||
this._layoutManager!.updateNodeSize(args.node.getId(), args.size);
|
||||
}
|
||||
|
||||
private _topicMoved(args: { node: Topic; position: PositionType }) {
|
||||
this._layoutManager.moveNode(args.node.getId(), args.position);
|
||||
this._layoutManager!.moveNode(args.node.getId(), args.position);
|
||||
}
|
||||
|
||||
private _topicDisconect(node: Topic) {
|
||||
this._layoutManager.disconnectNode(node.getId());
|
||||
this._layoutManager!.disconnectNode(node.getId());
|
||||
}
|
||||
|
||||
private _topicConnected(args: { parentNode: Topic; childNode: Topic }) {
|
||||
this._layoutManager.connectNode(
|
||||
this._layoutManager!.connectNode(
|
||||
args.parentNode.getId(),
|
||||
args.childNode.getId(),
|
||||
args.childNode.getOrder(),
|
||||
@ -64,27 +65,27 @@ class EventBusDispatcher {
|
||||
}
|
||||
|
||||
private _childShrinked(node: Topic) {
|
||||
this._layoutManager.updateShrinkState(node.getId(), node.areChildrenShrunken());
|
||||
this._layoutManager!.updateShrinkState(node.getId(), node.areChildrenShrunken());
|
||||
}
|
||||
|
||||
private _topicAdded(node: Topic) {
|
||||
// Central topic must not be added twice ...
|
||||
if (node.getId() !== 0) {
|
||||
this._layoutManager.addNode(node.getId(), { width: 10, height: 10 }, node.getPosition());
|
||||
this._layoutManager.updateShrinkState(node.getId(), node.areChildrenShrunken());
|
||||
this._layoutManager!.addNode(node.getId(), { width: 10, height: 10 }, node.getPosition());
|
||||
this._layoutManager!.updateShrinkState(node.getId(), node.areChildrenShrunken());
|
||||
}
|
||||
}
|
||||
|
||||
private _topicRemoved(node: Topic) {
|
||||
this._layoutManager.removeNode(node.getId());
|
||||
this._layoutManager!.removeNode(node.getId());
|
||||
}
|
||||
|
||||
private _forceLayout() {
|
||||
this._layoutManager.layout(true);
|
||||
this._layoutManager!.layout(true);
|
||||
}
|
||||
|
||||
getLayoutManager() {
|
||||
return this._layoutManager;
|
||||
getLayoutManager(): LayoutManager {
|
||||
return this._layoutManager!;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,21 +24,17 @@ class Node {
|
||||
private _id: number;
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
_parent: Node | null;
|
||||
_parent!: Node | null;
|
||||
|
||||
private _sorter: ChildrenSorterStrategy;
|
||||
|
||||
private _properties;
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
_children: Node[];
|
||||
_children!: Node[];
|
||||
|
||||
constructor(id: number, size: SizeType, position: PositionType, sorter: ChildrenSorterStrategy) {
|
||||
$assert(typeof id === 'number' && Number.isFinite(id), 'id can not be null');
|
||||
$assert(size, 'size can not be null');
|
||||
$assert(position, 'position can not be null');
|
||||
$assert(sorter, 'sorter can not be null');
|
||||
|
||||
this._id = id;
|
||||
this._sorter = sorter;
|
||||
this._properties = {};
|
||||
@ -49,7 +45,7 @@ class Node {
|
||||
}
|
||||
|
||||
/** */
|
||||
getId() {
|
||||
getId(): number {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
@ -74,7 +70,7 @@ class Node {
|
||||
}
|
||||
|
||||
/** */
|
||||
setShrunken(value) {
|
||||
setShrunken(value: boolean) {
|
||||
this._setProperty('shrink', value);
|
||||
}
|
||||
|
||||
@ -132,31 +128,27 @@ class Node {
|
||||
}
|
||||
|
||||
/** */
|
||||
hasSizeChanged() {
|
||||
hasSizeChanged(): boolean {
|
||||
return this._isPropertyChanged('size');
|
||||
}
|
||||
|
||||
/** */
|
||||
getPosition() {
|
||||
getPosition(): PositionType {
|
||||
return this._getProperty('position');
|
||||
}
|
||||
|
||||
/** */
|
||||
setSize(size) {
|
||||
setSize(size: SizeType) {
|
||||
$assert($defined(size), 'Size can not be null');
|
||||
this._setProperty('size', { ...size });
|
||||
}
|
||||
|
||||
/** */
|
||||
getSize() {
|
||||
getSize(): SizeType {
|
||||
return this._getProperty('size');
|
||||
}
|
||||
|
||||
/** */
|
||||
setFreeDisplacement(displacement) {
|
||||
$assert($defined(displacement), 'Position can not be null');
|
||||
$assert($defined(displacement.x), 'x can not be null');
|
||||
$assert($defined(displacement.y), 'y can not be null');
|
||||
setFreeDisplacement(displacement: PositionType) {
|
||||
const oldDisplacement = this.getFreeDisplacement();
|
||||
const newDisplacement = {
|
||||
x: oldDisplacement.x + displacement.x,
|
||||
@ -177,12 +169,7 @@ class Node {
|
||||
return freeDisplacement || { x: 0, y: 0 };
|
||||
}
|
||||
|
||||
/** */
|
||||
setPosition(position: PositionType) {
|
||||
$assert($defined(position), 'Position can not be null');
|
||||
$assert($defined(position.x), 'x can not be null');
|
||||
$assert($defined(position.y), 'y can not be null');
|
||||
|
||||
// This is a performance improvement to avoid movements that really could be avoided.
|
||||
const currentPos = this.getPosition();
|
||||
if (
|
||||
@ -213,7 +200,7 @@ class Node {
|
||||
this._properties[key] = prop;
|
||||
}
|
||||
|
||||
_getProperty(key) {
|
||||
_getProperty(key: string) {
|
||||
const prop = this._properties[key];
|
||||
return $defined(prop) ? prop.value : null;
|
||||
}
|
||||
@ -229,7 +216,7 @@ class Node {
|
||||
}
|
||||
|
||||
/** @return {String} returns id, order, position, size and shrink information */
|
||||
toString() {
|
||||
toString(): string {
|
||||
return `[id:${this.getId()}, order:${this.getOrder()}, position: {${this.getPosition().x},${
|
||||
this.getPosition().y
|
||||
}}, size: {${this.getSize().width},${
|
||||
|
@ -15,21 +15,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import { $assert } from '@wisemapping/core-js';
|
||||
import PositionType from '../PositionType';
|
||||
import Node from './Node';
|
||||
|
||||
class RootedTreeSet {
|
||||
private _rootNodes: Node[];
|
||||
|
||||
protected _children: Node[];
|
||||
protected _children!: Node[];
|
||||
|
||||
constructor() {
|
||||
this._rootNodes = [];
|
||||
}
|
||||
|
||||
setRoot(root: Node) {
|
||||
$assert(root, 'root can not be null');
|
||||
this._rootNodes.push(this._decodate(root));
|
||||
}
|
||||
|
||||
@ -43,7 +42,6 @@ class RootedTreeSet {
|
||||
}
|
||||
|
||||
add(node: Node) {
|
||||
$assert(node, 'node can not be null');
|
||||
if (this.find(node.getId(), false)) {
|
||||
throw new Error(`node already exits with this id. Id:${node.getId()}: ${this.dump()}`);
|
||||
}
|
||||
@ -56,7 +54,6 @@ class RootedTreeSet {
|
||||
* @throws will throw an error if nodeId is null or undefined
|
||||
*/
|
||||
remove(nodeId: number) {
|
||||
$assert($defined(nodeId), 'nodeId can not be null');
|
||||
const node = this.find(nodeId);
|
||||
this._rootNodes = this._rootNodes.filter((n) => n !== node);
|
||||
}
|
||||
@ -69,9 +66,6 @@ class RootedTreeSet {
|
||||
* @throws will throw an error if node with id childId is already a child of parent
|
||||
*/
|
||||
connect(parentId: number, childId: number) {
|
||||
$assert($defined(parentId), 'parent can not be null');
|
||||
$assert($defined(childId), 'child can not be null');
|
||||
|
||||
const parent = this.find(parentId);
|
||||
const child = this.find(childId, true);
|
||||
$assert(
|
||||
@ -90,7 +84,6 @@ class RootedTreeSet {
|
||||
* @throws will throw an error if node is not connected
|
||||
*/
|
||||
disconnect(nodeId: number) {
|
||||
$assert($defined(nodeId), 'nodeId can not be null');
|
||||
const node = this.find(nodeId);
|
||||
$assert(node._parent, 'Node is not connected');
|
||||
|
||||
@ -107,8 +100,6 @@ class RootedTreeSet {
|
||||
* @return node
|
||||
*/
|
||||
find(id: number, validate = true): Node {
|
||||
$assert($defined(id), 'id can not be null');
|
||||
|
||||
const graphs = this._rootNodes;
|
||||
let result: Node | null = null;
|
||||
for (let i = 0; i < graphs.length; i++) {
|
||||
|
@ -35,8 +35,6 @@ class NodeModel extends INodeModel {
|
||||
private _parent: NodeModel | null;
|
||||
|
||||
constructor(type: NodeModelType, mindmap: Mindmap, id?: number) {
|
||||
$assert(type, 'Node type can not be null');
|
||||
$assert(mindmap, 'mindmap can not be null');
|
||||
super(mindmap);
|
||||
|
||||
this._properties = {};
|
||||
@ -46,6 +44,7 @@ class NodeModel extends INodeModel {
|
||||
|
||||
this._children = [];
|
||||
this._features = [];
|
||||
this._parent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,6 @@ import Mindmap from '../model/Mindmap';
|
||||
import FeatureModelFactory from '../model/FeatureModelFactory';
|
||||
import NodeModel from '../model/NodeModel';
|
||||
import XMLMindmapSerializer from './XMLMindmapSerializer';
|
||||
import FeatureModel from '../model/FeatureModel';
|
||||
|
||||
class XMLSerializerBeta implements XMLMindmapSerializer {
|
||||
private static MAP_ROOT_NODE = 'map';
|
||||
@ -297,12 +296,6 @@ class XMLSerializerBeta implements XMLMindmapSerializer {
|
||||
return topic;
|
||||
}
|
||||
|
||||
private _deserializeIcon(domElem: Element): FeatureModel {
|
||||
let icon = domElem.getAttribute('id');
|
||||
icon = icon ? icon.replace('images/', 'icons/legacy/') : 'missing';
|
||||
return FeatureModelFactory.createModel('icon', { id: icon });
|
||||
}
|
||||
|
||||
_deserializeLink(domElem: Element) {
|
||||
return FeatureModelFactory.createModel('link', { url: domElem.getAttribute('url') });
|
||||
}
|
||||
|
@ -33,6 +33,10 @@ class XMLSerializerTango implements XMLMindmapSerializer {
|
||||
|
||||
private _idsMap: Record<number, Element>;
|
||||
|
||||
constructor() {
|
||||
this._idsMap = {};
|
||||
}
|
||||
|
||||
toXML(mindmap: Mindmap): Document {
|
||||
$assert(mindmap, 'Can not save a null mindmap');
|
||||
|
||||
@ -242,7 +246,6 @@ class XMLSerializerTango implements XMLMindmapSerializer {
|
||||
`This seem not to be a map document. Found tag: ${rootElem.tagName}`,
|
||||
);
|
||||
|
||||
this._idsMap = {};
|
||||
// Start the loading process ...
|
||||
const version = rootElem.getAttribute('version') || 'pela';
|
||||
const mindmap = new Mindmap(mapId, version);
|
||||
|
@ -20,9 +20,7 @@ import SizeType from '../SizeType';
|
||||
import Topic from '../Topic';
|
||||
|
||||
class LineTopicShape extends Line {
|
||||
private _topic: Topic;
|
||||
|
||||
private _size: SizeType;
|
||||
private _size: SizeType | null;
|
||||
|
||||
constructor(topic: Topic) {
|
||||
const stokeColor = topic.getConnectionColor();
|
||||
@ -30,7 +28,7 @@ class LineTopicShape extends Line {
|
||||
strokeColor: stokeColor,
|
||||
strokeWidth: 1,
|
||||
});
|
||||
this._topic = topic;
|
||||
this._size = null;
|
||||
}
|
||||
|
||||
setSize(width: number, height: number): void {
|
||||
@ -39,7 +37,7 @@ class LineTopicShape extends Line {
|
||||
super.setTo(width, height);
|
||||
}
|
||||
|
||||
getSize() {
|
||||
getSize(): SizeType | null {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
|
@ -83,12 +83,12 @@ class SymmetricTestSuite extends TestSuite {
|
||||
'Symmetry is not respected',
|
||||
);
|
||||
$assert(
|
||||
manager.find(8).getPosition().y - manager.find(1).getPosition().y ==
|
||||
manager.find(8).getPosition().y - manager.find(1).getPosition().y ===
|
||||
-(manager.find(11).getPosition().y - manager.find(1).getPosition().y),
|
||||
'Symmetry is not respected',
|
||||
);
|
||||
$assert(
|
||||
manager.find(9).getPosition().y - manager.find(1).getPosition().y ==
|
||||
manager.find(9).getPosition().y - manager.find(1).getPosition().y ===
|
||||
-(manager.find(11).getPosition().y - manager.find(1).getPosition().y),
|
||||
'Symmetry is not respected',
|
||||
);
|
||||
@ -136,20 +136,20 @@ class SymmetricTestSuite extends TestSuite {
|
||||
this._plotPrediction(graph1, prediction1a);
|
||||
$assert(
|
||||
prediction1a.position.x < manager.find(9).getPosition().x &&
|
||||
prediction1a.position.y == manager.find(9).getPosition().y,
|
||||
prediction1a.position.y === manager.find(9).getPosition().y,
|
||||
'Prediction incorrectly positioned',
|
||||
);
|
||||
$assert(prediction1a.order == 0, 'Prediction order should be 0');
|
||||
$assert(prediction1a.order === 0, 'Prediction order should be 0');
|
||||
|
||||
console.log('\tAdded as child of node 1 and dropped at (155, -90):');
|
||||
const prediction1b = manager.predict(1, null, { x: -155, y: -90 });
|
||||
this._plotPrediction(graph1, prediction1b);
|
||||
$assert(
|
||||
prediction1b.position.x > manager.find(1).getPosition().x &&
|
||||
prediction1b.position.y == manager.find(1).getPosition().y,
|
||||
prediction1b.position.y === manager.find(1).getPosition().y,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction1b.order == 0, 'Prediction order should be 0');
|
||||
$assert(prediction1b.order === 0, 'Prediction order should be 0');
|
||||
|
||||
// Graph 2
|
||||
const graph2 = manager.plot('testSymmetricPredict2', { width: 1000, height: 400 });
|
||||
@ -161,10 +161,10 @@ class SymmetricTestSuite extends TestSuite {
|
||||
// Prediction calculator error
|
||||
$assert(
|
||||
prediction2d.position.y < manager.find(7).getPosition().y &&
|
||||
prediction2d.position.x == manager.find(7).getPosition().x,
|
||||
prediction2d.position.x === manager.find(7).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction2d.order == 0, 'Prediction order should be 0');
|
||||
$assert(prediction2d.order === 0, 'Prediction order should be 0');
|
||||
|
||||
console.log('\tAdded as child of node 5 and dropped at (375, 15):');
|
||||
const prediction2a = manager.predict(5, null, { x: 375, y: 15 });
|
||||
@ -173,10 +173,10 @@ class SymmetricTestSuite extends TestSuite {
|
||||
$assert(
|
||||
prediction2a.position.y > manager.find(7).getPosition().y &&
|
||||
prediction2a.position.y < manager.find(8).getPosition().y &&
|
||||
prediction2a.position.x == manager.find(7).getPosition().x,
|
||||
prediction2a.position.x === manager.find(7).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction2a.order == 1, 'Prediction order should be 1');
|
||||
$assert(prediction2a.order === 1, 'Prediction order should be 1');
|
||||
|
||||
console.log('\tAdded as child of node 5 and dropped at (375, 45):');
|
||||
const prediction2b = manager.predict(5, null, { x: 375, y: 45 });
|
||||
@ -184,20 +184,20 @@ class SymmetricTestSuite extends TestSuite {
|
||||
$assert(
|
||||
prediction2b.position.y > manager.find(8).getPosition().y &&
|
||||
prediction2b.position.y < manager.find(11).getPosition().y &&
|
||||
prediction2b.position.x == manager.find(7).getPosition().x,
|
||||
prediction2b.position.x === manager.find(7).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction2b.order == 2, 'Prediction order should be 2');
|
||||
$assert(prediction2b.order === 2, 'Prediction order should be 2');
|
||||
|
||||
console.log('\tAdded as child of node 5 and dropped at (375, 45):');
|
||||
const prediction2c = manager.predict(5, null, { x: 375, y: 65 });
|
||||
this._plotPrediction(graph2, prediction2c);
|
||||
$assert(
|
||||
prediction2c.position.y > manager.find(11).getPosition().y &&
|
||||
prediction2c.position.x == manager.find(11).getPosition().x,
|
||||
prediction2c.position.x === manager.find(11).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction2c.order == 3, 'Prediction order should be 3');
|
||||
$assert(prediction2c.order === 3, 'Prediction order should be 3');
|
||||
|
||||
// Graph 3
|
||||
const graph3 = manager.plot('testSymmetricPredict3', { width: 1000, height: 400 });
|
||||
@ -208,20 +208,20 @@ class SymmetricTestSuite extends TestSuite {
|
||||
$assert(
|
||||
prediction3a.position.y > manager.find(5).getPosition().y &&
|
||||
prediction3a.position.y < manager.find(6).getPosition().y &&
|
||||
prediction3a.position.x == manager.find(5).getPosition().x,
|
||||
prediction3a.position.x === manager.find(5).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction3a.order == 2, 'Prediction order should be 2');
|
||||
$assert(prediction3a.order === 2, 'Prediction order should be 2');
|
||||
|
||||
console.log('\tAdded as child of node 3 and dropped at (255, 110):');
|
||||
const prediction3b = manager.predict(3, null, { x: 255, y: 110 });
|
||||
this._plotPrediction(graph3, prediction3b);
|
||||
$assert(
|
||||
prediction3b.position.y > manager.find(6).getPosition().y &&
|
||||
prediction3b.position.x == manager.find(6).getPosition().x,
|
||||
prediction3b.position.x === manager.find(6).getPosition().x,
|
||||
'Prediction incorrectly positioned',
|
||||
);
|
||||
$assert(prediction3b.order == 3, 'Prediction order should be 3');
|
||||
$assert(prediction3b.order === 3, 'Prediction order should be 3');
|
||||
|
||||
// Graph 4
|
||||
console.log('\tAdded as child of node 2 and dropped at (-260, 0):');
|
||||
@ -231,10 +231,10 @@ class SymmetricTestSuite extends TestSuite {
|
||||
$assert(
|
||||
prediction4.position.y > manager.find(9).getPosition().y &&
|
||||
prediction4.position.y < manager.find(10).getPosition().y &&
|
||||
prediction4.position.x == manager.find(9).getPosition().x,
|
||||
prediction4.position.x === manager.find(9).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction4.order == 1, 'Prediction order should be 1');
|
||||
$assert(prediction4.order === 1, 'Prediction order should be 1');
|
||||
|
||||
// Graph 5
|
||||
console.log('\tPredict nodes added with no position:');
|
||||
@ -242,40 +242,40 @@ class SymmetricTestSuite extends TestSuite {
|
||||
const prediction5a = manager.predict(1, null, null);
|
||||
this._plotPrediction(graph5, prediction5a);
|
||||
$assert(
|
||||
prediction5a.position.y == manager.find(1).getPosition().y &&
|
||||
prediction5a.position.y === manager.find(1).getPosition().y &&
|
||||
prediction5a.position.x > manager.find(1).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction5a.order == 0, 'Prediction order should be 0');
|
||||
$assert(prediction5a.order === 0, 'Prediction order should be 0');
|
||||
|
||||
const prediction5b = manager.predict(2, null, null);
|
||||
this._plotPrediction(graph5, prediction5b);
|
||||
$assert(
|
||||
prediction5b.position.y > manager.find(10).getPosition().y &&
|
||||
prediction5b.position.x < manager.find(2).getPosition().x &&
|
||||
prediction5b.position.x == manager.find(10).getPosition().x,
|
||||
prediction5b.position.x === manager.find(10).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction5b.order == 2, 'Prediction order should be 2');
|
||||
$assert(prediction5b.order === 2, 'Prediction order should be 2');
|
||||
|
||||
const prediction5c = manager.predict(3, null, null);
|
||||
this._plotPrediction(graph5, prediction5c);
|
||||
$assert(
|
||||
prediction5c.position.y > manager.find(6).getPosition().y &&
|
||||
prediction5c.position.x > manager.find(3).getPosition().x &&
|
||||
prediction5c.position.x == manager.find(6).getPosition().x,
|
||||
prediction5c.position.x === manager.find(6).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction5c.order == 3, 'Prediction order should be 3');
|
||||
$assert(prediction5c.order === 3, 'Prediction order should be 3');
|
||||
|
||||
const prediction5d = manager.predict(10, null, null);
|
||||
this._plotPrediction(graph5, prediction5d);
|
||||
$assert(
|
||||
prediction5d.position.y == manager.find(10).getPosition().y &&
|
||||
prediction5d.position.y === manager.find(10).getPosition().y &&
|
||||
prediction5d.position.x < manager.find(10).getPosition().x,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction5d.order == 0, 'Prediction order should be 0');
|
||||
$assert(prediction5d.order === 0, 'Prediction order should be 0');
|
||||
|
||||
console.log('OK!\n\n');
|
||||
}
|
||||
@ -295,54 +295,54 @@ class SymmetricTestSuite extends TestSuite {
|
||||
const prediction1a = manager.predict(1, 2, { x: -250, y: -20 });
|
||||
this._plotPrediction(graph1, prediction1a);
|
||||
$assert(
|
||||
prediction1a.position.x == manager.find(2).getPosition().x &&
|
||||
prediction1a.position.y == manager.find(2).getPosition().y,
|
||||
prediction1a.position.x === manager.find(2).getPosition().x &&
|
||||
prediction1a.position.y === manager.find(2).getPosition().y,
|
||||
'Prediction position should be the same as node 2',
|
||||
);
|
||||
$assert(
|
||||
prediction1a.order == manager.find(2).getOrder(),
|
||||
prediction1a.order === manager.find(2).getOrder(),
|
||||
'Predicition order should be the same as node 2',
|
||||
);
|
||||
|
||||
const prediction1b = manager.predict(1, 2, { x: -250, y: 20 });
|
||||
this._plotPrediction(graph1, prediction1b);
|
||||
$assert(
|
||||
prediction1b.position.x == manager.find(2).getPosition().x &&
|
||||
prediction1b.position.y == manager.find(2).getPosition().y,
|
||||
prediction1b.position.x === manager.find(2).getPosition().x &&
|
||||
prediction1b.position.y === manager.find(2).getPosition().y,
|
||||
'Prediction position should be the same as node 2',
|
||||
);
|
||||
$assert(
|
||||
prediction1b.order == manager.find(2).getOrder(),
|
||||
prediction1b.order === manager.find(2).getOrder(),
|
||||
'Predicition order should be the same as node 2',
|
||||
);
|
||||
|
||||
const prediction1c = manager.predict(0, 2, { x: -100, y: -20 });
|
||||
this._plotPrediction(graph1, prediction1c);
|
||||
$assert(
|
||||
prediction1c.position.x == manager.find(1).getPosition().x &&
|
||||
prediction1c.position.x === manager.find(1).getPosition().x &&
|
||||
prediction1c.position.y < manager.find(1).getPosition().y,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction1c.order == 1, 'Prediction order should be 1');
|
||||
$assert(prediction1c.order === 1, 'Prediction order should be 1');
|
||||
|
||||
const prediction1d = manager.predict(0, 2, { x: -100, y: 20 });
|
||||
this._plotPrediction(graph1, prediction1d);
|
||||
$assert(
|
||||
prediction1d.position.x == manager.find(1).getPosition().x &&
|
||||
prediction1d.position.x === manager.find(1).getPosition().x &&
|
||||
prediction1d.position.y > manager.find(1).getPosition().y,
|
||||
'Prediction is incorrectly positioned',
|
||||
);
|
||||
$assert(prediction1d.order == 3, 'Prediction order should be 3');
|
||||
$assert(prediction1d.order === 3, 'Prediction order should be 3');
|
||||
|
||||
const prediction1e = manager.predict(1, 2, { x: -250, y: 0 });
|
||||
this._plotPrediction(graph1, prediction1e);
|
||||
$assert(
|
||||
prediction1e.position.x == manager.find(2).getPosition().x &&
|
||||
prediction1e.position.y == manager.find(2).getPosition().y,
|
||||
prediction1e.position.x === manager.find(2).getPosition().x &&
|
||||
prediction1e.position.y === manager.find(2).getPosition().y,
|
||||
'Prediction position should be the same as node 2',
|
||||
);
|
||||
$assert(
|
||||
prediction1e.order == manager.find(2).getOrder(),
|
||||
prediction1e.order === manager.find(2).getOrder(),
|
||||
'Predicition order should be the same as node 2',
|
||||
);
|
||||
|
||||
|
@ -197,7 +197,7 @@ unencrypted.]]></text>
|
||||
<topic position="1100,26" order="0" text="but it can't encrypted" shape="line" id="1190504719"/>
|
||||
<topic position="1190,51" order="1" text="unless you have some UDP SSL thing" shape="line" id="878085542"/>
|
||||
</topic>
|
||||
<topic position="-1190,76" order="3" shape="line" id="252326982" bgColor="undefined">
|
||||
<topic position="-1190,76" order="3" shape="line" id="252326982">
|
||||
<text><![CDATA[Egerstad said the process of snooping on the traffic is trivial. The problem is not with Tor, which
|
||||
still works as intended, but with users' expectations: the Tor system is designed to merely
|
||||
anonymize Internet traffic and does not perform end-to-end
|
||||
|
@ -320,7 +320,7 @@
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="1190,2" order="1" text="Spin-offs" shape="line" id="309">
|
||||
<topic position="-1190,-10" order="0" text="undefined" shape="line" id="300"/>
|
||||
<topic position="-1190,-10" order="0" shape="line" id="300"/>
|
||||
</topic>
|
||||
<topic position="1280,27" order="2" text="Industry contracts" shape="line" id="310">
|
||||
<topic position="-1280,-35" order="0" text="Industry revenue per staff " shape="line" id="297"/>
|
||||
@ -330,7 +330,7 @@
|
||||
per 1,000 researchers [contracts/researchers]]]></text>
|
||||
</topic>
|
||||
<topic position="-1460,15" order="2" text="Share of industry income from foreign companies" shape="line" id="307"/>
|
||||
<topic position="-1550,40" order="3" text="undefined" shape="line" id="90"/>
|
||||
<topic position="-1550,40" order="3" shape="line" id="90"/>
|
||||
<topic position="-1640,65" order="4" text="Difficulties faced by research organization in collaborating with SMEs" shape="line" id="311"/>
|
||||
</topic>
|
||||
</topic>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<topic position="-200,-50" order="1" shape="rectangle" id="5" bgColor="#cccccc">
|
||||
<text><![CDATA[Baraloto et al. 2010. Functional trait variation and sampling strategies in species-rich plant
|
||||
communities]]></text>
|
||||
<topic position="-200,-350" order="1" text="undefined" shape="line" id="6"/>
|
||||
<topic position="-200,-350" order="1" shape="line" id="6"/>
|
||||
<topic position="290,-150" order="0" shape="line" id="7">
|
||||
<text><![CDATA[However, the fast pace of
|
||||
development of plant trait meta-analyses also suggests that
|
||||
@ -46,7 +46,6 @@ tb.]]></text>
|
||||
failed to accurately estimate the variance of trait values. This
|
||||
indicates that in situations where accurate estimation of plotlevel
|
||||
variance is desired, complete censuses are essential.]]></text>
|
||||
<note><![CDATA[undefined]]></note>
|
||||
</topic>
|
||||
<topic position="830,0" order="6" shape="line" id="15">
|
||||
<text><![CDATA[We suggest that, in these studies,
|
||||
@ -104,9 +103,9 @@ construir classificações mais detalhadas e com mais dados confiáveis.
|
||||
colonization groups based on the timing of seedling, sapling, and
|
||||
tree recruitment in secondary forests.]]></text>
|
||||
</topic>
|
||||
<topic position="740,-12" order="5" text="undefined" shape="line" id="27"/>
|
||||
<topic position="830,13" order="6" text="undefined" shape="line" id="28"/>
|
||||
<topic position="920,38" order="7" text="undefined" shape="line" id="29"/>
|
||||
<topic position="740,-12" order="5" shape="line" id="27"/>
|
||||
<topic position="830,13" order="6" shape="line" id="28"/>
|
||||
<topic position="920,38" order="7" shape="line" id="29"/>
|
||||
<topic position="1010,63" order="8" shape="line" id="30">
|
||||
<text><![CDATA[Classifying functional types
|
||||
based on functional traits with low plasticity, such as wood density
|
||||
|
@ -1,17 +1,17 @@
|
||||
<map name="freeMind_resources" version="tango">
|
||||
<topic central="true" text="FreeMind Resources" id="1330730879">
|
||||
<topic position="200,-100" order="0" text="Application" shape="line" id="906353570" bgColor="undefined">
|
||||
<topic position="200,-50" order="0" text="What is it?" shape="line" id="293234618" bgColor="undefined">
|
||||
<topic position="200,-100" order="0" text="Application" shape="line" id="906353570">
|
||||
<topic position="200,-50" order="0" text="What is it?" shape="line" id="293234618">
|
||||
<topic position="200,-50" order="0" text="A Freeware (as in free beer) Mindmapping tool coded in Java" shape="line" id="666230517"/>
|
||||
<topic position="-290,-75" order="0" text="Expects Java 1.4 or above on client machine" shape="line" id="339571721"/>
|
||||
</topic>
|
||||
<topic position="-290,-125" order="0" text="How to do?" shape="line" id="39960632" bgColor="undefined">
|
||||
<topic position="-290,-125" order="0" text="How to do?" shape="line" id="39960632">
|
||||
<topic position="290,-162" order="0" text="Install it" shape="line" id="904501221">
|
||||
<topic position="-290,-212" order="0" text="Links" shape="line" id="1911559485">
|
||||
<topic position="290,-237" order="0" text="Download the Java Runtime Environment (at least J2RE1.4)" shape="line" id="1031016126" bgColor="undefined">
|
||||
<topic position="290,-237" order="0" text="Download the Java Runtime Environment (at least J2RE1.4)" shape="line" id="1031016126">
|
||||
<link url="http://java.sun.com/j2se" urlType="url"/>
|
||||
</topic>
|
||||
<topic position="380,-212" order="1" text="Download the Application" shape="line" id="1612101865" bgColor="undefined">
|
||||
<topic position="380,-212" order="1" text="Download the Application" shape="line" id="1612101865">
|
||||
<link url="http://freemind.sourceforge.net/wiki/index.php/Main_Page#Download_and_install" urlType="url"/>
|
||||
</topic>
|
||||
</topic>
|
||||
@ -64,12 +64,12 @@ Ctrl + F in your browser?]]></note>
|
||||
</topic>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="-290,-37" order="0" text="Applet Browser" shape="line" id="1647062097" bgColor="undefined">
|
||||
<topic position="290,-62" order="0" text="What is it?" shape="rounded rectangle" id="287577997" bgColor="undefined">
|
||||
<topic position="-290,-37" order="0" text="Applet Browser" shape="line" id="1647062097">
|
||||
<topic position="290,-62" order="0" text="What is it?" shape="rounded rectangle" id="287577997">
|
||||
<topic position="-290,-87" order="0" text="A Java applet based browser " shape="line" id="1855944960"/>
|
||||
<topic position="-380,-62" order="1" text="Expects Java 1.4 or above on client machine" shape="line" id="300344325"/>
|
||||
</topic>
|
||||
<topic position="380,-37" order="1" text="How to do?" shape="line" shrink="true" id="1254385465" bgColor="undefined">
|
||||
<topic position="380,-37" order="1" text="How to do?" shape="line" shrink="true" id="1254385465">
|
||||
<topic position="-380,-62" order="0" text="See examples" shape="line" id="1491154453">
|
||||
<topic position="380,-87" order="0" text="Public Maps" shape="line" id="1082166644">
|
||||
<link url="http://freemind.sourceforge.net/PublicMaps.html" urlType="url"/>
|
||||
@ -101,8 +101,8 @@ site.]]></text>
|
||||
</topic>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="-380,-12" order="1" text="Flash Browser" shape="line" id="866838286" bgColor="undefined">
|
||||
<topic position="380,-37" order="0" text="What is it?" shape="line" id="1079211058" bgColor="undefined">
|
||||
<topic position="-380,-12" order="1" text="Flash Browser" shape="line" id="866838286">
|
||||
<topic position="380,-37" order="0" text="What is it?" shape="line" id="1079211058">
|
||||
<topic position="-380,-74" order="0" text="A browser which uses Shockwave Flash" shape="line" id="1719479201"/>
|
||||
<topic position="-470,-49" order="1" text="Does not require Java 1.4 or above on client machine" shape="line" id="838930706"/>
|
||||
<topic position="-560,-24" order="2" text="Expects Flash Player on client machine" shape="line" id="961870575">
|
||||
@ -110,7 +110,7 @@ site.]]></text>
|
||||
<topic position="650,-24" order="1" text="Recommend Flash Player 8" shape="line" id="913615141"/>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="470,-12" order="1" text="How to do?" shape="line" id="1824115095" bgColor="undefined">
|
||||
<topic position="470,-12" order="1" text="How to do?" shape="line" id="1824115095">
|
||||
<topic position="-470,-37" order="0" text="See examples" shape="line" id="1242194014">
|
||||
<topic position="470,-62" order="0" text="Hardware Support for Linux" shape="line" id="1249980290">
|
||||
<link url="http://eric.lavar.de/comp/linux/hw/" urlType="url"/>
|
||||
|
@ -2,19 +2,19 @@
|
||||
<topic central="true" id="704795576">
|
||||
<text><![CDATA[Writing an Essay
|
||||
With FreeMind]]></text>
|
||||
<topic position="200,-200" order="0" text="Getting Started" shape="line" shrink="true" id="60307947" bgColor="undefined">
|
||||
<topic position="200,-150" order="0" shape="line" id="484974719" bgColor="undefined">
|
||||
<topic position="200,-200" order="0" text="Getting Started" shape="line" shrink="true" id="60307947">
|
||||
<topic position="200,-150" order="0" shape="line" id="484974719">
|
||||
<text><![CDATA[The first thing you'll want to do is to create a new FreeMind file for your essay. Select File->New
|
||||
on the menu, and a blank file will appear.
|
||||
]]></text>
|
||||
</topic>
|
||||
<topic position="-290,-250" order="0" shape="line" id="1072554383" bgColor="undefined">
|
||||
<topic position="-290,-250" order="0" shape="line" id="1072554383">
|
||||
<text><![CDATA[Next, click in the centre of the map, and replace the text there with the essay title you have
|
||||
chosen. It's good to have the question you're answering before you the whole time, so you can
|
||||
immediately see how your ideas relate to
|
||||
it.]]></text>
|
||||
</topic>
|
||||
<topic position="-380,-225" order="1" shape="line" id="1631286703" bgColor="undefined">
|
||||
<topic position="-380,-225" order="1" shape="line" id="1631286703">
|
||||
<text><![CDATA[<!--
|
||||
p { margin-top: 0 }
|
||||
-->
|
||||
@ -28,22 +28,22 @@ it.]]></text>
|
||||
|
||||
(When you're a bit more familiar with FreeMind, you'll find it quicker to use the Shortcut Keys -- you can also use Alt + Shift + Left, or Alt + Shift + Right to move between maps.)]]></text>
|
||||
</topic>
|
||||
<topic position="-470,-200" order="2" text="You're now ready to start work on the essay." shape="line" id="538231078" bgColor="undefined"/>
|
||||
<topic position="-470,-200" order="2" text="You're now ready to start work on the essay." shape="line" id="538231078"/>
|
||||
</topic>
|
||||
<topic position="-290,-62" order="0" text="The process of research" shape="line" shrink="true" id="1886958546" bgColor="undefined">
|
||||
<topic position="290,-124" order="0" shape="line" id="499702363" bgColor="undefined">
|
||||
<topic position="-290,-62" order="0" text="The process of research" shape="line" shrink="true" id="1886958546">
|
||||
<topic position="290,-124" order="0" shape="line" id="499702363">
|
||||
<text><![CDATA[If a question is worth asking at all (and be generous to your teachers, and assume that their
|
||||
question is!), then it's not going to have the kind of answer that you can just make up on the spot.
|
||||
It will require
|
||||
research.]]></text>
|
||||
</topic>
|
||||
<topic position="380,-99" order="1" text="Research requires both finding things out about the world, and hard thinking." shape="line" id="1374284784" bgColor="undefined"/>
|
||||
<topic position="470,-74" order="2" shape="line" id="1038997740" bgColor="undefined">
|
||||
<topic position="380,-99" order="1" text="Research requires both finding things out about the world, and hard thinking." shape="line" id="1374284784"/>
|
||||
<topic position="470,-74" order="2" shape="line" id="1038997740">
|
||||
<text><![CDATA[FreeMind helps you with both aspects of research. FreeMind helps you to capture all the new
|
||||
information you need for your essay, and also to order your
|
||||
thoughts.]]></text>
|
||||
</topic>
|
||||
<topic position="560,-49" order="3" text="FreeMind does this by facilitating:" shape="line" id="1522470300" bgColor="undefined">
|
||||
<topic position="560,-49" order="3" text="FreeMind does this by facilitating:" shape="line" id="1522470300">
|
||||
<topic position="-560,-99" order="0" text="Taking Notes" shape="line" id="1963065372">
|
||||
<link url="http://#Freemind_Link_513978291" urlType="url"/>
|
||||
</topic>
|
||||
@ -57,7 +57,7 @@ thoughts.]]></text>
|
||||
<link url="http://#Freemind_Link_341601142" urlType="url"/>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="650,-24" order="4" text="When you've made your outline you can" shape="line" id="759053646" bgColor="undefined">
|
||||
<topic position="650,-24" order="4" text="When you've made your outline you can" shape="line" id="759053646">
|
||||
<topic position="-650,-61" order="0" text="Print your map" shape="line" id="996906209"/>
|
||||
<topic position="-740,-36" order="1" text="Export to your wordprocessor" shape="line" id="1501502447">
|
||||
<link url="http://#Freemind_Link_877777095" urlType="url"/>
|
||||
@ -67,8 +67,8 @@ thoughts.]]></text>
|
||||
</topic>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="-380,-37" order="1" text="Planning an Essay" shape="line" shrink="true" id="1034561457" bgColor="undefined">
|
||||
<topic position="380,-87" order="0" text="Brainstorming" shape="line" shrink="true" id="1" bgColor="undefined">
|
||||
<topic position="-380,-37" order="1" text="Planning an Essay" shape="line" shrink="true" id="1034561457">
|
||||
<topic position="380,-87" order="0" text="Brainstorming" shape="line" shrink="true" id="1">
|
||||
<topic position="-380,-162" order="0" shape="line" id="1420002558">
|
||||
<text><![CDATA[Brainstorming is a way of trying to geting all your ideas about a topic down on paper as quickly as
|
||||
possible.]]></text>
|
||||
@ -83,18 +83,18 @@ later.]]></text>
|
||||
<topic position="-740,-62" order="4" text="Pressing Insert adds another idea as a subidea of the one you've currently selected." shape="line" id="1371557121"/>
|
||||
<topic position="-830,-37" order="5" text="(The imagination you'll have to supply yourself!)" shape="line" id="443781940"/>
|
||||
</topic>
|
||||
<topic position="470,-62" order="1" text="Taking Notes" shape="line" shrink="true" id="513978291" bgColor="undefined">
|
||||
<topic position="-470,-124" order="0" shape="line" id="709453371" bgColor="undefined">
|
||||
<topic position="470,-62" order="1" text="Taking Notes" shape="line" shrink="true" id="513978291">
|
||||
<topic position="-470,-124" order="0" shape="line" id="709453371">
|
||||
<text><![CDATA[Different people take notes in different ways. Whichever way you take notes, you should find
|
||||
FreeMind
|
||||
helpful.]]></text>
|
||||
</topic>
|
||||
<topic position="-560,-99" order="1" shape="line" id="249608113" bgColor="undefined">
|
||||
<topic position="-560,-99" order="1" shape="line" id="249608113">
|
||||
<text><![CDATA[One good way of using FreeMind is to add one node per book or article you read. Name the node a
|
||||
short version of the article title.
|
||||
]]></text>
|
||||
</topic>
|
||||
<topic position="-650,-74" order="2" shape="line" shrink="true" id="1470413282" bgColor="undefined">
|
||||
<topic position="-650,-74" order="2" shape="line" shrink="true" id="1470413282">
|
||||
<text><![CDATA[Then add your notes on the article as a node note. To insert a note, go to the View menu, and
|
||||
select "Show Note Window". You can then add your notes
|
||||
below.]]></text>
|
||||
@ -104,8 +104,8 @@ helpful to hide it after you've added your note, by selecting "Show Note Window"
|
||||
menu.]]></text>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="-740,-49" order="3" text="Don't forget to take full references for all the quotations you use. " shape="line" id="1226928695" bgColor="undefined"/>
|
||||
<topic position="-830,-24" order="4" text="FreeMind can also do some clever things with web links and email addresses." shape="line" shrink="true" id="1195317986" bgColor="undefined">
|
||||
<topic position="-740,-49" order="3" text="Don't forget to take full references for all the quotations you use. " shape="line" id="1226928695"/>
|
||||
<topic position="-830,-24" order="4" text="FreeMind can also do some clever things with web links and email addresses." shape="line" shrink="true" id="1195317986">
|
||||
<topic position="830,-86" order="0" shape="line" id="1167090962">
|
||||
<text><![CDATA[If you're researching on the web, then FreeMind can automatically link your note to the web page
|
||||
you're writing about.
|
||||
@ -132,7 +132,7 @@ address.]]></text>
|
||||
</topic>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="560,-37" order="2" text="Sifting and organising your ideas" shape="line" shrink="true" id="331016293" bgColor="undefined">
|
||||
<topic position="560,-37" order="2" text="Sifting and organising your ideas" shape="line" shrink="true" id="331016293">
|
||||
<topic position="-560,-124" order="0" shape="line" id="136989740">
|
||||
<text><![CDATA[After you've done a bit of brainstorming, and have written all the ideas you can think of, it's time
|
||||
to start sorting your ideas
|
||||
@ -174,7 +174,7 @@ menu, and call the new one it something like "Essay_Outline v1".
|
||||
]]></text>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="650,-12" order="3" text="Outlining" shape="line" shrink="true" id="341601142" bgColor="undefined">
|
||||
<topic position="650,-12" order="3" text="Outlining" shape="line" shrink="true" id="341601142">
|
||||
<topic position="-650,-87" order="0" text="Now you know what your main point is, you can write an outline of the argument of the essay." shape="line" id="190098699"/>
|
||||
<topic position="-740,-62" order="1" text="The point of producing an outline is to work out how you will argue for your essay's main claim." shape="line" id="132833105"/>
|
||||
<topic position="-830,-37" order="2" shape="line" id="1132818589">
|
||||
@ -237,14 +237,14 @@ point.]]></text>
|
||||
</topic>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="-470,-12" order="2" text="From Outline to Finished Work" shape="line" shrink="true" id="1755853195" bgColor="undefined">
|
||||
<topic position="470,-74" order="0" shape="line" id="1449950809" bgColor="undefined">
|
||||
<topic position="-470,-12" order="2" text="From Outline to Finished Work" shape="line" shrink="true" id="1755853195">
|
||||
<topic position="470,-74" order="0" shape="line" id="1449950809">
|
||||
<text><![CDATA[Writing the outline of your essay is the hard part. Once you have a good outline, it's much easier
|
||||
to write a good essay or a good
|
||||
presentation.]]></text>
|
||||
</topic>
|
||||
<topic position="560,-49" order="1" text="You'll probably find it easier to to the actual writing of the essay in your wordprocessor." shape="line" id="1607766784" bgColor="undefined"/>
|
||||
<topic position="650,-24" order="2" text="Exporting your outline to your Wordprocessor" shape="line" shrink="true" id="877777095" bgColor="undefined">
|
||||
<topic position="560,-49" order="1" text="You'll probably find it easier to to the actual writing of the essay in your wordprocessor." shape="line" id="1607766784"/>
|
||||
<topic position="650,-24" order="2" text="Exporting your outline to your Wordprocessor" shape="line" shrink="true" id="877777095">
|
||||
<topic position="-650,-99" order="0" shape="line" shrink="true" id="1821901940">
|
||||
<text><![CDATA[FreeMind currently exports much better to OpenOffice than to Microsoft Word. So if you don't yet
|
||||
have OpenOffice, it's well worth downloading it (it's
|
||||
@ -280,7 +280,7 @@ wordprocessor as
|
||||
normal.]]></text>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="740,1" order="3" text="Making a presentation" shape="line" shrink="true" id="781772166" bgColor="undefined">
|
||||
<topic position="740,1" order="3" text="Making a presentation" shape="line" shrink="true" id="781772166">
|
||||
<topic position="-740,-74" order="0" text="FreeMind also provides a good way of outlining PowerPoint presentations." shape="line" id="1714771405"/>
|
||||
<topic position="-830,-49" order="1" text="You'll need OpenOffice again." shape="line" id="233010529"/>
|
||||
<topic position="-920,-24" order="2" text="Follow the instructions above to export your outline to OpenOffice." shape="line" id="1394183501"/>
|
||||
@ -296,50 +296,50 @@ best
|
||||
results.]]></text>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="830,26" order="4" text="Things to check before you submit your essay" shape="line" shrink="true" id="1657086138" bgColor="undefined">
|
||||
<topic position="830,26" order="4" text="Things to check before you submit your essay" shape="line" shrink="true" id="1657086138">
|
||||
<topic position="-830,-111" order="0" shape="line" id="1855894453">
|
||||
<text><![CDATA[(This advice doesn't tell you anything about how to use FreeMind, but it may help you get a better
|
||||
mark in your
|
||||
essay!)]]></text>
|
||||
</topic>
|
||||
<topic position="-920,-86" order="1" text="Does my essay have a main claim?" shape="line" id="1803078302" bgColor="undefined">
|
||||
<topic position="-920,-86" order="1" text="Does my essay have a main claim?" shape="line" id="1803078302">
|
||||
<note><![CDATA[Another way of asking this question is can you sum up in a sentence what the main point is that your essay is making?) If you don't have a main claim (or don't know what your main claim is!), then your essay will not get a good mark. You are assessed on the quality of the argument you put forward for your main claim, and in order to be able to do this we (and you) need to know what your main claim is.]]></note>
|
||||
</topic>
|
||||
<topic position="-1010,-61" order="2" text="Does my main claim provide a full answer the question that I have been asked?" shape="line" id="107276913" bgColor="undefined">
|
||||
<topic position="-1010,-61" order="2" text="Does my main claim provide a full answer the question that I have been asked?" shape="line" id="107276913">
|
||||
<note><![CDATA[You must be honest with yourself at this point: if you suspect that you haven't fully answered the question, then you must either (a) revise your answer so that you do have a full answer to the question, or (b) provide an argument for why it is that the angle you want to bring to the question is legitimate (for example, explain why it is legitimate to focus on just one aspect of the question).]]></note>
|
||||
</topic>
|
||||
<topic position="-1100,-36" order="3" text="Have I made it obvious what my main claim is?" shape="line" id="1628680821" bgColor="undefined">
|
||||
<topic position="-1100,-36" order="3" text="Have I made it obvious what my main claim is?" shape="line" id="1628680821">
|
||||
<note><![CDATA[You should state what your main claim is in at least two places, first in the introduction, and second in the conclusion. (The bits in between should be devoted to arguing for your main claim).]]></note>
|
||||
</topic>
|
||||
<topic position="-1190,-11" order="4" text="Do I have an argument for my main claim?" shape="line" id="927542090" bgColor="undefined">
|
||||
<topic position="-1190,-11" order="4" text="Do I have an argument for my main claim?" shape="line" id="927542090">
|
||||
<note><![CDATA[What reasons have you put forward as to why a reasonable (but sceptical) person should accept that your main claim is true? If you don't have any reasons (but merely a gut intuition) then you need to go back and revise, and find some arguments.]]></note>
|
||||
</topic>
|
||||
<topic position="-1280,14" order="5" text="Is my argument for my main claim sound?" shape="line" id="337592890" bgColor="undefined">
|
||||
<topic position="-1280,14" order="5" text="Is my argument for my main claim sound?" shape="line" id="337592890">
|
||||
<note><![CDATA[Does your main claim follow logically from the supporting reasons you put forward? And are those supporting reasons themselves true (or at least plausibly true)?]]></note>
|
||||
</topic>
|
||||
<topic position="-1370,39" order="6" text="Do I have an introduction which provides an overview of the structure of my argument?" shape="line" id="1338320981" bgColor="undefined">
|
||||
<topic position="-1370,39" order="6" text="Do I have an introduction which provides an overview of the structure of my argument?" shape="line" id="1338320981">
|
||||
<note><![CDATA[It is not enough e.g. to say that “I will be looking at arguments on both sides of this issue and coming to a conclusion”. You should tell us which arguments you will be looking at, whatyour evaluation of each of these arguments will be, and howthis analysis justifies the overall main claim you will be making. There are two reasons to give an overview of the structure of your argument: (a) it makes it much easier for the reader to grasp what you are saying, and why; (b) writing a summary of the structure of your argument is a good way of testing that you do in fact have a coherent argument.]]></note>
|
||||
</topic>
|
||||
<topic position="-1460,64" order="7" text="What reasons might a reasonable person have for doubting my main claim?" shape="line" id="1521390030" bgColor="undefined">
|
||||
<topic position="-1460,64" order="7" text="What reasons might a reasonable person have for doubting my main claim?" shape="line" id="1521390030">
|
||||
<note><![CDATA[Remember that in any academic debate, anything worth saying will be disputed. If you can't think of any reasons why someone might doubt your main claim, it's likely that you are in the grip of a dogmatic certainty that you are right. This is not good: your essay will come across as a rant, which is the last thing you want.]]></note>
|
||||
</topic>
|
||||
<topic position="-1550,89" order="8" text="Have I responded to these reasons for doubting my main claim in a convincing way?" shape="line" id="1843933327" bgColor="undefined">
|
||||
<topic position="-1550,89" order="8" text="Have I responded to these reasons for doubting my main claim in a convincing way?" shape="line" id="1843933327">
|
||||
<note><![CDATA[To be convincing, you might show that the doubts, while reasonable, are not well founded; or you could make your main claim more specific or nuanced in deference to them.]]></note>
|
||||
</topic>
|
||||
<topic position="-1640,114" order="9" text="Is there any material in my essay which might seem irrelevant to establishing my main point?" shape="line" id="982795475" bgColor="undefined">
|
||||
<topic position="-1640,114" order="9" text="Is there any material in my essay which might seem irrelevant to establishing my main point?" shape="line" id="982795475">
|
||||
<note><![CDATA[If there is, then either delete this material, or explain why this material is after all relevant.]]></note>
|
||||
</topic>
|
||||
<topic position="-1730,139" order="10" text="Have I fully acknowledged all my sources, and marked all quotations as quotations?" shape="line" id="606334721" bgColor="undefined">
|
||||
<topic position="-1730,139" order="10" text="Have I fully acknowledged all my sources, and marked all quotations as quotations?" shape="line" id="606334721">
|
||||
<note><![CDATA[If not then you are guilty of plagiarism. This is a serious offence, and you are likely to fail your course..]]></note>
|
||||
</topic>
|
||||
</topic>
|
||||
</topic>
|
||||
<topic position="-560,13" order="3" text="About this map" shape="line" shrink="true" id="854745518" bgColor="undefined">
|
||||
<topic position="560,-24" order="0" text="Version 0.1, Jan 2 2008" shape="line" id="1464926185" bgColor="undefined"/>
|
||||
<topic position="650,1" order="1" text="James Wilson" shape="line" id="1351075037" bgColor="undefined">
|
||||
<topic position="-560,13" order="3" text="About this map" shape="line" shrink="true" id="854745518">
|
||||
<topic position="560,-24" order="0" text="Version 0.1, Jan 2 2008" shape="line" id="1464926185"/>
|
||||
<topic position="650,1" order="1" text="James Wilson" shape="line" id="1351075037">
|
||||
<link url="http://mailto:j.g.wilson@peak.keele.ac.uk" urlType="mail"/>
|
||||
</topic>
|
||||
<topic position="740,26" order="2" text="Notes on this map" shape="line" id="1843583599" bgColor="undefined">
|
||||
<topic position="740,26" order="2" text="Notes on this map" shape="line" id="1843583599">
|
||||
<note><![CDATA[This map is intended to help someone who has to write an argumentative essay in a subject such as history or philosophy to write better essays with the help of FreeMind. Copyright for this map resides with the author. Released under the Creative Commons Attribution-ShareAlike licence v.2.00. http://creativecommons.org/licenses/by-sa/2.0/uk/
|
||||
|
||||
|
||||
|
@ -2,15 +2,22 @@
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": false,
|
||||
"module": "amd",
|
||||
"moduleResolution": "node",
|
||||
"target": "ES2020",
|
||||
"target": "es6",
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"declaration": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
"noImplicitAny": false,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"strictFunctionTypes": true,
|
||||
|
||||
"rootDirs": [
|
||||
"src",
|
||||
]
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 78 KiB |
@ -7,7 +7,7 @@
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="<%=PUBLIC_URL%>/favicon.ico" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap" rel="stylesheet" onload="if(media!='all')media='all'" media="none"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap" rel="stylesheet" rel="preload"/>
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* 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 React, { ReactElement, Suspense, useEffect } from 'react';
|
||||
import { FormattedMessage, IntlProvider } from 'react-intl';
|
||||
import { Route, Routes, BrowserRouter as Router, useNavigate } from 'react-router-dom';
|
||||
@ -22,12 +39,14 @@ const EditorPage = React.lazy(() => import('./components/editor-page'));
|
||||
const MapsPage = React.lazy(() => import('./components/maps-page'));
|
||||
|
||||
// Google Analytics Initialization.
|
||||
ReactGA.initialize([
|
||||
{
|
||||
trackingId: AppConfig.getGoogleAnalyticsAccount(),
|
||||
},
|
||||
]);
|
||||
|
||||
const trackingId = AppConfig.getGoogleAnalyticsAccount();
|
||||
if (trackingId) {
|
||||
ReactGA.initialize([
|
||||
{
|
||||
trackingId: trackingId,
|
||||
},
|
||||
]);
|
||||
}
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
|
@ -17,7 +17,6 @@
|
||||
*/
|
||||
|
||||
import Client from '../client';
|
||||
import CacheDecoratorClient from '../client/cache-decorator-client';
|
||||
import MockClient from '../client/mock-client';
|
||||
import RestClient from '../client/rest-client';
|
||||
|
||||
@ -91,8 +90,7 @@ class _AppConfig {
|
||||
result = new MockClient();
|
||||
}
|
||||
|
||||
// Wrap with a cache decorator ...
|
||||
return new CacheDecoratorClient(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
getBaseUrl(): string {
|
||||
|
@ -57,8 +57,8 @@ export default abstract class AppI18n {
|
||||
|
||||
public static getDefaultLocale(): Locale {
|
||||
// Fetch local from local storage ...
|
||||
let result: Locale;
|
||||
const userLocaleCode: string = localStorage.getItem(AppI18n.LOCAL_STORAGE_KEY);
|
||||
let result: Locale | null = null;
|
||||
const userLocaleCode: string | null = localStorage.getItem(AppI18n.LOCAL_STORAGE_KEY);
|
||||
if (userLocaleCode) {
|
||||
result = localeFromStr(userLocaleCode);
|
||||
}
|
||||
|
@ -1,143 +0,0 @@
|
||||
import Client, {
|
||||
AccountInfo,
|
||||
BasicMapInfo,
|
||||
ChangeHistory,
|
||||
ImportMapInfo,
|
||||
Label,
|
||||
MapInfo,
|
||||
NewUser,
|
||||
Permission,
|
||||
Oauth2CallbackResult,
|
||||
ForgotPasswordResult,
|
||||
} from '..';
|
||||
import { LocaleCode } from '../../app-i18n';
|
||||
|
||||
class CacheDecoratorClient implements Client {
|
||||
private client: Client;
|
||||
|
||||
constructor(client: Client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
processGoogleCallback(code: string): Promise<Oauth2CallbackResult> {
|
||||
return this.client.processGoogleCallback(code);
|
||||
}
|
||||
|
||||
confirmAccountSync(email: string, code: string): Promise<void> {
|
||||
return this.client.confirmAccountSync(email, code);
|
||||
}
|
||||
|
||||
fetchStarred(id: number): Promise<boolean> {
|
||||
return this.client.fetchStarred(id);
|
||||
}
|
||||
|
||||
onSessionExpired(callback?: () => void): () => void {
|
||||
return this.client.onSessionExpired(callback);
|
||||
}
|
||||
|
||||
deleteAccount(): Promise<void> {
|
||||
return this.client.deleteAccount();
|
||||
}
|
||||
|
||||
importMap(model: ImportMapInfo): Promise<number> {
|
||||
return this.client.importMap(model);
|
||||
}
|
||||
|
||||
createMap(map: BasicMapInfo): Promise<number> {
|
||||
return this.client.createMap(map);
|
||||
}
|
||||
|
||||
deleteMaps(ids: number[]): Promise<void> {
|
||||
return this.client.deleteMaps(ids);
|
||||
}
|
||||
|
||||
deleteMap(id: number): Promise<void> {
|
||||
return this.client.deleteMap(id);
|
||||
}
|
||||
|
||||
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
||||
return this.client.renameMap(id, basicInfo);
|
||||
}
|
||||
|
||||
fetchAllMaps(): Promise<MapInfo[]> {
|
||||
return this.client.fetchAllMaps();
|
||||
}
|
||||
|
||||
fetchMapPermissions(id: number): Promise<Permission[]> {
|
||||
return this.client.fetchMapPermissions(id);
|
||||
}
|
||||
|
||||
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
|
||||
return this.client.addMapPermissions(id, message, permissions);
|
||||
}
|
||||
|
||||
deleteMapPermission(id: number, email: string): Promise<void> {
|
||||
return this.client.deleteMapPermission(id, email);
|
||||
}
|
||||
|
||||
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
|
||||
return this.client.duplicateMap(id, basicInfo);
|
||||
}
|
||||
|
||||
updateAccountLanguage(locale: LocaleCode): Promise<void> {
|
||||
return this.client.updateAccountLanguage(locale);
|
||||
}
|
||||
|
||||
updateAccountPassword(pasword: string): Promise<void> {
|
||||
return this.client.updateAccountPassword(pasword);
|
||||
}
|
||||
|
||||
updateAccountInfo(firstname: string, lastname: string): Promise<void> {
|
||||
return this.client.updateAccountInfo(firstname, lastname);
|
||||
}
|
||||
|
||||
updateStarred(id: number, starred: boolean): Promise<void> {
|
||||
return this.client.updateStarred(id, starred);
|
||||
}
|
||||
|
||||
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
|
||||
return this.client.updateMapToPublic(id, isPublic);
|
||||
}
|
||||
|
||||
fetchLabels(): Promise<Label[]> {
|
||||
return this.client.fetchLabels();
|
||||
}
|
||||
|
||||
createLabel(title: string, color: string): Promise<number> {
|
||||
return this.client.createLabel(title, color);
|
||||
}
|
||||
|
||||
deleteLabel(id: number): Promise<void> {
|
||||
return this.client.deleteLabel(id);
|
||||
}
|
||||
|
||||
addLabelToMap(labelId: number, mapId: number): Promise<void> {
|
||||
return this.client.addLabelToMap(labelId, mapId);
|
||||
}
|
||||
|
||||
deleteLabelFromMap(labelId: number, mapId: number): Promise<void> {
|
||||
return this.client.deleteLabelFromMap(labelId, mapId);
|
||||
}
|
||||
|
||||
fetchAccountInfo(): Promise<AccountInfo> {
|
||||
return this.client.fetchAccountInfo();
|
||||
}
|
||||
|
||||
registerNewUser(user: NewUser): Promise<void> {
|
||||
return this.client.registerNewUser(user);
|
||||
}
|
||||
|
||||
resetPassword(email: string): Promise<ForgotPasswordResult> {
|
||||
return this.client.resetPassword(email);
|
||||
}
|
||||
|
||||
fetchHistory(id: number): Promise<ChangeHistory[]> {
|
||||
return this.client.fetchHistory(id);
|
||||
}
|
||||
|
||||
revertHistory(id: number, cid: number): Promise<void> {
|
||||
return this.client.revertHistory(id, cid);
|
||||
}
|
||||
}
|
||||
|
||||
export default CacheDecoratorClient;
|
@ -118,12 +118,12 @@ interface Client {
|
||||
registerNewUser(user: NewUser): Promise<void>;
|
||||
resetPassword(email: string): Promise<ForgotPasswordResult>;
|
||||
processGoogleCallback(code: string): Promise<Oauth2CallbackResult>;
|
||||
confirmAccountSync(email: string, code: string): Promise<void>;
|
||||
confirmAccountSync(email: string, code?: string): Promise<void>;
|
||||
|
||||
fetchHistory(id: number): Promise<ChangeHistory[]>;
|
||||
revertHistory(id: number, cid: number): Promise<void>;
|
||||
|
||||
onSessionExpired(callback?: () => void): () => void;
|
||||
onSessionExpired(callback?: () => void): (() => void) | undefined;
|
||||
}
|
||||
|
||||
export default Client;
|
||||
|
@ -128,10 +128,10 @@ class MockClient implements Client {
|
||||
}
|
||||
|
||||
fetchStarred(id: number): Promise<boolean> {
|
||||
return Promise.resolve(this.maps.find((m) => m.id == id).starred);
|
||||
return Promise.resolve(Boolean(this.maps.find((m) => m.id == id)?.starred));
|
||||
}
|
||||
|
||||
onSessionExpired(callback?: () => void): () => void {
|
||||
onSessionExpired(callback?: () => void): (() => void) | undefined {
|
||||
return callback;
|
||||
}
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
/* eslint-disable react/display-name */
|
||||
import React, { ComponentType, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import Client from '../../classes/client';
|
||||
import ClientHealthSentinel from '../../classes/client/client-health-sentinel';
|
||||
import { activeInstance, sessionExpired } from '../../redux/clientSlice';
|
||||
|
||||
function withSessionExpirationHandling<T>(Component: ComponentType<T>) {
|
||||
return (hocProps: T): React.ReactElement => {
|
||||
const client: Client = useSelector(activeInstance);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (client) {
|
||||
client.onSessionExpired(() => {
|
||||
dispatch(sessionExpired());
|
||||
});
|
||||
} else {
|
||||
console.warn('Session expiration wont be handled because could not find client');
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ClientHealthSentinel />
|
||||
<Component {...hocProps} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default withSessionExpirationHandling;
|
10
packages/webapp/src/components/common/csrf-input/index.tsx
Normal file
10
packages/webapp/src/components/common/csrf-input/index.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import { getCsrfToken, getCsrfTokenParameter } from '../../../utils';
|
||||
|
||||
const CSRFInput = (): React.ReactElement => {
|
||||
const token = getCsrfToken();
|
||||
const tokenParam = getCsrfTokenParameter();
|
||||
return <>{token && tokenParam && <input type="hidden" value={token} name={tokenParam} />}</>;
|
||||
};
|
||||
|
||||
export default CSRFInput;
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { Button } from '@mui/material';
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { containerStyle, lineStyle, textStyle } from './style';
|
||||
|
@ -2,7 +2,7 @@ import { css, SerializedStyles } from '@emotion/react';
|
||||
|
||||
export const containerStyle = (
|
||||
responsive: boolean,
|
||||
maxWidth: number,
|
||||
maxWidth: number | undefined,
|
||||
breakPointDownMd: string,
|
||||
): SerializedStyles => {
|
||||
return css([
|
||||
|
@ -26,19 +26,23 @@ import {
|
||||
} from '@wisemapping/editor';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import AppI18n, { Locales } from '../../classes/app-i18n';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { hotkeysEnabled } from '../../redux/editorSlice';
|
||||
import ReactGA from 'react-ga4';
|
||||
import { useFetchAccount, useFetchMapById } from '../../redux/clientSlice';
|
||||
import {
|
||||
useFetchAccount,
|
||||
useFetchMapById,
|
||||
activeInstance,
|
||||
sessionExpired,
|
||||
} from '../../redux/clientSlice';
|
||||
import EditorOptionsBuilder from './EditorOptionsBuilder';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import MapInfoImpl from '../../classes/editor-map-info';
|
||||
import { MapInfo } from '@wisemapping/editor';
|
||||
import { activeInstance } from '../../redux/clientSlice';
|
||||
import Client from '../../classes/client';
|
||||
import AppConfig from '../../classes/app-config';
|
||||
import exampleMap from '../../classes/client/mock-client/example-map.wxml';
|
||||
import withSessionExpirationHandling from '../HOCs/withSessionExpirationHandling';
|
||||
import ClientHealthSentinel from '../common/client-health-sentinel';
|
||||
|
||||
const buildPersistenceManagerForEditor = (mode: string): PersistenceManager => {
|
||||
let persistenceManager: PersistenceManager;
|
||||
@ -72,6 +76,7 @@ const buildPersistenceManagerForEditor = (mode: string): PersistenceManager => {
|
||||
export type EditorPropsType = {
|
||||
isTryMode: boolean;
|
||||
};
|
||||
|
||||
type ActionType =
|
||||
| 'open'
|
||||
| 'share'
|
||||
@ -98,6 +103,17 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => {
|
||||
const userLocale = AppI18n.getUserLocale();
|
||||
const theme = useTheme();
|
||||
const client: Client = useSelector(activeInstance);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (client) {
|
||||
client.onSessionExpired(() => {
|
||||
dispatch(sessionExpired());
|
||||
});
|
||||
} else {
|
||||
console.warn('Session expiration wont be handled because could not find client');
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
ReactGA.send({ hitType: 'pageview', page: window.location.pathname, title: `Map Editor` });
|
||||
@ -163,6 +179,7 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => {
|
||||
defaultLocale={Locales.EN.code}
|
||||
messages={userLocale.message as Record<string, string>}
|
||||
>
|
||||
<ClientHealthSentinel />
|
||||
<Editor
|
||||
onAction={setActiveDialog}
|
||||
options={options}
|
||||
@ -197,4 +214,4 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withSessionExpirationHandling(EditorPage);
|
||||
export default EditorPage;
|
||||
|
@ -15,9 +15,9 @@ import ReactGA from 'react-ga4';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { getCsrfToken, getCsrfTokenParameter } from '../../utils';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Button } from '@mui/material';
|
||||
import CSRFInput from '../common/csrf-input';
|
||||
|
||||
const ForgotPassword = () => {
|
||||
const [email, setEmail] = useState<string>('');
|
||||
@ -84,7 +84,7 @@ const ForgotPassword = () => {
|
||||
<GlobalError error={error} />
|
||||
|
||||
<form onSubmit={handleOnSubmit}>
|
||||
<input type="hidden" value={getCsrfToken()} name={getCsrfTokenParameter()} />
|
||||
<CSRFInput />
|
||||
<Input
|
||||
type="email"
|
||||
name="email"
|
||||
|
@ -11,10 +11,10 @@ import Typography from '@mui/material/Typography';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import Link from '@mui/material/Link';
|
||||
import ReactGA from 'react-ga4';
|
||||
import { getCsrfToken, getCsrfTokenParameter } from '../../utils';
|
||||
import Separator from '../common/separator';
|
||||
import GoogleButton from '../common/google-button';
|
||||
import AppConfig from '../../classes/app-config';
|
||||
import CSRFInput from '../common/csrf-input';
|
||||
|
||||
const LoginError = () => {
|
||||
// @Todo: This must be reviewed to be based on navigation state.
|
||||
@ -70,7 +70,7 @@ const LoginPage = (): React.ReactElement => {
|
||||
|
||||
<FormControl>
|
||||
<form action="/c/perform-login" method="POST">
|
||||
<input type="hidden" value={getCsrfToken()} name={getCsrfTokenParameter()} />
|
||||
<CSRFInput />
|
||||
<Input
|
||||
name="username"
|
||||
type="email"
|
||||
@ -121,7 +121,12 @@ const LoginPage = (): React.ReactElement => {
|
||||
defaultMessage: 'Sign in with Google',
|
||||
})}
|
||||
onClick={() => {
|
||||
window.location.href = AppConfig.getGoogleOauth2Url();
|
||||
const authUrl = AppConfig.getGoogleOauth2Url();
|
||||
if (authUrl) {
|
||||
window.location.href = authUrl;
|
||||
} else {
|
||||
console.log('GoogleOauth2Url is not configured.');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FormContainer>
|
||||
|
@ -89,7 +89,7 @@ const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => {
|
||||
const extensionFile = file.name.split('.').pop();
|
||||
const extensionAccept = ['wxml', 'mm'];
|
||||
|
||||
if (!extensionAccept.includes(extensionFile)) {
|
||||
if (!extensionAccept.includes(extensionFile!)) {
|
||||
setErrorFile({
|
||||
error: true,
|
||||
message: intl.formatMessage(
|
||||
@ -108,8 +108,8 @@ const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => {
|
||||
model.contentType = 'application/xml';
|
||||
|
||||
const fileContent = event?.target?.result;
|
||||
const mapConent: string =
|
||||
typeof fileContent === 'string' ? fileContent : fileContent.toString();
|
||||
const mapConent: string | undefined =
|
||||
typeof fileContent === 'string' ? fileContent : fileContent?.toString();
|
||||
|
||||
try {
|
||||
const importer: Importer = TextImporterFactory.create(extensionFile, mapConent);
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
@ -19,13 +36,11 @@ const LabelDialog = ({ mapsId, onClose }: MultiDialogProps): React.ReactElement
|
||||
const client: Client = useSelector(activeInstance);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// TODO: pass down map data instead of using query?
|
||||
const { data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', () => {
|
||||
return client.fetchAllMaps();
|
||||
});
|
||||
const [error, setError] = React.useState<ErrorInfo>();
|
||||
|
||||
const maps = data.filter((m) => mapsId.includes(m.id));
|
||||
const maps = data?.filter((m) => mapsId.includes(m.id));
|
||||
|
||||
const changeLabelMutation = useMutation<
|
||||
void,
|
||||
@ -44,11 +59,9 @@ const LabelDialog = ({ mapsId, onClose }: MultiDialogProps): React.ReactElement
|
||||
|
||||
const handleChangesInLabels = (label: Label, checked: boolean) => {
|
||||
setError(undefined);
|
||||
changeLabelMutation.mutate({
|
||||
maps,
|
||||
label,
|
||||
checked,
|
||||
});
|
||||
if (maps) {
|
||||
changeLabelMutation.mutate({ maps, label, checked });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -66,21 +79,27 @@ const LabelDialog = ({ mapsId, onClose }: MultiDialogProps): React.ReactElement
|
||||
paperCss={classes.paper}
|
||||
error={error}
|
||||
>
|
||||
<>
|
||||
<Typography variant="body2" marginTop="10px" css={classes.title as Interpolation<Theme>}>
|
||||
<FormattedMessage id="label.add-for" defaultMessage="Editing labels for " />
|
||||
{maps.length > 1 ? (
|
||||
<FormattedMessage
|
||||
id="label.maps-count"
|
||||
defaultMessage="{count} maps"
|
||||
values={{ count: maps.length }}
|
||||
/>
|
||||
) : (
|
||||
maps.map((m) => m.title).join(', ')
|
||||
)}
|
||||
</Typography>
|
||||
<LabelSelector onChange={handleChangesInLabels} maps={maps} />
|
||||
</>
|
||||
{maps && (
|
||||
<>
|
||||
<Typography
|
||||
variant="body2"
|
||||
marginTop="10px"
|
||||
css={classes.title as Interpolation<Theme>}
|
||||
>
|
||||
<FormattedMessage id="label.add-for" defaultMessage="Editing labels for " />
|
||||
{maps && maps.length > 1 ? (
|
||||
<FormattedMessage
|
||||
id="label.maps-count"
|
||||
defaultMessage="{count} maps"
|
||||
values={{ count: maps.length }}
|
||||
/>
|
||||
) : (
|
||||
maps.map((m) => m.title).join(', ')
|
||||
)}
|
||||
</Typography>
|
||||
<LabelSelector onChange={handleChangesInLabels} maps={maps} />
|
||||
</>
|
||||
)}
|
||||
</BaseDialog>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* 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 React, { ErrorInfo, ReactElement, useEffect } from 'react';
|
||||
import Drawer from '@mui/material/Drawer';
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
@ -200,7 +217,7 @@ const MapsPage = (): ReactElement => {
|
||||
);
|
||||
|
||||
const container = document !== undefined ? () => document.body : undefined;
|
||||
|
||||
const label = labels.find((l) => l.id === labelToDelete);
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={userLocale.code}
|
||||
@ -210,7 +227,7 @@ const MapsPage = (): ReactElement => {
|
||||
<div css={classes.root}>
|
||||
<AppBar
|
||||
position="fixed"
|
||||
css={[classes.appBar, open && classes.appBarShift]}
|
||||
css={[classes.appBar, classes.appBarShift]}
|
||||
variant="outlined"
|
||||
elevation={0}
|
||||
>
|
||||
@ -321,14 +338,14 @@ const MapsPage = (): ReactElement => {
|
||||
<MapsList filter={filter} />
|
||||
</main>
|
||||
</div>
|
||||
{labelToDelete && (
|
||||
{label && labelToDelete && (
|
||||
<LabelDeleteConfirm
|
||||
onClose={() => setLabelToDelete(null)}
|
||||
onConfirm={() => {
|
||||
handleLabelDelete(labelToDelete);
|
||||
setLabelToDelete(null);
|
||||
}}
|
||||
label={labels.find((l) => l.id === labelToDelete)}
|
||||
label={label}
|
||||
/>
|
||||
)}
|
||||
</IntlProvider>
|
||||
|
@ -20,7 +20,7 @@ const RegistrationCallbackPage = (): React.ReactElement => {
|
||||
const client: Client = useSelector(activeInstance);
|
||||
|
||||
const [showError, setShowError] = useState(false);
|
||||
const [callbackResult, setCallbackResult] = useState<Oauth2CallbackResult>(undefined);
|
||||
const [callbackResult, setCallbackResult] = useState<Oauth2CallbackResult>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
@ -37,6 +37,10 @@ const RegistrationCallbackPage = (): React.ReactElement => {
|
||||
|
||||
useEffect(() => {
|
||||
const googleOauthCode = new URLSearchParams(window.location.search).get('code');
|
||||
if (!googleOauthCode) {
|
||||
throw new Error(`Missing code definition: ${window.location.search}`);
|
||||
}
|
||||
|
||||
client
|
||||
.processGoogleCallback(googleOauthCode)
|
||||
.then((result) => {
|
||||
@ -54,8 +58,13 @@ const RegistrationCallbackPage = (): React.ReactElement => {
|
||||
}, []);
|
||||
|
||||
const confirmAccountSynching = () => {
|
||||
const callback = callbackResult;
|
||||
if (!callback) {
|
||||
throw new Error(`callbackResult can not be null`);
|
||||
}
|
||||
|
||||
client
|
||||
.confirmAccountSync(callbackResult.email, callbackResult.syncCode)
|
||||
.confirmAccountSync(callback.email, callback.syncCode)
|
||||
.then(() => {
|
||||
navigate('/c/maps/');
|
||||
})
|
||||
|
@ -69,7 +69,12 @@ const RegistrationForm = () => {
|
||||
const maxFormWidth = 350;
|
||||
|
||||
const handleRegisterWithGoogleClick = () => {
|
||||
window.location.href = AppConfig.getGoogleOauth2Url();
|
||||
const url = AppConfig.getGoogleOauth2Url();
|
||||
if (url) {
|
||||
window.location.href = url;
|
||||
} else {
|
||||
console.error('Auth callback url is null');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -55,7 +55,7 @@ export const clientSlice = createSlice({
|
||||
type MapLoadResult = {
|
||||
isLoading: boolean;
|
||||
error: ErrorInfo | null;
|
||||
map: MapInfo | null;
|
||||
map: MapInfo | undefined;
|
||||
};
|
||||
|
||||
export const useFetchMapById = (id: number): MapLoadResult => {
|
||||
@ -65,12 +65,12 @@ export const useFetchMapById = (id: number): MapLoadResult => {
|
||||
});
|
||||
|
||||
// If the map can not be loaded, create an error object.
|
||||
let map: MapInfo;
|
||||
let errorMsg: ErrorInfo = error;
|
||||
let map: MapInfo | undefined;
|
||||
let errorMsg: ErrorInfo | null = error;
|
||||
if (!isLoading) {
|
||||
// Sanitize error structure ...
|
||||
if (errorMsg) {
|
||||
errorMsg = Object.keys(error).length !== 0 ? error : null;
|
||||
errorMsg = Object.keys(errorMsg).length !== 0 ? error : null;
|
||||
}
|
||||
// Seach for object...
|
||||
map = data?.find((m) => m.id == id);
|
||||
|
@ -1,18 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": false,
|
||||
"module": "amd",
|
||||
"moduleResolution": "node",
|
||||
"strict": false,
|
||||
"target": "es6",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "@emotion/react"
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ export const getCsrfToken = (): string | null => {
|
||||
return meta.getAttribute('content');
|
||||
};
|
||||
|
||||
export const getCsrfTokenParameter = (): string => {
|
||||
export const getCsrfTokenParameter = (): string | null => {
|
||||
const meta = document.head.querySelector('meta[name="_csrf_parameter"]');
|
||||
if (!meta) {
|
||||
return '';
|
||||
|
@ -1,15 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": false,
|
||||
"module": "es6",
|
||||
"target": "es6",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "@emotion/react"
|
||||
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
{
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": false,
|
||||
"module": "amd",
|
||||
"moduleResolution": "node",
|
||||
"strict": false,
|
||||
"target": "es6",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"strictNullChecks": true,
|
||||
"rootDirs": [
|
||||
"src",
|
||||
],
|
||||
"jsxImportSource": "@emotion/react",
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user