Add automation
2
.gitignore
vendored
@ -50,3 +50,5 @@ Thumbs.db
|
|||||||
|
|
||||||
**/build/**/*
|
**/build/**/*
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
|
*/test/playground/dist
|
@ -17,7 +17,6 @@ pipelines:
|
|||||||
- cypress
|
- cypress
|
||||||
script:
|
script:
|
||||||
- export CYPRESS_imageSnaphots="true"
|
- export CYPRESS_imageSnaphots="true"
|
||||||
- yarn install
|
|
||||||
- yarn bootstrap
|
- yarn bootstrap
|
||||||
- yarn build
|
- yarn build
|
||||||
- yarn lint
|
- yarn lint
|
||||||
|
@ -3,7 +3,7 @@ services:
|
|||||||
e2e:
|
e2e:
|
||||||
image: cypress/included:8.4.1
|
image: cypress/included:8.4.1
|
||||||
container_name: wisemapping-integration-tests
|
container_name: wisemapping-integration-tests
|
||||||
entrypoint: '/bin/sh -c "yarn bootstrap && yarn test:integration"'
|
entrypoint: '/bin/sh -c "yarn bootstrap && yarn build && yarn test:integration"'
|
||||||
working_dir: /e2e
|
working_dir: /e2e
|
||||||
environment:
|
environment:
|
||||||
- CYPRESS_imageSnaphots=true
|
- CYPRESS_imageSnaphots=true
|
||||||
|
@ -3,7 +3,7 @@ services:
|
|||||||
e2e:
|
e2e:
|
||||||
image: cypress/included:8.4.1
|
image: cypress/included:8.4.1
|
||||||
container_name: wisemapping-integration-tests
|
container_name: wisemapping-integration-tests
|
||||||
entrypoint: '/bin/sh -c "yarn bootstrap && yarn test:integration"'
|
entrypoint: '/bin/sh -c "yarn bootstrap && yarn build && yarn test:integration"'
|
||||||
working_dir: /e2e
|
working_dir: /e2e
|
||||||
environment:
|
environment:
|
||||||
- CYPRESS_imageSnaphots=true
|
- CYPRESS_imageSnaphots=true
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cross-browser implementation of creating an XML document object.
|
* Cross-browser implementation of creating an XML document object.
|
||||||
*/
|
*/
|
||||||
@ -48,7 +46,7 @@ export const createDocument = function () {
|
|||||||
obj - object to inspect
|
obj - object to inspect
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const $defined = function (obj) {
|
export const $defined = function (obj) {
|
||||||
return obj != undefined;
|
return obj != undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
5
packages/editor/cypress/fixtures/example.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
16
packages/editor/cypress/integration/relationship.test.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
context('Relationship Topics', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/editor.html');
|
||||||
|
cy.reload();
|
||||||
|
cy.get('[test-id="30-11-relationship"]').click({ force: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Change shape relationship', () => {
|
||||||
|
cy.get('[test-id="control-56"]').trigger('mousedown', { force: true });
|
||||||
|
cy.get('body').trigger('mousemove', { clientX: 500, clientY: 200 });
|
||||||
|
cy.get('body').trigger('mouseup');
|
||||||
|
cy.matchImageSnapshot('changeShapeRealtionship');
|
||||||
|
|
||||||
|
cy.get('[test-id="control-56"]').invoke('attr', 'cy').should('eq', '-131.75');
|
||||||
|
});
|
||||||
|
});
|
67
packages/editor/cypress/integration/topicFontChange.test.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
context('Edit Topic', () => {
|
||||||
|
// TODO: review why click({force: true}) is needed in these tests
|
||||||
|
// also, why is the element outside the viewport in screenshots?
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/editor.html');
|
||||||
|
cy.reload();
|
||||||
|
cy.get('[test-id=1]').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Change Main Topic Text', () => {
|
||||||
|
cy.get('body').type('New Title Main Topic{enter}');
|
||||||
|
cy.get('[test-id=1] > text > tspan').should('have.text', 'New Title Main Topic');
|
||||||
|
cy.matchImageSnapshot('changeMainTopicText');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Change Font Size', () => {
|
||||||
|
cy.get('#fontSizeTip').click();
|
||||||
|
cy.get('.popover #small').click();
|
||||||
|
|
||||||
|
cy.get('[test-id=1] > text').invoke('attr', 'font-size').should('eq', '8.0625');
|
||||||
|
cy.matchImageSnapshot('changeFontSizeSmall');
|
||||||
|
|
||||||
|
cy.get('#fontSizeTip').click();
|
||||||
|
cy.get('.popover #normal').click({ force: true });
|
||||||
|
|
||||||
|
cy.get('[test-id=1] > text').invoke('attr', 'font-size').should('eq', '10.75');
|
||||||
|
cy.matchImageSnapshot('changeFontSizeNormal');
|
||||||
|
|
||||||
|
cy.get('#fontSizeTip').click();
|
||||||
|
cy.get('.popover #large').click({ force: true });
|
||||||
|
|
||||||
|
cy.get('[test-id=1] > text').invoke('attr', 'font-size').should('eq', '13.4375');
|
||||||
|
cy.matchImageSnapshot('changeFontSizeLarge');
|
||||||
|
|
||||||
|
cy.get('#fontSizeTip').click();
|
||||||
|
cy.get('.popover #huge').click({ force: true });
|
||||||
|
|
||||||
|
cy.get('[test-id=1] > text').invoke('attr', 'font-size').should('eq', '20.15625');
|
||||||
|
cy.matchImageSnapshot('changeFontSizeHuge');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Change Font type', () => {
|
||||||
|
cy.get('#fontFamilyTip').click();
|
||||||
|
cy.get('[model="Times"]').click({ force: true });
|
||||||
|
|
||||||
|
cy.get('[test-id=1] > text').invoke('attr', 'font-family').should('eq', 'Times');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('changeFontType');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Change Font Italic', () => {
|
||||||
|
cy.get('#fontItalicTip').click();
|
||||||
|
|
||||||
|
cy.get('[test-id=1] > text').invoke('attr', 'font-style').should('eq', 'italic');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('changeFontItalic');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Change Font color', () => {
|
||||||
|
cy.get('#fontColorTip').click();
|
||||||
|
cy.get('[title="RGB (153, 0, 255)"]').click({ force: true });
|
||||||
|
|
||||||
|
cy.get('[test-id=1] > text').invoke('attr', 'fill').should('eq', 'rgb(153, 0, 255)');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('changeFontColor');
|
||||||
|
});
|
||||||
|
});
|
49
packages/editor/cypress/integration/topicManager.test.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
context('Node manager', () => {
|
||||||
|
before(() => {
|
||||||
|
cy.visit('/editor.html');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shortcut add sibling node', () => {
|
||||||
|
cy.contains('Mind Mapping').click();
|
||||||
|
cy.get('body').type('{enter}').type('Mind Mapping rocks!!').type('{enter}');
|
||||||
|
|
||||||
|
cy.get('[test-id=36] > text > tspan').should('exist');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('editor-shortcut-edit');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shortcut add child node', () => {
|
||||||
|
cy.contains('Mind Mapping rocks!!').click();
|
||||||
|
cy.get('body').type('{insert}').type('Child 1 mind Mapping rocks!!').type('{enter}');
|
||||||
|
cy.get('body').type('{enter}').type('Child 2 mind Mapping rocks!!').type('{enter}');
|
||||||
|
|
||||||
|
cy.get('[test-id=36] > text > tspan').should('exist');
|
||||||
|
cy.get('[test-id=37] > text > tspan').should('exist');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('addChildNodeSortcut');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Delete topic', () => {
|
||||||
|
cy.get('[test-id=37]').click();
|
||||||
|
cy.get('body').type('{del}');
|
||||||
|
|
||||||
|
cy.get('[test-id=37]').should('not.exist');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('deleteTopicShortcut');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('undo changes', () => {
|
||||||
|
cy.get('#undoEditionTip').click();
|
||||||
|
|
||||||
|
cy.get('[test-id=36] > text > tspan').should('exist');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('undoChange');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Save changes', () => {
|
||||||
|
cy.contains('Mind Mapping rocks!!').click();
|
||||||
|
cy.get('body').type('{ctrl}s');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('saveChagesShortcut');
|
||||||
|
});
|
||||||
|
});
|
35
packages/editor/cypress/integration/topicPosition.test.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
context('Change topic position', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/editor.html');
|
||||||
|
cy.reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Move up node "Mind Mapping"', () => {
|
||||||
|
const position = { clientX: 270, clientY: 160 };
|
||||||
|
cy.contains('Mind Mapping').trigger('mousedown');
|
||||||
|
cy.get('body').trigger('mousemove', position);
|
||||||
|
cy.get('body').trigger('mouseup');
|
||||||
|
cy.matchImageSnapshot('moveupNode');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Move down node "Mind Mapping"', () => {
|
||||||
|
cy.contains('Mind Mapping').trigger('mousedown');
|
||||||
|
cy.get('body').trigger('mousemove', { clientX: 350, clientY: 380 });
|
||||||
|
cy.get('body').trigger('mouseup');
|
||||||
|
cy.matchImageSnapshot('movedownNode');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Move default position node "Mind Mapping"', () => {
|
||||||
|
cy.contains('Mind Mapping').trigger('mousedown');
|
||||||
|
cy.get('body').trigger('mousemove', { clientX: 270, clientY: 240 });
|
||||||
|
cy.get('body').trigger('mouseup');
|
||||||
|
cy.matchImageSnapshot('moveDefaultPosition');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Move left node "Mind Mapping"', () => {
|
||||||
|
cy.contains('Mind Mapping').trigger('mousedown');
|
||||||
|
cy.get('body').trigger('mousemove', { clientX: 700, clientY: 240 });
|
||||||
|
cy.get('body').trigger('mouseup');
|
||||||
|
cy.matchImageSnapshot('moveleftNode');
|
||||||
|
});
|
||||||
|
});
|
44
packages/editor/cypress/integration/topicShape.test.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
context('Change Topic shape', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/editor.html');
|
||||||
|
cy.reload();
|
||||||
|
cy.contains('Try it Now!').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('change to square shape', () => {
|
||||||
|
cy.get('#topicShapeTip').click();
|
||||||
|
cy.get('#rectagle').click();
|
||||||
|
|
||||||
|
cy.get('[test-id=11] > rect').eq(1).invoke('attr', 'rx').should('eq', '0');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('changeToSquareShape');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('change to rounded rectagle', () => {
|
||||||
|
cy.get('#topicShapeTip').click();
|
||||||
|
// TODO: The parameter {force: true} was placed because it does not detect that the element is visible
|
||||||
|
cy.get('#rounded_rectagle').click({ force: true });
|
||||||
|
|
||||||
|
cy.get('[test-id=11] > rect').eq(1).invoke('attr', 'rx').should('eq', '4.05');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('changeToRoundedRectagle');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('change to line', () => {
|
||||||
|
cy.get('#topicShapeTip').click();
|
||||||
|
// TODO: The parameter {force: true} was placed because it does not detect that the element is visible
|
||||||
|
cy.get('#line').click({ force: true });
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('changeToLine');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('change to elipse shape', () => {
|
||||||
|
cy.get('#topicShapeTip').click();
|
||||||
|
// TODO: The parameter {force: true} was placed because it does not detect that the element is visible
|
||||||
|
cy.get('#elipse').click({ force: true });
|
||||||
|
|
||||||
|
cy.get('[test-id=11] > rect').eq(1).invoke('attr', 'rx').should('eq', '12.15');
|
||||||
|
|
||||||
|
cy.matchImageSnapshot('changeToElipseShape');
|
||||||
|
});
|
||||||
|
});
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 206 KiB |
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 113 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 102 KiB |
@ -8,13 +8,12 @@ const { merge } = require('webpack-merge');
|
|||||||
const playgroundConfig = {
|
const playgroundConfig = {
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
entry: {
|
entry: {
|
||||||
"editor.bundle": path.join(__dirname, 'src', 'index.tsx'),
|
|
||||||
viewmode: path.resolve(__dirname, './test/playground/map-render/js/viewmode'),
|
viewmode: path.resolve(__dirname, './test/playground/map-render/js/viewmode'),
|
||||||
embedded: path.resolve(__dirname, './test/playground/map-render/js/embedded'),
|
embedded: path.resolve(__dirname, './test/playground/map-render/js/embedded'),
|
||||||
editor: path.resolve(__dirname, './test/playground/map-render/js/editor'),
|
editor: path.resolve(__dirname, './test/playground/map-render/js/editor'),
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'test/playground/dist'),
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
library: {
|
library: {
|
||||||
type: 'umd',
|
type: 'umd',
|
||||||
@ -24,7 +23,6 @@ const playgroundConfig = {
|
|||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
port: 8081,
|
port: 8081,
|
||||||
open: false,
|
open: false,
|
||||||
writeToDisk: true,
|
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
After Width: | Height: | Size: 5.1 MiB |
After Width: | Height: | Size: 73 KiB |
@ -34,49 +34,49 @@ abstract class ActionDispatcher extends Events {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract addRelationship(model: RelationshipModel, mindmap: Mindmap);
|
abstract addRelationship(model: RelationshipModel, mindmap: Mindmap);
|
||||||
|
|
||||||
abstract addTopics(models: NodeModel[], parentTopicId: any[]);
|
abstract addTopics(models: NodeModel[], parentTopicId: any[]);
|
||||||
|
|
||||||
abstract deleteEntities(topicsIds: number[], relIds: number[]);
|
abstract deleteEntities(topicsIds: number[], relIds: number[]);
|
||||||
|
|
||||||
abstract dragTopic(topicId: number, position: Point, order: number, parentTopic: Topic);
|
abstract dragTopic(topicId: number, position: Point, order: number, parentTopic: Topic);
|
||||||
|
|
||||||
abstract moveTopic(topicId: number, position: any);
|
abstract moveTopic(topicId: number, position: any);
|
||||||
|
|
||||||
abstract moveControlPoint(ctrlPoint: this, point: any);
|
abstract moveControlPoint(ctrlPoint: this, point: any);
|
||||||
|
|
||||||
abstract changeFontFamilyToTopic(topicIds: number[], fontFamily: string);
|
abstract changeFontFamilyToTopic(topicIds: number[], fontFamily: string);
|
||||||
|
|
||||||
abstract changeFontStyleToTopic(topicsIds: number[]);
|
abstract changeFontStyleToTopic(topicsIds: number[]);
|
||||||
|
|
||||||
abstract changeFontColorToTopic(topicsIds: number[], color: string);
|
abstract changeFontColorToTopic(topicsIds: number[], color: string);
|
||||||
|
|
||||||
abstract changeFontSizeToTopic(topicsIds: number[], size: number);
|
abstract changeFontSizeToTopic(topicsIds: number[], size: number);
|
||||||
|
|
||||||
abstract changeBackgroundColorToTopic(topicsIds: number[], color: string);
|
abstract changeBackgroundColorToTopic(topicsIds: number[], color: string);
|
||||||
|
|
||||||
abstract changeBorderColorToTopic(topicsIds: number[], color: string);
|
abstract changeBorderColorToTopic(topicsIds: number[], color: string);
|
||||||
|
|
||||||
abstract changeShapeTypeToTopic(topicsIds: number[], shapeType: string);
|
abstract changeShapeTypeToTopic(topicsIds: number[], shapeType: string);
|
||||||
|
|
||||||
abstract changeFontWeightToTopic(topicsIds: number[]);
|
abstract changeFontWeightToTopic(topicsIds: number[]);
|
||||||
|
|
||||||
abstract changeTextToTopic(topicsIds: number[], text: string);
|
abstract changeTextToTopic(topicsIds: number[], text: string);
|
||||||
|
|
||||||
abstract shrinkBranch(topicsIds: number[], collapse: boolean);
|
abstract shrinkBranch(topicsIds: number[], collapse: boolean);
|
||||||
|
|
||||||
abstract addFeatureToTopic(topicId: number, type: string, attributes: object);
|
abstract addFeatureToTopic(topicId: number, type: string, attributes: object);
|
||||||
|
|
||||||
abstract changeFeatureToTopic(topicId: number, featureId: any, attributes: object);
|
abstract changeFeatureToTopic(topicId: number, featureId: any, attributes: object);
|
||||||
|
|
||||||
abstract removeFeatureFromTopic(topicId: number, featureId: number);
|
abstract removeFeatureFromTopic(topicId: number, featureId: number);
|
||||||
|
|
||||||
static setInstance = (dispatcher: ActionDispatcher) => {
|
static setInstance = (dispatcher: ActionDispatcher) => {
|
||||||
this._instance = dispatcher;
|
this._instance = dispatcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
static getInstance = (): ActionDispatcher => ActionDispatcher._instance;
|
static getInstance = (): ActionDispatcher => ActionDispatcher._instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ActionDispatcher;
|
export default ActionDispatcher;
|
||||||
|
@ -23,25 +23,25 @@ import ActionDispatcher from './ActionDispatcher';
|
|||||||
|
|
||||||
class ControlPoint {
|
class ControlPoint {
|
||||||
constructor() {
|
constructor() {
|
||||||
const control1 = new Elipse({
|
this.control1 = new Elipse({
|
||||||
width: 6,
|
width: 6,
|
||||||
height: 6,
|
height: 6,
|
||||||
stroke: '1 solid #6589de',
|
stroke: '1 solid #6589de',
|
||||||
fillColor: 'gray',
|
fillColor: 'gray',
|
||||||
visibility: false,
|
visibility: false,
|
||||||
});
|
});
|
||||||
control1.setCursor('pointer');
|
this.control1.setCursor('pointer');
|
||||||
|
|
||||||
const control2 = new Elipse({
|
this.control2 = new Elipse({
|
||||||
width: 6,
|
width: 6,
|
||||||
height: 6,
|
height: 6,
|
||||||
stroke: '1 solid #6589de',
|
stroke: '1 solid #6589de',
|
||||||
fillColor: 'gray',
|
fillColor: 'gray',
|
||||||
visibility: false,
|
visibility: false,
|
||||||
});
|
});
|
||||||
control2.setCursor('pointer');
|
this.control2.setCursor('pointer');
|
||||||
|
|
||||||
this._controlPointsController = [control1, control2];
|
this._controlPointsController = [this.control1, this.control2];
|
||||||
this._controlLines = [
|
this._controlLines = [
|
||||||
new Line({ strokeColor: '#6589de', strokeWidth: 1, opacity: 0.3 }),
|
new Line({ strokeColor: '#6589de', strokeWidth: 1, opacity: 0.3 }),
|
||||||
new Line({ strokeColor: '#6589de', strokeWidth: 1, opacity: 0.3 }),
|
new Line({ strokeColor: '#6589de', strokeWidth: 1, opacity: 0.3 }),
|
||||||
@ -84,6 +84,11 @@ class ControlPoint {
|
|||||||
this._endPoint[1] = { ...this._line.getLine().getTo() };
|
this._endPoint[1] = { ...this._line.getLine().getTo() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setControlPointTestId(ctrlPoint1, ctrlPoint2) {
|
||||||
|
this.control1.setTestId(ctrlPoint1);
|
||||||
|
this.control2.setTestId(ctrlPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
redraw() {
|
redraw() {
|
||||||
if ($defined(this._line)) this._createControlPoint();
|
if ($defined(this._line)) this._createControlPoint();
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ class Relationship extends ConnectionLine {
|
|||||||
this._line2d.setCursor('pointer');
|
this._line2d.setCursor('pointer');
|
||||||
this._line2d.setStroke(1, 'solid', strokeColor);
|
this._line2d.setStroke(1, 'solid', strokeColor);
|
||||||
this._line2d.setDashed(4, 2);
|
this._line2d.setDashed(4, 2);
|
||||||
|
this._line2d.setTestId(`${model.getFromNode()}-${model.getToNode()}-relationship`);
|
||||||
this._focusShape = this._createLine(this.getLineType(), ConnectionLine.SIMPLE_CURVED);
|
this._focusShape = this._createLine(this.getLineType(), ConnectionLine.SIMPLE_CURVED);
|
||||||
this._focusShape.setStroke(2, 'solid', '#3f96ff');
|
this._focusShape.setStroke(2, 'solid', '#3f96ff');
|
||||||
|
|
||||||
@ -83,6 +84,12 @@ class Relationship extends ConnectionLine {
|
|||||||
if ($defined(model.getSrcCtrlPoint())) {
|
if ($defined(model.getSrcCtrlPoint())) {
|
||||||
const srcPoint = { ...model.getSrcCtrlPoint() };
|
const srcPoint = { ...model.getSrcCtrlPoint() };
|
||||||
this.setSrcControlPoint(srcPoint);
|
this.setSrcControlPoint(srcPoint);
|
||||||
|
|
||||||
|
// Set test id in control point
|
||||||
|
this._controlPointsController.setControlPointTestId(
|
||||||
|
`control-${Math.abs(srcPoint.x)}`,
|
||||||
|
`control-${Math.abs(srcPoint.y)}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if ($defined(model.getDestCtrlPoint())) {
|
if ($defined(model.getDestCtrlPoint())) {
|
||||||
const destPoint = { ...model.getDestCtrlPoint() };
|
const destPoint = { ...model.getDestCtrlPoint() };
|
||||||
|
@ -103,9 +103,9 @@ class RelationshipPivot {
|
|||||||
const model = this._designer.getModel();
|
const model = this._designer.getModel();
|
||||||
const topics = model.getTopics();
|
const topics = model.getTopics();
|
||||||
|
|
||||||
topics.forEach(((topic) => {
|
topics.forEach((topic) => {
|
||||||
topic.removeEvent('ontfocus', this._onTopicClick);
|
topic.removeEvent('ontfocus', this._onTopicClick);
|
||||||
}));
|
});
|
||||||
|
|
||||||
workspace.removeChild(this._pivot);
|
workspace.removeChild(this._pivot);
|
||||||
workspace.removeChild(this._startArrow);
|
workspace.removeChild(this._startArrow);
|
||||||
@ -166,9 +166,7 @@ class RelationshipPivot {
|
|||||||
// Avoid circular connections ...
|
// Avoid circular connections ...
|
||||||
if (targetTopic.getId() !== sourceTopic.getId()) {
|
if (targetTopic.getId() !== sourceTopic.getId()) {
|
||||||
const relModel = mindmap.createRelationship(targetTopic.getId(), sourceTopic.getId());
|
const relModel = mindmap.createRelationship(targetTopic.getId(), sourceTopic.getId());
|
||||||
this._designer
|
this._designer.getActionDispatcher().addRelationship(relModel);
|
||||||
.getActionDispatcher()
|
|
||||||
.addRelationship(relModel);
|
|
||||||
}
|
}
|
||||||
this.dispose();
|
this.dispose();
|
||||||
}
|
}
|
||||||
|
@ -16,16 +16,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
import { $assert, $defined } from '@wisemapping/core-js';
|
||||||
import {
|
import {
|
||||||
$assert,
|
Rect, Image, Line, Text, Group,
|
||||||
$defined,
|
|
||||||
} from '@wisemapping/core-js';
|
|
||||||
import {
|
|
||||||
Rect,
|
|
||||||
Image,
|
|
||||||
Line,
|
|
||||||
Text,
|
|
||||||
Group,
|
|
||||||
} from '@wisemapping/web2d';
|
} from '@wisemapping/web2d';
|
||||||
|
|
||||||
import NodeGraph from './NodeGraph';
|
import NodeGraph from './NodeGraph';
|
||||||
@ -41,22 +34,18 @@ import NoteEditor from './widget/NoteEditor';
|
|||||||
import ActionDispatcher from './ActionDispatcher';
|
import ActionDispatcher from './ActionDispatcher';
|
||||||
import LinkEditor from './widget/LinkEditor';
|
import LinkEditor from './widget/LinkEditor';
|
||||||
|
|
||||||
import TopicEventDispatcher, {
|
import TopicEventDispatcher, { TopicEvent } from './TopicEventDispatcher';
|
||||||
TopicEvent,
|
import { TopicShape } from './model/INodeModel';
|
||||||
} from './TopicEventDispatcher';
|
|
||||||
import {
|
|
||||||
TopicShape,
|
|
||||||
} from './model/INodeModel';
|
|
||||||
|
|
||||||
const ICON_SCALING_FACTOR = 1.3;
|
const ICON_SCALING_FACTOR = 1.3;
|
||||||
|
|
||||||
class Topic extends NodeGraph {
|
class Topic extends NodeGraph {
|
||||||
/**
|
/**
|
||||||
* @extends mindplot.NodeGraph
|
* @extends mindplot.NodeGraph
|
||||||
* @constructs
|
* @constructs
|
||||||
* @param model
|
* @param model
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
constructor(model, options) {
|
constructor(model, options) {
|
||||||
super(model, options);
|
super(model, options);
|
||||||
this._children = [];
|
this._children = [];
|
||||||
@ -92,9 +81,9 @@ class Topic extends NodeGraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} type the topic shape type
|
* @param {String} type the topic shape type
|
||||||
* @see {@link mindplot.model.INodeModel}
|
* @see {@link mindplot.model.INodeModel}
|
||||||
*/
|
*/
|
||||||
setShapeType(type) {
|
setShapeType(type) {
|
||||||
this._setShapeType(type, true);
|
this._setShapeType(type, true);
|
||||||
}
|
}
|
||||||
@ -331,10 +320,10 @@ class Topic extends NodeGraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* assigns the new feature model to the topic's node model and adds the respective icon
|
* assigns the new feature model to the topic's node model and adds the respective icon
|
||||||
* @param {mindplot.model.FeatureModel} featureModel
|
* @param {mindplot.model.FeatureModel} featureModel
|
||||||
* @return {mindplot.Icon} the icon corresponding to the feature model
|
* @return {mindplot.Icon} the icon corresponding to the feature model
|
||||||
*/
|
*/
|
||||||
addFeature(featureModel) {
|
addFeature(featureModel) {
|
||||||
const iconGroup = this.getOrBuildIconGroup();
|
const iconGroup = this.getOrBuildIconGroup();
|
||||||
this.closeEditors();
|
this.closeEditors();
|
||||||
@ -648,6 +637,9 @@ class Topic extends NodeGraph {
|
|||||||
|
|
||||||
// Register listeners ...
|
// Register listeners ...
|
||||||
this._registerDefaultListenersToElement(group, this);
|
this._registerDefaultListenersToElement(group, this);
|
||||||
|
|
||||||
|
// Set test id
|
||||||
|
group.setTestId(model.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
_registerDefaultListenersToElement(elem, topic) {
|
_registerDefaultListenersToElement(elem, topic) {
|
||||||
@ -852,8 +844,8 @@ class Topic extends NodeGraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Point: references the center of the rect shape.!!!
|
* Point: references the center of the rect shape.!!!
|
||||||
*/
|
*/
|
||||||
setPosition(point) {
|
setPosition(point) {
|
||||||
$assert(point, 'position can not be null');
|
$assert(point, 'position can not be null');
|
||||||
// allowed param reassign to avoid risks of existing code relying in this side-effect
|
// allowed param reassign to avoid risks of existing code relying in this side-effect
|
||||||
@ -890,8 +882,9 @@ class Topic extends NodeGraph {
|
|||||||
|
|
||||||
getIncomingLines() {
|
getIncomingLines() {
|
||||||
const children = this.getChildren();
|
const children = this.getChildren();
|
||||||
return children.filter((node) => $defined(node.getOutgoingLine()))
|
return children
|
||||||
.map(((node) => node.getOutgoingLine()));
|
.filter((node) => $defined(node.getOutgoingLine()))
|
||||||
|
.map((node) => node.getOutgoingLine());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@ -986,8 +979,8 @@ class Topic extends NodeGraph {
|
|||||||
const sourceParent = sourceTopic.getModel().getParent();
|
const sourceParent = sourceTopic.getModel().getParent();
|
||||||
relationship.setVisibility(
|
relationship.setVisibility(
|
||||||
value
|
value
|
||||||
&& (targetParent == null || !targetParent.areChildrenShrunken())
|
&& (targetParent == null || !targetParent.areChildrenShrunken())
|
||||||
&& (sourceParent == null || !sourceParent.areChildrenShrunken()),
|
&& (sourceParent == null || !sourceParent.areChildrenShrunken()),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1055,8 +1048,7 @@ class Topic extends NodeGraph {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const oldSize = this.getSize();
|
const oldSize = this.getSize();
|
||||||
const hasSizeChanged = oldSize.width !== roundedSize.width
|
const hasSizeChanged = oldSize.width !== roundedSize.width || oldSize.height !== roundedSize.height;
|
||||||
|| oldSize.height !== roundedSize.height;
|
|
||||||
if (hasSizeChanged || force) {
|
if (hasSizeChanged || force) {
|
||||||
NodeGraph.prototype.setSize.call(this, roundedSize);
|
NodeGraph.prototype.setSize.call(this, roundedSize);
|
||||||
|
|
||||||
@ -1329,9 +1321,9 @@ class Topic extends NodeGraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param childTopic
|
* @param childTopic
|
||||||
* @return {Boolean} true if childtopic is a child topic of this topic or the topic itself
|
* @return {Boolean} true if childtopic is a child topic of this topic or the topic itself
|
||||||
*/
|
*/
|
||||||
isChildTopic(childTopic) {
|
isChildTopic(childTopic) {
|
||||||
let result = this.getId() === childTopic.getId();
|
let result = this.getId() === childTopic.getId();
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
@ -34,7 +34,9 @@ class BootstrapDialog extends Options {
|
|||||||
|
|
||||||
this.setOptions(options);
|
this.setOptions(options);
|
||||||
this.options.onEventData.dialog = this;
|
this.options.onEventData.dialog = this;
|
||||||
this._native = $('<div class="modal fade" tabindex="-1"></div>').append('<div class="modal-dialog"></div>');
|
this._native = $('<div class="modal fade" tabindex="-1"></div>').append(
|
||||||
|
'<div class="modal-dialog"></div>',
|
||||||
|
);
|
||||||
const content = $('<div class="modal-content"></div>');
|
const content = $('<div class="modal-content"></div>');
|
||||||
const header = this._buildHeader(title);
|
const header = this._buildHeader(title);
|
||||||
|
|
||||||
@ -65,17 +67,31 @@ class BootstrapDialog extends Options {
|
|||||||
footer = $('<div class="modal-footer" style="paddingTop:5;textAlign:center">');
|
footer = $('<div class="modal-footer" style="paddingTop:5;textAlign:center">');
|
||||||
}
|
}
|
||||||
if (this.options.acceptButton) {
|
if (this.options.acceptButton) {
|
||||||
this.acceptButton = $(`<button type="button" class="btn btn-primary" id="acceptBtn" data-dismiss="modal">${$msg('ACCEPT')}</button>`);
|
this.acceptButton = $(
|
||||||
|
`<button type="button" class="btn btn-primary" id="acceptBtn" data-dismiss="modal">${$msg(
|
||||||
|
'ACCEPT',
|
||||||
|
)}</button>`,
|
||||||
|
);
|
||||||
footer.append(this.acceptButton);
|
footer.append(this.acceptButton);
|
||||||
this.acceptButton.unbind('click').on('click', this.options.onEventData, this.onAcceptClick);
|
this.acceptButton
|
||||||
|
.unbind('click')
|
||||||
|
.on('click', this.options.onEventData, this.onAcceptClick);
|
||||||
}
|
}
|
||||||
if (this.options.removeButton) {
|
if (this.options.removeButton) {
|
||||||
this.removeButton = $(`<button type="button" class="btn btn-secondary" id="removeBtn" data-dismiss="modal">${$msg('REMOVE')}</button>`);
|
this.removeButton = $(
|
||||||
|
`<button type="button" class="btn btn-secondary" id="removeBtn" data-dismiss="modal">${$msg(
|
||||||
|
'REMOVE',
|
||||||
|
)}</button>`,
|
||||||
|
);
|
||||||
footer.append(this.removeButton);
|
footer.append(this.removeButton);
|
||||||
this.removeButton.on('click', this.options.onEventData, this.onRemoveClick);
|
this.removeButton.on('click', this.options.onEventData, this.onRemoveClick);
|
||||||
}
|
}
|
||||||
if (this.options.cancelButton) {
|
if (this.options.cancelButton) {
|
||||||
footer.append(`<button type="button" class="btn btn-secondary" data-dismiss="modal">${$msg('CANCEL')}</button>`);
|
footer.append(
|
||||||
|
`<button type="button" class="btn btn-secondary" data-dismiss="modal">${$msg(
|
||||||
|
'CANCEL',
|
||||||
|
)}</button>`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return footer;
|
return footer;
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,10 @@ class BootstrapDialogRequest extends BootstrapDialog {
|
|||||||
|
|
||||||
this._native.find('.modal-body').load(url, () => {
|
this._native.find('.modal-body').load(url, () => {
|
||||||
me.acceptButton.unbind('click').click(() => {
|
me.acceptButton.unbind('click').click(() => {
|
||||||
if ($defined(global.submitDialogForm) && typeof (global.submitDialogForm) === 'function') {
|
if (
|
||||||
|
$defined(global.submitDialogForm)
|
||||||
|
&& typeof global.submitDialogForm === 'function'
|
||||||
|
) {
|
||||||
global.submitDialogForm();
|
global.submitDialogForm();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -61,7 +64,7 @@ class BootstrapDialogRequest extends BootstrapDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onDialogShown() {
|
onDialogShown() {
|
||||||
if ($defined(global.onDialogShown) && typeof (global.onDialogShown) === 'function') {
|
if ($defined(global.onDialogShown) && typeof global.onDialogShown === 'function') {
|
||||||
global.onDialogShown();
|
global.onDialogShown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
relationships.forEach((relationship) => {
|
relationships.forEach((relationship) => {
|
||||||
if (
|
if (
|
||||||
mindmap.findNodeById(relationship.getFromNode()) !== null
|
mindmap.findNodeById(relationship.getFromNode()) !== null
|
||||||
&& mindmap.findNodeById(relationship.getToNode()) !== null
|
&& mindmap.findNodeById(relationship.getToNode()) !== null
|
||||||
) {
|
) {
|
||||||
// Isolated relationships are not persisted ....
|
// Isolated relationships are not persisted ....
|
||||||
const relationDom = XMLSerializerPela._relationshipToXML(document, relationship);
|
const relationDom = XMLSerializerPela._relationshipToXML(document, relationship);
|
||||||
@ -83,7 +83,9 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
parentTopic.setAttribute('position', `${pos.x},${pos.y}`);
|
parentTopic.setAttribute('position', `${pos.x},${pos.y}`);
|
||||||
|
|
||||||
const order = topic.getOrder();
|
const order = topic.getOrder();
|
||||||
if (typeof order === 'number' && Number.isFinite(order)) { parentTopic.setAttribute('order', order.toString()); }
|
if (typeof order === 'number' && Number.isFinite(order)) {
|
||||||
|
parentTopic.setAttribute('order', order.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = topic.getText();
|
const text = topic.getText();
|
||||||
@ -99,8 +101,7 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
const size = topic.getImageSize();
|
const size = topic.getImageSize();
|
||||||
parentTopic.setAttribute(
|
parentTopic.setAttribute(
|
||||||
'image',
|
'image',
|
||||||
`${size.width},${size.height
|
`${size.width},${size.height}:${topic.getImageUrl()}`,
|
||||||
}:${topic.getImageUrl()}`,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,10 +133,10 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
$defined(fontFamily)
|
$defined(fontFamily)
|
||||||
|| $defined(fontSize)
|
|| $defined(fontSize)
|
||||||
|| $defined(fontColor)
|
|| $defined(fontColor)
|
||||||
|| $defined(fontWeight)
|
|| $defined(fontWeight)
|
||||||
|| $defined(fontStyle)
|
|| $defined(fontStyle)
|
||||||
) {
|
) {
|
||||||
parentTopic.setAttribute('fontStyle', font);
|
parentTopic.setAttribute('fontStyle', font);
|
||||||
}
|
}
|
||||||
@ -226,13 +227,13 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dom
|
* @param dom
|
||||||
* @param mapId
|
* @param mapId
|
||||||
* @throws will throw an error if dom is null or undefined
|
* @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 mapId is null or undefined
|
||||||
* @throws will throw an error if the document element is not consistent with a wisemap's root
|
* @throws will throw an error if the document element is not consistent with a wisemap's root
|
||||||
* element
|
* element
|
||||||
*/
|
*/
|
||||||
loadFromDom(dom: Document, mapId: string) {
|
loadFromDom(dom: Document, mapId: string) {
|
||||||
$assert(dom, 'dom can not be null');
|
$assert(dom, 'dom can not be null');
|
||||||
$assert(mapId, 'mapId can not be null');
|
$assert(mapId, 'mapId can not be null');
|
||||||
@ -253,7 +254,9 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
// Add all the topics nodes ...
|
// Add all the topics nodes ...
|
||||||
const childNodes = Array.from(rootElem.childNodes);
|
const childNodes = Array.from(rootElem.childNodes);
|
||||||
const topicsNodes = childNodes
|
const topicsNodes = childNodes
|
||||||
.filter((child: ChildNode) => (child.nodeType === 1 && (child as Element).tagName === 'topic'))
|
.filter(
|
||||||
|
(child: ChildNode) => child.nodeType === 1 && (child as Element).tagName === 'topic',
|
||||||
|
)
|
||||||
.map((c) => c as Element);
|
.map((c) => c as Element);
|
||||||
topicsNodes.forEach((child) => {
|
topicsNodes.forEach((child) => {
|
||||||
const topic = this._deserializeNode(child, mindmap);
|
const topic = this._deserializeNode(child, mindmap);
|
||||||
@ -262,7 +265,9 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
|
|
||||||
// Then all relationshops, they are connected to topics ...
|
// Then all relationshops, they are connected to topics ...
|
||||||
const relationshipsNodes = childNodes
|
const relationshipsNodes = childNodes
|
||||||
.filter((child: ChildNode) => (child.nodeType === 1 && (child as Element).tagName === 'relationship'))
|
.filter(
|
||||||
|
(child: ChildNode) => child.nodeType === 1 && (child as Element).tagName === 'relationship',
|
||||||
|
)
|
||||||
.map((c) => c as Element);
|
.map((c) => c as Element);
|
||||||
relationshipsNodes.forEach((child) => {
|
relationshipsNodes.forEach((child) => {
|
||||||
try {
|
try {
|
||||||
@ -280,9 +285,7 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_deserializeNode(domElem: Element, mindmap: Mindmap) {
|
_deserializeNode(domElem: Element, mindmap: Mindmap) {
|
||||||
const type = domElem.getAttribute('central') != null
|
const type = domElem.getAttribute('central') != null ? 'CentralTopic' : 'MainTopic';
|
||||||
? 'CentralTopic'
|
|
||||||
: 'MainTopic';
|
|
||||||
|
|
||||||
// Load attributes...
|
// Load attributes...
|
||||||
let id: number | null = null;
|
let id: number | null = null;
|
||||||
@ -480,16 +483,16 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method ensures that the output String has only
|
* This method ensures that the output String has only
|
||||||
* valid XML unicode characters as specified by the
|
* valid XML unicode characters as specified by the
|
||||||
* XML 1.0 standard. For reference, please see
|
* XML 1.0 standard. For reference, please see
|
||||||
* <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
|
* <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
|
||||||
* standard</a>. This method will return an empty
|
* standard</a>. This method will return an empty
|
||||||
* String if the input is null or empty.
|
* String if the input is null or empty.
|
||||||
*
|
*
|
||||||
* @param in The String whose non-valid characters we want to remove.
|
* @param in The String whose non-valid characters we want to remove.
|
||||||
* @return The in String, stripped of non-valid characters.
|
* @return The in String, stripped of non-valid characters.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
rmXmlInv(str) {
|
rmXmlInv(str) {
|
||||||
if (str == null || str === undefined) return null;
|
if (str == null || str === undefined) return null;
|
||||||
@ -499,11 +502,11 @@ class XMLSerializerPela implements XMLMindmapSerializer {
|
|||||||
const c = str.charCodeAt(i);
|
const c = str.charCodeAt(i);
|
||||||
if (
|
if (
|
||||||
c === 0x9
|
c === 0x9
|
||||||
|| c === 0xa
|
|| c === 0xa
|
||||||
|| c === 0xd
|
|| c === 0xd
|
||||||
|| (c >= 0x20 && c <= 0xd7ff)
|
|| (c >= 0x20 && c <= 0xd7ff)
|
||||||
|| (c >= 0xe000 && c <= 0xfffd)
|
|| (c >= 0xe000 && c <= 0xfffd)
|
||||||
|| (c >= 0x10000 && c <= 0x10ffff)
|
|| (c >= 0x10000 && c <= 0x10ffff)
|
||||||
) {
|
) {
|
||||||
result += str.charAt(i);
|
result += str.charAt(i);
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,11 @@ import ToolbarPaneItem from './ToolbarPaneItem';
|
|||||||
import { buildHtml, css } from './ColorPaletteHtml';
|
import { buildHtml, css } from './ColorPaletteHtml';
|
||||||
|
|
||||||
// rgbToHex implementation from https://stackoverflow.com/a/3627747/58128
|
// rgbToHex implementation from https://stackoverflow.com/a/3627747/58128
|
||||||
export const rgb2hex = (rgb) => `#${
|
export const rgb2hex = (rgb) => `#${rgb
|
||||||
rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)
|
.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)
|
||||||
.slice(1)
|
.slice(1)
|
||||||
.map((n) => parseInt(n, 10)
|
.map((n) => parseInt(n, 10).toString(16).padStart(2, '0'))
|
||||||
.toString(16).padStart(2, '0')).join('')}`;
|
.join('')}`;
|
||||||
|
|
||||||
class ColorPalettePanel extends ToolbarPaneItem {
|
class ColorPalettePanel extends ToolbarPaneItem {
|
||||||
constructor(buttonId, model, baseUrl) {
|
constructor(buttonId, model, baseUrl) {
|
||||||
@ -38,10 +38,7 @@ class ColorPalettePanel extends ToolbarPaneItem {
|
|||||||
_load() {
|
_load() {
|
||||||
if (!ColorPalettePanel._panelContent) {
|
if (!ColorPalettePanel._panelContent) {
|
||||||
// Load all the CSS styles ...
|
// Load all the CSS styles ...
|
||||||
$('<style>')
|
$('<style>').append(css).appendTo($('head')).attr({ type: 'text/css' });
|
||||||
.append(css)
|
|
||||||
.appendTo($('head'))
|
|
||||||
.attr({ type: 'text/css' });
|
|
||||||
|
|
||||||
ColorPalettePanel._panelContent = buildHtml();
|
ColorPalettePanel._panelContent = buildHtml();
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
test: /.(js$)/,
|
test: /.(js$)/,
|
||||||
use: ['babel-loader'],
|
use: ['babel-loader'],
|
||||||
exclude: [
|
exclude: [/node_modules/],
|
||||||
/node_modules/,
|
|
||||||
],
|
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -8,23 +8,25 @@ const common = require('./webpack.common');
|
|||||||
const playgroundConfig = {
|
const playgroundConfig = {
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
entry: {
|
entry: {
|
||||||
mindplot: path.resolve(__dirname, './src/index.js'),
|
|
||||||
layout: path.resolve(__dirname, './test/playground/layout/context-loader'),
|
layout: path.resolve(__dirname, './test/playground/layout/context-loader'),
|
||||||
},
|
},
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'test/playground/dist'),
|
||||||
|
filename: '[name].js',
|
||||||
|
library: {
|
||||||
|
type: 'umd',
|
||||||
|
},
|
||||||
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
port: 8083,
|
port: 8083,
|
||||||
open: false,
|
open: false,
|
||||||
writeToDisk: true,
|
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.css$/i,
|
test: /\.css$/i,
|
||||||
use: [
|
use: ['style-loader', 'css-loader?url=false'],
|
||||||
'style-loader',
|
|
||||||
'css-loader?url=false',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -117,9 +117,9 @@ class ElementClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* /*
|
* /*
|
||||||
* Returns element type name.
|
* Returns element type name.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
getType() {
|
getType() {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -161,12 +161,12 @@ class ElementClass {
|
|||||||
setStroke(width, style, color, opacity) {
|
setStroke(width, style, color, opacity) {
|
||||||
if (
|
if (
|
||||||
style != null
|
style != null
|
||||||
&& style !== undefined
|
&& style !== undefined
|
||||||
&& style !== 'dash'
|
&& style !== 'dash'
|
||||||
&& style !== 'dot'
|
&& style !== 'dot'
|
||||||
&& style !== 'solid'
|
&& style !== 'solid'
|
||||||
&& style !== 'longdash'
|
&& style !== 'longdash'
|
||||||
&& style !== 'dashdot'
|
&& style !== 'dashdot'
|
||||||
) {
|
) {
|
||||||
throw new Error(`Unsupported stroke style: '${style}'`);
|
throw new Error(`Unsupported stroke style: '${style}'`);
|
||||||
}
|
}
|
||||||
@ -288,6 +288,10 @@ class ElementClass {
|
|||||||
getParent() {
|
getParent() {
|
||||||
return this.peer.getParent();
|
return this.peer.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTestId(testId) {
|
||||||
|
this.peer._native.setAttribute('test-id', testId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Element._SIGNATURE_MULTIPLE_ARGUMENTS = -1;
|
Element._SIGNATURE_MULTIPLE_ARGUMENTS = -1;
|
||||||
|
@ -51,7 +51,6 @@ class WorkspacePeer extends ElementPeer {
|
|||||||
|
|
||||||
setCoordSize(width, height) {
|
setCoordSize(width, height) {
|
||||||
const viewBox = this._native.getAttribute('viewBox');
|
const viewBox = this._native.getAttribute('viewBox');
|
||||||
|
|
||||||
let coords = [0, 0, 0, 0];
|
let coords = [0, 0, 0, 0];
|
||||||
if (viewBox != null) {
|
if (viewBox != null) {
|
||||||
coords = viewBox.split(/ /);
|
coords = viewBox.split(/ /);
|
||||||
|
@ -20,7 +20,7 @@ module.exports = {
|
|||||||
image: './test/playground/image.js',
|
image: './test/playground/image.js',
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist', 'tests'),
|
path: path.resolve(__dirname, 'test/playground/dist'),
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
publicPath: '/',
|
publicPath: '/',
|
||||||
},
|
},
|
||||||
@ -36,9 +36,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
use: 'babel-loader',
|
use: 'babel-loader',
|
||||||
test: /.js$/,
|
test: /.js$/,
|
||||||
exclude: [
|
exclude: [/node_modules/],
|
||||||
/node_modules/,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|svg)$/i,
|
test: /\.(png|svg)$/i,
|
||||||
@ -55,107 +53,77 @@ module.exports = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
new CleanWebpackPlugin(),
|
new CleanWebpackPlugin(),
|
||||||
new CopyPlugin({
|
new CopyPlugin({
|
||||||
patterns: [
|
patterns: [{ from: 'test/playground/styles.css', to: 'styles.css' }],
|
||||||
{ from: 'test/playground/styles.css', to: 'styles.css' },
|
}),
|
||||||
],
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['index'],
|
||||||
|
filename: 'index.html',
|
||||||
|
template: 'test/playground/index.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['arrow'],
|
||||||
|
filename: 'arrow.html',
|
||||||
|
template: 'test/playground/arrow.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['curvedLine'],
|
||||||
|
filename: 'curvedLine.html',
|
||||||
|
template: 'test/playground/curvedLine.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['events'],
|
||||||
|
filename: 'events.html',
|
||||||
|
template: 'test/playground/events.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['font'],
|
||||||
|
filename: 'font.html',
|
||||||
|
template: 'test/playground/font.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['rect'],
|
||||||
|
filename: 'rect.html',
|
||||||
|
template: 'test/playground/rect.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['line'],
|
||||||
|
filename: 'line.html',
|
||||||
|
template: 'test/playground/line.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['workspace'],
|
||||||
|
filename: 'workspace.html',
|
||||||
|
template: 'test/playground/workspace.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['polyLine'],
|
||||||
|
filename: 'polyLine.html',
|
||||||
|
template: 'test/playground/polyLine.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['shapes'],
|
||||||
|
filename: 'shapes.html',
|
||||||
|
template: 'test/playground/shapes.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['group'],
|
||||||
|
filename: 'group.html',
|
||||||
|
template: 'test/playground/group.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['prototype'],
|
||||||
|
filename: 'prototype.html',
|
||||||
|
template: 'test/playground/prototype.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['text'],
|
||||||
|
filename: 'text.html',
|
||||||
|
template: 'test/playground/text.html',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
chunks: ['image'],
|
||||||
|
filename: 'image.html',
|
||||||
|
template: 'test/playground/image.html',
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['index'],
|
|
||||||
filename: 'index.html',
|
|
||||||
template: 'test/playground/index.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['arrow'],
|
|
||||||
filename: 'arrow.html',
|
|
||||||
template: 'test/playground/arrow.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['curvedLine'],
|
|
||||||
filename: 'curvedLine.html',
|
|
||||||
template: 'test/playground/curvedLine.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['events'],
|
|
||||||
filename: 'events.html',
|
|
||||||
template: 'test/playground/events.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['font'],
|
|
||||||
filename: 'font.html',
|
|
||||||
template: 'test/playground/font.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['rect'],
|
|
||||||
filename: 'rect.html',
|
|
||||||
template: 'test/playground/rect.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['line'],
|
|
||||||
filename: 'line.html',
|
|
||||||
template: 'test/playground/line.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['workspace'],
|
|
||||||
filename: 'workspace.html',
|
|
||||||
template: 'test/playground/workspace.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['polyLine'],
|
|
||||||
filename: 'polyLine.html',
|
|
||||||
template: 'test/playground/polyLine.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['shapes'],
|
|
||||||
filename: 'shapes.html',
|
|
||||||
template: 'test/playground/shapes.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['group'],
|
|
||||||
filename: 'group.html',
|
|
||||||
template: 'test/playground/group.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['prototype'],
|
|
||||||
filename: 'prototype.html',
|
|
||||||
template: 'test/playground/prototype.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['text'],
|
|
||||||
filename: 'text.html',
|
|
||||||
template: 'test/playground/text.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
{
|
|
||||||
chunks: ['image'],
|
|
||||||
filename: 'image.html',
|
|
||||||
template: 'test/playground/image.html',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -1,35 +1,36 @@
|
|||||||
/* eslint-disable no-undef */
|
/* eslint-disable no-undef */
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack')
|
const webpack = require('webpack');
|
||||||
|
|
||||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
webpack
|
webpack;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
app: path.join(__dirname, 'src', 'index.tsx')
|
app: path.join(__dirname, 'src', 'index.tsx'),
|
||||||
},
|
},
|
||||||
target: 'web',
|
target: 'web',
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.tsx', '.js', '.jsx']
|
extensions: ['.ts', '.tsx', '.js', '.jsx'],
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].bundle.js',
|
filename: '[name].bundle.js',
|
||||||
path: path.resolve(__dirname, 'dist')
|
path: path.resolve(__dirname, 'dist'),
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [{
|
rules: [
|
||||||
test: /\.tsx?$/,
|
{
|
||||||
use: 'ts-loader',
|
test: /\.tsx?$/,
|
||||||
exclude: '/node_modules/'
|
use: 'ts-loader',
|
||||||
},
|
exclude: '/node_modules/',
|
||||||
{
|
},
|
||||||
test: /\.(png|jpe?g|gif|svg)$/,
|
{
|
||||||
type: 'asset/inline',
|
test: /\.(png|jpe?g|gif|svg)$/,
|
||||||
},
|
type: 'asset/inline',
|
||||||
]
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
usedExports: true,
|
usedExports: true,
|
||||||
@ -37,23 +38,24 @@ module.exports = {
|
|||||||
cacheGroups: {
|
cacheGroups: {
|
||||||
vendors: {
|
vendors: {
|
||||||
test: /node_modules\/.*/,
|
test: /node_modules\/.*/,
|
||||||
name: "vendors",
|
name: 'vendors',
|
||||||
chunks: "all",
|
chunks: 'all',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CleanWebpackPlugin(),
|
new CleanWebpackPlugin(),
|
||||||
new CopyWebpackPlugin({
|
new CopyWebpackPlugin({
|
||||||
patterns: [{
|
patterns: [
|
||||||
from: 'public/*',
|
{
|
||||||
to: '[name].[ext]',
|
from: 'public/*',
|
||||||
globOptions: {
|
to: '[name].[ext]',
|
||||||
ignore: [
|
globOptions: {
|
||||||
'**/index.html'
|
ignore: ['**/index.html'],
|
||||||
]
|
},
|
||||||
}
|
},
|
||||||
}]
|
],
|
||||||
})]
|
}),
|
||||||
}
|
],
|
||||||
|
};
|
||||||
|
@ -4,18 +4,20 @@ const path = require('path');
|
|||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
module.exports = merge(common, {
|
module.exports = merge(common, {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: true
|
minimize: true,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: path.join(__dirname, 'public/index.html'),
|
template: path.join(__dirname, 'public/index.html'),
|
||||||
templateParameters: {
|
templateParameters: {
|
||||||
PUBLIC_URL: process.env.PUBLIC_URL ? process.env.PUBLIC_URL : 'https://www.wisemapping.com'
|
PUBLIC_URL: process.env.PUBLIC_URL
|
||||||
},
|
? process.env.PUBLIC_URL
|
||||||
base: process.env.PUBLIC_URL ? process.env.PUBLIC_URL : 'https://www.wisemapping.com'
|
: 'https://www.wisemapping.com',
|
||||||
})
|
},
|
||||||
]
|
base: process.env.PUBLIC_URL ? process.env.PUBLIC_URL : 'https://www.wisemapping.com',
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|