mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-15 19:47:57 +01:00
6ba917cf32
commit 81e9041e19344df18d8e91a31edb69ea0bce6bf7 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sun Dec 5 14:35:11 2021 -0800 Fix serialization bug commit 290223f15aa3902ef3291e0f392a92d04e9ccd0e Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sun Dec 5 09:36:59 2021 -0800 Fix serialization bug commit 3c1a2e37cf7be34780b760eb6f2fd3e3ac577ed1 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sun Dec 5 09:24:13 2021 -0800 Fix missing references commit 98a7fd3e1659eb32cee43144da4a10b98cfcfed0 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sun Dec 5 09:08:38 2021 -0800 Fix compile commit 9f5146b353f0fdb34a5b83db6d120bc09a96a073 Merge: 218e074 d3dc44c Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sun Dec 5 09:03:17 2021 -0800 Merge branch 'develop' into feature/mindplot_tests_playground commit 218e074b7330d0a02ac7afee0b644737f3bb6b03 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sat Dec 4 17:46:22 2021 -0800 Add jquery missing dependency commit c01a748a84a2359dcf1a49d9593369c9fefe1e76 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sat Dec 4 17:41:47 2021 -0800 Remove undercore commit d680b063b819563f4fae38571055aad4c55180b7 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sat Dec 4 17:36:58 2021 -0800 Add missing dependencies commit be9aa21245e84c97fa9fe3545299c6bb01772ef1 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sat Dec 4 17:25:23 2021 -0800 Fix missign dependencies. commit 2472fa453c43b64286552edb7120d4d2c395eba4 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sat Dec 4 17:08:48 2021 -0800 Fix compilation commit a013d07dc15a3bddda1e42cad373abbdfc525c74 Merge: f2ac8fe a81e984 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Sat Dec 4 16:57:19 2021 -0800 Merge branch 'develop' into feature/mindplot_tests_playground commit f2ac8fe17de071a09f80a20f49eb42c66b5f2f2b Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Thu Dec 2 18:59:03 2021 -0800 Hack: Add declaration of designer as global variable. commit 432167acbb055fba19f1e8469db4ffe8ad7793b7 Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Thu Dec 2 18:51:13 2021 -0800 Hack the initialization of extended hotkey pluggin. commit 794db35e88f6bd232094b4f104c8fe6a8fab34be Author: Paulo Gustavo Veiga <pveiga@wisemapping.com> Date: Thu Dec 2 17:57:21 2021 -0800 Add keyboard function commit e47a48d51f1af0ebde4ebea07cb467a8e5a7a372 Author: Matias Arriola <matias.arriola@gmail.com> Date: Thu Dec 2 14:50:43 2021 -0300 Fix editor snapshot commit 9bf8baef1216352ed1f9dde4658c479c0044b093 Author: Matias Arriola <matias.arriola@gmail.com> Date: Thu Dec 2 13:14:13 2021 -0300 Add editor test to mindplot playground Add missing imports and fix BootstrapDialog references commit b2dcc3034fc638f58cdb59e96ab7d6e2435f634a Author: Matias Arriola <matias.arriola@gmail.com> Date: Thu Dec 2 11:56:10 2021 -0300 Add embedded test to mindplot playground commit 08b514e1aa7b51c4df56b2b3cb7f28c191adeae7 Author: Matias Arriola <matias.arriola@gmail.com> Date: Thu Dec 2 10:27:31 2021 -0300 Fix mindplot layout test Upgrade raphael to avoid error Load raphael from context-loader
519 lines
16 KiB
JavaScript
519 lines
16 KiB
JavaScript
/*
|
|
* Copyright [2015] [wisemapping]
|
|
*
|
|
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
|
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
|
* "powered by wisemapping" text requirement on every single page;
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the license at
|
|
*
|
|
* http://www.wisemapping.org/license
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
import { $assert, $defined, createDocument } from '@wisemapping/core-js';
|
|
import * as web2d from '@wisemapping/web2d';
|
|
import Mindmap from '../model/Mindmap';
|
|
import INodeModel, { TopicShape } from '../model/INodeModel';
|
|
import TopicFeature from '../TopicFeature';
|
|
import ConnectionLine from '../ConnectionLine';
|
|
|
|
/**
|
|
* @class
|
|
*/
|
|
// eslint-disable-next-line camelcase
|
|
class XMLSerializer_Pela {
|
|
toXML(mindmap) {
|
|
$assert(mindmap, 'Can not save a null mindmap');
|
|
|
|
const document = createDocument();
|
|
|
|
// Store map attributes ...
|
|
const mapElem = document.createElement('map');
|
|
const name = mindmap.getId();
|
|
if ($defined(name)) {
|
|
mapElem.setAttribute('name', this.rmXmlInv(name));
|
|
}
|
|
const version = mindmap.getVersion();
|
|
if ($defined(version)) {
|
|
mapElem.setAttribute('version', version);
|
|
}
|
|
|
|
document.appendChild(mapElem);
|
|
|
|
// Create branches ...
|
|
const topics = mindmap.getBranches();
|
|
for (let i = 0; i < topics.length; i++) {
|
|
const topic = topics[i];
|
|
const topicDom = this._topicToXML(document, topic);
|
|
mapElem.appendChild(topicDom);
|
|
}
|
|
|
|
// Create Relationships
|
|
const relationships = mindmap.getRelationships();
|
|
if (relationships.length > 0) {
|
|
for (let j = 0; j < relationships.length; j++) {
|
|
const relationship = relationships[j];
|
|
if (
|
|
mindmap.findNodeById(relationship.getFromNode()) !== null
|
|
&& mindmap.findNodeById(relationship.getToNode()) !== null
|
|
) {
|
|
// Isolated relationships are not persisted ....
|
|
const relationDom = XMLSerializer_Pela._relationshipToXML(document, relationship);
|
|
mapElem.appendChild(relationDom);
|
|
}
|
|
}
|
|
}
|
|
|
|
return document;
|
|
}
|
|
|
|
_topicToXML(document, topic) {
|
|
const parentTopic = document.createElement('topic');
|
|
|
|
// Set topic attributes...
|
|
if (topic.getType() === INodeModel.CENTRAL_TOPIC_TYPE) {
|
|
parentTopic.setAttribute('central', 'true');
|
|
} else {
|
|
const pos = topic.getPosition();
|
|
parentTopic.setAttribute('position', `${pos.x},${pos.y}`);
|
|
|
|
const order = topic.getOrder();
|
|
if (typeof order === 'number' && Number.isFinite(order)) { parentTopic.setAttribute('order', order); }
|
|
}
|
|
|
|
const text = topic.getText();
|
|
if ($defined(text)) {
|
|
this._noteTextToXML(document, parentTopic, text);
|
|
}
|
|
|
|
const shape = topic.getShapeType();
|
|
if ($defined(shape)) {
|
|
parentTopic.setAttribute('shape', shape);
|
|
|
|
if (shape === TopicShape.IMAGE) {
|
|
parentTopic.setAttribute(
|
|
'image',
|
|
`${topic.getImageSize().width},${topic.getImageSize().height
|
|
}:${topic.getImageUrl()}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
if (topic.areChildrenShrunken() && topic.getType() !== INodeModel.CENTRAL_TOPIC_TYPE) {
|
|
parentTopic.setAttribute('shrink', 'true');
|
|
}
|
|
|
|
// Font properties ...
|
|
const id = topic.getId();
|
|
parentTopic.setAttribute('id', id);
|
|
|
|
let font = '';
|
|
|
|
const fontFamily = topic.getFontFamily();
|
|
font += `${fontFamily || ''};`;
|
|
|
|
const fontSize = topic.getFontSize();
|
|
font += `${fontSize || ''};`;
|
|
|
|
const fontColor = topic.getFontColor();
|
|
font += `${fontColor || ''};`;
|
|
|
|
const fontWeight = topic.getFontWeight();
|
|
font += `${fontWeight || ''};`;
|
|
|
|
const fontStyle = topic.getFontStyle();
|
|
font += `${fontStyle || ''};`;
|
|
|
|
if (
|
|
$defined(fontFamily)
|
|
|| $defined(fontSize)
|
|
|| $defined(fontColor)
|
|
|| $defined(fontWeight)
|
|
|| $defined(fontStyle)
|
|
) {
|
|
parentTopic.setAttribute('fontStyle', font);
|
|
}
|
|
|
|
const bgColor = topic.getBackgroundColor();
|
|
if ($defined(bgColor)) {
|
|
parentTopic.setAttribute('bgColor', bgColor);
|
|
}
|
|
|
|
const brColor = topic.getBorderColor();
|
|
if ($defined(brColor)) {
|
|
parentTopic.setAttribute('brColor', brColor);
|
|
}
|
|
|
|
const metadata = topic.getMetadata();
|
|
if ($defined(metadata)) {
|
|
parentTopic.setAttribute('metadata', metadata);
|
|
}
|
|
|
|
// Serialize features ...
|
|
const features = topic.getFeatures();
|
|
for (let i = 0; i < features.length; i++) {
|
|
const feature = features[i];
|
|
|
|
const featureType = feature.getType();
|
|
const featureDom = document.createElement(featureType);
|
|
const attributes = feature.getAttributes();
|
|
|
|
for (const key in attributes) {
|
|
const value = attributes[key];
|
|
if (key === 'text') {
|
|
const cdata = document.createCDATASection(this.rmXmlInv(value));
|
|
featureDom.appendChild(cdata);
|
|
} else {
|
|
featureDom.setAttribute(key, this.rmXmlInv(value));
|
|
}
|
|
}
|
|
parentTopic.appendChild(featureDom);
|
|
}
|
|
|
|
// CHILDREN TOPICS
|
|
const childTopics = topic.getChildren();
|
|
for (let j = 0; j < childTopics.length; j++) {
|
|
const childTopic = childTopics[j];
|
|
const childDom = this._topicToXML(document, childTopic);
|
|
parentTopic.appendChild(childDom);
|
|
}
|
|
return parentTopic;
|
|
}
|
|
|
|
_noteTextToXML(document, elem, text) {
|
|
if (text.indexOf('\n') === -1) {
|
|
elem.setAttribute('text', this.rmXmlInv(text));
|
|
} else {
|
|
const textDom = document.createElement('text');
|
|
const cdata = document.createCDATASection(this.rmXmlInv(text));
|
|
textDom.appendChild(cdata);
|
|
elem.appendChild(textDom);
|
|
}
|
|
}
|
|
|
|
static _relationshipToXML(document, relationship) {
|
|
const result = document.createElement('relationship');
|
|
result.setAttribute('srcTopicId', relationship.getFromNode());
|
|
result.setAttribute('destTopicId', relationship.getToNode());
|
|
|
|
const lineType = relationship.getLineType();
|
|
result.setAttribute('lineType', lineType);
|
|
if (lineType === ConnectionLine.CURVED || lineType === ConnectionLine.SIMPLE_CURVED) {
|
|
if ($defined(relationship.getSrcCtrlPoint())) {
|
|
const srcPoint = relationship.getSrcCtrlPoint();
|
|
result.setAttribute(
|
|
'srcCtrlPoint',
|
|
`${Math.round(srcPoint.x)},${Math.round(srcPoint.y)}`,
|
|
);
|
|
}
|
|
if ($defined(relationship.getDestCtrlPoint())) {
|
|
const destPoint = relationship.getDestCtrlPoint();
|
|
result.setAttribute(
|
|
'destCtrlPoint',
|
|
`${Math.round(destPoint.x)},${Math.round(destPoint.y)}`,
|
|
);
|
|
}
|
|
}
|
|
result.setAttribute('endArrow', relationship.getEndArrow());
|
|
result.setAttribute('startArrow', relationship.getStartArrow());
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @param dom
|
|
* @param mapId
|
|
* @throws will throw an error if dom is null or undefined
|
|
* @throws will throw an error if mapId is null or undefined
|
|
* @throws will throw an error if the document element is not consistent with a wisemap's root
|
|
* element
|
|
*/
|
|
loadFromDom(dom, mapId) {
|
|
$assert(dom, 'dom can not be null');
|
|
$assert(mapId, 'mapId can not be null');
|
|
|
|
const rootElem = dom.documentElement;
|
|
|
|
// Is a wisemap?.
|
|
$assert(
|
|
rootElem.tagName === XMLSerializer_Pela.MAP_ROOT_NODE,
|
|
'This seem not to be a map document.',
|
|
);
|
|
|
|
this._idsMap = {};
|
|
// Start the loading process ...
|
|
const version = rootElem.getAttribute('version');
|
|
|
|
const mindmap = new Mindmap(mapId, version);
|
|
const children = rootElem.childNodes;
|
|
for (let i = 0; i < children.length; i++) {
|
|
const child = children[i];
|
|
if (child.nodeType === 1) {
|
|
switch (child.tagName) {
|
|
case 'topic': {
|
|
const topic = this._deserializeNode(child, mindmap);
|
|
mindmap.addBranch(topic);
|
|
break;
|
|
}
|
|
case 'relationship': {
|
|
const relationship = XMLSerializer_Pela._deserializeRelationship(child, mindmap);
|
|
if (relationship != null) {
|
|
mindmap.addRelationship(relationship);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this._idsMap = null;
|
|
mindmap.setId(mapId);
|
|
return mindmap;
|
|
}
|
|
|
|
_deserializeNode(domElem, mindmap) {
|
|
const type = domElem.getAttribute('central') != null
|
|
? INodeModel.CENTRAL_TOPIC_TYPE
|
|
: INodeModel.MAIN_TOPIC_TYPE;
|
|
|
|
// Load attributes...
|
|
let id = domElem.getAttribute('id');
|
|
if ($defined(id)) {
|
|
id = parseInt(id, 10);
|
|
}
|
|
|
|
if (this._idsMap[id]) {
|
|
id = null;
|
|
} else {
|
|
this._idsMap[id] = domElem;
|
|
}
|
|
|
|
const topic = mindmap.createNode(type, id);
|
|
|
|
// Set text property is it;s defined...
|
|
const text = domElem.getAttribute('text');
|
|
if ($defined(text) && text) {
|
|
topic.setText(text);
|
|
}
|
|
|
|
const fontStyle = domElem.getAttribute('fontStyle');
|
|
if ($defined(fontStyle) && fontStyle) {
|
|
const font = fontStyle.split(';');
|
|
|
|
if (font[0]) {
|
|
topic.setFontFamily(font[0]);
|
|
}
|
|
|
|
if (font[1]) {
|
|
topic.setFontSize(font[1]);
|
|
}
|
|
|
|
if (font[2]) {
|
|
topic.setFontColor(font[2]);
|
|
}
|
|
|
|
if (font[3]) {
|
|
topic.setFontWeight(font[3]);
|
|
}
|
|
|
|
if (font[4]) {
|
|
topic.setFontStyle(font[4]);
|
|
}
|
|
}
|
|
|
|
const shape = domElem.getAttribute('shape');
|
|
if ($defined(shape)) {
|
|
topic.setShapeType(shape);
|
|
|
|
if (shape === TopicShape.IMAGE) {
|
|
const image = domElem.getAttribute('image');
|
|
const size = image.substring(0, image.indexOf(':'));
|
|
const url = image.substring(image.indexOf(':') + 1, image.length);
|
|
topic.setImageUrl(url);
|
|
|
|
const split = size.split(',');
|
|
topic.setImageSize(split[0], split[1]);
|
|
}
|
|
}
|
|
|
|
const bgColor = domElem.getAttribute('bgColor');
|
|
if ($defined(bgColor)) {
|
|
topic.setBackgroundColor(bgColor);
|
|
}
|
|
|
|
const borderColor = domElem.getAttribute('brColor');
|
|
if ($defined(borderColor)) {
|
|
topic.setBorderColor(borderColor);
|
|
}
|
|
|
|
const order = domElem.getAttribute('order');
|
|
if ($defined(order) && order !== 'NaN') {
|
|
// Hack for broken maps ...
|
|
topic.setOrder(parseInt(order, 10));
|
|
}
|
|
|
|
const isShrink = domElem.getAttribute('shrink');
|
|
// Hack: Some production maps has been stored with the central topic collapsed. This is a bug.
|
|
if ($defined(isShrink) && type !== INodeModel.CENTRAL_TOPIC_TYPE) {
|
|
topic.setChildrenShrunken(isShrink);
|
|
}
|
|
|
|
const position = domElem.getAttribute('position');
|
|
if ($defined(position)) {
|
|
const pos = position.split(',');
|
|
topic.setPosition(pos[0], pos[1]);
|
|
}
|
|
|
|
const metadata = domElem.getAttribute('metadata');
|
|
if ($defined(metadata)) {
|
|
topic.setMetadata(metadata);
|
|
}
|
|
|
|
// Creating icons and children nodes
|
|
const children = domElem.childNodes;
|
|
for (let i = 0; i < children.length; i++) {
|
|
const child = children[i];
|
|
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
if (child.tagName === 'topic') {
|
|
const childTopic = this._deserializeNode(child, mindmap);
|
|
childTopic.connectTo(topic);
|
|
} else if (TopicFeature.isSupported(child.tagName)) {
|
|
// Load attributes ...
|
|
const namedNodeMap = child.attributes;
|
|
const attributes = {};
|
|
for (let j = 0; j < namedNodeMap.length; j++) {
|
|
const attribute = namedNodeMap.item(j);
|
|
attributes[attribute.name] = attribute.value;
|
|
}
|
|
|
|
// Has text node ?.
|
|
const textAttr = XMLSerializer_Pela._deserializeTextAttr(child);
|
|
if (textAttr) {
|
|
attributes.text = textAttr;
|
|
}
|
|
|
|
// Create a new element ....
|
|
const featureType = child.tagName;
|
|
const feature = TopicFeature.createModel(featureType, attributes);
|
|
topic.addFeature(feature);
|
|
} else if (child.tagName === 'text') {
|
|
const nodeText = XMLSerializer_Pela._deserializeNodeText(child);
|
|
topic.setText(nodeText);
|
|
}
|
|
}
|
|
}
|
|
return topic;
|
|
}
|
|
|
|
static _deserializeTextAttr(domElem) {
|
|
let value = domElem.getAttribute('text');
|
|
if (!$defined(value)) {
|
|
const children = domElem.childNodes;
|
|
for (let i = 0; i < children.length; i++) {
|
|
const child = children[i];
|
|
if (child.nodeType === Node.CDATA_SECTION_NODE) {
|
|
value = child.nodeValue;
|
|
}
|
|
}
|
|
} else {
|
|
// Notes must be decoded ...
|
|
value = unescape(value);
|
|
|
|
// Hack for empty nodes ...
|
|
if (value === '') {
|
|
value = ' ';
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static _deserializeNodeText(domElem) {
|
|
const children = domElem.childNodes;
|
|
let value = null;
|
|
for (let i = 0; i < children.length; i++) {
|
|
const child = children[i];
|
|
if (child.nodeType === Node.CDATA_SECTION_NODE) {
|
|
value = child.nodeValue;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static _deserializeRelationship(domElement, mindmap) {
|
|
const srcId = domElement.getAttribute('srcTopicId');
|
|
const destId = domElement.getAttribute('destTopicId');
|
|
const lineType = domElement.getAttribute('lineType');
|
|
const srcCtrlPoint = domElement.getAttribute('srcCtrlPoint');
|
|
const destCtrlPoint = domElement.getAttribute('destCtrlPoint');
|
|
|
|
// If for some reason a relationship lines has source and dest nodes the same, don't import it.
|
|
if (srcId === destId) {
|
|
return null;
|
|
}
|
|
// Is the connections points valid ?. If it's not, do not load the relationship ...
|
|
if (mindmap.findNodeById(srcId) == null || mindmap.findNodeById(destId) == null) {
|
|
return null;
|
|
}
|
|
|
|
const model = mindmap.createRelationship(srcId, destId);
|
|
model.setLineType(lineType);
|
|
if ($defined(srcCtrlPoint) && srcCtrlPoint !== '') {
|
|
model.setSrcCtrlPoint(web2d.Point.fromString(srcCtrlPoint));
|
|
}
|
|
if ($defined(destCtrlPoint) && destCtrlPoint !== '') {
|
|
model.setDestCtrlPoint(web2d.Point.fromString(destCtrlPoint));
|
|
}
|
|
model.setEndArrow('false');
|
|
model.setStartArrow('true');
|
|
return model;
|
|
}
|
|
|
|
/**
|
|
* This method ensures that the output String has only
|
|
* valid XML unicode characters as specified by the
|
|
* XML 1.0 standard. For reference, please see
|
|
* <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
|
|
* standard</a>. This method will return an empty
|
|
* String if the input is null or empty.
|
|
*
|
|
* @param in The String whose non-valid characters we want to remove.
|
|
* @return The in String, stripped of non-valid characters.
|
|
*/
|
|
// eslint-disable-next-line class-methods-use-this
|
|
rmXmlInv(str) {
|
|
if (str == null || str === undefined) return null;
|
|
|
|
let result = '';
|
|
for (let i = 0; i < str.length; i++) {
|
|
const c = str.charCodeAt(i);
|
|
if (
|
|
c === 0x9
|
|
|| c === 0xa
|
|
|| c === 0xd
|
|
|| (c >= 0x20 && c <= 0xd7ff)
|
|
|| (c >= 0xe000 && c <= 0xfffd)
|
|
|| (c >= 0x10000 && c <= 0x10ffff)
|
|
) {
|
|
result += str.charAt(i);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* a wisemap's root element tag name
|
|
* @constant
|
|
* @type {String}
|
|
* @default
|
|
*/
|
|
XMLSerializer_Pela.MAP_ROOT_NODE = 'map';
|
|
|
|
export default XMLSerializer_Pela;
|