/node_modules/jest-css-modules"
17 | }
18 | },
19 | "author": {
20 | "name": "Nobuyuki Mukai"
21 | },
22 | "license": "MIT",
23 | "dependencies": {
24 | "@3yaa3yaa/markdowntextbox": "^0.4.0",
25 | "file-saver": "~2.0.5",
26 | "html2canvas": "^1.0.0-rc.7",
27 | "react-dnd": "^11.1.3",
28 | "react-dnd-html5-backend": "^11.1.3",
29 | "react-redux": "^7.2.2",
30 | "redux": "^4.0.5",
31 | "yarn": "^1.22.10",
32 | "crypto-js": "^4.0.0"
33 | },
34 | "peerDependencies": {
35 | "react": "^16.14.0"
36 | },
37 | "devDependencies": {
38 | "react": "^16.14.0",
39 | "@babel/cli": "^7.12.10",
40 | "@babel/core": "^7.12.10",
41 | "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
42 | "@babel/plugin-transform-react-jsx": "^7.12.12",
43 | "@babel/preset-env": "^7.12.11",
44 | "babel-core": "^7.0.0-bridge.0",
45 | "babel-jest": "^26.6.3",
46 | "babel-loader": "^8.2.2",
47 | "css-loader": "^5.0.1",
48 | "enzyme": "^3.11.0",
49 | "enzyme-adapter-react-16": "^1.15.5",
50 | "eslint": "^7.16.0",
51 | "file-loader": "^6.2.0",
52 | "jest": "^26.6.3",
53 | "jest-css-modules": "^2.1.0",
54 | "style-loader": "^2.0.0",
55 | "url-loader": "^4.1.1",
56 | "webpack": "^5.11.1",
57 | "webpack-cli": "^4.3.0"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Burger.css:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #humberger {
5 | position: relative;
6 | margin:0px;
7 | padding: 0px;
8 | height: 12px;
9 | width: 20px;
10 | display: inline-block;
11 | box-sizing: border-box;
12 | }
13 |
14 | #humberger div {
15 | position: absolute;
16 | left: 0;
17 | height: 2px;
18 | width: 20px;
19 | background-color: aliceblue;
20 | border-radius: 2px;
21 | display: inline-block;
22 | box-sizing: border-box;
23 | }
24 | #humberger div:nth-of-type(1) {
25 | top: 0px;
26 | }
27 | #humberger div:nth-of-type(2) {
28 | top: 5px;
29 | }
30 | #humberger div:nth-of-type(3) {
31 | bottom: 0px;
32 | }
--------------------------------------------------------------------------------
/src/Burger.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './Burger.css';
3 |
4 | class Burger extends Component {
5 |
6 | constructor(props) {
7 | super(props);
8 | }
9 |
10 | render() {
11 | return (
12 |
17 | );
18 | }
19 | }
20 |
21 | export default Burger;
22 |
--------------------------------------------------------------------------------
/src/Connector.css:
--------------------------------------------------------------------------------
1 | .Connector-Table {
2 | /*position: absolute;*/
3 | top:0%;
4 | bottom:0%;
5 | left:0px;
6 | right:0px;
7 | margin-top: 0px;
8 | margin-bottom: 0px;
9 | margin-left:0px;
10 | margin-right:0px;
11 | display: table;
12 | width: 30px;
13 | height:100%;
14 | table-layout: fixed;
15 | }
16 |
17 | .Connector-Row-top {
18 | height:auto;
19 | display: table-row;
20 | }
21 |
22 |
23 | .Connector-Row-bottom {
24 | height:100%;
25 | display: table-row;
26 | }
27 |
28 | .Connector-Single-TopLeft {
29 | display: table-cell;
30 | border-bottom:solid;
31 | border-bottom-width: 1px;
32 | height:5px;
33 | }
34 |
35 | .Connector-Single-TopRight {
36 | display: table-cell;
37 | border-bottom:solid;
38 | border-bottom-width: 1px;
39 | height:5px;
40 | }
41 |
42 | .Connector-Single-BottomLeft {
43 | display: table-cell;
44 |
45 | }
46 |
47 | .Connector-Single-BottomRight {
48 | list-style: none;
49 | display: table-cell;
50 | }
51 |
52 |
53 | .Connector-Vertical-TopLeft {
54 | display: table-cell;
55 | height:5px;
56 | }
57 |
58 | .Connector-Vertical-TopRight {
59 | display: table-cell;
60 | border-left: solid;
61 | border-left-width: 1px;
62 | height:5px;
63 | }
64 |
65 | .Connector-Vertical-BottomLeft {
66 | display: table-cell;
67 | }
68 |
69 | .Connector-Vertical-BottomRight {
70 | list-style: none;
71 | display: table-cell;
72 | border-left: solid;
73 | border-left-width: 1px;
74 | }
75 |
76 |
77 | .Connector-Top-TopLeft {
78 | display: table-cell;
79 | border-bottom:solid;
80 | border-bottom-width: 1px;
81 | height:5px;
82 | }
83 |
84 | .Connector-Top-TopRight {
85 | display: table-cell;
86 | border-bottom:solid;
87 | border-bottom-width: 1px;
88 | height:5px;
89 | }
90 |
91 | .Connector-Top-BottomLeft {
92 | display: table-cell;
93 | height:100%;
94 |
95 | }
96 |
97 | .Connector-Top-BottomRight {
98 | display: table-cell;
99 | border-left: solid;
100 | border-left-width: 1px;
101 | height:100%;
102 | }
103 |
104 |
105 | .Connector-Middle-TopLeft {
106 | display: table-cell;
107 | height:5px;
108 |
109 | }
110 |
111 | .Connector-Middle-TopRight {
112 | display: table-cell;
113 | border-left:solid;
114 | border-left-width: 1px;
115 | border-bottom:solid;
116 | border-bottom-width: 1px;
117 | height:5px;
118 |
119 | /*border-bottom-left-radius: 10px;*/
120 |
121 | }
122 |
123 | .Connector-Middle-BottomLeft {
124 | display: table-cell;
125 | height:100%;
126 |
127 | }
128 |
129 | .Connector-Middle-BottomRight {
130 | list-style: none;
131 | display: table-cell;
132 | border-left:solid;
133 | border-left-width: 1px;
134 | height:100%;
135 |
136 | }
137 |
138 |
139 |
140 | .Connector-Bottom-TopLeft {
141 | display: table-cell;
142 | height:5px;
143 | }
144 |
145 | .Connector-Bottom-TopRight {
146 | display: table-cell;
147 | border-left:solid;
148 | border-left-width: 1px;
149 | border-bottom:solid;
150 | border-bottom-width: 1px;
151 | height:5px;
152 | }
153 |
154 | .Connector-Bottom-BottomLeft {
155 | display: table-cell;
156 | height:100%;
157 | }
158 |
159 | .Connector-Bottom-BottomRight {
160 | display: table-cell;
161 | height:100%;
162 | }
163 |
--------------------------------------------------------------------------------
/src/Connector.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import "./Connector.css"
3 |
4 |
5 | // const canvasWidth = 30
6 | // const canvasHeight = 30
7 |
8 | class Connector extends Component {
9 |
10 | constructor(props) {
11 | super(props);
12 | }
13 | componentDidMount() {
14 | }
15 |
16 |
17 | _getTableStyle()
18 | {
19 | let isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
20 | let isEdge = navigator.userAgent.toLowerCase().indexOf('edge') > -1;
21 | if(isFirefox||isEdge)
22 | {
23 | return {position:"absolute"}
24 | }
25 | else
26 | {
27 | return {height:"100%"}
28 | }
29 | }
30 |
31 | _getSingleConnector()
32 | {
33 | return (
34 |
44 | )
45 | }
46 |
47 | _getVerticalConnector()
48 | {
49 | return (
50 |
60 | )
61 | }
62 |
63 | _getTopConnector()
64 | {
65 | return (
66 |
76 | )
77 | }
78 |
79 | _getMiddleConnector()
80 | {
81 | return (
82 |
92 | )
93 | }
94 |
95 |
96 | _getBottomConnector()
97 | {
98 | return (
99 |
109 | )
110 | }
111 | render() {
112 | switch(this.props.mode)
113 | {
114 | case "SINGLE":
115 | return this._getSingleConnector()
116 | case "VERTICAL":
117 | return this._getVerticalConnector()
118 | case "TOP":
119 | return this._getTopConnector()
120 | case "MIDDLE":
121 | return this._getMiddleConnector()
122 | case "BOTTOM":
123 | return this._getBottomConnector()
124 | default:
125 | return
126 | }
127 | }
128 | }
129 | export default Connector;
130 |
--------------------------------------------------------------------------------
/src/Deserializer.js:
--------------------------------------------------------------------------------
1 | import LeafData from "./LeafData";
2 | import Property from "./Property";
3 | import sha256 from 'crypto-js/sha256';
4 |
5 |
6 | export default class Deserializer
7 | {
8 | constructor(text)
9 | {
10 | this.text=text;
11 | this.data=this.convertInitialData(this.text);
12 | }
13 |
14 | convertInitialData(givenData)
15 | {
16 | if (givenData==null)
17 | {
18 | return null;
19 | }
20 | else
21 | {
22 | let parsedData = typeof(givenData)=="string" ? JSON.parse(givenData) : givenData;
23 | let root;
24 | let property;
25 | if("root" in parsedData)
26 | {
27 | root=this.convertToLeafData(parsedData.root);
28 | }
29 | else
30 | {
31 | root=new LeafData();
32 | }
33 | if("property" in parsedData)
34 | {
35 | property=this.convertToProperty(parsedData.property);
36 | }
37 | else
38 | {
39 | property=new Property();
40 | }
41 | property.initialTreeHash = sha256(JSON.stringify(root)).toString();
42 |
43 | return {root: root, property: property};
44 |
45 | }
46 | }
47 |
48 | convertToLeafData(data)
49 | {
50 | let out=new LeafData(data.id, data.description, [], data.imgs, data.color);
51 |
52 | for(let child of data.children)
53 | {
54 | out.children.push(this.convertToLeafData(child));
55 | }
56 | return out;
57 | }
58 |
59 | convertToProperty(data)
60 | {
61 | return Property.getNewObject(data);
62 | }
63 | }
--------------------------------------------------------------------------------
/src/DnDLeaf.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { DragSource, DropTarget } from 'react-dnd'
3 | import Leaf from "./Leaf";
4 |
5 | class DnDLeaf extends Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | }
10 |
11 | render() {
12 | const { connectDragSource, connectDropTarget } = this.props;
13 | return (
14 | connectDropTarget(connectDragSource(
15 |
16 |
27 |
28 | ))
29 | );
30 | }
31 | }
32 |
33 | const dragSpec = {
34 | beginDrag: (props) => { return props.leafdata },
35 | endDrag: (props,monitor,component)=>{
36 | let dragged=monitor.getItem()
37 | let dropped=monitor.getDropResult()
38 | if(dropped!=null)
39 | {
40 | if(dragged.id!=dropped.id)
41 | {
42 | component.props.move(dragged.id, dropped.id);
43 | }
44 | }
45 | }
46 | }
47 |
48 | const dropSpec = {
49 | drop: (props, monitor, component)=> {
50 | return props.leafdata;
51 | }
52 | }
53 |
54 |
55 | function collectDrag(connect, monitor) {
56 | return {
57 | connectDragSource: connect.dragSource(),
58 | isDragging: monitor.isDragging()
59 | }
60 | }
61 |
62 | function collectDrop(connect, monitor) {
63 | return {
64 | connectDropTarget: connect.dropTarget(),
65 | isOver: monitor.isOver()
66 | }
67 | }
68 |
69 | DnDLeaf=DropTarget("leaf", dropSpec, collectDrop)(DnDLeaf)
70 | DnDLeaf=DragSource("leaf", dragSpec, collectDrag)(DnDLeaf)
71 |
72 | export default DnDLeaf ;
73 |
--------------------------------------------------------------------------------
/src/ImageMenu.css:
--------------------------------------------------------------------------------
1 |
2 | .ImageMenu {
3 | display: block;
4 | width: 30px;
5 | }
6 |
7 | .ImageMenu-Label{
8 | vertical-align: top;
9 | }
10 |
11 | .ImageMenu-Item {
12 | vertical-align: top;
13 | height: 1px;
14 | visibility: hidden;
15 | }
16 |
17 |
18 | .ImageMenu-Canvas{
19 | display: none;
20 | }
21 |
22 |
23 | .ImageMenu-Label {
24 | display: block;
25 | }
26 | .ImageMenu-Img {
27 | display: inline-block;
28 | width:30px;
29 | }
30 |
31 | .ImageMenu-ButtonLabel {
32 | display: inline-block;
33 | color: whitesmoke;
34 | padding-top: 0px;
35 | padding-left: 3px;
36 | vertical-align: top;
37 | }
--------------------------------------------------------------------------------
/src/ImageMenu.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './ImageMenu.css';
3 | import previewimg from './images/gopreviewwhite.png';
4 | import downimg from './images/down.png';
5 | import rightimg from './images/right.png';
6 | import cameraimg from './images/camera.png';
7 | import paletteimg from './images/palette.png';
8 | import ImgCanvas from "./ImgCanvas";
9 | import Property from "./Property";
10 |
11 | export default class ImageMenu extends Component {
12 |
13 | constructor(props) {
14 | super(props);
15 | this.state={
16 | imgcanvas:""}
17 | }
18 |
19 |
20 | colorPickHandler(e)
21 | {
22 | //e.preventDefault()
23 | let color=e.target.value
24 | let newleaf=this.props.leafdata
25 | newleaf.color=color
26 | this.props.edit(newleaf)
27 | }
28 |
29 | fileChangeHandler(e)
30 | {
31 | //e.preventDefault()
32 | let file = e.target.files[0]
33 | if(file!=undefined){
34 | let reader = new FileReader()
35 | reader.onloadend = () => {
36 | let img=new Image()
37 | img.onload=()=>{
38 | let w= 1024
39 | let ratio= w /img.width
40 | let h=img.height*ratio
41 | this.setState( {imgcanvas:
42 | {
46 | ctx.drawImage(img,0,0,w,h);
47 | let newleaf=this.props.leafdata
48 | let imagedata=canvas.toDataURL("image/jpeg")
49 | if (newleaf.imgs==null)
50 | {newleaf.imgs = [imagedata]}
51 | else
52 | {newleaf.imgs.push([imagedata])}
53 | this.props.edit(newleaf)
54 | }
55 | }
56 | >
57 | })
58 | this.setState({imgcanvas:""})
59 | }
60 | img.src=reader.result
61 |
62 | }
63 | reader.readAsDataURL(file)
64 | }
65 | }
66 |
67 | downButtonStyle() {
68 | if(this.props.leafdata.id===0)
69 | {
70 | return {display:"none"}
71 | }
72 | else
73 | {
74 | return {}
75 | }
76 | }
77 |
78 | render() {
79 | return
80 |
81 |
82 |
83 | {this.props.changePreviewMode(Property.previewMode().Tree)}} />
85 |
86 |
87 |
88 |
89 |
90 | {this.fileChangeHandler(e)}} />
92 | {this.state.imgcanvas}
93 |
94 |
95 |
96 |
97 | {this.colorPickHandler(e)}} />
99 |
100 |
101 |
102 |
103 | {this.props.addChild(this.props.leafdata.id)}} />
105 |
106 |
107 |
108 |
109 | {this.props.addSibling(this.props.leafdata.id)}} />
111 |
112 |
113 | }
114 | }
--------------------------------------------------------------------------------
/src/ImgCanvas.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .ImgCanvas-canvas {
4 | display: none;
5 | }
6 |
--------------------------------------------------------------------------------
/src/ImgCanvas.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './ImgCanvas.css'
3 |
4 | class ImgCanvas extends Component {
5 |
6 | constructor(props) {
7 | super(props);
8 | this.canvasRef=React.createRef()
9 | }
10 |
11 | componentDidMount() {
12 | let canvas = this.canvasRef;
13 | let ctx=canvas.getContext('2d')
14 | this.props.setImage(ctx,canvas)
15 | //this.props.updateLeaf(this.canvasRef.toDataURL("image/jpeg",0.1))
16 | }
17 |
18 | render() {
19 | return {this.canvasRef=e}}>
20 | }
21 | }
22 |
23 |
24 | export default ImgCanvas;
25 |
--------------------------------------------------------------------------------
/src/ImgViewer.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .ImgViewer {
4 | width:auto;
5 | }
6 |
7 |
8 | .ImgViewer-div {
9 | width: auto;
10 | margin:5px;
11 |
12 | }
13 |
14 | .ImgViewer-img {
15 | width: 180px;
16 | margin:5px;
17 | }
18 |
--------------------------------------------------------------------------------
/src/ImgViewer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './ImgViewer.css';
3 |
4 | class ImgViewer extends Component {
5 |
6 | constructor(props) {
7 | super(props);
8 | }
9 |
10 | _generateImgs(imgs)
11 | {
12 | return imgs.map((img)=> )
13 | }
14 |
15 |
16 | _getDOM()
17 | {
18 | if (this.props.leafdata.imgs!=null)
19 | {
20 | return (
21 |
22 | {this._generateImgs(this.props.leafdata.imgs)}
23 |
)
24 | }
25 | else
26 | {
27 | return
28 | }
29 |
30 |
31 | }
32 |
33 | render() {
34 | return (
35 | this._getDOM()
36 | );
37 | }
38 | }
39 |
40 | export default ImgViewer;
41 |
--------------------------------------------------------------------------------
/src/InstructionMessage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Property from "./Property";
3 |
4 |
5 | export default class InstructionMessage extends Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | this.previewMode=this.props.previewMode;
10 | }
11 |
12 | getContent()
13 | {
14 | switch (this.previewMode) {
15 | case Property.previewMode().Label:
16 | return
17 |
No Labels!
18 |
Try adding #label on your Mind Map!
19 |
20 | default:
21 | return
22 |
No content!
23 |
Start adding items on your Mind Map!
24 |
25 | }
26 | }
27 |
28 | getRandomImage()
29 | {
30 | let items = ['🥺','👻','👽','🙈','🙉','🙊','👺','👾','🤖'];
31 | let random = Math.floor( Math.random() * items.length );
32 | return items[random];
33 | }
34 |
35 |
36 | render() {
37 | return
38 |
{this.getRandomImage()}
39 | {this.getContent()}
40 |
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/Leaf.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .Leaf-Row{
4 | position: static;
5 | display: table-row;
6 | vertical-align: middle;
7 | }
8 |
9 | .Leaf-Columns{
10 | position: static;
11 | display: table-cell;
12 | margin:0px;
13 | vertical-align: top;
14 | }
15 |
16 | .Leaf-Command {
17 | display:none;
18 | }
19 | .Leaf-Command-Label{
20 | margin:0px;
21 | padding:0px;
22 | font-size: small;
23 | color: green;
24 | border:none;
25 | border-color: whitesmoke;
26 | border-width:1px;
27 | }
28 |
--------------------------------------------------------------------------------
/src/Leaf.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './Leaf.css';
3 | import ImgViewer from './ImgViewer'
4 | import ImageMenu from "./ImageMenu";
5 | import MarkDownTextBoxWrapper from "./MarkDownTextBoxWrapper";
6 | import StateProvider from './StateProvider';
7 | import LeafData from "./LeafData";
8 |
9 | class Leaf extends Component {
10 |
11 | constructor(props) {
12 | super(props);
13 | this.leafTextAreaRef=React.createRef()
14 | this.leafRef=React.createRef()
15 | this.state={flag:true};
16 | this.textValueBuffer="";
17 |
18 | }
19 |
20 | edit()
21 | {
22 | let newleaf= LeafData.getNewObject(this.props.leafdata);
23 | newleaf.description= this.textValueBuffer;
24 | this.props.edit(newleaf);
25 | }
26 |
27 |
28 | keyDownHandler(e) {
29 | switch (e.keyCode) {
30 | case 13: //Enter
31 | if (e.shiftKey != true && this.props.leafdata.id!=0) {
32 | e.preventDefault();
33 | this.props.addSibling(this.props.leafdata.id);
34 | }
35 | break;
36 | case 9: //Tab
37 | if (e.shiftKey!=true)
38 | {
39 | e.preventDefault()
40 | this.props.addChild(this.props.leafdata.id)
41 | }
42 | else
43 | {
44 | e.preventDefault()
45 | this.props.walk(StateProvider.whereToMove().LEVELUP);
46 | }
47 | break;
48 | case 46: //Delete
49 | e.preventDefault()
50 | this.props.delete(this.props.leafdata.id)
51 | break;
52 | case 38: //UP
53 |
54 | if (e.shiftKey!=true)
55 | {
56 | e.preventDefault()
57 | this.props.walk(StateProvider.whereToMove().UP);
58 | }
59 | break;
60 | case 40: //Down
61 | if (e.shiftKey!=true)
62 | {
63 | e.preventDefault();
64 | this.props.walk(StateProvider.whereToMove().DOWN);
65 | break;
66 | }
67 | }
68 | }
69 |
70 | leafUpdateHandler(e)
71 | {
72 | this.textValueBuffer=e.target.value;
73 | this.edit()
74 | }
75 |
76 | stateChange()
77 | {
78 | this.setState({flag: this.state.flag===false})
79 | }
80 |
81 | _getLeafStyle()
82 | {
83 | let color=this.props.leafdata.color;
84 | if(color==undefined){color="silver"};
85 |
86 | return {
87 | textAlign: "left",
88 | backgroundColor: color,
89 | padding: "10px",
90 | marginTop: "1px",
91 | marginBottom: "1px",
92 | marginLeft:"0px",
93 | marginRight:"0px",
94 | borderRadius:"10px",
95 | resize: "both"
96 | }
97 | }
98 |
99 | _getMenuVisibility()
100 | {
101 | if(this._getIsFocused())
102 | {
103 | return {display: "block" }
104 | }
105 | else
106 | {
107 | return {display: "none"}
108 | }
109 | }
110 |
111 | _getIsFocused()
112 | {
113 | if(this.props.leafdata.id==this.props.focusId)
114 | {
115 | return true;
116 | }
117 | else
118 | {
119 | return false;
120 | }
121 | }
122 |
123 | _getDescriptionStyle()
124 | {
125 | return {minWidth: "100px", maxWidth: "200px"};
126 | }
127 |
128 |
129 |
130 | _getDOM(){
131 | return (
132 | this.keyDownHandler(e)}
134 | style={this._getLeafStyle()}
135 | ref={(e)=>{this.leafRef=e}} >
136 |
137 |
{this.props.jump(this.props.leafdata.id)}}
139 | >
140 |
141 |
142 | this.leafUpdateHandler(e)}
144 | focus={this._getIsFocused()}
145 | descriptionStyle={this._getDescriptionStyle()}
146 | textAreaStyle={{height:"170px",fontFamily:"sans-serif", fontSize:"100%"}}
147 | />
148 |
149 |
150 |
151 |
152 |
153 | {this.props.edit(leaf);this.stateChange();}}
155 | addChild={this.props.addChild}
156 | addSibling={this.props.addSibling}
157 | changePreviewMode={this.props.changePreviewMode}
158 | style={this._getMenuVisibility()}/>
159 |
160 |
161 |
162 |
163 | )
164 | }
165 |
166 | render() {
167 | return (
168 | this._getDOM()
169 | );
170 | }
171 | }
172 |
173 | export default Leaf ;
174 |
--------------------------------------------------------------------------------
/src/LeafData.js:
--------------------------------------------------------------------------------
1 | export default class LeafData{
2 | constructor(id=0, description="", children=[], imgs=[],color="silver")
3 | {
4 | this.id=id;
5 | this.description=description;
6 | this.children=children;
7 | this.imgs=imgs;
8 | this.color=color;
9 | }
10 |
11 | static getNewObject(rawdata)
12 | {
13 | try{
14 | return new LeafData(rawdata.id, rawdata.description, rawdata.children, rawdata.imgs, rawdata.color)
15 | }catch(e)
16 | {
17 | console.error("failed to generate new leaf object :" + e.message)
18 |
19 | }
20 | }
21 |
22 | isLeafDataClass()
23 | {
24 | return true;
25 | }
26 |
27 | getLeaf(id)
28 | {
29 | if(this.id===id)
30 | {
31 | return this;
32 | }
33 | else
34 | {
35 | for(let leaf of this.children)
36 | {
37 | let child=leaf.getLeaf(id)
38 | if(child!=null)
39 | {
40 | return child;
41 | }
42 | }
43 | }
44 | return null;
45 | }
46 |
47 | isNullObject()
48 | {
49 | if(this.children.length===0 && this.description==="" && this.imgs.length===0)
50 | {
51 | return true;
52 | }
53 | else
54 | {
55 | return false;
56 | }
57 | }
58 |
59 | getParent(id)
60 | {
61 | if(this.children.find(l => l.id===id) != undefined)
62 | {
63 | return this;
64 | }
65 | else
66 | {
67 | for(let l of this.children)
68 | {
69 | let parent=l.getParent(id);
70 | if(parent!=null)
71 | {
72 | return parent;
73 | }
74 | }
75 | }
76 | return null;
77 | }
78 |
79 |
80 | getSiblings(id)
81 | {
82 | return this.getParent(id).children;
83 | }
84 |
85 | getElderBrother(id)
86 | {
87 | let brothers=this.getSiblings(id);
88 | let elderbrother=null;
89 | for(let brother of brothers)
90 | {
91 | if(brother.id===id){return elderbrother};
92 | elderbrother=brother;
93 | }
94 | return null;
95 | }
96 |
97 | isLastRecord(id)
98 | {
99 | if(this.getYoungerBrother(id)===null)
100 | {
101 | return true;
102 | }
103 | else
104 | {
105 | return false;
106 | }
107 | }
108 |
109 | getYoungerBrother(id)
110 | {
111 | let brothers=this.getSiblings(id);
112 | let wasMe=false;
113 | for(let brother of brothers)
114 | {
115 | if(wasMe){return brother};
116 | if(brother.id===id){wasMe=true};
117 | }
118 | return null;
119 | }
120 |
121 |
122 |
123 | getChildren( id)
124 | {
125 | let l = this.getLeaf(id);
126 | if(l===null)
127 | {
128 | return [];
129 | }
130 | else
131 | {
132 | return l.children;
133 | }
134 | }
135 |
136 | getAllFamilyMembers()
137 | {
138 | let out=[this];
139 | out=out.concat(this.getAllChildren());
140 | return out;
141 | }
142 |
143 |
144 | getAllChildren()
145 | {
146 | let out=[];
147 | this._setChildrenInArray(this.id, out)
148 | return out;
149 | }
150 |
151 |
152 | _setChildrenInArray(id, out)
153 | {
154 | let current = this.getLeaf(id);
155 | if(id!=this.id)
156 | {
157 | out.push(current);
158 | }
159 | current.children.forEach((child)=>{this._setChildrenInArray(child.id, out)});
160 | }
161 |
162 | filterAndSortLeafs(leafs, parentid)
163 | {
164 | let out=[];
165 | if(Array.isArray(leafs) && leafs.length>0)
166 | {
167 | let bigbrother = leafs.filter((leaf)=>{return (leaf.parentid==parentid && leaf.elderbrotherid==0)})[0];
168 | StateProvider.recursivelyGetSiblings(leafs, bigbrother, out);
169 | return out;
170 | }
171 | else
172 | {
173 | return null;
174 | }
175 | }
176 |
177 | getRandomId()
178 | {
179 | let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
180 | let str = '';
181 | for (let i = 0; i < 8; i++) {
182 | str += chars.charAt(Math.floor(Math.random() * chars.length));
183 | }
184 | return str;
185 | }
186 |
187 | getNewId()
188 | {
189 | const random = this.getRandomId()
190 | return this.getLeaf(random)===null ? random : this.getNewId()
191 | // return this.getLatestId()+1;
192 | }
193 |
194 | getLatestId()
195 | {
196 | let children=this.getAllChildren()
197 | if(children.length>0)
198 | {
199 | return children.sort((a,b)=>{return b.id-a.id})[0].id;
200 | }
201 | else
202 | {
203 | return 0;
204 | }
205 | }
206 |
207 | labelExists(label)
208 | {
209 | let regexp= new RegExp('#' + label+ '(:|\r\n|\n|\r| |$)','g');
210 | if(regexp.test(this.description))
211 | {
212 | return true;
213 | }
214 | else
215 | {
216 | return false;
217 | }
218 | }
219 |
220 | codeExists()
221 | {
222 | let regexp=/```([\n\r]|.)*```/;
223 | if(regexp.test(this.description))
224 | {
225 | return true;
226 | }
227 | else
228 | {
229 | return false;
230 | }
231 | }
232 |
233 |
234 | getLabelValues(label)
235 | {
236 | let regexp;
237 | if(label==="")
238 | {
239 | regexp= new RegExp('#([^ ]+?)(\r\n|\n|\r| |$)','g')
240 | }
241 | else
242 | {
243 | regexp= new RegExp('#' + label+ ':([^ ]+?)(\r\n|\n|\r| |$)','g')
244 | };
245 | return [...this.description.matchAll(regexp)].map(el=>{return el[1]});
246 | }
247 |
248 | getLabelFieldsOfChildren()
249 | {
250 | let items=[this];
251 | items=items.concat(this.getAllChildren());
252 | let array=[];
253 | if(items===null){return array};
254 | for(let item of items)
255 | {
256 | let regexp = new RegExp('#([^ ]+?)(\r\n|\n|\r| |$)','g');
257 | array=array.concat([...item.description.matchAll(regexp)].map(el=>{return el[1]}));
258 | }
259 | array=array.map(el=>{return el.replace(/:.*/,'')}); //Remove Value
260 | array=array.filter(el=>!isFinite(el)) //Remove Numbers
261 | array=array.filter((x, i, self) => self.indexOf(x) === i); //Remove Duplicates
262 | return array;
263 | }
264 |
265 | getNumericValuesOfChildren(label="")
266 | {
267 | return this.getChildrenValues(label).filter(el=>isFinite(el));
268 | }
269 |
270 | getChildrenValues(label="")
271 | {
272 | let items=[this];
273 | items=items.concat(this.getAllChildren());
274 | let array=[];
275 | if(items===null){return array};
276 | for(let item of items)
277 | {
278 | array=array.concat(item.getLabelValues(label));
279 | }
280 | return array;
281 | }
282 |
283 |
284 |
285 | sumLabelsOfChildren(label)
286 | {
287 | let array=this.getNumericValuesOfChildren(label);
288 | let reducer=(acc, cur)=>{
289 | return acc+parseFloat(cur);
290 | };
291 | return array.reduce(reducer,0);
292 | }
293 |
294 | countLabelsOfChildren(label)
295 | {
296 | let array=this.getNumericValuesOfChildren(label);
297 | return array.length;
298 | }
299 |
300 | meanLabelsOfChildren(label)
301 | {
302 | return Math.round((this.sumLabelsOfChildren(label)/this.countLabelsOfChildren(label)) * 10) / 10 // 出力:123.5
303 | }
304 |
305 | }
--------------------------------------------------------------------------------
/src/MainWindow.css:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | .MainWindow {
5 | position: relative;
6 | }
7 |
8 | .MainWindow-Preview {
9 | position: absolute;
10 | z-index: 1;
11 | }
12 |
13 | .MainWindow-Content {
14 | position: absolute;
15 | z-index: 0;
16 | }
17 |
--------------------------------------------------------------------------------
/src/MainWindow.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Tree from "./Tree";
3 | import PreviewPanel from "./PreviewPanel";
4 | import Property from "./Property";
5 | import './MainWindow.css'
6 |
7 | class MainWindow extends Component {
8 |
9 | constructor(props) {
10 | super(props);
11 | this.mainRef = React.createRef();
12 | this.mainContentRef = React.createRef();
13 | this.height='0px';
14 | }
15 |
16 | _getPreviewScreen()
17 | {
18 | if(this.props.property.previewMode!=Property.previewMode().none)
19 | {
20 | return
24 | }
25 | }
26 |
27 | _getTreeStyle() {
28 | if (this.props.property.previewMode != Property.previewMode().none) {
29 | return {filter: "blur(10px)",
30 | opacity: "0.7",
31 | position: "fixed",
32 | overflow:"hidden"}
33 | }
34 | }
35 |
36 | _getMainStyle()
37 | {
38 | return {height: this.height};
39 | }
40 |
41 |
42 | render() {
43 | return
44 |
45 | {this._getPreviewScreen()}
46 |
47 |
{this.mainContentRef=e}}
49 | style={this._getTreeStyle()}>
50 |
64 |
65 |
66 | }
67 | }
68 |
69 | export default MainWindow;
70 |
--------------------------------------------------------------------------------
/src/MarkDownTextBoxWrapper.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './Leaf.css';
3 | import { MarkdownTextBox } from '@3yaa3yaa/markdowntextbox';
4 | import ReservedList from "./Reserved";
5 |
6 | export default class MarkDownTextBoxWrapper extends Component {
7 |
8 | constructor(props) {
9 | super(props);
10 | this.reservedList = new ReservedList((label)=>{return this.props.leafdata.sumLabelsOfChildren(label)}
11 | , (label)=>{return this.props.leafdata.countLabelsOfChildren(label)});
12 | }
13 |
14 |
15 | render() {
16 | return (
17 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Menu.css:
--------------------------------------------------------------------------------
1 |
2 | .Menu {
3 | position: relative;
4 | }
5 |
6 | .Menu-Command {
7 | display:none;
8 | }
9 |
10 |
11 | .Menu-Command-Burger{
12 | float: left;
13 | margin:0px;
14 | padding:0px;
15 | font-size: small;
16 | color: darkgray;
17 | border:none;
18 | border-color: whitesmoke;
19 | border-width:1px;
20 | }
21 |
--------------------------------------------------------------------------------
/src/Menu.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './Menu.css';
3 | import Burger from './Burger'
4 | import MenuModal from './MenuModal'
5 | import onClickOutside from 'react-onclickoutside';
6 |
7 | class Menu extends Component {
8 |
9 | constructor(props) {
10 | super(props);
11 | this.state={modalDisplay:false}
12 | }
13 |
14 | _closeModal() {
15 | this.setState({modalDisplay:false})
16 | }
17 |
18 |
19 | _switchModal()
20 | {
21 | let nextState=(this.state.modalDisplay === false)
22 | this.setState({modalDisplay:nextState})
23 | }
24 | _getModal()
25 | {
26 | return {this._closeModal()}}/>
32 | }
33 |
34 |
35 | _getPositionStyle(event)
36 | {
37 | if(this.state.modalDisplay==false)
38 | {
39 | const out={display:"none"}
40 | return out;
41 | }
42 | const out={
43 | left: 20 ,
44 | top: 0
45 | }
46 | return out;
47 | }
48 |
49 | handleClickOutside() {
50 | this._closeModal()
51 | }
52 |
53 |
54 | render() {
55 | return (
56 |
57 |
58 | {this._switchModal() }}
60 | >
61 |
62 | {this._getModal()}
63 |
64 | );
65 | }
66 | }
67 |
68 | export default onClickOutside(Menu) ;
69 |
--------------------------------------------------------------------------------
/src/MenuModal.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .MenuModal {
4 | position: absolute;
5 | width:auto;
6 | min-width: 120px;
7 | height:auto;
8 | background-color: whitesmoke;
9 | z-index: 1;
10 | border-radius:10px;
11 | filter: drop-shadow(1px 1px 1px rgba(0,0,0,0.6));
12 | }
13 |
14 | .MenuModal-Command {
15 | display:block;
16 | margin-left: 20px;
17 | }
18 | .MenuModal-Command-Label{
19 | margin:10px;
20 | padding:0px;
21 | font-size: small;
22 | color: darkgray;
23 | border:none;
24 | border-color: beige;
25 | border-width:1px;
26 | }
27 |
28 | .MenuModal-canvas{
29 | display: none;
30 | }
31 |
32 | .MenuModal-Command-Burger{
33 | float: left;
34 | margin:0px;
35 | padding:0px;
36 | font-size: small;
37 | color: darkgray;
38 | border:none;
39 | border-color: beige;
40 | border-width:1px;
41 | }
42 |
--------------------------------------------------------------------------------
/src/MenuModal.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './MenuModal.css';
3 | import ImgCanvas from './ImgCanvas'
4 |
5 | class MenuModal extends Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | this.state={
10 | imgcanvas:""}
11 | }
12 |
13 | colorPickHandler(e)
14 | {
15 | //e.preventDefault()
16 | let color=e.target.value
17 | let newleaf=this.props.leafdata
18 | newleaf.color=color
19 | this.props.edit(newleaf)
20 | }
21 |
22 | fileChangeHander(e)
23 | {
24 | //e.preventDefault()
25 | let file = e.target.files[0]
26 | let reader = new FileReader()
27 | reader.onloadend = () => {
28 | let img=new Image()
29 | img.onload=()=>{
30 | let w= 200
31 | let ratio= w /img.width
32 | let h=img.height*ratio
33 | this.setState( {imgcanvas:
34 | {
38 | ctx.drawImage(img,0,0,w,h);
39 | let newleaf=this.props.leafdata
40 | let imagedata=canvas.toDataURL("image/jpeg")
41 | if (newleaf.imgs==null)
42 | {newleaf.imgs = [imagedata]}
43 | else
44 | {newleaf.imgs.push([imagedata])}
45 | this.props.edit(newleaf)
46 | }
47 | }
48 | >
49 | })
50 | this.setState({imgcanvas:""})
51 | }
52 | img.src=reader.result
53 |
54 | }
55 | reader.readAsDataURL(file)
56 | }
57 |
58 | _getModal()
59 | {
60 | return(
61 | { this.menuModalRef=e}}>
62 | Add Picture
63 |
64 | {this.fileChangeHander(e);this.props.closeModal()}}>
65 |
66 | Pick Color
67 | {this.colorPickHandler(e);this.props.closeModal()}}>
68 |
69 |
70 | Level Down
71 | {this.props.addChild(this.props.leafdata.id);this.props.closeModal()}}>
72 |
73 | Down
74 | {this.props.addSibling(this.props.leafdata.id);this.props.closeModal()}}>
75 |
76 |
77 | )
78 | }
79 |
80 | render() {
81 | //return this._getModal()
82 | return {this._getModal()}{this.state.imgcanvas}
83 | }
84 | }
85 |
86 | export default MenuModal;
87 |
--------------------------------------------------------------------------------
/src/PreviewLabels.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .PreviewLabel-Items {
4 | display: inline-block;
5 | margin: 5px;
6 | vertical-align: top;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/src/PreviewLabels.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './PreviewLabels.css'
3 | import ReadOnlyLeaf from "./ReadOnlyLeaf";
4 | import InstructionMessage from "./InstructionMessage";
5 | import Property from "./Property";
6 |
7 | export default class PreviewLabels extends Component {
8 |
9 | constructor(props) {
10 | super(props);
11 | this.leafdata=this.props.leafdata;
12 | this.fields=this.props.leafdata.getLabelFieldsOfChildren();
13 | }
14 |
15 | getSummary(field)
16 | {
17 | let count = this.leafdata.countLabelsOfChildren(field);
18 | let sum=this.leafdata.sumLabelsOfChildren(field);
19 | let mean=this.leafdata.meanLabelsOfChildren(field);
20 | if(sum>0 && count>1)
21 | {
22 | return
23 |
{`Count: ${count}`}
24 |
{`Total: ${sum}`}
25 |
{`Average: ${mean}`}
26 |
27 |
28 | }
29 | else
30 | {
31 | return "";
32 | }
33 | }
34 |
35 | getContent()
36 | {
37 | if(this.fields.length>0)
38 | {
39 | return this.fields.map((field, fieldid)=>{
40 | let items=this.leafdata.getAllFamilyMembers().map((child, itemid)=>{
41 | if(child.labelExists(field))
42 | {
43 | return
46 |
47 |
;
48 | }
49 | else
50 | {
51 | return null;
52 | }
53 | }).filter((item)=>{return item!=null});
54 | return
{field} {items}{this.getSummary(field)}
55 | })
56 | }
57 | else
58 | {
59 | return
60 | }
61 | }
62 |
63 |
64 | render() {
65 | return {this.getContent()}
66 | }
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/src/PreviewList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Property from "./Property";
3 | import { MarkdownTextBox } from '@3yaa3yaa/markdowntextbox';
4 | import ImgViewer from "./ImgViewer";
5 | import InstructionMessage from "./InstructionMessage";
6 |
7 | export default class PreviewList extends Component {
8 |
9 | constructor(props) {
10 | super(props);
11 | this.leafdata=this.props.leafdata;
12 | this.fields=this.props.leafdata.getLabelFieldsOfChildren();
13 | }
14 |
15 | getHeader()
16 | {
17 | let array = ["Content","Images"];
18 | array= array.concat(this.fields);
19 | array = array.map((el,index)=>{return {el}
})
20 |
21 | return {array}
;
22 | }
23 |
24 | removeLabelAndFunction(text)
25 | {
26 | let out=text;
27 | out=out.replace(/#[^ ]+?(\n|\r|\r\n| |$)/g,'');
28 | out=out.replace(/=[^ ]+?(\n|\r|\r\n| |$)/g,'');
29 | return out;
30 | }
31 |
32 | getContent()
33 | {
34 | let array = [this.leafdata];
35 | array=array.concat(this.leafdata.getAllChildren(this.leafdata.id));
36 | return array.map((item,rownum)=>{
37 | let cells=[ ];
39 | cells.push()
40 | for(let field of this.fields)
41 | {
42 | let val="";
43 | if(item.labelExists(field))
44 | {
45 | let tmp = item.getLabelValues(field);
46 | if(tmp.length>0)
47 | {
48 | val = tmp;
49 | }
50 | else
51 | {
52 | val = '\u2705';
53 | }
54 | }
55 | else
56 | {
57 | val = '';
58 | }
59 | cells.push(val);
60 | }
61 |
62 | cells=cells.map((el,colnum)=>{return {el}
});
66 | return {cells}
});
67 | }
68 |
69 | GetPreviewListStyle() {
70 | return {display: "table",
71 | width:"auto",
72 | borderStyle: "solid",
73 | borderWidth: "0.3px",
74 | borderColor: "darkslategray",
75 | marginTop: "15px",
76 | marginRight:"15px"}
77 | }
78 |
79 |
80 | GetPreviewListHeaderStyle() {
81 | return {display: "table-header-group",
82 | fontWeight: "bold"}
83 | }
84 |
85 | GetPreviewListRowStyle() {
86 | return {display: "table-row"}
87 | }
88 |
89 | GetPreviewListCellStyle() {
90 | return {display: "table-cell",
91 | verticalAlign: "top",
92 | textAlign: "left",
93 | maxWidth:"600px",
94 | padding: "3px",
95 | borderStyle: "solid",
96 | borderWidth: "0.3px",
97 | borderColor: "darkslategray"}
98 | }
99 |
100 | getContentOrInstruction()
101 | {
102 | if(this.leafdata.isNullObject())
103 | {
104 | return
105 | }
106 | else
107 | {
108 | return
109 | {this.getHeader()}
110 | {this.getContent()}
111 |
112 | }
113 | }
114 |
115 |
116 | render() {
117 | return this.getContentOrInstruction()
118 | }
119 | }
120 |
121 |
--------------------------------------------------------------------------------
/src/PreviewMenu.css:
--------------------------------------------------------------------------------
1 |
2 | .PreviewMenu {
3 | margin-left: 10px;
4 | margin-top: 0px;
5 | margin-right: 10px;
6 | }
7 |
8 | .PreviewMenu-Item {
9 | visibility: hidden;
10 | height: 3px;
11 | margin: 0px;
12 | }
13 |
14 | .PreviewMenu-buttons{
15 | list-style: none;
16 | }
17 |
18 |
19 | .PreviewMenu-button{
20 | vertical-align: top;
21 | height:40px;
22 | list-style: none;
23 | }
24 |
25 | .html2canvas-container { width: 3000px !important; height: 3000px !important; }
26 |
27 |
28 | .PreviewMenu-Img {
29 | display: inline-block;
30 | width:30px;
31 | height: 30px;
32 | border-radius: 5px;
33 | /*border-style: solid;*/
34 | background-color: lightgray;
35 | /*border-color: silver;*/
36 | vertical-align: top;
37 | }
38 |
39 | .PreviewMenu-ButtonLabel {
40 | display: inline-block;
41 | color: gray;
42 | padding-top: 3px;
43 | padding-left: 5px;
44 | vertical-align: center;
45 | }
--------------------------------------------------------------------------------
/src/PreviewMenu.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './PreviewMenu.css';
3 | import Property from "./Property";
4 | import backToEditImg from './images/backtoedit.png'
5 | import goPreviewImg from './images/gopreview.png'
6 | import exportImg from './images/export.png'
7 | import tableImg from './images/gotable.png'
8 | import documentImg from './images/document.png'
9 | import labelimg from "./images/label.png"
10 |
11 | export default class PreviewMenu extends Component {
12 |
13 | constructor(props) {
14 | super(props);
15 | this.export=this.props.export;
16 | this.changePreviewMode=this.props.changePreviewMode;
17 | }
18 |
19 | getCommandButton(previewMode, buttonimg, text, onClick)
20 | {
21 | const id="PreviewMenu-" + text;
22 | return
23 |
24 |
25 | {text}
26 |
27 | {onClick(e)}} />
29 |
30 | }
31 |
32 | getCommandLabelStyle(previewMode)
33 | {
34 | if(previewMode===this.props.previewMode)
35 | {
36 | return {fontWeight:"bold"}
37 | }
38 | }
39 |
40 | getButtons()
41 | {
42 | return
43 | {this.getCommandButton(Property.previewMode().none, backToEditImg,"Back"
44 | , () => {this.changePreviewMode(Property.previewMode().none)})}
45 | {this.getCommandButton(Property.previewMode().Tree, goPreviewImg,"Preview"
46 | , () => {this.changePreviewMode(Property.previewMode().Tree)})}
47 | {this.getCommandButton(Property.previewMode().Sentence, documentImg,"Composition"
48 | , () => {this.changePreviewMode(Property.previewMode().Sentence)})}
49 | {this.getCommandButton(Property.previewMode().Label, labelimg,"Labels"
50 | , () => {this.changePreviewMode(Property.previewMode().Label)})}
51 | {this.getCommandButton(Property.previewMode().List, tableImg,"List"
52 | , () => {this.changePreviewMode(Property.previewMode().List)})}
53 | {this.getCommandButton(Property.previewMode().none, exportImg,"Export"
54 | , () => {this.export()})}
55 | ;
56 | }
57 |
58 | render() {
59 | return
60 | {this.getButtons()}
61 |
62 | }
63 | }
--------------------------------------------------------------------------------
/src/PreviewPanel.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .PreviewPanel {
4 | display:table-row;
5 | width:100%;
6 | min-width: 500px;
7 | height:auto;
8 | min-width: 400px;
9 | border-radius:10px;
10 | filter: drop-shadow(1px 1px 1px rgba(0,0,0,0.6));
11 | overflow: auto;
12 | }
13 |
14 | .PreviewPanel-Menu {
15 | display: table-cell;
16 | margin-top: 5px;
17 | width: 175px;
18 | min-width: 175px;
19 | vertical-align: top;
20 | /*position: fixed;*/
21 | margin-right: 0px;
22 | }
23 | .PreviewPanel-Main {
24 | display:table-cell;
25 | width: fit-content;
26 | margin-top: 4px;
27 | vertical-align: top;
28 | margin-left: 5px;
29 | }
30 |
--------------------------------------------------------------------------------
/src/PreviewPanel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './PreviewPanel.css';
3 | import Property from "./Property";
4 | import Tree from './Tree'
5 | import PreviewMenu from "./PreviewMenu";
6 | import PreviewLabels from "./PreviewLabels";
7 | import html2canvas from "html2canvas";
8 | import { saveAs } from "file-saver";
9 | import PreviewSentence from "./PreviewSentence";
10 | import PreviewList from "./PreviewList";
11 |
12 | class PreviewPanel extends Component {
13 |
14 | constructor(props) {
15 | super(props);
16 | this.leafdata=this.props.leafdata;
17 | this.changePreviewMode=this.props.changePreviewMode;
18 | this.previewRef = React.createRef();
19 | }
20 |
21 | getContent()
22 | {
23 | switch(this.props.previewMode)
24 | {
25 | case Property.previewMode().Tree:
26 | let props = new Property();
27 | props.isReadOnly=Property.readOnlyLevel().hardReadOnly;
28 | return ;
29 | case Property.previewMode().List:
30 | return ;
31 | case Property.previewMode().Label:
32 | return ;
33 | case Property.previewMode().Sentence:
34 | return ;
35 | default:
36 | return "";
37 | }
38 | }
39 |
40 | doExport()
41 | {
42 | switch (this.props.previewMode) {
43 | case Property.previewMode().Sentence:
44 | case Property.previewMode().Label:
45 | case Property.previewMode().List:
46 | let blob=new Blob([this.previewRef.current.innerHTML], {type: "text/plain;charset=utf-8"})
47 | saveAs(blob,"treemindmap.html");
48 | break;
49 | default:
50 | html2canvas(this.previewRef.current).then(function(canvas) {
51 | canvas.toBlob((blob => {saveAs(blob,'treemindmap.png')}));
52 | });
53 | break;
54 | }
55 | }
56 |
57 | getPreviewMainStyle()
58 | {
59 | switch (this.props.previewMode) {
60 | case Property.previewMode().Sentence:
61 | case Property.previewMode().Label:
62 | case Property.previewMode().List:
63 | return {width:"100%"};
64 | default:
65 | return {width:"fit-content"};
66 | }
67 | }
68 |
69 |
70 | render() {
71 | return
72 |
73 |
{this.doExport()}}
74 | changePreviewMode={this.changePreviewMode}
75 | previewMode={this.props.previewMode}
76 | />
77 |
78 |
79 | {this.getContent()}
80 |
81 |
82 | }
83 | }
84 |
85 | export default PreviewPanel;
86 |
--------------------------------------------------------------------------------
/src/PreviewSentence.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Property from "./Property";
3 | import MarkDownTextBoxWrapper from "./MarkDownTextBoxWrapper";
4 | import ImgViewer from "./ImgViewer";
5 | import InstructionMessage from "./InstructionMessage";
6 | import LeafData from "./LeafData";
7 |
8 | export default class PreviewSentence extends Component {
9 |
10 | constructor(props) {
11 | super(props);
12 | this.leafdata=this.props.leafdata;
13 | this.fields=this.props.leafdata.getLabelFieldsOfChildren();
14 | }
15 |
16 | getContent()
17 | {
18 | if(this.leafdata.isNullObject())
19 | {
20 | return
21 | }
22 | else
23 | {
24 | let out=[];
25 | this.fillContents(this.leafdata,1, out);
26 | return out;
27 | }
28 | }
29 |
30 | fillContents(leafdata, depth, out)
31 | {
32 | if(leafdata.description!="")
33 | {
34 | out.push(this.getTag(depth,leafdata));
35 | }
36 | if(leafdata.imgs.length>0)
37 | {
38 | out.push();
39 | }
40 | leafdata.children.forEach((child)=>this.fillContents(child, depth+1, out))
41 | }
42 |
43 | removeHeader(text)
44 | {
45 | return text.replace(/h[1-7]\./g,'');
46 | }
47 |
48 | firstlineHasSpecialCharacter(text) {
49 | let re = /^[^\n]*(```|#|\=sum|\=count|\=mean)/g;
50 | return re.test(text);
51 | }
52 |
53 |
54 |
55 | getTag(depth,leafdata)
56 | {
57 | let outputdata = LeafData.getNewObject(leafdata);
58 | outputdata.description=this.removeHeader(leafdata.description)
59 | if(outputdata.children.length>0 && depth<7 && !this.firstlineHasSpecialCharacter(outputdata.description)) {
60 | outputdata.description = 'h' + depth + '.' + outputdata.description;
61 | }
62 | return
63 |
64 |
;
65 |
66 | }
67 |
68 |
69 | render() {
70 | return
71 | {this.getContent()}
72 |
73 | }
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/src/Property.js:
--------------------------------------------------------------------------------
1 | export default class Property{
2 | constructor(focusId=0,
3 | isReadOnly=Property.readOnlyLevel().canEdit,
4 | previewMode=Property.previewMode().none,
5 | initialTreeHash="")
6 | {
7 | this.focusId=focusId;
8 | this.isReadOnly=isReadOnly;
9 | this.previewMode=previewMode;
10 | this.initialTreeHash=initialTreeHash;
11 | }
12 |
13 | static readOnlyLevel()
14 | {
15 | return {
16 | canEdit:0,
17 | softReadOnly:1,
18 | hardReadOnly:2
19 | }
20 | }
21 |
22 | static previewMode()
23 | {
24 | return {
25 | none:0,
26 | Tree:1,
27 | List:2,
28 | Label:3,
29 | Sentence:4
30 | }
31 | }
32 |
33 |
34 | static getNewObject(rawdata)
35 | {
36 | try{
37 | return new Property(rawdata.focusId, rawdata.isReadOnly, rawdata.previewMode, rawdata.initialTreeHash)
38 | }catch(e)
39 | {
40 | return new Property();
41 | console.error("failed to generate new property object :" + e.message)
42 | }
43 | }
44 |
45 |
46 |
47 | }
--------------------------------------------------------------------------------
/src/ReadOnlyLeaf.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Leaf from "./Leaf";
3 |
4 | export default class ReadOnlyLeaf extends Component {
5 |
6 | constructor(props) {
7 | super(props);
8 | }
9 |
10 | render() {
11 | return (
12 |
13 | {}}
16 | addChild={()=>{}}
17 | delete={()=>{}}
18 | addSibling={()=>{}}
19 | move={()=>{}}
20 | walk={()=>{}}
21 | jump={()=>{}}
22 | changePreviewMode={()=>{}}
23 | />
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Reserved.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Reserved } from '@3yaa3yaa/markdowntextbox'
3 |
4 |
5 | export default class ReservedList
6 | {
7 | constructor(callback_sum, callback_count)
8 | {
9 | let arr=[];
10 | this.callback_sum=callback_sum;
11 | this.callback_count=callback_count;
12 | arr.push(new Reserved('#',[" ","\n","\r\n","\r"], (node, key)=>{return this.getTagJSX(node, key)},"label(:value)"))
13 | arr.push(new Reserved('=count(',[")"], (node, key)=>{return this.getCountJSX(node, key)},"label"))
14 | arr.push(new Reserved('=sum(',[")"], (node, key)=>{return this.getSumJSX(node, key)},"label"))
15 | arr.push(new Reserved('=mean(',[")"], (node, key)=>{return this.getMeanJSX(node, key)},"label"))
16 | this.items=arr;
17 | }
18 |
19 | getMeanJSX(text, key){
20 | if(text===null || text===undefined){text=""};
21 | return {this.callback_sum(text)/this.callback_count(text)}
;
22 | }
23 |
24 | getSumJSX(text, key)
25 | {
26 | if(text===null || text===undefined){text=""};
27 | return {this.callback_sum(text)}
;
28 | }
29 |
30 | getCountJSX(text, key)
31 | {
32 | if(text===null || text===undefined){text=""};
33 | return {this.callback_count(text)}
;
34 | }
35 |
36 |
37 | getTagJSX(text, key)
38 | {
39 | return {text}
;
40 | }
41 |
42 | getTagStyle()
43 | {
44 | return {
45 | display:"block",
46 | textAlign: "justify",
47 | verticalAlign:"middle",
48 | backgroundColor: "#FFDDFF",
49 | fontsize:"8px",
50 | paddingLeft: "10px",
51 | paddingRight: "10px",
52 | borderBottomLeftRadius:"20px",
53 | borderTopLeftRadius:"20px",
54 | borderBottomRightRadius:"20px",
55 | borderTopRightRadius:"20px",
56 | width: "fit-content",
57 | marginBottom:"2px",
58 | // height: "10px",
59 | color: "#FF00FF"
60 | }
61 | }
62 |
63 | getBoldTagStyle()
64 | {
65 | let tagstyle= this.getTagStyle();
66 | tagstyle= Object.assign(tagstyle, {fontWeight:"bold"})
67 | return tagstyle;
68 | }
69 | }
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/StateProvider.js:
--------------------------------------------------------------------------------
1 | import LeafData from './LeafData'
2 | import Property from "./Property";
3 |
4 | class StateProvider
5 | {
6 | // Action
7 | static deleteAction(id)
8 | {
9 | return { type: 'delete',id }
10 | }
11 | static addRootAction()
12 | {
13 | return { type: 'addRoot' }
14 | }
15 | static addSiblingAction(id)
16 | {
17 | return { type: 'addSibling', id }
18 | }
19 | static addChildAction(id)
20 | {
21 | return { type: 'addChild', id }
22 | }
23 | static editAction(leaf)
24 | {
25 | return { type: 'edit', leaf }
26 | }
27 |
28 | static moveAction(from, to)
29 | {
30 | return { type: 'move', from, to }
31 | }
32 |
33 | static walkAction(whereTo)
34 | {
35 | return { type: 'walk', whereTo }
36 | }
37 |
38 | static jumpAction(id)
39 | {
40 | return { type: 'jump', id }
41 | }
42 |
43 | static changeModeAction(mode)
44 | {
45 | return { type: 'changeMode', mode }
46 | }
47 |
48 | static changePreviewModeAction(mode)
49 | {
50 | return { type: 'changePreviewMode', mode }
51 | }
52 |
53 |
54 | // Reducer
55 | static leafReducer(state = { root: new LeafData(), property: new Property() }, action) {
56 | try{
57 | let result;
58 | if(state.property.isReadOnly===Property.readOnlyLevel().canEdit || action.type==="changeMode" || action.type==="changePreviewMode")
59 | {
60 | switch (action.type) {
61 | case 'delete':
62 | result= StateProvider.delete(state, action.id,state.property.focusId);
63 | break;
64 | case 'addRoot':
65 | result= StateProvider.addRoot(state ,state.property.focusId,state.property.focusId);
66 | break;
67 | case 'addSibling':
68 | let youngerbrothers=state.root.getYoungerBrother(state.property.focusId);
69 | if(youngerbrothers===null)
70 | {result= StateProvider.addSibling(state ,action.id)}
71 | else
72 | {result = StateProvider.walk(state, state.property.focusId, StateProvider.whereToMove().DOWN)};
73 | break;
74 | case 'addChild':
75 | let children = state.root.getChildren(state.property.focusId);
76 | if(children.length===0)
77 | {result = StateProvider.addChild(state ,action.id)}
78 | else
79 | {result = StateProvider.walk(state, state.property.focusId, StateProvider.whereToMove().LEVELDOWN)};
80 | break;
81 | case 'edit':
82 | result= StateProvider.edit(state ,action.leaf,state.property.focusId);
83 | break;
84 | case 'move':
85 | result= StateProvider.move(state, action.from, action.to ,state.property.focusId);
86 | break;
87 | case 'walk':
88 | result = StateProvider.walk(state, state.property.focusId, action.whereTo);
89 | break;
90 | case 'jump':
91 | result = StateProvider.jump(state, action.id);
92 | break;
93 | case 'changeMode':
94 | result = StateProvider.changeMode(state, action.mode);
95 | break;
96 | case 'changePreviewMode':
97 | result = StateProvider.changePreviewMode(state, action.mode);
98 | break;
99 | default:
100 | result= state;
101 | break;
102 | }
103 | return result;
104 | }
105 | else
106 | {
107 | return state;
108 | }
109 |
110 | }catch(e)
111 | {
112 | console.error("Failed to update state: "+ e.message)
113 | return state;
114 | }
115 |
116 | }
117 |
118 | //Reducer implementation
119 | static addRoot(state,id,focusId)
120 | {
121 | if (state.root!=null)
122 | {
123 | return {root:state.root, property: state.property}
124 | }
125 | else
126 | {
127 | let leaf = new LeafData(0, "", []);
128 | let property = Property.getNewObject(state.property);
129 | property.focusId=leaf.id;
130 | return { root: leaf, property: property}
131 | }
132 | }
133 |
134 | static addChild(state, id)
135 | {
136 | let current=state.root.getLeaf(id);
137 | let leaf=new LeafData(state.root.getNewId(), "", []);
138 | current.children=current.children.concat(leaf);
139 |
140 | let property = Property.getNewObject(state.property);
141 | property.focusId=leaf.id;
142 |
143 | return { root: LeafData.getNewObject(state.root), property: property }
144 | }
145 |
146 | static addSibling(state, id)
147 | {
148 | let parent=state.root.getParent(id);
149 | if(parent===null)
150 | {
151 | return { root: state.root, property: state.property }
152 | }
153 | else
154 | {
155 | let leaf=new LeafData(state.root.getNewId());
156 | parent.children=parent.children.concat(leaf);
157 |
158 | let property = Property.getNewObject(state.property);
159 | property.focusId=leaf.id;
160 | return { root: LeafData.getNewObject(state.root), property:property }
161 | }
162 | }
163 |
164 | static edit(state, newleaf, focusId)
165 | {
166 | let leaf = state.root.getLeaf(newleaf.id);
167 | leaf.description=newleaf.description;
168 | leaf.imgs=newleaf.imgs;
169 | leaf.color=newleaf.color;
170 | return { root: state.root , property:state.property}
171 | }
172 |
173 | static move(state, from, to, focusId)
174 | {
175 | let current=state.root.getLeaf(from);
176 | let currentParent = state.root.getParent(from);
177 | let destination = state.root.getLeaf(to);
178 | if(destination!=null && current!=null && currentParent!=null)
179 | {
180 | if(currentParent.id!=destination.id)
181 | {
182 | let newleaf = LeafData.getNewObject(current);
183 | destination.children=destination.children.concat(newleaf);
184 | currentParent.children=currentParent.children.filter(child=>child.id!=from);
185 | }
186 | }
187 | return { root: LeafData.getNewObject(state.root) , property:state.property}
188 | }
189 |
190 |
191 | static delete(state, id, focusId)
192 | {
193 | if(state.root!=null && state.root.id!=id)
194 | {
195 | let parent=state.root.getParent(id);
196 | parent.children=parent.children.filter(child=>child.id!=id);
197 |
198 | let property = Property.getNewObject(state.property);
199 | property.focusId=parent.id;
200 |
201 | return {root: LeafData.getNewObject(state.root), property: property}
202 | }
203 | else
204 | {
205 | return {root: state.root , property:state.property}
206 | }
207 | }
208 |
209 |
210 | static whereToMove()
211 | {
212 | return {
213 | LEVELDOWN: "LEVELDOWN",
214 | LEVELUP: "LEVELUP",
215 | DOWN: "DOWN",
216 | UP: "UP"
217 | }
218 | }
219 |
220 |
221 | static walk(state, focusId, whereToMove)
222 | {
223 | let destination = StateProvider.whereToMove();
224 | let moveTo="";
225 | switch (whereToMove) {
226 | case destination.UP:
227 | let elderBrother=state.root.getElderBrother(focusId);
228 | if(elderBrother!=null){moveTo=elderBrother.id}
229 | else{moveTo=focusId};
230 | break;
231 | case destination.DOWN:
232 | let youngerBrother=state.root.getYoungerBrother(focusId);
233 | if(youngerBrother!=null){moveTo=youngerBrother.id}
234 | else{moveTo=focusId};
235 | break;
236 | case destination.LEVELUP:
237 | let parent=state.root.getParent(focusId);
238 | if(parent!=null){moveTo=parent.id}
239 | else {moveTo=focusId};
240 | break;
241 | case destination.LEVELDOWN:
242 | let children = state.root.getChildren(focusId);
243 | if(children.length>0){moveTo=children[0].id}
244 | else{moveTo=focusId}
245 | break;
246 | default:
247 | moveTo=focusId;
248 | break;
249 | }
250 | let property=Property.getNewObject(state.property)
251 | property.focusId=moveTo;
252 |
253 | return { root: state.root , property:property}
254 | }
255 |
256 | static jump(state, focusId)
257 | {
258 | let property=Property.getNewObject(state.property)
259 | property.focusId=focusId;
260 | return { root: state.root , property: property}
261 | }
262 |
263 | static changeMode(state, mode)
264 | {
265 | let property=Property.getNewObject(state.property)
266 | property.isReadOnly=mode;
267 | return { root: state.root , property: property}
268 | }
269 |
270 |
271 | static changePreviewMode(state, mode)
272 | {
273 | let property=Property.getNewObject(state.property)
274 | property.previewMode=mode;
275 |
276 | if(mode!=Property.previewMode().none)
277 | {
278 | property.isReadOnly=Property.readOnlyLevel().softReadOnly;
279 | }
280 | else
281 | {
282 | property.isReadOnly=Property.readOnlyLevel().canEdit;
283 | }
284 | return { root: state.root , property: property}
285 | }
286 |
287 |
288 | // Map Redux state to component props
289 | static mapStateToProps(state) {
290 | return {
291 | root: state.root,
292 | property: state.property
293 | }
294 | }
295 |
296 | // Map Redux actions to component props
297 | static mapDispatchToProps(dispatch) {
298 | return {
299 | delete: (id) => dispatch(StateProvider.deleteAction(id)),
300 | addRoot: () => dispatch(StateProvider.addRootAction()),
301 | addSibling: (id) => dispatch(StateProvider.addSiblingAction(id)),
302 | addChild: (id) => dispatch(StateProvider.addChildAction(id)),
303 | edit: (leaf) => dispatch(StateProvider.editAction(leaf)),
304 | move: (from, to) => dispatch(StateProvider.moveAction(from, to)),
305 | walk: (whereTo) => dispatch(StateProvider.walkAction(whereTo)),
306 | jump: (id) => dispatch(StateProvider.jumpAction(id)),
307 | changeMode: (mode) => dispatch(StateProvider.changeModeAction(mode)),
308 | changePreviewMode: (mode) => dispatch(StateProvider.changePreviewModeAction(mode))
309 | }
310 | }
311 | }
312 |
313 | export default StateProvider;
--------------------------------------------------------------------------------
/src/Tree.css:
--------------------------------------------------------------------------------
1 |
2 | ul {
3 | padding-left: 0px;
4 | }
5 |
6 | .Tree {
7 | display: flex;
8 | flex-direction: row;
9 | flex-wrap: nowrap;
10 | margin-top: 15px;
11 | }
12 |
13 |
14 |
15 | .Tree-Element {
16 | display: table ;
17 | list-style: none;
18 | }
19 |
20 |
21 | .Tree-Trunk {
22 | position:relative;
23 | list-style: none;
24 | display: table-cell;
25 | vertical-align: top;
26 | height:5px;
27 | min-width: 30px;
28 | }
29 |
30 | .Tree-Trunk-Sub {
31 | list-style: none;
32 | display: table-cell;
33 | vertical-align: top;
34 | height:10px;
35 | }
36 |
37 |
38 | .Tree-Branch {
39 | list-style: none;
40 | display: table-cell;
41 | }
42 | /*
43 | .Tree-Connector {
44 | position: center;
45 | width: 30px;
46 | height: 30px;
47 | margin-top: 15px;
48 | margin-left: 0px;
49 | border-left: 0px solid #5bc0de;
50 | border-top: 3px solid #5bc0de;
51 | vertical-align: middle;
52 | border-right: 8px solid #5bc0de;
53 | box-sizing: border-box;
54 | }*/
--------------------------------------------------------------------------------
/src/Tree.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './Tree.css';
3 | import DnDLeaf from "./DnDLeaf";
4 | import Connector from "./Connector"
5 | import StateProvider from "./StateProvider"
6 | import { DndProvider } from "react-dnd";
7 | import {HTML5Backend} from "react-dnd-html5-backend";
8 | import Property from "./Property";
9 |
10 | class Tree extends Component {
11 |
12 | constructor(props) {
13 | super(props);
14 | }
15 |
16 | _getFocusId()
17 | {
18 | if(this.props.property.isReadOnly!=Property.readOnlyLevel().canEdit)
19 | {
20 | return -1;
21 | }
22 | else
23 | {
24 | return this.props.property.focusId;
25 | }
26 | }
27 |
28 | safeExec(callback)
29 | {
30 | if(typeof callback === 'function')
31 | {
32 | return callback
33 | }
34 | else
35 | {
36 | return ()=>{return ""}
37 | }
38 | }
39 |
40 | _getLeaf(leaf)
41 | {
42 | return
53 | }
54 |
55 | _getConnector(leaf)
56 | {
57 | // let arr = [ ]
58 | // return arr;
59 | return ;
60 | }
61 | //
62 | // _getConnectorSub(originalleaf,rootleaf,result)
63 | // {
64 | // StateProvider.filterAndSortLeafs(this.props.root,rootleaf.id).slice(1).forEach(
65 | // (leaf)=>{
66 | // result.push()
67 | // this._getConnectorSub(originalleaf,leaf,result)
68 | // })
69 | // }
70 |
71 | _getVertical(leaf)
72 | {
73 | if(this._isLastRecord(leaf,this.props.root))
74 | {
75 | return ""
76 | }
77 | else
78 | {
79 | return "VERTICAL"
80 | }
81 | }
82 |
83 |
84 |
85 | _formatLeaf(dataarr) {
86 | let out = []
87 | if(dataarr!=null)
88 | {
89 | dataarr.forEach((leaf)=>{
90 | out.push((
91 |
92 |
93 | {this._getConnector(leaf)}
94 |
95 |
96 |
97 |
98 | {this._getLeaf(leaf)}
99 |
100 |
101 |
102 |
103 | {this._formatLeaf(leaf.getChildren(leaf.id))}
104 |
105 |
106 | ))
107 | })
108 | }
109 | return
110 | }
111 |
112 | _getMode(root, id)
113 | {
114 | let out=""
115 | let parent=root.getParent(id);
116 | if(parent===null)
117 | {out=""}
118 | else
119 | {
120 | let filtered=parent.children;
121 | if(id==filtered[0].id)
122 | {
123 | if (filtered.length==1)
124 | {out="SINGLE"}
125 | else
126 | {out = "TOP"}
127 | }
128 | else
129 | {
130 | if(id==filtered[filtered.length-1].id)
131 | {out = "BOTTOM"}
132 | else
133 | {out="MIDDLE"}
134 | }
135 | }
136 | return out
137 | }
138 |
139 | _getTree()
140 | {
141 | return this._formatLeaf([this.props.root])
142 | }
143 |
144 |
145 | render() {
146 | return (
147 |
148 |
149 | {this._getTree()}
150 |
151 |
152 | );
153 | }
154 | }
155 |
156 | //Tree=DragDropContext(HTML5Backend)(Tree)
157 | export default Tree;
158 |
--------------------------------------------------------------------------------
/src/images/backtoedit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/backtoedit.png
--------------------------------------------------------------------------------
/src/images/camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/camera.png
--------------------------------------------------------------------------------
/src/images/document.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/document.png
--------------------------------------------------------------------------------
/src/images/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/down.png
--------------------------------------------------------------------------------
/src/images/export.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/export.png
--------------------------------------------------------------------------------
/src/images/gopreview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/gopreview.png
--------------------------------------------------------------------------------
/src/images/gopreviewwhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/gopreviewwhite.png
--------------------------------------------------------------------------------
/src/images/gotable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/gotable.png
--------------------------------------------------------------------------------
/src/images/label.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/label.png
--------------------------------------------------------------------------------
/src/images/palette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/palette.png
--------------------------------------------------------------------------------
/src/images/right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/3yaa3yaa/TreeMindMap/7450413950a0ce32d0243309997e81fe27f1d766/src/images/right.png
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './index.css';
3 | import StateProvider from './StateProvider';
4 | import { Provider, connect } from 'react-redux'
5 | import {compose,createStore,applyMiddleware } from "redux";
6 | import Deserializer from "./Deserializer";
7 | import MainWindow from "./MainWindow";
8 |
9 | // Connected Component
10 | const App = connect(
11 | StateProvider.mapStateToProps,
12 | StateProvider.mapDispatchToProps
13 | )(MainWindow)
14 |
15 |
16 |
17 | export const Map=props=>{
18 | const { initialState, stateHandler, middleware } = props;
19 | let store;
20 | let deserializer=new Deserializer(initialState);
21 | let convertedInitialState=deserializer.data;
22 |
23 | const finalCreateStore = middleware ? compose(
24 | applyMiddleware(middleware)
25 | )(createStore): createStore;
26 |
27 | if(convertedInitialState == null)
28 | {
29 | // store = createStore(StateProvider.leafReducer)
30 | store = finalCreateStore(StateProvider.leafReducer)
31 | }
32 | else
33 | {
34 | // store = createStore(StateProvider.leafReducer, convertedInitialState)
35 | store = finalCreateStore(StateProvider.leafReducer, convertedInitialState)
36 | }
37 | if(stateHandler!=null)
38 | {
39 | store.subscribe(()=>stateHandler(store.getState()))
40 | }
41 | return (
42 |
43 |
44 |
45 | )
46 | }
47 |
48 | export function Render(initialState, stateHandler, elementId,ReactDOM, middleware){
49 | ReactDOM.render(
50 | ,
53 | document.getElementById(elementId)
54 | )
55 |
56 | }
57 |
58 | // If you want your app to work offline and load faster, you can change
59 | // unregister() to register() below. Note this comes with some pitfalls.
60 | // Learn more about service workers: http://bit.ly/CRA-PWA
61 | //serviceWorker.unregister();
62 |
--------------------------------------------------------------------------------
/test/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/test/Deserializer.test.js:
--------------------------------------------------------------------------------
1 | import Deserializer from '../src/Deserializer'
2 | import LeafData from "../src/LeafData";
3 |
4 | describe('A suite', function() {
5 |
6 |
7 | it('should deserialize properly', function(){
8 | let test ="{\"root\":{\"id\":0,\"description\":\"\",\"children\":[{\"id\":1,\"description\":\"\",\"children\":[{\"id\":2,\"description\":\"\",\"children\":[],\"imgs\":[],\"color\":\"silver\"},{\"id\":3,\"description\":\"\",\"children\":[],\"imgs\":[],\"color\":\"silver\"}],\"imgs\":[],\"color\":\"silver\"}],\"imgs\":[],\"color\":\"silver\"},\"focusId\":3}"
9 | let expected0=new LeafData(0);
10 | let expected1=new LeafData(1);
11 | let expected2=new LeafData(2);
12 | let expected3=new LeafData(3);
13 | expected0.children.push(expected1);
14 | expected1.children.push(expected2);
15 | expected1.children.push(expected3);
16 |
17 | let deserialized= new Deserializer(test);
18 |
19 | expect(deserialized.data.root instanceof LeafData).toBe(true);
20 | expect(deserialized.data.root).toEqual(expected0);
21 | })
22 |
23 | });
24 |
--------------------------------------------------------------------------------
/test/LeafData.test.js:
--------------------------------------------------------------------------------
1 | import LeafData from "../src/LeafData";
2 |
3 | describe('A suite', function() {
4 |
5 | it('should collect tree data properly', function(){
6 | let data0= new LeafData(0,"data0",[]);
7 | let data1= new LeafData(1,"data1",[]);
8 | let data2= new LeafData(2,"data2",[]);
9 | let data3= new LeafData(3,"data3",[]);
10 | let data4= new LeafData(4,"data4",[]);
11 | let data5= new LeafData(5,"data5",[]);
12 | let data6= new LeafData(6,"data6",[]);
13 | let data7= new LeafData(7,"data7",[]);
14 |
15 | data0.children.push(data1);
16 | data0.children.push(data2);
17 | data1.children.push(data3);
18 | data2.children.push(data4);
19 | data4.children.push(data5);
20 | data5.children.push(data6);
21 | data4.children.push(data7);
22 |
23 | expect(data0.getLeaf(0)).toEqual(data0);
24 | expect(data0.getLeaf(1)).toEqual(data1);
25 | expect(data0.getLeaf(2)).toEqual(data2);
26 | expect(data0.getLeaf(3)).toEqual(data3);
27 | expect(data0.getLeaf(4)).toEqual(data4);
28 | expect(data0.getLeaf(5)).toEqual(data5);
29 | expect(data0.getLeaf(6)).toEqual(data6);
30 |
31 | expect(data1.getAllChildren()).toEqual([data3]);
32 | expect(data2.getAllChildren().sort((a,b)=>{return a.id-b.id})).toEqual([data4, data5,data6,data7]);
33 | expect(data0.getAllChildren().sort((a,b)=>{return a.id-b.id})).toEqual([data1,data2,data3,data4,data5,data6,data7]);
34 | expect(/^.{8}$/.test(data0.getNewId())).toEqual(true);
35 | expect(data0.getParent(6)).toEqual(data5)
36 | expect(data0.getSiblings(7)).toEqual([data5,data7])
37 | })
38 |
39 |
40 | it('should get Parents correctly', function(){
41 | let data0= new LeafData(0,"data0",[]);
42 | let data1= new LeafData(1,"data1",[]);
43 | let data2= new LeafData(2,"data2",[]);
44 | let data3= new LeafData(3,"data3",[]);
45 | let data4= new LeafData(4,"data4",[]);
46 |
47 | data0.children.push(data1);
48 | data0.children.push(data2);
49 | data1.children.push(data3);
50 | data2.children.push(data4);
51 |
52 | expect(data0.getParent(1)).toEqual(data0);
53 | expect(data0.getParent(2)).toEqual(data0);
54 | expect(data0.getParent(3)).toEqual(data1);
55 | expect(data0.getParent(4)).toEqual(data2);
56 | })
57 |
58 |
59 | it('should calculate correctly', function(){
60 | let data0= new LeafData(0,"#10",[]);
61 | let data1= new LeafData(1,"abc#10",[]);
62 | let data2= new LeafData(2,"abc#10 def",[]);
63 | let data3= new LeafData(3,"abc#10.5",[]);
64 |
65 | data0.children.push(data1);
66 | data1.children.push(data2);
67 | data2.children.push(data3);
68 |
69 | expect(data0.sumLabelsOfChildren()).toEqual(40.5);
70 | expect(data1.sumLabelsOfChildren()).toEqual(30.5);
71 | expect(data2.sumLabelsOfChildren()).toEqual(20.5);
72 | expect(data3.sumLabelsOfChildren()).toEqual(10.5);
73 |
74 | expect(data0.countLabelsOfChildren()).toEqual(4);
75 | expect(data1.countLabelsOfChildren()).toEqual(3);
76 | expect(data2.countLabelsOfChildren()).toEqual(2);
77 | expect(data3.countLabelsOfChildren()).toEqual(1);
78 |
79 |
80 | expect(data0.getLabelFieldsOfChildren()).toEqual([]);
81 | })
82 |
83 | it('should calculate multiple tags correctly', function(){
84 | let data0= new LeafData(0,"#10 #10",[]);
85 | let data1= new LeafData(1,"abc#10 #10",[]);
86 | let data2= new LeafData(2,"abc#10 def #10",[]);
87 | let data3= new LeafData(3,"abc#10.5 #10",[]);
88 |
89 | data0.children.push(data1);
90 | data1.children.push(data2);
91 | data2.children.push(data3);
92 |
93 |
94 | expect(data0.sumLabelsOfChildren()).toEqual(80.5);
95 | expect(data1.sumLabelsOfChildren()).toEqual(60.5);
96 | expect(data2.sumLabelsOfChildren()).toEqual(40.5);
97 | expect(data3.sumLabelsOfChildren()).toEqual(20.5);
98 |
99 | expect(data0.countLabelsOfChildren()).toEqual(8);
100 | expect(data1.countLabelsOfChildren()).toEqual(6);
101 | expect(data2.countLabelsOfChildren()).toEqual(4);
102 | expect(data3.countLabelsOfChildren()).toEqual(2);
103 |
104 | expect(data0.getLabelFieldsOfChildren()).toEqual([]);
105 | })
106 |
107 | it('should calculate label values correctly', function(){
108 | let data0= new LeafData(0,"#test:10",[]);
109 | let data1= new LeafData(1,"abc#test:10",[]);
110 | let data2= new LeafData(2,"abc#test:10",[]);
111 | let data3= new LeafData(3,"abc#test:10.5",[]);
112 | let data4= new LeafData(4,"#test",[]);
113 |
114 | data0.children.push(data1);
115 | data1.children.push(data2);
116 | data2.children.push(data3);
117 | data3.children.push(data4);
118 | ;
119 | expect(data0.sumLabelsOfChildren("test")).toEqual(40.5);
120 | expect(data1.sumLabelsOfChildren("test")).toEqual(30.5);
121 | expect(data2.sumLabelsOfChildren("test")).toEqual(20.5);
122 | expect(data3.sumLabelsOfChildren("test")).toEqual(10.5);
123 | expect(data4.sumLabelsOfChildren("test")).toEqual(0);
124 |
125 | expect(data0.countLabelsOfChildren("test")).toEqual(4);
126 | expect(data1.countLabelsOfChildren("test")).toEqual(3);
127 | expect(data2.countLabelsOfChildren("test")).toEqual(2);
128 | expect(data3.countLabelsOfChildren("test")).toEqual(1);
129 | expect(data4.countLabelsOfChildren("test")).toEqual(0);
130 |
131 |
132 | expect(data0.getLabelFieldsOfChildren()).toEqual(["test"]);
133 | })
134 |
135 |
136 | it('should returns proper fields', function(){
137 | let data0= new LeafData(0,"#test1:10 #test2:100",[]);
138 | let data1= new LeafData(1,"abc#test1:10 #test2:100",[]);
139 | let data2= new LeafData(2,"abc#test1:10 #test2:100",[]);
140 | let data3= new LeafData(3,"abc#test1:10.5 #test2:100.5",[]);
141 | let data4= new LeafData(4,"#test3",[]);
142 |
143 | data0.children.push(data1);
144 | data1.children.push(data2);
145 | data2.children.push(data3);
146 | data3.children.push(data4);
147 |
148 | expect(data0.sumLabelsOfChildren("test1")).toEqual(40.5);
149 | expect(data1.sumLabelsOfChildren("test1")).toEqual(30.5);
150 | expect(data2.sumLabelsOfChildren("test1")).toEqual(20.5);
151 | expect(data3.sumLabelsOfChildren("test1")).toEqual(10.5);
152 | expect(data4.sumLabelsOfChildren("test1")).toEqual(0);
153 |
154 | expect(data0.sumLabelsOfChildren("test2")).toEqual(400.5);
155 | expect(data1.sumLabelsOfChildren("test2")).toEqual(300.5);
156 | expect(data2.sumLabelsOfChildren("test2")).toEqual(200.5);
157 | expect(data3.sumLabelsOfChildren("test2")).toEqual(100.5);
158 | expect(data4.sumLabelsOfChildren("test2")).toEqual(0);
159 |
160 |
161 | expect(data0.countLabelsOfChildren("test1")).toEqual(4);
162 | expect(data1.countLabelsOfChildren("test1")).toEqual(3);
163 | expect(data2.countLabelsOfChildren("test1")).toEqual(2);
164 | expect(data3.countLabelsOfChildren("test1")).toEqual(1);
165 | expect(data4.countLabelsOfChildren("test1")).toEqual(0);
166 |
167 | expect(data0.countLabelsOfChildren("test2")).toEqual(4);
168 | expect(data1.countLabelsOfChildren("test2")).toEqual(3);
169 | expect(data2.countLabelsOfChildren("test2")).toEqual(2);
170 | expect(data3.countLabelsOfChildren("test2")).toEqual(1);
171 | expect(data4.countLabelsOfChildren("test2")).toEqual(0);
172 |
173 | expect(data0.getLabelFieldsOfChildren()).toEqual(["test1","test2","test3"]);
174 |
175 | expect(data0.getLabelValues("test1")).toEqual(["10"]);
176 | expect(data0.getLabelValues("test2")).toEqual(["100"]);
177 | expect(data3.getLabelValues("test1")).toEqual(["10.5"]);
178 | expect(data3.getLabelValues("test2")).toEqual(["100.5"]);
179 | expect(data4.getLabelValues("test1")).toEqual([]);
180 | expect(data4.getLabelValues("test2")).toEqual([]);
181 | expect(data4.getLabelValues("test3")).toEqual([]);
182 |
183 |
184 | expect(data0.labelExists("test1")).toEqual(true);
185 | expect(data0.labelExists("test2")).toEqual(true);
186 | expect(data0.labelExists("test3")).toEqual(false);
187 | expect(data1.labelExists("test1")).toEqual(true);
188 | expect(data1.labelExists("test2")).toEqual(true);
189 | expect(data1.labelExists("test3")).toEqual(false);
190 | expect(data2.labelExists("test1")).toEqual(true);
191 | expect(data2.labelExists("test2")).toEqual(true);
192 | expect(data2.labelExists("test3")).toEqual(false);
193 | expect(data3.labelExists("test1")).toEqual(true);
194 | expect(data3.labelExists("test2")).toEqual(true);
195 | expect(data3.labelExists("test3")).toEqual(false);
196 | expect(data4.labelExists("test1")).toEqual(false);
197 | expect(data4.labelExists("test2")).toEqual(false);
198 | expect(data4.labelExists("test3")).toEqual(true);
199 |
200 | })
201 |
202 |
203 | it('should calculate multiple tags correctly', function(){
204 | let data0= new LeafData(0,"#10\n#10",[]);
205 | let data1= new LeafData(1,"#abc #10\n#10",[]);
206 | let data2= new LeafData(2,"#abc #10 #def\n#10",[]);
207 | let data3= new LeafData(3,"#abc #10.5\n#10",[]);
208 |
209 | data0.children.push(data1);
210 | data1.children.push(data2);
211 | data2.children.push(data3);
212 |
213 | expect(data0.sumLabelsOfChildren()).toEqual(80.5);
214 | expect(data1.sumLabelsOfChildren()).toEqual(60.5);
215 | expect(data2.sumLabelsOfChildren()).toEqual(40.5);
216 | expect(data3.sumLabelsOfChildren()).toEqual(20.5);
217 |
218 | expect(data0.countLabelsOfChildren()).toEqual(8);
219 | expect(data1.countLabelsOfChildren()).toEqual(6);
220 | expect(data2.countLabelsOfChildren()).toEqual(4);
221 | expect(data3.countLabelsOfChildren()).toEqual(2);
222 |
223 |
224 | expect(data0.getLabelFieldsOfChildren()).toEqual(["abc","def"]);
225 | })
226 |
227 | it('should calculate multiple tags correctly simple version', function(){
228 | let data0= new LeafData(0,"#10\n#10",[]);
229 |
230 |
231 | expect(data0.getLabelValues("")).toEqual(["10","10"]);
232 |
233 | expect(data0.sumLabelsOfChildren()).toEqual(20);
234 | expect(data0.countLabelsOfChildren()).toEqual(2);
235 | })
236 |
237 |
238 | it('should know it has code block', function(){
239 | let data0= new LeafData(0,"```\ntest\n```",[]);
240 | let data1= new LeafData(0,"```\ntest\n",[]);
241 | let data2= new LeafData(0,"test",[]);
242 | let data3= new LeafData(0,"```\ntest\n``",[]);
243 | let data4= new LeafData(0,"```\ntest``\ntest\n```",[]);
244 | let data5= new LeafData(0,"test\n```\ntest``\ntest\n```\ntest",[]);
245 |
246 |
247 | expect(data0.codeExists()).toEqual(true);
248 | expect(data1.codeExists()).toEqual(false);
249 | expect(data2.codeExists()).toEqual(false);
250 | expect(data3.codeExists()).toEqual(false);
251 | expect(data4.codeExists()).toEqual(true);
252 | expect(data5.codeExists()).toEqual(true);
253 | })
254 |
255 |
256 |
257 | });
258 |
--------------------------------------------------------------------------------
/test/PNGStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/test/StateProvider.test.js:
--------------------------------------------------------------------------------
1 | import LeafData from "../src/LeafData";
2 | import Property from "../src/Property";
3 | import StateProvider from "../src/StateProvider";
4 |
5 | describe('A suite', function() {
6 |
7 | it('should add root properly', function(){
8 | let tested = StateProvider.addRoot({root:null, property:new Property()}, 0, 0)
9 | expect(tested.root).toEqual(new LeafData(0,"",[]));
10 | })
11 |
12 | it('should add children properly', function(){
13 | let tested = StateProvider.addRoot({root:null, property:new Property()}, 0, 0)
14 | tested=StateProvider.addChild(tested,0);
15 |
16 | // let expected1=new LeafData(0,"",[]);
17 | // let expected2=new LeafData(1,"",[]);
18 | // expected1.children.push(expected2);
19 | expect(tested.root.id).toEqual(0);
20 | expect(tested.root.description).toEqual("");
21 | expect(/^.{8}$/.test(tested.root.children[0].id) ).toBe(true);
22 | })
23 |
24 | it('cannot add siblings below the root', function(){
25 | let tested = StateProvider.addRoot({root:null, property:new Property()}, 0, 0)
26 | tested=StateProvider.addSibling(tested,0);
27 |
28 | let expected1=new LeafData(0);
29 | expect(tested.root).toEqual(expected1);
30 | })
31 |
32 |
33 |
34 |
35 |
36 | });
37 |
--------------------------------------------------------------------------------
/test/map.test.js:
--------------------------------------------------------------------------------
1 | import { Map } from "../src/index";
2 | import React from 'react';
3 | import { shallow, mount, render } from 'enzyme';
4 | import LeafData from "../src/LeafData";
5 | import Property from "../src/Property";
6 |
7 |
8 | describe('A suite', function() {
9 |
10 | it('should add node properly', function(){
11 | const wrapper=mount( );
12 | expect(wrapper.find('.Leaf').length).toBe(1);
13 | wrapper.find('[id="0-menu-right"]').simulate("click");
14 | expect(wrapper.find('.Leaf').length).toBe(2);
15 | });
16 |
17 | it('should edit value properly', function(){
18 | const wrapper=mount( );
19 | wrapper.find('.Leaf').find('.text').simulate("change", { target: { value: "foo" }});
20 | expect(wrapper.find('.Leaf').at(0).text()).toEqual(expect.stringContaining("foo"));
21 | });
22 |
23 | it('should edit value properly to an existing map', function(){
24 | let data0= new LeafData(0,"first level:\n=sum()",[]);
25 | let data1= new LeafData(1,"second level:\n=count()",[]);
26 | let data2= new LeafData(2,"third level:\n#10.5",[]);
27 | let data3= new LeafData(3,"fourth level:\n#20.5",[]);
28 | let data4= new LeafData(4,"fifth level:\n#30.5",[]);
29 | data0.children.push(data1);
30 | data1.children.push(data2);
31 | data2.children.push(data3);
32 | data3.children.push(data4);
33 | let prop=new Property();
34 |
35 | const wrapper=mount( );
36 | wrapper.find('.Leaf').at(0).find('.text').simulate("change", { target: { value: "foo" }});
37 | expect(wrapper.find('.Leaf').at(0).text()).toEqual(expect.stringContaining("foo"));
38 | expect(wrapper.find('.Leaf').at(1).text()).toEqual(expect.stringContaining("second"));
39 | });
40 |
41 | });
42 |
43 |
44 |
--------------------------------------------------------------------------------
/test/middleware.test.js:
--------------------------------------------------------------------------------
1 | import { Map } from "../src/index";
2 | import React from 'react';
3 | import { shallow, mount, render } from 'enzyme';
4 | import LeafData from "../src/LeafData";
5 | import Property from "../src/Property";
6 |
7 | const middleware = store => next => action => {
8 | next(action);
9 | // console.log("middleware called" + JSON.stringify(action))
10 | setTimeout(()=> console.log("middleware call every 1 sec") , 1000)
11 | };
12 |
13 | describe('A suite', function() {
14 |
15 | jest.useFakeTimers();
16 | it('should execute middleware call', function(){
17 | const wrapper=mount();
18 | wrapper.find('.Leaf').find('.text').simulate("change", { target: { value: "foo" }});
19 | expect(wrapper.find('.Leaf').at(0).text()).toEqual(expect.stringContaining("foo"));
20 | jest.runAllTimers()
21 | });
22 |
23 |
24 | });
25 |
26 |
27 |
--------------------------------------------------------------------------------
/test/previewLabel.test.js:
--------------------------------------------------------------------------------
1 | import PreviewLabels from "../src/PreviewLabels";
2 | import LeafData from "../src/LeafData";
3 | import React from 'react';
4 | import { shallow, mount, render } from 'enzyme';
5 |
6 |
7 | describe('A suite', function() {
8 |
9 | it('should calculate numbers properly', function(){
10 |
11 | const sel = id => `[testkey="${id}"]`;
12 | let data0= new LeafData(0,"first level:\n=sum()",[]);
13 | let data1= new LeafData(1,"second level:\n=count()",[]);
14 | let data2= new LeafData(2,"third level:\n#10.5",[]);
15 | let data3= new LeafData(3,"fourth level:\n#20.5",[]);
16 | let data4= new LeafData(4,"fifth level:\n#30.5",[]);
17 |
18 | data0.children.push(data1);
19 | data1.children.push(data2);
20 | data2.children.push(data3);
21 | data3.children.push(data4);
22 |
23 | const wrapper=mount();
24 | expect(wrapper.exists(sel('hasnodata'))).toEqual(true);
25 | });
26 |
27 |
28 | it('should recognize label exists properly', function(){
29 | let data0= new LeafData(0,"first level",[]);
30 | let data1= new LeafData(1,"second level",[]);
31 | let data2= new LeafData(2,"third level:\n#label1",[]);
32 | let data3= new LeafData(3,"fourth level:\n#label2",[]);
33 | let data4= new LeafData(4,"fifth level:\n#label3",[]);
34 |
35 | data0.children.push(data1);
36 | data1.children.push(data2);
37 | data2.children.push(data3);
38 | data3.children.push(data4);
39 |
40 |
41 | const sel = id => `[testkey="${id}"]`;
42 | const wrapper=mount();
43 | //console.log(wrapper.debug());
44 |
45 | expect(wrapper.exists(sel('hasnodata'))).toEqual(false);
46 | expect(wrapper.find(sel('val-0')).at(0).text()).toEqual(expect.stringContaining("label1"));
47 | //expect(wrapper.exists(sel('val-0-0'))).toEqual(true);
48 | expect(wrapper.find(sel('val-0')).find('.description').text()).toEqual('third level:\nlabel1');
49 |
50 |
51 | expect(wrapper.find(sel('val-1')).at(0).text()).toEqual(expect.stringContaining("label2"));
52 | expect(wrapper.find(sel('val-1')).find('.description').text()).toEqual('fourth level:\nlabel2');
53 |
54 |
55 | expect(wrapper.find(sel('val-2')).at(0).text()).toEqual(expect.stringContaining("label3"));
56 | expect(wrapper.find(sel('val-2')).find('.description').text()).toEqual('fifth level:\nlabel3');
57 |
58 | expect(wrapper.exists(sel('val-3'))).toEqual(false);
59 |
60 | });
61 |
62 | it('should calculate label values properly', function(){
63 | let data0= new LeafData(0,"first level:\n=sum(label)",[]);
64 | let data1= new LeafData(1,"second level:\n=count(label)",[]);
65 | let data2= new LeafData(2,"third level:\n#label:10.5",[]);
66 | let data3= new LeafData(3,"fourth level:\n#label:20.5",[]);
67 | let data4= new LeafData(4,"fifth level:\n#label:30.5",[]);
68 |
69 | data0.children.push(data1);
70 | data1.children.push(data2);
71 | data2.children.push(data3);
72 | data3.children.push(data4);
73 |
74 |
75 | const sel = id => `[testkey="${id}"]`;
76 | const wrapper=mount();
77 | //console.log(wrapper.debug());
78 | expect(wrapper.exists(sel('hasnodata'))).toEqual(false);
79 | expect(wrapper.find(sel('val-0')).at(0).text()).toEqual(expect.stringContaining("label"));
80 |
81 | expect(wrapper.find(sel('val-0')).find('.description').at(0).text()).toEqual('third level:\nlabel:10.5');
82 | expect(wrapper.find(sel('val-0')).find('.description').at(1).text()).toEqual('fourth level:\nlabel:20.5');
83 | expect(wrapper.find(sel('val-0')).find('.description').at(2).text()).toEqual('fifth level:\nlabel:30.5');
84 |
85 | expect(wrapper.exists(sel('val-1'))).toEqual(false);
86 |
87 | });
88 |
89 | });
90 |
91 |
92 |
--------------------------------------------------------------------------------
/test/previewList.test.js:
--------------------------------------------------------------------------------
1 | import PreviewList from "../src/PreviewList";
2 | import LeafData from "../src/LeafData";
3 | import React from 'react';
4 | import { shallow, mount, render } from 'enzyme';
5 |
6 |
7 | describe('A suite', function() {
8 |
9 | it('should display items properly', function(){
10 | let data0= new LeafData(0,"data0",[]);
11 | let data1= new LeafData(1,"data1",[]);
12 | let data2= new LeafData(2,"data2",[]);
13 | let data3= new LeafData(3,"data3",[]);
14 | let data4= new LeafData(4,"data4",[]);
15 | let data5= new LeafData(5,"data5",[]);
16 | let data6= new LeafData(6,"data6",[]);
17 | let data7= new LeafData(7,"data7",[]);
18 |
19 | data0.children.push(data1);
20 | data1.children.push(data3);
21 | data0.children.push(data2);
22 | data2.children.push(data4);
23 | data4.children.push(data7);
24 | data4.children.push(data5);
25 | data5.children.push(data6);
26 |
27 | const wrapper=mount();
28 | //console.log(wrapper.debug());
29 | expect(wrapper.find('.description').at(0).text()).toBe("data0");
30 | expect(wrapper.find('.description').at(1).text()).toBe("data1");
31 | expect(wrapper.find('.description').at(2).text()).toBe("data3");
32 | expect(wrapper.find('.description').at(3).text()).toBe("data2");
33 | expect(wrapper.find('.description').at(4).text()).toBe("data4");
34 | expect(wrapper.find('.description').at(5).text()).toBe("data7");
35 | expect(wrapper.find('.description').at(6).text()).toBe("data5");
36 | expect(wrapper.find('.description').at(7).text()).toBe("data6");
37 | });
38 |
39 |
40 | it('should calculate numbers properly', function(){
41 |
42 | const sel = id => `[testkey="${id}"]`;
43 | let data0= new LeafData(0,"first level:\n=sum()",[]);
44 | let data1= new LeafData(1,"second level:\n=count()",[]);
45 | let data2= new LeafData(2,"third level:\n#10.5",[]);
46 | let data3= new LeafData(3,"fourth level:\n#20.5",[]);
47 | let data4= new LeafData(4,"fifth level:\n#30.5",[]);
48 |
49 | data0.children.push(data1);
50 | data1.children.push(data2);
51 | data2.children.push(data3);
52 | data3.children.push(data4);
53 |
54 | const wrapper=mount();
55 | //console.log(wrapper.debug());
56 | expect(wrapper.find(sel('val-0-0')).at(0).text()).toEqual(expect.stringContaining("first level"));
57 | expect(wrapper.find(sel('val-0-1')).at(0).text()).toEqual('');
58 |
59 | expect(wrapper.find(sel('val-1-0')).at(0).text()).toEqual(expect.stringContaining("second level"));
60 | expect(wrapper.find(sel('val-1-1')).at(0).text()).toEqual('');
61 |
62 |
63 | expect(wrapper.find(sel('val-2-0')).at(0).text()).toEqual(expect.stringContaining("third level"));
64 | expect(wrapper.find(sel('val-2-1')).at(0).text()).toEqual('');
65 |
66 |
67 | expect(wrapper.find(sel('val-3-0')).at(0).text()).toEqual(expect.stringContaining("fourth level"));
68 | expect(wrapper.find(sel('val-3-1')).at(0).text()).toEqual('');
69 |
70 |
71 | expect(wrapper.find(sel('val-4-0')).at(0).text()).toEqual(expect.stringContaining("fifth level"));
72 | expect(wrapper.find(sel('val-4-1')).at(0).text()).toEqual('');
73 |
74 | });
75 |
76 |
77 | it('should recognize label exists properly', function(){
78 | let data0= new LeafData(0,"first level",[]);
79 | let data1= new LeafData(1,"second level",[]);
80 | let data2= new LeafData(2,"third level:\n#label1",[]);
81 | let data3= new LeafData(3,"fourth level:\n#label2",[]);
82 | let data4= new LeafData(4,"fifth level:\n#label3",[]);
83 |
84 | data0.children.push(data1);
85 | data1.children.push(data2);
86 | data2.children.push(data3);
87 | data3.children.push(data4);
88 |
89 |
90 | const sel = id => `[testkey="${id}"]`;
91 | const wrapper=mount();
92 | //console.log(wrapper.debug());
93 | expect(wrapper.find(sel('val-0-0')).at(0).text()).toEqual(expect.stringContaining("first level"));
94 | expect(wrapper.find(sel('val-0-1')).at(0).text()).toEqual('');
95 | expect(wrapper.find(sel('val-0-2')).at(0).text()).toEqual('');
96 | expect(wrapper.find(sel('val-0-3')).at(0).text()).toEqual('');
97 | expect(wrapper.find(sel('val-0-4')).at(0).text()).toEqual('');
98 |
99 | expect(wrapper.find(sel('val-1-0')).at(0).text()).toEqual(expect.stringContaining("second level"));
100 | expect(wrapper.find(sel('val-1-1')).at(0).text()).toEqual('');
101 | expect(wrapper.find(sel('val-1-2')).at(0).text()).toEqual('');
102 | expect(wrapper.find(sel('val-1-3')).at(0).text()).toEqual('');
103 | expect(wrapper.find(sel('val-1-4')).at(0).text()).toEqual('');
104 |
105 |
106 | expect(wrapper.find(sel('val-2-0')).at(0).text()).toEqual(expect.stringContaining("third level"));
107 | expect(wrapper.find(sel('val-2-1')).at(0).text()).toEqual('');
108 | expect(wrapper.find(sel('val-2-2')).at(0).text()).toEqual('\u2705');
109 | expect(wrapper.find(sel('val-2-3')).at(0).text()).toEqual('');
110 | expect(wrapper.find(sel('val-2-4')).at(0).text()).toEqual('');
111 |
112 |
113 |
114 | expect(wrapper.find(sel('val-3-0')).at(0).text()).toEqual(expect.stringContaining("fourth level"));
115 | expect(wrapper.find(sel('val-3-1')).at(0).text()).toEqual('');
116 | expect(wrapper.find(sel('val-3-2')).at(0).text()).toEqual('');
117 | expect(wrapper.find(sel('val-3-3')).at(0).text()).toEqual('\u2705');
118 | expect(wrapper.find(sel('val-3-4')).at(0).text()).toEqual('');
119 |
120 |
121 | expect(wrapper.find(sel('val-4-0')).at(0).text()).toEqual(expect.stringContaining("fifth level"));
122 | expect(wrapper.find(sel('val-4-1')).at(0).text()).toEqual('');
123 | expect(wrapper.find(sel('val-4-2')).at(0).text()).toEqual('');
124 | expect(wrapper.find(sel('val-4-3')).at(0).text()).toEqual('');
125 | expect(wrapper.find(sel('val-4-4')).at(0).text()).toEqual('\u2705');
126 | });
127 |
128 | it('should calculate label values properly', function(){
129 | let data0= new LeafData(0,"first level:\n=sum(label)",[]);
130 | let data1= new LeafData(1,"second level:\n=count(label)",[]);
131 | let data2= new LeafData(2,"third level:\n#label:10.5",[]);
132 | let data3= new LeafData(3,"fourth level:\n#label:20.5",[]);
133 | let data4= new LeafData(4,"fifth level:\n#label:30.5",[]);
134 |
135 | data0.children.push(data1);
136 | data1.children.push(data2);
137 | data2.children.push(data3);
138 | data3.children.push(data4);
139 |
140 |
141 | const sel = id => `[testkey="${id}"]`;
142 | const wrapper=mount();
143 | //console.log(wrapper.debug());
144 | expect(wrapper.find(sel('val-0-0')).at(0).text()).toEqual(expect.stringContaining("first level"));
145 | expect(wrapper.find(sel('val-0-1')).at(0).text()).toEqual('');
146 | expect(wrapper.find(sel('val-0-2')).at(0).text()).toEqual('');
147 |
148 | expect(wrapper.find(sel('val-1-0')).at(0).text()).toEqual(expect.stringContaining("second level"));
149 | expect(wrapper.find(sel('val-1-1')).at(0).text()).toEqual('');
150 | expect(wrapper.find(sel('val-1-2')).at(0).text()).toEqual('');
151 |
152 |
153 | expect(wrapper.find(sel('val-2-0')).at(0).text()).toEqual(expect.stringContaining("third level"));
154 | expect(wrapper.find(sel('val-2-1')).at(0).text()).toEqual('');
155 | expect(wrapper.find(sel('val-2-2')).at(0).text()).toEqual('10.5');
156 |
157 |
158 |
159 | expect(wrapper.find(sel('val-3-0')).at(0).text()).toEqual(expect.stringContaining("fourth level"));
160 | expect(wrapper.find(sel('val-3-1')).at(0).text()).toEqual('');
161 | expect(wrapper.find(sel('val-3-2')).at(0).text()).toEqual('20.5');
162 |
163 |
164 | expect(wrapper.find(sel('val-4-0')).at(0).text()).toEqual(expect.stringContaining("fifth level"));
165 | expect(wrapper.find(sel('val-4-1')).at(0).text()).toEqual('');
166 | expect(wrapper.find(sel('val-4-2')).at(0).text()).toEqual('30.5');
167 | });
168 |
169 | });
170 |
171 |
172 |
--------------------------------------------------------------------------------
/test/previewSentence.test.js:
--------------------------------------------------------------------------------
1 | import PreviewSentence from "../src/PreviewSentence";
2 | import LeafData from "../src/LeafData";
3 | import React from 'react';
4 | import { shallow, mount, render } from 'enzyme';
5 |
6 |
7 | describe('A suite', function() {
8 |
9 | it('should display header properly', function(){
10 | let data0= new LeafData(0,"data0",[]);
11 | let data1= new LeafData(1,"h1.data1",[]);
12 | let data2= new LeafData(2,"data2",[]);
13 | let data3= new LeafData(3,"data3h1.",[]);
14 | let data4= new LeafData(4,"h3.data4",[]);
15 | let data5= new LeafData(5,"data5",[]);
16 | let data6= new LeafData(6,"data6",[]);
17 | let data7= new LeafData(7,"data7",[]);
18 |
19 | data0.children.push(data1);
20 | data1.children.push(data3);
21 | data0.children.push(data2);
22 | data2.children.push(data4);
23 | data4.children.push(data7);
24 | data4.children.push(data5);
25 | data5.children.push(data6);
26 |
27 | const wrapper=mount();
28 | //console.log(wrapper.debug());
29 | expect(wrapper.find('h1').at(0).text()).toBe("data0");
30 | expect(wrapper.find('h2').at(0).text()).toBe("data1");
31 | expect(wrapper.find('h2').at(1).text()).toBe("data2");
32 | expect(wrapper.find('h3').at(0).text()).toBe("data4");
33 | expect(wrapper.find('h4').at(0).text()).toBe("data5");
34 | });
35 |
36 |
37 | it('should calculate numbers properly', function(){
38 | let data0= new LeafData(0,"first level:\n=sum()",[]);
39 | let data1= new LeafData(1,"second level:\n=count()",[]);
40 | let data2= new LeafData(2,"third level:\n=mean()",[]);
41 | let data3= new LeafData(3,"fourth level:\n#10.5",[]);
42 | let data4= new LeafData(4,"fifth level:\n#20.5",[]);
43 | let data5= new LeafData(5,"sixth level:\n#30.5",[]);
44 |
45 | data0.children.push(data1);
46 | data1.children.push(data2);
47 | data2.children.push(data3);
48 | data3.children.push(data4);
49 | data4.children.push(data5);
50 |
51 | const wrapper=mount();
52 | //console.log(wrapper.debug());
53 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(0).text()).toEqual(expect.stringContaining("61.5"));
54 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(1).text()).toEqual(expect.stringContaining("3"));
55 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(2).text()).toEqual(expect.stringContaining("20.5"));
56 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(3).text()).toEqual(expect.stringContaining("10.5"));
57 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(4).text()).toEqual(expect.stringContaining("20.5"));
58 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(5).text()).toEqual(expect.stringContaining("30.5"));
59 | });
60 |
61 |
62 |
63 | it('should calculate labels properly', function(){
64 | let data0= new LeafData(0,"first level:\n=sum(label)",[]);
65 | let data1= new LeafData(1,"second level:\n=count(label)",[]);
66 | let data2= new LeafData(2,"third level:\n=mean(label)",[]);
67 | let data3= new LeafData(3,"fourth level:\n#label:10.5",[]);
68 | let data4= new LeafData(4,"fifth level:\n#label:20.5",[]);
69 | let data5= new LeafData(5,"sixth level:\n#label:30.5",[]);
70 |
71 | data0.children.push(data1);
72 | data1.children.push(data2);
73 | data2.children.push(data3);
74 | data3.children.push(data4);
75 | data4.children.push(data5);
76 |
77 | const wrapper=mount();
78 | //console.log(wrapper.debug());
79 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(0).text()).toEqual(expect.stringContaining("61.5"));
80 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(1).text()).toEqual(expect.stringContaining("3"));
81 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(2).text()).toEqual(expect.stringContaining("20.5"));
82 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(3).text()).toEqual(expect.stringContaining("10.5"));
83 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(4).text()).toEqual(expect.stringContaining("20.5"));
84 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(5).text()).toEqual(expect.stringContaining("30.5"));
85 | });
86 |
87 |
88 | it('should calculate numbers on first level properly', function(){
89 | let data0= new LeafData(0,"=sum()",[]);
90 | let data1= new LeafData(1,"=count()",[]);
91 | let data2= new LeafData(2,"=mean()",[]);
92 | let data3= new LeafData(3,"#10.5",[]);
93 | let data4= new LeafData(4,"#20.5",[]);
94 | let data5= new LeafData(5,"#30.5",[]);
95 |
96 | data0.children.push(data1);
97 | data1.children.push(data2);
98 | data2.children.push(data3);
99 | data3.children.push(data4);
100 | data4.children.push(data5);
101 |
102 | const wrapper=mount();
103 | //console.log(wrapper.debug());
104 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(0).text()).toEqual(expect.stringContaining("61.5"));
105 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(1).text()).toEqual(expect.stringContaining("3"));
106 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(2).text()).toEqual(expect.stringContaining("20.5"));
107 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(3).text()).toEqual(expect.stringContaining("10.5"));
108 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(4).text()).toEqual(expect.stringContaining("20.5"));
109 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(5).text()).toEqual(expect.stringContaining("30.5"));
110 | });
111 |
112 |
113 | it('should calculate numbers on first level properly', function(){
114 | let data0= new LeafData(0,"=sum(label)",[]);
115 | let data1= new LeafData(1,"=count(label)",[]);
116 | let data2= new LeafData(2,"=mean(label)",[]);
117 | let data3= new LeafData(3,"#label:10.5",[]);
118 | let data4= new LeafData(4,"#label:20.5",[]);
119 | let data5= new LeafData(5,"#label:30.5",[]);
120 |
121 | data0.children.push(data1);
122 | data1.children.push(data2);
123 | data2.children.push(data3);
124 | data3.children.push(data4);
125 | data4.children.push(data5);
126 |
127 | const wrapper=mount();
128 | //console.log(wrapper.debug());
129 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(0).text()).toEqual(expect.stringContaining("61.5"));
130 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(1).text()).toEqual(expect.stringContaining("3"));
131 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(2).text()).toEqual(expect.stringContaining("20.5"));
132 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(3).text()).toEqual(expect.stringContaining("10.5"));
133 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(4).text()).toEqual(expect.stringContaining("20.5"));
134 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(5).text()).toEqual(expect.stringContaining("30.5"));
135 | });
136 |
137 |
138 | it('should calculate numbers on first level properly', function(){
139 | let data0= new LeafData(0,"test=sum()",[]);
140 | let data1= new LeafData(1,"test=count()",[]);
141 | let data2= new LeafData(2,"test=mean()",[]);
142 | let data3= new LeafData(3,"test#10.5",[]);
143 | let data4= new LeafData(4,"test#20.5",[]);
144 | let data5= new LeafData(5,"test#30.5",[]);
145 |
146 | data0.children.push(data1);
147 | data1.children.push(data2);
148 | data2.children.push(data3);
149 | data3.children.push(data4);
150 | data4.children.push(data5);
151 |
152 | const wrapper=mount();
153 | //console.log(wrapper.debug());
154 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(0).text()).toEqual(expect.stringContaining("61.5"));
155 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(1).text()).toEqual(expect.stringContaining("3"));
156 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(2).text()).toEqual(expect.stringContaining("20.5"));
157 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(3).text()).toEqual(expect.stringContaining("10.5"));
158 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(4).text()).toEqual(expect.stringContaining("20.5"));
159 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(5).text()).toEqual(expect.stringContaining("30.5"));
160 | });
161 |
162 |
163 | it('should calculate numbers on first level properly', function(){
164 | let data0= new LeafData(0,"test=sum(label)",[]);
165 | let data1= new LeafData(1,"test=count(label)",[]);
166 | let data2= new LeafData(2,"test=mean(label)",[]);
167 | let data3= new LeafData(3,"test#label:10.5",[]);
168 | let data4= new LeafData(4,"test#label:20.5",[]);
169 | let data5= new LeafData(5,"test#label:30.5",[]);
170 |
171 | data0.children.push(data1);
172 | data1.children.push(data2);
173 | data2.children.push(data3);
174 | data3.children.push(data4);
175 | data4.children.push(data5);
176 |
177 | const wrapper=mount();
178 | //console.log(wrapper.debug());
179 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(0).text()).toEqual(expect.stringContaining("61.5"));
180 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(1).text()).toEqual(expect.stringContaining("3"));
181 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(2).text()).toEqual(expect.stringContaining("20.5"));
182 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(3).text()).toEqual(expect.stringContaining("10.5"));
183 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(4).text()).toEqual(expect.stringContaining("20.5"));
184 | expect(wrapper.find('.PreviewSentence-Paragraph .description').at(5).text()).toEqual(expect.stringContaining("30.5"));
185 | });
186 |
187 | });
188 |
189 |
190 |
--------------------------------------------------------------------------------
/test/previewTree.test.js:
--------------------------------------------------------------------------------
1 | import Tree from "../src/Tree";
2 | import LeafData from "../src/LeafData";
3 | import React from 'react';
4 | import { shallow, mount, render } from 'enzyme';
5 | import Property from "../src/Property";
6 |
7 |
8 | describe('A suite', function() {
9 |
10 | it('should calculate numbers properly', function(){
11 | let data0= new LeafData(0,"first level:\n=sum()",[]);
12 | let data1= new LeafData(1,"second level:\n=count()",[]);
13 | let data2= new LeafData(2,"third level:\n#10.5",[]);
14 | let data3= new LeafData(3,"fourth level:\n#20.5",[]);
15 | let data4= new LeafData(4,"fifth level:\n#30.5",[]);
16 |
17 | data0.children.push(data1);
18 | data1.children.push(data2);
19 | data2.children.push(data3);
20 | data3.children.push(data4);
21 |
22 | let prop=new Property();
23 | const wrapper=mount();
24 |
25 | expect(wrapper.find('.description').at(0).text()).toEqual(expect.stringContaining("61.5"));
26 | expect(wrapper.find('.description').at(1).text()).toEqual(expect.stringContaining("3"));
27 | expect(wrapper.find('.description').at(2).text()).toEqual(expect.stringContaining("10.5"));
28 | expect(wrapper.find('.description').at(3).text()).toEqual(expect.stringContaining("20.5"));
29 | expect(wrapper.find('.description').at(4).text()).toEqual(expect.stringContaining("30.5"));
30 |
31 | let fs = require("fs");
32 | const dir='./test/__html__'
33 | if (!fs.existsSync(dir)){
34 | fs.mkdirSync(dir);
35 | fs.writeFileSync("./test/__html__/previewTree.test.multiple.labels.html", wrapper.html());
36 | }
37 | });
38 |
39 | });
40 |
41 |
42 |
--------------------------------------------------------------------------------
/test/setupTests.js:
--------------------------------------------------------------------------------
1 | import Enzyme from 'enzyme'
2 | import EnzymeAdapter from 'enzyme-adapter-react-16'
3 | Enzyme.configure({
4 | adapter: new EnzymeAdapter(),
5 | disableLifecycleMethods: true
6 | })
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 |
2 | var path = require('path');
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | path: path.resolve(__dirname, 'build'),
7 | filename: 'bundle.js',
8 | libraryTarget: 'commonjs2'
9 | },
10 | module: {
11 | rules: [
12 | {
13 | test: /\.js$/,
14 | include: path.resolve(__dirname, 'src'),
15 | use: {
16 | loader: 'babel-loader',
17 | options: {
18 | presets: ['@babel/preset-env'],
19 | }
20 | }
21 | },
22 | {
23 | test: /\.css/,
24 | include: path.resolve(__dirname, 'src'),
25 | use: [
26 | 'style-loader',
27 | {
28 | loader: 'css-loader',
29 | options: {
30 | url: false
31 | },
32 | }
33 | ]
34 | },
35 | {
36 | test: /\.(png|jpe?g|gif)$/i,
37 | include: path.resolve(__dirname, 'src'),
38 | use: {
39 | loader: 'url-loader',
40 | options: {
41 | limit: 10000,
42 | },
43 | },
44 | },
45 | ]
46 | },
47 | externals: {
48 | 'react': 'commonjs react'
49 | }
50 | };
--------------------------------------------------------------------------------