mirror of
https://github.com/lxsang/antos-frontend.git
synced 2024-12-27 17:58:22 +01:00
GraphEditor move to antosdk-apps repository
This commit is contained in:
parent
eb4e52a31a
commit
4552840440
@ -1,10 +0,0 @@
|
|||||||
coffee_files = main.coffee
|
|
||||||
|
|
||||||
jsfiles = libs/svg-pan-zoom.js libs/mermaidAPI.js
|
|
||||||
|
|
||||||
cssfiles = main.css
|
|
||||||
copyfiles = scheme.html package.json
|
|
||||||
|
|
||||||
|
|
||||||
PKG_NAME=GraphEditor
|
|
||||||
include ../pkg.mk
|
|
@ -1,273 +0,0 @@
|
|||||||
/* Flowchart variables */
|
|
||||||
/* Sequence Diagram variables */
|
|
||||||
/* Gantt chart variables */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .mermaid .label {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node rect,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node circle,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node ellipse,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node polygon {
|
|
||||||
fill: #ECECFF;
|
|
||||||
stroke: #CCCCFF;
|
|
||||||
stroke-width: 1px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .edgePath .path {
|
|
||||||
stroke: #333333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .edgeLabel {
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .cluster rect {
|
|
||||||
fill: #ffffde !important;
|
|
||||||
rx: 4 !important;
|
|
||||||
stroke: #aaaa33 !important;
|
|
||||||
stroke-width: 1px !important;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .cluster text {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .actor {
|
|
||||||
stroke: #CCCCFF;
|
|
||||||
fill: #ECECFF;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] text.actor {
|
|
||||||
fill: black;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .actor-line {
|
|
||||||
stroke: grey;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .messageLine0 {
|
|
||||||
stroke-width: 1.5;
|
|
||||||
stroke-dasharray: "2 2";
|
|
||||||
marker-end: "url(#arrowhead)";
|
|
||||||
stroke: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .messageLine1 {
|
|
||||||
stroke-width: 1.5;
|
|
||||||
stroke-dasharray: "2 2";
|
|
||||||
stroke: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #arrowhead {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #crosshead path {
|
|
||||||
fill: #333 !important;
|
|
||||||
stroke: #333 !important;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .messageText {
|
|
||||||
fill: #333;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .labelBox {
|
|
||||||
stroke: #CCCCFF;
|
|
||||||
fill: #ECECFF;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .labelText {
|
|
||||||
fill: black;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .loopText {
|
|
||||||
fill: black;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .loopLine {
|
|
||||||
stroke-width: 2;
|
|
||||||
stroke-dasharray: "2 2";
|
|
||||||
marker-end: "url(#arrowhead)";
|
|
||||||
stroke: #CCCCFF;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .note {
|
|
||||||
stroke: #aaaa33;
|
|
||||||
fill: #fff5ad;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .noteText {
|
|
||||||
fill: black;
|
|
||||||
stroke: none;
|
|
||||||
font-family: 'trebuchet ms', verdana, arial;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
/** Section styling */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section {
|
|
||||||
stroke: none;
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section0 {
|
|
||||||
fill: rgba(102, 102, 255, 0.49);
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section2 {
|
|
||||||
fill: #fff400;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section3 {
|
|
||||||
fill: white;
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle0 {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle1 {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle2 {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle3 {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle {
|
|
||||||
text-anchor: start;
|
|
||||||
font-size: 11px;
|
|
||||||
text-height: 14px;
|
|
||||||
}
|
|
||||||
/* Grid and axis */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .grid .tick {
|
|
||||||
stroke: lightgrey;
|
|
||||||
opacity: 0.3;
|
|
||||||
shape-rendering: crispEdges;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .grid path {
|
|
||||||
stroke-width: 0;
|
|
||||||
}
|
|
||||||
/* Today line */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .today {
|
|
||||||
fill: none;
|
|
||||||
stroke: red;
|
|
||||||
stroke-width: 2px;
|
|
||||||
}
|
|
||||||
/* Task styling */
|
|
||||||
/* Default task */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task {
|
|
||||||
stroke-width: 2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText {
|
|
||||||
text-anchor: middle;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutsideRight {
|
|
||||||
fill: black;
|
|
||||||
text-anchor: start;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutsideLeft {
|
|
||||||
fill: black;
|
|
||||||
text-anchor: end;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
/* Specific task settings for the sections*/
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText3 {
|
|
||||||
fill: white;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task3 {
|
|
||||||
fill: #8a90dd;
|
|
||||||
stroke: #534fbc;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutside0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutside2 {
|
|
||||||
fill: black;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutside1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutside3 {
|
|
||||||
fill: black;
|
|
||||||
}
|
|
||||||
/* Active task */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .active0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .active1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .active2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .active3 {
|
|
||||||
fill: #bfc7ff;
|
|
||||||
stroke: #534fbc;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeText3 {
|
|
||||||
fill: black !important;
|
|
||||||
}
|
|
||||||
/* Completed task */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .done0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .done1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .done2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .done3 {
|
|
||||||
stroke: grey;
|
|
||||||
fill: lightgrey;
|
|
||||||
stroke-width: 2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneText3 {
|
|
||||||
fill: black !important;
|
|
||||||
}
|
|
||||||
/* Tasks on the critical line */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .crit0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .crit1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .crit2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .crit3 {
|
|
||||||
stroke: #ff8888;
|
|
||||||
fill: red;
|
|
||||||
stroke-width: 2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCrit0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCrit1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCrit2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCrit3 {
|
|
||||||
stroke: #ff8888;
|
|
||||||
fill: #bfc7ff;
|
|
||||||
stroke-width: 2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCrit0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCrit1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCrit2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCrit3 {
|
|
||||||
stroke: #ff8888;
|
|
||||||
fill: lightgrey;
|
|
||||||
stroke-width: 2;
|
|
||||||
cursor: pointer;
|
|
||||||
shape-rendering: crispEdges;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCritText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCritText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCritText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCritText3 {
|
|
||||||
fill: black !important;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCritText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCritText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCritText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCritText3 {
|
|
||||||
fill: black !important;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .titleText {
|
|
||||||
text-anchor: middle;
|
|
||||||
font-size: 18px;
|
|
||||||
fill: black;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node text {
|
|
||||||
font-family: 'trebuchet ms', verdana, arial;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] div.mermaidTooltip {
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
max-width: 200px;
|
|
||||||
padding: 2px;
|
|
||||||
font-family: 'trebuchet ms', verdana, arial;
|
|
||||||
font-size: 12px;
|
|
||||||
background: #ffffde;
|
|
||||||
border: 1px solid #aaaa33;
|
|
||||||
border-radius: 2px;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
@ -1,353 +0,0 @@
|
|||||||
/* Flowchart variables */
|
|
||||||
/* Sequence Diagram variables */
|
|
||||||
/* Gantt chart variables */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .mermaid .label {
|
|
||||||
font-family: 'trebuchet ms', verdana, arial;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node rect,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node circle,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node ellipse,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node polygon {
|
|
||||||
fill: #cde498;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .edgePath .path {
|
|
||||||
stroke: green;
|
|
||||||
stroke-width: 1.5px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .edgeLabel {
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .cluster rect {
|
|
||||||
fill: #cdffb2 !important;
|
|
||||||
rx: 4 !important;
|
|
||||||
stroke: #6eaa49 !important;
|
|
||||||
stroke-width: 1px !important;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .cluster text {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .actor {
|
|
||||||
stroke: #13540c;
|
|
||||||
fill: #cde498;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] text.actor {
|
|
||||||
fill: black;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .actor-line {
|
|
||||||
stroke: grey;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .messageLine0 {
|
|
||||||
stroke-width: 1.5;
|
|
||||||
stroke-dasharray: "2 2";
|
|
||||||
marker-end: "url(#arrowhead)";
|
|
||||||
stroke: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .messageLine1 {
|
|
||||||
stroke-width: 1.5;
|
|
||||||
stroke-dasharray: "2 2";
|
|
||||||
stroke: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #arrowhead {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #crosshead path {
|
|
||||||
fill: #333 !important;
|
|
||||||
stroke: #333 !important;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .messageText {
|
|
||||||
fill: #333;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .labelBox {
|
|
||||||
stroke: #326932;
|
|
||||||
fill: #cde498;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .labelText {
|
|
||||||
fill: black;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .loopText {
|
|
||||||
fill: black;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .loopLine {
|
|
||||||
stroke-width: 2;
|
|
||||||
stroke-dasharray: "2 2";
|
|
||||||
marker-end: "url(#arrowhead)";
|
|
||||||
stroke: #326932;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .note {
|
|
||||||
stroke: #6eaa49;
|
|
||||||
fill: #fff5ad;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .noteText {
|
|
||||||
fill: black;
|
|
||||||
stroke: none;
|
|
||||||
font-family: 'trebuchet ms', verdana, arial;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
/** Section styling */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section {
|
|
||||||
stroke: none;
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section0 {
|
|
||||||
fill: #6eaa49;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section2 {
|
|
||||||
fill: #6eaa49;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .section3 {
|
|
||||||
fill: white;
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle0 {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle1 {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle2 {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle3 {
|
|
||||||
fill: #333;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .sectionTitle {
|
|
||||||
text-anchor: start;
|
|
||||||
font-size: 11px;
|
|
||||||
text-height: 14px;
|
|
||||||
}
|
|
||||||
/* Grid and axis */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .grid .tick {
|
|
||||||
stroke: lightgrey;
|
|
||||||
opacity: 0.3;
|
|
||||||
shape-rendering: crispEdges;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .grid path {
|
|
||||||
stroke-width: 0;
|
|
||||||
}
|
|
||||||
/* Today line */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .today {
|
|
||||||
fill: none;
|
|
||||||
stroke: red;
|
|
||||||
stroke-width: 2px;
|
|
||||||
}
|
|
||||||
/* Task styling */
|
|
||||||
/* Default task */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task {
|
|
||||||
stroke-width: 2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText {
|
|
||||||
text-anchor: middle;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutsideRight {
|
|
||||||
fill: black;
|
|
||||||
text-anchor: start;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutsideLeft {
|
|
||||||
fill: black;
|
|
||||||
text-anchor: end;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
/* Specific task settings for the sections*/
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskText3 {
|
|
||||||
fill: white;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .task3 {
|
|
||||||
fill: #487e3a;
|
|
||||||
stroke: #13540c;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutside0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutside2 {
|
|
||||||
fill: black;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutside1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .taskTextOutside3 {
|
|
||||||
fill: black;
|
|
||||||
}
|
|
||||||
/* Active task */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .active0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .active1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .active2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .active3 {
|
|
||||||
fill: #cde498;
|
|
||||||
stroke: #13540c;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeText3 {
|
|
||||||
fill: black !important;
|
|
||||||
}
|
|
||||||
/* Completed task */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .done0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .done1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .done2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .done3 {
|
|
||||||
stroke: grey;
|
|
||||||
fill: lightgrey;
|
|
||||||
stroke-width: 2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneText3 {
|
|
||||||
fill: black !important;
|
|
||||||
}
|
|
||||||
/* Tasks on the critical line */
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .crit0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .crit1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .crit2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .crit3 {
|
|
||||||
stroke: #ff8888;
|
|
||||||
fill: red;
|
|
||||||
stroke-width: 2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCrit0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCrit1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCrit2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCrit3 {
|
|
||||||
stroke: #ff8888;
|
|
||||||
fill: #cde498;
|
|
||||||
stroke-width: 2;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCrit0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCrit1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCrit2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCrit3 {
|
|
||||||
stroke: #ff8888;
|
|
||||||
fill: lightgrey;
|
|
||||||
stroke-width: 2;
|
|
||||||
cursor: pointer;
|
|
||||||
shape-rendering: crispEdges;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCritText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCritText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCritText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .doneCritText3 {
|
|
||||||
fill: black !important;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCritText0,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCritText1,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCritText2,
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .activeCritText3 {
|
|
||||||
fill: black !important;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .titleText {
|
|
||||||
text-anchor: middle;
|
|
||||||
font-size: 18px;
|
|
||||||
fill: black;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
afx-app-window[data-id="graph_editor_win"] g.classGroup text {
|
|
||||||
fill: #13540c;
|
|
||||||
stroke: none;
|
|
||||||
font-family: 'trebuchet ms', verdana, arial;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] g.classGroup rect {
|
|
||||||
fill: #cde498;
|
|
||||||
stroke: #13540c;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] g.classGroup line {
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] svg .classLabel .box {
|
|
||||||
stroke: none;
|
|
||||||
stroke-width: 0;
|
|
||||||
fill: #cde498;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] svg .classLabel .label {
|
|
||||||
fill: #13540c;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .relation {
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
fill: none;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .composition {
|
|
||||||
fill: #13540c;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #compositionStart {
|
|
||||||
fill: #13540c;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #compositionEnd {
|
|
||||||
fill: #13540c;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .aggregation {
|
|
||||||
fill: #cde498;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #aggregationStart {
|
|
||||||
fill: #cde498;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #aggregationEnd {
|
|
||||||
fill: #cde498;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #dependencyStart {
|
|
||||||
fill: #13540c;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #dependencyEnd {
|
|
||||||
fill: #13540c;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #extensionStart {
|
|
||||||
fill: #13540c;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] #extensionEnd {
|
|
||||||
fill: #13540c;
|
|
||||||
stroke: #13540c;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] .node text {
|
|
||||||
font-family: 'trebuchet ms', verdana, arial;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] div.mermaidTooltip {
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
max-width: 200px;
|
|
||||||
padding: 2px;
|
|
||||||
font-family: 'trebuchet ms', verdana, arial;
|
|
||||||
font-size: 12px;
|
|
||||||
background: #cdffb2;
|
|
||||||
border: 1px solid #6eaa49;
|
|
||||||
border-radius: 2px;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,252 +0,0 @@
|
|||||||
# Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
|
||||||
|
|
||||||
# AnTOS Web desktop is is licensed under the GNU General Public
|
|
||||||
# License v3.0, see the LICENCE file for more information
|
|
||||||
|
|
||||||
# This program is free software: you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of
|
|
||||||
# the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
# General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
#along with this program. If not, see https://www.gnu.org/licenses/.
|
|
||||||
class GraphEditor extends this.OS.GUI.BaseApplication
|
|
||||||
constructor: ( args ) ->
|
|
||||||
super "GraphEditor", args
|
|
||||||
|
|
||||||
main: () ->
|
|
||||||
me = @
|
|
||||||
#mermaid.initialize { startOnLoad: false }
|
|
||||||
mermaid.initialize {
|
|
||||||
theme: 'forest'
|
|
||||||
}
|
|
||||||
@currfile = if @args and @args.length > 0 then @args[0].asFileHandler() else "Untitled".asFileHandler()
|
|
||||||
@currfile.dirty = false
|
|
||||||
@datarea = @find "datarea"
|
|
||||||
@preview = @find "preview"
|
|
||||||
@btctn = @find "btn-container"
|
|
||||||
@.editor = ace.edit @datarea
|
|
||||||
@.editor.setOptions {
|
|
||||||
enableBasicAutocompletion: true,
|
|
||||||
enableLiveAutocompletion: true,
|
|
||||||
fontSize: "10pt"
|
|
||||||
}
|
|
||||||
#@.editor.completers.push { getCompletions: ( editor, session, pos, prefix, callback ) -> }
|
|
||||||
@editor.getSession().setUseWrapMode true
|
|
||||||
@editor.session.setMode "ace/mode/text"
|
|
||||||
@editor.setTheme "ace/theme/monokai"
|
|
||||||
@editor.on "input", () ->
|
|
||||||
if me.editormux
|
|
||||||
me.editormux = false
|
|
||||||
return false
|
|
||||||
if not me.currfile.dirty
|
|
||||||
me.currfile.dirty = true
|
|
||||||
|
|
||||||
|
|
||||||
if not me.currfile.basename
|
|
||||||
me.editormux = true
|
|
||||||
me.editor.setValue GraphEditor.dummymermaid
|
|
||||||
me.renderSVG false
|
|
||||||
|
|
||||||
|
|
||||||
@editor.container.addEventListener "keydown", (e) ->
|
|
||||||
me.renderSVG true if e.keyCode is 13
|
|
||||||
, true
|
|
||||||
|
|
||||||
@bindKey "CTRL-R", () -> me.renderSVG false
|
|
||||||
@bindKey "ALT-G", () -> me.export "SVG"
|
|
||||||
@bindKey "ALT-P", () -> me.export "PNG"
|
|
||||||
@bindKey "ALT-N", () -> me.actionFile "#{me.name}-New"
|
|
||||||
@bindKey "ALT-O", () -> me.actionFile "#{me.name}-Open"
|
|
||||||
@bindKey "CTRL-S", () -> me.actionFile "#{me.name}-Save"
|
|
||||||
@bindKey "ALT-W", () -> me.actionFile "#{me.name}-Saveas"
|
|
||||||
@bindKey "CTRL-M", () -> me.svgToCanvas(()->)
|
|
||||||
|
|
||||||
@on "hboxchange", () ->
|
|
||||||
me.editor.resize()
|
|
||||||
me.calibrate()
|
|
||||||
@on "focus", () -> me.editor.focus()
|
|
||||||
(@find "btn-zoomin").set "onbtclick", (e) ->
|
|
||||||
me.pan.zoomIn() if me.pan
|
|
||||||
(@find "btn-zoomout").set "onbtclick", (e) ->
|
|
||||||
me.pan.zoomOut() if me.pan
|
|
||||||
(@find "btn-reset").set "onbtclick", (e) ->
|
|
||||||
me.pan.resetZoom() if me.pan
|
|
||||||
|
|
||||||
@open @currfile
|
|
||||||
|
|
||||||
menu: () ->
|
|
||||||
me = @
|
|
||||||
menu = [{
|
|
||||||
text: "__(File)",
|
|
||||||
child: [
|
|
||||||
{ text: "__(New)", dataid: "#{@name}-New", shortcut: "A-N" },
|
|
||||||
{ text: "__(Open)", dataid: "#{@name}-Open", shortcut: "A-O" },
|
|
||||||
{ text: "__(Save)", dataid: "#{@name}-Save", shortcut: "C-S" },
|
|
||||||
{ text: "__(Save as)",dataid: "#{@name}-Saveas" , shortcut: "A-W" },
|
|
||||||
{ text: "__(Render)", dataid: "#{@name}-Render", shortcut: "C-R" },
|
|
||||||
{
|
|
||||||
text: "__(Export as)",
|
|
||||||
child: [
|
|
||||||
{ text: "SVG", shortcut: "A-G" },
|
|
||||||
{ text: "PNG", shortcut: "A-P" }
|
|
||||||
],
|
|
||||||
onmenuselect: (e) -> me.export e.item.data.text
|
|
||||||
},
|
|
||||||
],
|
|
||||||
onmenuselect: (e) -> me.actionFile e.item.data.dataid
|
|
||||||
}]
|
|
||||||
menu
|
|
||||||
open: (file) ->
|
|
||||||
return if file.path is "Untitled"
|
|
||||||
me = @
|
|
||||||
file.dirty = false
|
|
||||||
file.read (d) ->
|
|
||||||
me.currfile = file
|
|
||||||
me.editormux = true
|
|
||||||
me.currfile.dirty = false
|
|
||||||
me.editor.setValue d
|
|
||||||
me.scheme.set "apptitle", "#{me.currfile.basename}"
|
|
||||||
me.renderSVG false
|
|
||||||
save: (file) ->
|
|
||||||
me = @
|
|
||||||
file.write "text/plain", (d) ->
|
|
||||||
return me.error __("Error saving file {0}", file.basename) if d.error
|
|
||||||
file.dirty = false
|
|
||||||
file.text = file.basename
|
|
||||||
me.scheme.set "apptitle", "#{me.currfile.basename}"
|
|
||||||
|
|
||||||
actionFile: (e) ->
|
|
||||||
me = @
|
|
||||||
saveas = () ->
|
|
||||||
me.openDialog "FileDiaLog", (d, n) ->
|
|
||||||
me.currfile.setPath "#{d}/#{n}"
|
|
||||||
me.save me.currfile
|
|
||||||
, __("Save as"), { file: me.currfile }
|
|
||||||
switch e
|
|
||||||
when "#{@name}-Open"
|
|
||||||
@openDialog "FileDiaLog", ( d, f ) ->
|
|
||||||
me.open "#{d}/#{f}".asFileHandler()
|
|
||||||
, __("Open file")
|
|
||||||
when "#{@name}-Save"
|
|
||||||
@currfile.cache = @editor.getValue()
|
|
||||||
return @save @currfile if @currfile.basename
|
|
||||||
saveas()
|
|
||||||
when "#{@name}-Saveas"
|
|
||||||
@currfile.cache = @editor.getValue()
|
|
||||||
saveas()
|
|
||||||
when "#{@name}-Render"
|
|
||||||
me.renderSVG false
|
|
||||||
when "#{@name}-New"
|
|
||||||
@currfile = "Untitled".asFileHandler()
|
|
||||||
@currfile.cache = ""
|
|
||||||
@currfile.dirty = false
|
|
||||||
@editormux = true
|
|
||||||
@editor.setValue("")
|
|
||||||
|
|
||||||
export: (t) ->
|
|
||||||
me = @
|
|
||||||
me.openDialog "FileDiaLog", (d, n) ->
|
|
||||||
fp = "#{d}/#{n}".asFileHandler()
|
|
||||||
try
|
|
||||||
switch t
|
|
||||||
when "SVG"
|
|
||||||
fp.cache = me.svgtext()
|
|
||||||
fp.write "text/plain", (r) ->
|
|
||||||
return me.error __("Cannot export to {0}: {1}", t, r.error) if r.error
|
|
||||||
me.notify __("File exported")
|
|
||||||
when "PNG"
|
|
||||||
# toDataURL("image/png")
|
|
||||||
me.svgToCanvas (canvas) ->
|
|
||||||
try
|
|
||||||
fp.cache = canvas.toDataURL "image/png"
|
|
||||||
fp.write "base64", (r) ->
|
|
||||||
return me.error __("Cannot export to {0}: {1}", t, r.error) if r.error
|
|
||||||
me.notify __("File exported")
|
|
||||||
catch e
|
|
||||||
me.error __("Cannot export to PNG in this browser: {0}", e.message)
|
|
||||||
catch e
|
|
||||||
me.error __("Cannot export: {0}", e.message)
|
|
||||||
, __("Export as"), { file: me.currfile }
|
|
||||||
|
|
||||||
|
|
||||||
renderSVG: (silent) ->
|
|
||||||
me = @
|
|
||||||
id = Math.floor(Math.random() * 100000) + 1
|
|
||||||
#if silent
|
|
||||||
# mermaid.parseError = (e, h) ->
|
|
||||||
#else
|
|
||||||
# mermaid.parseError = (e, h) ->
|
|
||||||
# me.error e
|
|
||||||
text = @editor.getValue()
|
|
||||||
try
|
|
||||||
mermaid.parse text
|
|
||||||
catch e
|
|
||||||
me.error __("Syntax error: {0}", e.str) if not silent
|
|
||||||
return
|
|
||||||
mermaid.render "c#{id}", text, (text, f) ->
|
|
||||||
me.preview.innerHTML = text
|
|
||||||
$(me.preview).append me.btctn
|
|
||||||
me.calibrate()
|
|
||||||
svg = $(me.preview).children("svg")[0]
|
|
||||||
$(svg).attr("style", "")
|
|
||||||
me.pan = svgPanZoom svg, {
|
|
||||||
zoomEnabled: true,
|
|
||||||
controlIconsEnabled: false,
|
|
||||||
fit: true,
|
|
||||||
center: true,
|
|
||||||
minZoom: 0.1
|
|
||||||
}
|
|
||||||
#rd $($.parseHTML text).
|
|
||||||
, me.preview
|
|
||||||
|
|
||||||
svgtext: () ->
|
|
||||||
svg = $(@preview).children("svg")[0]
|
|
||||||
serializer = new XMLSerializer()
|
|
||||||
return serializer.serializeToString(svg)
|
|
||||||
|
|
||||||
svgToCanvas: (f) ->
|
|
||||||
me = @
|
|
||||||
img = new Image()
|
|
||||||
svgStr = @svgtext()
|
|
||||||
img.onload = () ->
|
|
||||||
canvas = me.find "offscreen"
|
|
||||||
canvas.width = img.width
|
|
||||||
canvas.height = img.height
|
|
||||||
canvas.getContext("2d").drawImage img, 0, 0, img.width, img.height
|
|
||||||
f(canvas)
|
|
||||||
img.src = 'data:image/svg+xml;base64,' + btoa(svgStr)
|
|
||||||
|
|
||||||
calibrate: () ->
|
|
||||||
svg = ($ @preview).children("svg")[0]
|
|
||||||
if svg
|
|
||||||
prs = [$(@preview).width(), $(@preview).height()]
|
|
||||||
$(svg).attr "width", prs[0] + "px"
|
|
||||||
$(svg).attr "height", prs[1] + "px"
|
|
||||||
|
|
||||||
cleanup: (evt) ->
|
|
||||||
return unless @currfile.dirty
|
|
||||||
me = @
|
|
||||||
evt.preventDefault()
|
|
||||||
@.openDialog "YesNoDialog", (d) ->
|
|
||||||
if d
|
|
||||||
me.currfile.dirty = false
|
|
||||||
me.quit()
|
|
||||||
, __("Quit"), { text: __("Quit without saving ?") }
|
|
||||||
|
|
||||||
GraphEditor.dummymermaid = """
|
|
||||||
graph TD;
|
|
||||||
A-->B;
|
|
||||||
A-->C;
|
|
||||||
B-->D;
|
|
||||||
C-->D;
|
|
||||||
"""
|
|
||||||
GraphEditor.dependencies = [
|
|
||||||
"ace/ace"
|
|
||||||
]
|
|
||||||
this.OS.register "GraphEditor", GraphEditor
|
|
@ -1,22 +0,0 @@
|
|||||||
afx-app-window[data-id="graph_editor_win"] div[data-id="preview"]
|
|
||||||
{
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] afx-button button
|
|
||||||
{
|
|
||||||
border-radius: 0;
|
|
||||||
padding-top:2px;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] afx-resizer{
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
afx-app-window[data-id="graph_editor_win"] div[data-id="btn-container"]{
|
|
||||||
background-color: transparent;
|
|
||||||
position: absolute;
|
|
||||||
bottom:10px;
|
|
||||||
right: 10px;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"app":"GraphEditor",
|
|
||||||
"name":"Graph Editor",
|
|
||||||
"description":"Create graph with dot language or mermaid",
|
|
||||||
"info":{
|
|
||||||
"author": "Xuan Sang LE",
|
|
||||||
"email": "xsang.le@gmail.com",
|
|
||||||
"licences": "GPLv3"
|
|
||||||
},
|
|
||||||
"version":"0.0.1-a",
|
|
||||||
"category":"Office",
|
|
||||||
"iconclass": "fa fa-sitemap",
|
|
||||||
"mimes":["text/.*graphviz"]
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
<afx-app-window data-id="graph_editor_win" apptitle="__(Graph editor)" width="650" height="500">
|
|
||||||
<afx-hbox>
|
|
||||||
<div data-id="datarea"></div>
|
|
||||||
<afx-resizer data-width="5" ></afx-resizer>
|
|
||||||
<div data-id="preview">
|
|
||||||
<div data-height="25" data-id="btn-container">
|
|
||||||
<afx-button data-id="btn-zoomin" iconclass="fa fa-search-plus"></afx-button>
|
|
||||||
<afx-button data-id="btn-zoomout" iconclass="fa fa-search-minus"></afx-button>
|
|
||||||
<afx-button data-id="btn-reset" iconclass="fa fa-square-o"></afx-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<canvas data-id="offscreen" data-width="0" style="display:none" ></canvas>
|
|
||||||
</afx-hbox>
|
|
||||||
</afx-app-window>
|
|
Loading…
Reference in New Issue
Block a user