@qarakash/blockwriteai 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -602
- package/dist/blockwriteai.min.css +1 -0
- package/dist/blockwriteai.min.js +1 -0
- package/dist/plugins/blockwriteai-advanced-blocks.min.js +1 -0
- package/dist/plugins/blockwriteai-ai.min.js +1 -0
- package/dist/plugins/blockwriteai-code-assist.min.js +1 -0
- package/dist/plugins/blockwriteai-drawing.min.js +1 -0
- package/dist/plugins/blockwriteai-history.min.js +1 -0
- package/dist/plugins/blockwriteai-mermaid.min.js +1 -0
- package/dist/plugins/blockwriteai-signature-flow.min.js +1 -0
- package/dist/plugins/blockwriteai-signature.min.js +1 -0
- package/package.json +26 -18
- package/types/index.d.ts +1 -1
- package/dist/blockwriteai.css +0 -3762
- package/dist/blockwriteai.js +0 -6771
- package/dist/plugins/blockwriteai-advanced-blocks.js +0 -2282
- package/dist/plugins/blockwriteai-ai.js +0 -637
- package/dist/plugins/blockwriteai-code-assist.js +0 -609
- package/dist/plugins/blockwriteai-drawing.js +0 -178
- package/dist/plugins/blockwriteai-history.js +0 -23
- package/dist/plugins/blockwriteai-mermaid.js +0 -1986
- package/dist/plugins/blockwriteai-signature-flow.js +0 -493
- package/dist/plugins/blockwriteai-signature.js +0 -463
|
@@ -1,2282 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* BlockWriteAI Advanced Blocks Plugin
|
|
3
|
-
* Adds chart, LaTeX, audio, and columns/layout blocks.
|
|
4
|
-
*/
|
|
5
|
-
(function (global) {
|
|
6
|
-
"use strict";
|
|
7
|
-
|
|
8
|
-
var BlockWriteAI = global.BlockWriteAI;
|
|
9
|
-
if (!BlockWriteAI || BlockWriteAI.__advancedBlocksInstalled) return;
|
|
10
|
-
BlockWriteAI.__advancedBlocksInstalled = true;
|
|
11
|
-
|
|
12
|
-
var H = BlockWriteAI.helpers || {};
|
|
13
|
-
var el = H.el;
|
|
14
|
-
var esc = H.escapeHTML || function (value) {
|
|
15
|
-
return String(value == null ? "" : value).replace(/[&<>"]/g, function (ch) {
|
|
16
|
-
return { "&": "&", "<": "<", ">": ">", '"': """ }[ch];
|
|
17
|
-
});
|
|
18
|
-
};
|
|
19
|
-
var sanitize = H.sanitizeHTML || function (value) { return String(value || ""); };
|
|
20
|
-
var inline = H.renderOutputInline || sanitize;
|
|
21
|
-
var faIcon = H.faIcon || function (name, label) {
|
|
22
|
-
return '<i class="fa-solid fa-' + esc(name) + '" aria-hidden="true"></i><span class="rbe-sr-only">' + esc(label || name) + "</span>";
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function injectStyles() {
|
|
26
|
-
if (document.querySelector("style[data-blockwriteai-advanced-blocks]")) return;
|
|
27
|
-
var style = document.createElement("style");
|
|
28
|
-
style.dataset.blockwriteaiAdvancedBlocks = "true";
|
|
29
|
-
style.textContent =
|
|
30
|
-
".rbe-plugin-card{border:1px solid var(--rbe-border,#d7dee8);border-radius:8px;background:#fff;padding:12px;display:grid;gap:12px;}" +
|
|
31
|
-
".rbe-plugin-toolbar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;}" +
|
|
32
|
-
".rbe-plugin-toolbar label{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:750;color:#667085;}" +
|
|
33
|
-
".rbe-plugin-toolbar input,.rbe-plugin-toolbar select,.rbe-plugin-card textarea{border:1px solid var(--rbe-border,#d7dee8);border-radius:7px;background:#fff;color:#172033;font:14px/1.4 Arial,sans-serif;padding:8px 9px;}" +
|
|
34
|
-
".rbe-plugin-toolbar input[type='color']{width:40px;min-width:40px;height:34px;padding:3px;}" +
|
|
35
|
-
".rbe-plugin-card textarea{width:100%;min-height:150px;resize:vertical;font-family:Consolas,'Liberation Mono',monospace;}" +
|
|
36
|
-
".rbe-plugin-preview{border:1px dashed #cbd5e1;border-radius:8px;background:#f8fbff;min-height:120px;padding:12px;overflow:auto;}" +
|
|
37
|
-
".rbe-chart-block{position:relative;}" +
|
|
38
|
-
".rbe-chart-preview-wrap{position:relative;}" +
|
|
39
|
-
".rbe-chart-type-bar{position:absolute;left:50%;top:50%;z-index:4;display:flex;gap:6px;align-items:center;border:1px solid #cbd5e1;border-radius:999px;background:rgba(255,255,255,.96);padding:7px;box-shadow:0 16px 40px rgba(15,23,42,.16);opacity:0;pointer-events:none;transform:translate(-50%,-50%) scale(.96);transition:opacity .16s ease,transform .16s ease;}" +
|
|
40
|
-
".rbe-chart-preview-wrap:hover .rbe-chart-type-bar,.rbe-chart-type-bar:focus-within{opacity:1;pointer-events:auto;transform:translate(-50%,-50%) scale(1);}" +
|
|
41
|
-
".rbe-chart-type-btn{width:34px;height:34px;border:1px solid #d7dee8;border-radius:999px;background:#fff;color:#344054;display:inline-grid;place-items:center;cursor:pointer;}" +
|
|
42
|
-
".rbe-chart-type-btn:hover,.rbe-chart-type-btn.is-active{border-color:#2563eb;background:#eaf1ff;color:#1d4ed8;}" +
|
|
43
|
-
".rbe-chart-slice-colors{display:flex;flex-wrap:wrap;gap:8px;align-items:center;}" +
|
|
44
|
-
".rbe-chart-slice-colors[hidden],.rbe-chart-series-color[hidden]{display:none!important;}" +
|
|
45
|
-
".rbe-chart-slice-label{font-size:12px;font-weight:800;color:#667085;}" +
|
|
46
|
-
".rbe-chart-slice-list{display:flex;flex-wrap:wrap;gap:6px;align-items:center;}" +
|
|
47
|
-
".rbe-chart-slice-chip{display:inline-flex;align-items:center;gap:4px;border:1px solid #d7dee8;border-radius:999px;background:#fff;padding:3px 6px;font-size:11px;font-weight:750;color:#475467;}" +
|
|
48
|
-
".rbe-chart-slice-chip input{width:28px!important;min-width:28px!important;height:24px!important;padding:2px!important;border-radius:999px;}" +
|
|
49
|
-
".rbe-chart-preview svg,.rbe-output-chart svg{width:100%;height:auto;max-height:300px;}" +
|
|
50
|
-
".rbe-output-chart,.rbe-output-mermaid,.rbe-output-latex,.rbe-output-audio,.rbe-output-drawing,.rbe-output-columns{margin:0 0 15px;}" +
|
|
51
|
-
".rbe-output-chart{border:1px solid #d7dee8;border-radius:8px;padding:12px;background:#fff;}" +
|
|
52
|
-
".rbe-output-chart-title{display:block;margin-bottom:8px;font-weight:760;}" +
|
|
53
|
-
".rbe-chart-caption{width:min(560px,100%);min-height:42px;margin:0 auto;border:1px solid var(--rbe-border,#d7dee8);border-radius:8px;background:#fff;padding:10px 12px;text-align:center;outline:none;}" +
|
|
54
|
-
".rbe-chart-caption:focus{border-color:#2563eb;box-shadow:0 0 0 3px rgba(37,99,235,.12);}" +
|
|
55
|
-
".rbe-chart-caption:empty:before{content:attr(data-placeholder);color:#98a2b3;}" +
|
|
56
|
-
".rbe-output-chart-caption{display:block;margin:10px auto 0;color:#475467;font-size:13px;font-weight:650;}" +
|
|
57
|
-
".rbe-latex-preview,.rbe-output-latex{font-family:Georgia,'Times New Roman',serif;font-size:20px;line-height:1.6;text-align:center;font-style:italic;}" +
|
|
58
|
-
".rbe-output-latex{display:block;width:100%;}" +
|
|
59
|
-
".rbe-latex-frac{display:inline-grid;grid-template-rows:auto auto;vertical-align:middle;text-align:center;line-height:1.1;}.rbe-latex-frac span:first-child{border-bottom:1px solid currentColor;padding:0 2px;}" +
|
|
60
|
-
".rbe-output-align-left{text-align:left;}" +
|
|
61
|
-
".rbe-output-align-center{text-align:center;}" +
|
|
62
|
-
".rbe-output-align-right{text-align:right;}" +
|
|
63
|
-
".rbe-output-align-center>.rbe-output-mermaid-diagram,.rbe-output-align-center>.rbe-output-mermaid,.rbe-output-align-center>svg{margin-left:auto;margin-right:auto;}" +
|
|
64
|
-
".rbe-output-align-right>.rbe-output-mermaid-diagram,.rbe-output-align-right>.rbe-output-mermaid,.rbe-output-align-right>svg{margin-left:auto;margin-right:0;}" +
|
|
65
|
-
".rbe-mermaid-block{gap:10px;}" +
|
|
66
|
-
".rbe-mermaid-card{position:relative;min-height:220px;display:grid;gap:10px;align-items:stretch;border:1px solid #d7dee8;border-radius:10px;background:#fbfdff;padding:14px;}" +
|
|
67
|
-
".rbe-mermaid-card-head{display:flex;align-items:center;justify-content:space-between;gap:10px;}" +
|
|
68
|
-
".rbe-mermaid-card-title{font-weight:820;color:#172033;font-size:14px;}" +
|
|
69
|
-
".rbe-mermaid-card-preview{min-height:160px;display:grid;place-items:center;border:1px dashed #cbd5e1;border-radius:9px;background:#fff;padding:12px;overflow:auto;}" +
|
|
70
|
-
".rbe-mermaid-card-preview .rbe-output-mermaid-diagram{max-width:100%;width:100%;}" +
|
|
71
|
-
".rbe-mermaid-card-empty{color:#667085;font-weight:750;font-size:13px;}" +
|
|
72
|
-
".rbe-mermaid-edit-btn{position:absolute;right:12px;top:12px;width:34px;height:34px;border:1px solid #cbd5e1;border-radius:999px;background:#fff;color:#172033;display:grid;place-items:center;cursor:pointer;box-shadow:0 12px 28px rgba(15,23,42,.12);}" +
|
|
73
|
-
".rbe-mermaid-edit-btn:hover,.rbe-mermaid-edit-btn:focus-visible{border-color:#2563eb;color:#1d4ed8;background:#eaf1ff;}" +
|
|
74
|
-
".rbe-mermaid-modal-open{overflow:hidden!important;}" +
|
|
75
|
-
".rbe-mermaid-modal{position:fixed;inset:0;z-index:10000;background:rgba(15,23,42,.46);display:grid;place-items:stretch;padding:22px;}" +
|
|
76
|
-
".rbe-mermaid-dialog{display:grid;grid-template-rows:auto 1fr auto;min-height:0;border-radius:14px;background:#fff;box-shadow:0 28px 80px rgba(15,23,42,.32);overflow:hidden;}" +
|
|
77
|
-
".rbe-mermaid-modal-head,.rbe-mermaid-modal-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-bottom:1px solid #e2e8f0;}" +
|
|
78
|
-
".rbe-mermaid-modal-foot{border-top:1px solid #e2e8f0;border-bottom:0;justify-content:flex-end;}" +
|
|
79
|
-
".rbe-mermaid-modal-title{margin:0;font-size:17px;font-weight:820;color:#172033;}" +
|
|
80
|
-
".rbe-mermaid-close{width:34px;height:34px;border:1px solid #cbd5e1;border-radius:999px;background:#fff;display:grid;place-items:center;cursor:pointer;}" +
|
|
81
|
-
".rbe-mermaid-modal-save,.rbe-mermaid-modal-cancel{border:1px solid #cbd5e1;border-radius:8px;background:#fff;color:#172033;font-weight:800;padding:9px 14px;cursor:pointer;}" +
|
|
82
|
-
".rbe-mermaid-modal-save{border-color:#2563eb;background:#2563eb;color:#fff;}" +
|
|
83
|
-
".rbe-mermaid-modal-body{min-height:0;overflow:hidden;padding:0;background:#f8fafc;}" +
|
|
84
|
-
".rbe-mermaid-modal .rbe-mermaid-block{height:100%;border:0;border-radius:0;background:transparent;padding:0;display:grid;grid-template-rows:auto 1fr;gap:0;}" +
|
|
85
|
-
".rbe-mermaid-toolbar{display:flex;flex-wrap:wrap;gap:7px;align-items:center;padding:8px;border:1px solid #d7dee8;border-radius:12px;background:#eef4fb;}" +
|
|
86
|
-
".rbe-mermaid-modal .rbe-mermaid-toolbar{position:relative;z-index:5;border-width:0 0 1px;border-radius:0;background:#edf2f8;padding:9px 14px;}" +
|
|
87
|
-
".rbe-mermaid-tool,.rbe-mermaid-icon-btn{width:34px;height:34px;border:1px solid transparent;border-radius:8px;background:transparent;color:#344054;display:inline-grid;place-items:center;cursor:pointer;}" +
|
|
88
|
-
".rbe-mermaid-icon-btn{border-color:#d7dee8;background:#fff;}" +
|
|
89
|
-
".rbe-mermaid-tool:hover,.rbe-mermaid-tool.is-active,.rbe-mermaid-icon-btn:hover,.rbe-mermaid-icon-btn.is-active{background:#dbeafe;border-color:#93c5fd;color:#1d4ed8;}" +
|
|
90
|
-
".rbe-mermaid-tool:disabled,.rbe-mermaid-icon-btn:disabled{opacity:.45;cursor:not-allowed;}" +
|
|
91
|
-
".rbe-mermaid-menu{position:relative;}" +
|
|
92
|
-
".rbe-mermaid-menu-btn{width:34px;height:34px;border:1px solid transparent;border-radius:8px;background:transparent;color:#344054;display:inline-grid;place-items:center;cursor:pointer;}" +
|
|
93
|
-
".rbe-mermaid-menu-btn:hover,.rbe-mermaid-menu:focus-within>.rbe-mermaid-menu-btn{background:#dbeafe;border-color:#93c5fd;color:#1d4ed8;}" +
|
|
94
|
-
".rbe-mermaid-popover{position:absolute;left:0;top:calc(100% + 6px);z-index:12;display:none;min-width:166px;border:1px solid #d7dee8;border-radius:8px;background:#fff;box-shadow:0 16px 34px rgba(15,23,42,.18);padding:6px;}" +
|
|
95
|
-
".rbe-mermaid-menu:focus-within>.rbe-mermaid-popover,.rbe-mermaid-menu:hover>.rbe-mermaid-popover{display:block;}" +
|
|
96
|
-
".rbe-mermaid-menu-row{position:relative;display:flex;align-items:center;gap:10px;min-height:34px;padding:7px 8px;border-radius:6px;font-size:14px;color:#344054;white-space:nowrap;}" +
|
|
97
|
-
".rbe-mermaid-menu-row:hover{background:#eef2f7;}" +
|
|
98
|
-
".rbe-mermaid-menu-row:after{content:'›';margin-left:auto;color:#667085;}" +
|
|
99
|
-
".rbe-mermaid-submenu{position:absolute;left:100%;top:-7px;display:none;min-width:270px;border:1px solid #d7dee8;border-radius:8px;background:#fff;box-shadow:0 16px 34px rgba(15,23,42,.18);padding:8px;}" +
|
|
100
|
-
".rbe-mermaid-menu-row:hover>.rbe-mermaid-submenu{display:block;}" +
|
|
101
|
-
".rbe-mermaid-popover:not(:has(.rbe-mermaid-menu-row:hover)) .rbe-mermaid-menu-row:first-child>.rbe-mermaid-submenu{display:block;}" +
|
|
102
|
-
".rbe-mermaid-menu-row-icon{width:18px;display:inline-grid;place-items:center;color:#344054;}" +
|
|
103
|
-
".rbe-mermaid-choice-grid{display:grid;grid-template-columns:repeat(10,22px);gap:7px;align-items:center;}" +
|
|
104
|
-
".rbe-mermaid-choice-grid:has(+ .rbe-mermaid-choice-grid){border-bottom:1px solid #e5e7eb;padding-bottom:8px;margin-bottom:8px;}" +
|
|
105
|
-
".rbe-mermaid-choice{width:22px;height:22px;border:0;background:transparent;color:#111827;display:grid;place-items:center;cursor:pointer;font:18px/1 Arial,sans-serif;border-radius:4px;}" +
|
|
106
|
-
".rbe-mermaid-choice:hover,.rbe-mermaid-choice.is-active{background:#dbeafe;color:#1d4ed8;}" +
|
|
107
|
-
".rbe-mermaid-line-menu .rbe-mermaid-popover{min-width:210px;}" +
|
|
108
|
-
".rbe-mermaid-line-menu .rbe-mermaid-menu-row:after{content:'';}" +
|
|
109
|
-
".rbe-mermaid-line-choice{width:100%;border:0;border-radius:6px;background:transparent;color:#344054;display:flex;align-items:center;gap:10px;padding:8px;text-align:left;cursor:pointer;font:14px/1.2 Arial,sans-serif;}" +
|
|
110
|
-
".rbe-mermaid-line-choice:hover{background:#eef2f7;color:#1d4ed8;}" +
|
|
111
|
-
".rbe-mermaid-menu-select,.rbe-mermaid-action-select,.rbe-mermaid-stylebar select,.rbe-mermaid-workspace input{border:1px solid #d7dee8;border-radius:8px;background:#fff;color:#172033;font:13px/1.2 Arial,sans-serif;padding:7px 9px;max-width:156px;}" +
|
|
112
|
-
".rbe-mermaid-workspace input{width:72px;}" +
|
|
113
|
-
".rbe-mermaid-stylebar,.rbe-mermaid-workspace{display:flex;flex-wrap:wrap;gap:7px;align-items:center;border:1px solid #d7dee8;border-radius:10px;background:#fbfdff;padding:6px;}" +
|
|
114
|
-
".rbe-mermaid-stylebar[hidden]{display:none!important;}" +
|
|
115
|
-
".rbe-mermaid-stylebar label,.rbe-mermaid-workspace label{display:inline-flex;gap:6px;align-items:center;font-size:12px;font-weight:800;color:#667085;}" +
|
|
116
|
-
".rbe-mermaid-stylebar label{height:32px;border:1px solid #d7dee8;border-radius:8px;background:#fff;padding:3px 6px;color:#344054;}" +
|
|
117
|
-
".rbe-mermaid-stylebar label:hover{border-color:#93c5fd;background:#eef6ff;color:#1d4ed8;}" +
|
|
118
|
-
".rbe-mermaid-stylebar .rbe-mermaid-icon-control,.rbe-mermaid-stylebar .rbe-mermaid-style-btn{position:relative;width:34px;height:32px;box-sizing:border-box;border:1px solid transparent;border-radius:8px;background:#fff;color:#344054;display:inline-grid;place-items:center;padding:0;cursor:pointer;}" +
|
|
119
|
-
".rbe-mermaid-stylebar .rbe-mermaid-icon-control:hover,.rbe-mermaid-stylebar .rbe-mermaid-style-btn:hover,.rbe-mermaid-stylebar .rbe-mermaid-style-btn.is-active{border-color:#93c5fd;background:#dbeafe;color:#1d4ed8;}" +
|
|
120
|
-
".rbe-mermaid-stylebar .rbe-mermaid-icon-control input,.rbe-mermaid-stylebar .rbe-mermaid-icon-control select{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;opacity:0!important;cursor:pointer;}" +
|
|
121
|
-
".rbe-mermaid-control-swatch{position:absolute;left:7px;right:7px;bottom:3px;height:3px;border-radius:999px;background:#2563eb;pointer-events:none;}" +
|
|
122
|
-
".rbe-mermaid-fill-swatch{background:var(--rbe-mermaid-fill,#eef5ff);}" +
|
|
123
|
-
".rbe-mermaid-stroke-swatch{background:var(--rbe-mermaid-stroke,#111827);}" +
|
|
124
|
-
".rbe-mermaid-text-swatch{background:var(--rbe-mermaid-text,#172033);}" +
|
|
125
|
-
".rbe-mermaid-highlight-swatch{background:var(--rbe-mermaid-highlight,transparent);}" +
|
|
126
|
-
".rbe-mermaid-stylebar.is-line-selection .rbe-mermaid-fill-control,.rbe-mermaid-stylebar.is-line-selection .rbe-mermaid-text-control{display:none;}" +
|
|
127
|
-
".rbe-mermaid-stylebar:not(.is-text-capable) .rbe-mermaid-text-control{display:none;}" +
|
|
128
|
-
".rbe-mermaid-stylebar .rbe-mermaid-hidden-control{display:none!important;}" +
|
|
129
|
-
".rbe-mermaid-hint{font-size:12px;font-weight:700;color:#667085;}" +
|
|
130
|
-
".rbe-mermaid-stylebar input[type='color']{width:28px;height:24px;padding:1px;border:1px solid #d7dee8;border-radius:6px;background:#fff;}" +
|
|
131
|
-
".rbe-mermaid-stylebar input[type='range']{width:90px;}" +
|
|
132
|
-
".rbe-mermaid-stylebar select{height:24px;max-width:86px;padding:2px 5px;font-size:12px;}" +
|
|
133
|
-
".rbe-mermaid-stylebar .rbe-mermaid-icon-control.is-active{border-color:#93c5fd;background:#dbeafe;color:#1d4ed8;}" +
|
|
134
|
-
".rbe-mermaid-toolbar-sep{width:1px;height:24px;background:#cbd5e1;margin:0 2px;}" +
|
|
135
|
-
".rbe-mermaid-stage-shell{display:grid;grid-template-columns:28px minmax(0,1fr);grid-template-rows:26px minmax(0,1fr);min-height:0;height:100%;background:#fff;}" +
|
|
136
|
-
".rbe-mermaid-ruler-corner{grid-column:1;grid-row:1;border-right:1px solid #cbd5e1;border-bottom:1px solid #cbd5e1;background:#f8fafc;}" +
|
|
137
|
-
".rbe-mermaid-top-ruler{grid-column:2;grid-row:1;position:relative;border-bottom:1px solid #cbd5e1;background:#f8fafc;background-image:repeating-linear-gradient(90deg,#cbd5e1 0,#cbd5e1 1px,transparent 1px,transparent 10px),repeating-linear-gradient(90deg,#94a3b8 0,#94a3b8 1px,transparent 1px,transparent 100px);}" +
|
|
138
|
-
".rbe-mermaid-side-ruler{grid-column:1;grid-row:2;position:relative;border-right:1px solid #cbd5e1;background:#f8fafc;background-image:repeating-linear-gradient(0deg,#cbd5e1 0,#cbd5e1 1px,transparent 1px,transparent 10px),repeating-linear-gradient(0deg,#94a3b8 0,#94a3b8 1px,transparent 1px,transparent 100px);}" +
|
|
139
|
-
".rbe-mermaid-top-ruler span,.rbe-mermaid-side-ruler span{position:absolute;color:#475467;font:11px/1 Arial,sans-serif;user-select:none;}" +
|
|
140
|
-
".rbe-mermaid-top-ruler span{top:5px;transform:translateX(-50%);}" +
|
|
141
|
-
".rbe-mermaid-side-ruler span{left:8px;transform:translateY(-50%) rotate(-90deg);transform-origin:center;}" +
|
|
142
|
-
".rbe-mermaid-stage{position:relative;border:1px solid #d7dee8;border-radius:8px;background-color:#fff;background-image:linear-gradient(45deg,#f8fafc 25%,transparent 25%),linear-gradient(-45deg,#f8fafc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#f8fafc 75%),linear-gradient(-45deg,transparent 75%,#f8fafc 75%);background-position:0 0,0 12px,12px -12px,-12px 0;background-size:24px 24px;overflow:auto;resize:vertical;min-height:320px;max-height:560px;}" +
|
|
143
|
-
".rbe-mermaid-modal .rbe-mermaid-stage{grid-column:2;grid-row:2;height:100%;min-height:0;max-height:none;border:0;border-radius:0;resize:none;}" +
|
|
144
|
-
".rbe-mermaid-canvas{display:block;width:auto;height:auto;min-width:100%;touch-action:none;cursor:crosshair;background:rgba(255,255,255,.72);}" +
|
|
145
|
-
".rbe-mermaid-canvas [data-el-id]{cursor:move;}" +
|
|
146
|
-
".rbe-mermaid-canvas .is-selected{outline:none;filter:drop-shadow(0 0 0 #2563eb);}" +
|
|
147
|
-
".rbe-mermaid-selected-stroke{stroke:#2563eb!important;stroke-width:2!important;fill:none!important;pointer-events:none;}" +
|
|
148
|
-
".rbe-mermaid-handle{fill:#fff;stroke:#2563eb;stroke-width:2;cursor:nwse-resize;transition:fill .12s ease;}" +
|
|
149
|
-
".rbe-mermaid-handle:hover{fill:var(--rbe-handle-color,#2563eb);}" +
|
|
150
|
-
".rbe-mermaid-handle[data-handle='ne'],.rbe-mermaid-handle[data-handle='sw']{cursor:nesw-resize;}" +
|
|
151
|
-
".rbe-mermaid-handle[data-handle='n'],.rbe-mermaid-handle[data-handle='s']{cursor:ns-resize;}" +
|
|
152
|
-
".rbe-mermaid-handle[data-handle='e'],.rbe-mermaid-handle[data-handle='w']{cursor:ew-resize;}" +
|
|
153
|
-
".rbe-mermaid-rotate{cursor:grab;}" +
|
|
154
|
-
".rbe-mermaid-rotate circle{fill:#2563eb;stroke:#fff;stroke-width:2;}" +
|
|
155
|
-
".rbe-mermaid-rotate text{fill:#fff;stroke:none;font:800 12px/1 Arial,sans-serif;pointer-events:none;}" +
|
|
156
|
-
".rbe-mermaid-rotate-icon{pointer-events:none;}" +
|
|
157
|
-
".rbe-mermaid-marquee{fill:rgba(37,99,235,.09);stroke:#2563eb;stroke-width:1.5;stroke-dasharray:6 4;pointer-events:none;}" +
|
|
158
|
-
".rbe-mermaid-arrow-origin{fill:#fff;stroke:#2563eb;stroke-width:2;pointer-events:none;}" +
|
|
159
|
-
".rbe-mermaid-hidden-text{visibility:hidden!important;}" +
|
|
160
|
-
".rbe-mermaid-text-editor{position:absolute;z-index:20;box-sizing:border-box;border:0;border-radius:0;background:transparent;outline:none;overflow:hidden;resize:none;color:#172033;box-shadow:none;text-align:center;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;caret-color:#0f172a;font-weight:400;}" +
|
|
161
|
-
".rbe-mermaid-text-editor::placeholder{color:#667085;opacity:.62;}" +
|
|
162
|
-
".rbe-mermaid-options{display:flex;flex-wrap:wrap;gap:8px;align-items:center;border:1px solid #d7dee8;border-radius:8px;background:#fff;padding:8px;}" +
|
|
163
|
-
".rbe-mermaid-options[hidden]{display:none;}" +
|
|
164
|
-
".rbe-mermaid-options input,.rbe-mermaid-options select{border:1px solid #d7dee8;border-radius:7px;padding:7px 8px;}" +
|
|
165
|
-
".rbe-mermaid-source{margin-top:0;}" +
|
|
166
|
-
".rbe-mermaid-source summary{cursor:pointer;font-weight:750;color:#475467;}" +
|
|
167
|
-
".rbe-output-mermaid-diagram{display:block;max-width:100%;max-height:560px;overflow:auto;border:1px solid #d7dee8;border-radius:8px;background:#fff;}" +
|
|
168
|
-
".rbe-output-mermaid-diagram svg{display:block;width:auto;max-width:none;height:auto;min-width:100%;border:0;border-radius:0;background:#fff;}" +
|
|
169
|
-
".rbe-output-mermaid-error{display:inline-block;border:1px solid #fecaca;border-radius:8px;background:#fff1f2;color:#991b1b;padding:10px 12px;font:13px/1.45 Consolas,'Liberation Mono',monospace;white-space:pre-wrap;}" +
|
|
170
|
-
".rbe-audio-dropzone{min-height:170px;}" +
|
|
171
|
-
".rbe-audio-error{border:1px solid #fecaca;border-radius:8px;background:#fff1f2;color:#991b1b;padding:8px 10px;font-size:13px;font-weight:700;}" +
|
|
172
|
-
".rbe-audio-card{display:grid;gap:10px;justify-items:center;text-align:center;}" +
|
|
173
|
-
".rbe-audio-card audio,.rbe-output-audio audio{width:min(560px,100%);}" +
|
|
174
|
-
".rbe-output-audio{display:grid;justify-items:center;text-align:center;}" +
|
|
175
|
-
".rbe-output-audio figcaption{font-weight:760;margin-bottom:8px;}" +
|
|
176
|
-
".rbe-drawing-text-input{min-width:220px;flex:1 1 260px;}" +
|
|
177
|
-
".rbe-drawing-text-apply{min-width:38px;}" +
|
|
178
|
-
".rbe-drawing-shell{display:grid;gap:10px;}" +
|
|
179
|
-
".rbe-drawing-canvas{width:100%;height:260px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;touch-action:none;}" +
|
|
180
|
-
".rbe-output-drawing img{max-width:100%;border:1px solid #d7dee8;border-radius:8px;background:#fff;}" +
|
|
181
|
-
".rbe-columns-block{overflow-x:auto;}" +
|
|
182
|
-
".rbe-columns-grid,.rbe-output-columns{display:grid;gap:12px;}" +
|
|
183
|
-
".rbe-column-field{display:grid;gap:8px;}" +
|
|
184
|
-
".rbe-column-header{min-height:38px;border:1px solid #d7dee8;border-radius:8px;padding:9px 10px;font-weight:760;background:#eef5ff!important;outline:none;}" +
|
|
185
|
-
".rbe-column-header:focus,.rbe-column-editor:focus{border-color:#2563eb;box-shadow:0 0 0 3px rgba(37,99,235,.12);}" +
|
|
186
|
-
".rbe-column-header:empty:before{content:attr(data-placeholder);color:#98a2b3;font-weight:650;}" +
|
|
187
|
-
".rbe-column-editor{min-height:120px;border:1px solid #d7dee8;border-radius:8px;padding:10px;background:#fbfdff;outline:none;}" +
|
|
188
|
-
".rbe-column-editor:empty:before{content:attr(data-placeholder);color:#98a2b3;}" +
|
|
189
|
-
".rbe-output-columns{grid-template-columns:repeat(var(--rbe-columns,2),minmax(180px,1fr));overflow-x:auto;}" +
|
|
190
|
-
".rbe-output-column{border:1px solid #e2e8f0;border-radius:8px;padding:12px;background:#fff;}" +
|
|
191
|
-
".rbe-output-column-header{margin:-12px -12px 10px;padding:10px 12px;border-bottom:1px solid #e2e8f0;border-radius:8px 8px 0 0;background:#eef5ff;font-weight:760;text-align:left;}" +
|
|
192
|
-
".rbe-output-column-body{min-width:0;}" +
|
|
193
|
-
".rbe-image-stage.is-media-menu-open{min-width:176px;}" +
|
|
194
|
-
".rbe-image-transform-panel{position:absolute;left:50%;top:10px;z-index:4;transform:translateX(-50%);display:grid;grid-template-columns:repeat(3,30px);gap:5px;align-items:center;justify-content:center;max-width:calc(100% - 16px);opacity:0;pointer-events:none;transition:opacity .18s ease,transform .18s ease;}" +
|
|
195
|
-
".rbe-image-stage.is-media-menu-open>.rbe-image-transform-panel{opacity:1;pointer-events:auto;transform:translateX(-50%) translateY(0);}" +
|
|
196
|
-
".rbe-image-transform-panel .rbe-media-action{position:static;left:auto;top:auto;width:30px;height:30px;opacity:1;pointer-events:auto;transform:none;box-shadow:0 8px 18px rgba(15,23,42,.14);}" +
|
|
197
|
-
".rbe-image-transform.is-active{background:#2563eb;color:#fff;}" +
|
|
198
|
-
"@media (max-width:900px){.rbe-plugin-toolbar input,.rbe-plugin-toolbar select,.rbe-plugin-card textarea{min-width:0;max-width:100%;}.rbe-chart-preview svg,.rbe-output-chart svg{max-height:260px;}.rbe-mermaid-modal{padding:10px;}.rbe-mermaid-dialog{border-radius:10px;}.rbe-mermaid-modal .rbe-mermaid-toolbar{overflow-x:auto;align-content:flex-start;}.rbe-mermaid-popover{max-width:calc(100vw - 28px);max-height:62dvh;overflow:auto;}.rbe-mermaid-submenu{max-width:calc(100vw - 44px);max-height:58dvh;overflow:auto;}.rbe-output-mermaid-diagram{max-height:60dvh;}.rbe-columns-grid{grid-template-columns:1fr!important;}.rbe-output-columns{grid-template-columns:1fr!important;}}" +
|
|
199
|
-
"@media (max-width:640px){.rbe-plugin-card{padding:10px;gap:10px;}.rbe-plugin-toolbar{display:grid;grid-template-columns:1fr;align-items:stretch;}.rbe-plugin-toolbar label{width:100%;justify-content:space-between;}.rbe-plugin-toolbar input,.rbe-plugin-toolbar select{width:100%;}.rbe-chart-type-bar{top:auto;bottom:10px;transform:translate(-50%,0) scale(.96);}.rbe-chart-preview-wrap:hover .rbe-chart-type-bar,.rbe-chart-type-bar:focus-within{transform:translate(-50%,0) scale(1);}.rbe-chart-slice-chip{width:100%;justify-content:space-between;}.rbe-latex-preview,.rbe-output-latex{font-size:18px;}.rbe-mermaid-modal{padding:0;}.rbe-mermaid-dialog{border-radius:0;}.rbe-mermaid-modal-head,.rbe-mermaid-modal-foot{padding:10px 12px;}.rbe-mermaid-modal-foot{flex-wrap:wrap;}.rbe-mermaid-modal-save,.rbe-mermaid-modal-cancel{flex:1 1 140px;}.rbe-mermaid-modal .rbe-mermaid-toolbar{gap:5px;padding:7px 8px;}.rbe-mermaid-tool,.rbe-mermaid-icon-btn,.rbe-mermaid-menu-btn{width:32px;height:32px;}.rbe-mermaid-stage-shell{grid-template-columns:22px minmax(0,1fr);grid-template-rows:22px minmax(0,1fr);}.rbe-mermaid-choice-grid{grid-template-columns:repeat(6,22px);}.rbe-mermaid-submenu{left:0;top:calc(100% + 6px);}.rbe-mermaid-stage{min-height:280px;}.rbe-mermaid-card-preview{min-height:140px;padding:8px;}.rbe-audio-card audio,.rbe-output-audio audio{width:100%;}.rbe-drawing-canvas{height:220px;}.rbe-image-transform-panel{grid-template-columns:repeat(3,28px);gap:4px;}.rbe-image-transform-panel .rbe-media-action{width:28px;height:28px;}.rbe-image-stage.is-media-menu-open{min-width:min(176px,100%);}}" +
|
|
200
|
-
"@media (max-width:900px){.rbe-mermaid-card,.rbe-mermaid-card-preview{min-width:0;max-width:100%;}.rbe-mermaid-card-preview .rbe-output-mermaid-diagram{width:100%;max-width:100%;}.rbe-mermaid-modal{overflow:hidden;}.rbe-mermaid-dialog{width:100%;max-width:100%;height:calc(100dvh - 20px);max-height:calc(100dvh - 20px);}.rbe-mermaid-stage-shell{width:100%;min-width:0;overflow:hidden;}.rbe-mermaid-modal .rbe-mermaid-stage{width:100%;min-width:0;overflow:auto;}.rbe-mermaid-modal .rbe-mermaid-block{min-width:0;}.rbe-mermaid-card-preview .rbe-output-mermaid-diagram svg{max-width:100%;}}" +
|
|
201
|
-
"@media (max-width:640px){.rbe-mermaid-card{padding:10px;min-height:180px;}.rbe-mermaid-card-preview{width:100%;max-width:100%;overflow:auto;}.rbe-mermaid-card-preview .rbe-output-mermaid-diagram{max-height:340px;overflow:hidden;}.rbe-mermaid-card-preview .rbe-output-mermaid-diagram svg{width:100%!important;min-width:0!important;max-width:100%;height:auto!important;}.rbe-mermaid-dialog{height:100dvh;max-height:100dvh;}.rbe-mermaid-modal-body{min-height:0;overflow:hidden;}.rbe-mermaid-modal .rbe-mermaid-toolbar{max-width:100%;overflow-x:auto;overflow-y:hidden;white-space:nowrap;}.rbe-mermaid-stage-shell{width:100%;min-width:0;overflow:hidden;}.rbe-mermaid-modal .rbe-mermaid-stage{width:100%;min-width:0;overflow:auto;}.rbe-mermaid-top-ruler{min-width:0;}.rbe-mermaid-canvas{min-width:100%;}.rbe-mermaid-toolbar-sep{display:none;}}" +
|
|
202
|
-
".rbe-mermaid-modal .rbe-mermaid-dialog{min-width:0;}" +
|
|
203
|
-
".rbe-mermaid-modal .rbe-mermaid-modal-body{display:grid;min-height:0;}" +
|
|
204
|
-
".rbe-mermaid-modal .rbe-mermaid-block{min-width:0;min-height:0;overflow:hidden;}" +
|
|
205
|
-
".rbe-mermaid-modal .rbe-mermaid-stage-shell{min-width:0;min-height:0;}" +
|
|
206
|
-
".rbe-mermaid-modal .rbe-mermaid-stage{overscroll-behavior:contain;-webkit-overflow-scrolling:touch;}" +
|
|
207
|
-
"@media (max-width:900px){.rbe-mermaid-modal{height:100dvh;max-height:100dvh;padding:8px;overflow:hidden;}.rbe-mermaid-dialog{width:100%;height:100%;max-height:100%;}.rbe-mermaid-modal-body{overflow:hidden;}.rbe-mermaid-modal .rbe-mermaid-block{grid-template-rows:auto minmax(0,1fr);}.rbe-mermaid-modal .rbe-mermaid-toolbar{flex-wrap:nowrap;align-items:center;max-width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:thin;}.rbe-mermaid-modal .rbe-mermaid-toolbar::-webkit-scrollbar{height:6px;}.rbe-mermaid-modal .rbe-mermaid-toolbar::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:999px;}.rbe-mermaid-modal .rbe-mermaid-stylebar{flex:0 0 auto;flex-wrap:nowrap;min-width:max-content;}.rbe-mermaid-modal .rbe-mermaid-popover{position:fixed;left:12px!important;right:12px;top:98px;width:auto;min-width:0;max-width:none;max-height:calc(100dvh - 180px);overflow:auto;}.rbe-mermaid-modal .rbe-mermaid-stage-shell{height:100%;}.rbe-mermaid-modal .rbe-mermaid-stage{height:100%;min-height:0;max-height:none;}.rbe-mermaid-modal .rbe-mermaid-canvas{max-width:none;max-height:none;}}" +
|
|
208
|
-
"@media (max-width:640px){.rbe-mermaid-modal{padding:0;}.rbe-mermaid-dialog{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;}.rbe-mermaid-modal-head{min-height:46px;padding:7px 10px;}.rbe-mermaid-modal-foot{display:flex;justify-content:center;align-items:center;width:100%;max-width:100%;min-height:56px;padding:8px 10px;background:#fff;overflow:hidden;}.rbe-mermaid-modal-save,.rbe-mermaid-modal-cancel{flex:0 0 auto;width:auto;min-width:112px;min-height:40px;white-space:nowrap;font-size:13px;}.rbe-mermaid-modal .rbe-mermaid-toolbar{gap:5px;padding:7px 8px;}.rbe-mermaid-modal .rbe-mermaid-stage-shell{grid-template-columns:20px minmax(0,1fr);grid-template-rows:22px minmax(0,1fr);}.rbe-mermaid-modal .rbe-mermaid-top-ruler span,.rbe-mermaid-modal .rbe-mermaid-side-ruler span{font-size:10px;}.rbe-mermaid-modal .rbe-mermaid-side-ruler span{left:5px;}.rbe-mermaid-modal .rbe-mermaid-popover{left:8px!important;right:8px;top:86px;max-height:calc(100dvh - 154px);}.rbe-mermaid-modal .rbe-mermaid-submenu{max-width:calc(100vw - 28px);}}" +
|
|
209
|
-
"@media (max-width:520px){.rbe-mermaid-modal .rbe-mermaid-popover{padding:6px;}.rbe-mermaid-modal .rbe-mermaid-menu-row{position:static;flex-wrap:wrap;white-space:normal;}.rbe-mermaid-modal .rbe-mermaid-menu-row:after{content:'';}.rbe-mermaid-modal .rbe-mermaid-menu-row>.rbe-mermaid-submenu{position:static;flex:1 1 100%;min-width:0;max-width:100%;margin-top:6px;border-radius:7px;box-shadow:none;}.rbe-mermaid-modal .rbe-mermaid-choice-grid{grid-template-columns:repeat(auto-fill,minmax(22px,1fr));}.rbe-mermaid-modal .rbe-mermaid-line-choice{font-size:13px;padding:7px;}}" +
|
|
210
|
-
"@media (max-width:420px){.rbe-mermaid-modal-title{font-size:15px;}.rbe-mermaid-modal-head{padding:7px 9px;}.rbe-mermaid-choice-grid{grid-template-columns:repeat(auto-fill,minmax(22px,1fr));}.rbe-mermaid-popover{max-width:calc(100vw - 16px);}.rbe-mermaid-submenu{max-width:calc(100vw - 24px);}.rbe-mermaid-modal .rbe-mermaid-tool,.rbe-mermaid-modal .rbe-mermaid-icon-btn,.rbe-mermaid-modal .rbe-mermaid-menu-btn{width:31px;height:31px;}.rbe-mermaid-modal .rbe-mermaid-stage-shell{grid-template-columns:18px minmax(0,1fr);grid-template-rows:20px minmax(0,1fr);}.rbe-mermaid-modal-foot{gap:8px;}.rbe-mermaid-modal-save,.rbe-mermaid-modal-cancel{min-width:104px;padding:8px 10px;}.rbe-mermaid-modal-save{font-size:0;}.rbe-mermaid-modal-save:after{content:'Save';font-size:13px;}}";
|
|
211
|
-
document.head.appendChild(style);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function numberList(value) {
|
|
215
|
-
return String(value || "")
|
|
216
|
-
.split(/[\s,]+/)
|
|
217
|
-
.map(function (item) { return Number(item); })
|
|
218
|
-
.filter(function (item) { return Number.isFinite(item); });
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function labelList(value) {
|
|
222
|
-
return String(value || "")
|
|
223
|
-
.split(",")
|
|
224
|
-
.map(function (item) { return item.trim(); })
|
|
225
|
-
.filter(Boolean);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
var DEFAULT_CHART_COLORS = ["#2563eb", "#16a34a", "#f59e0b", "#dc2626", "#7c3aed", "#0891b2", "#db2777", "#65a30d"];
|
|
229
|
-
|
|
230
|
-
function normalizeChartColor(value, fallback) {
|
|
231
|
-
value = String(value || "").trim();
|
|
232
|
-
return /^#[0-9a-f]{3}([0-9a-f]{3})?$/i.test(value) ? value : fallback;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function chartColorList(value, count) {
|
|
236
|
-
var colors = String(value || "")
|
|
237
|
-
.split(",")
|
|
238
|
-
.map(function (item, index) { return normalizeChartColor(item, DEFAULT_CHART_COLORS[index % DEFAULT_CHART_COLORS.length]); })
|
|
239
|
-
.filter(Boolean);
|
|
240
|
-
while (colors.length < count) colors.push(DEFAULT_CHART_COLORS[colors.length % DEFAULT_CHART_COLORS.length]);
|
|
241
|
-
return colors.slice(0, count);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function chartValueLabel(value) {
|
|
245
|
-
if (!Number.isFinite(value)) return "0";
|
|
246
|
-
return String(Math.round(value * 100) / 100);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function chartTickValues(max) {
|
|
250
|
-
var steps = 4;
|
|
251
|
-
var ticks = [];
|
|
252
|
-
for (var index = 0; index <= steps; index += 1) {
|
|
253
|
-
ticks.push((max / steps) * index);
|
|
254
|
-
}
|
|
255
|
-
return ticks;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function chartSvg(data) {
|
|
259
|
-
var type = data.type === "line" || data.type === "pie" ? data.type : "bar";
|
|
260
|
-
var labels = labelList(data.labels || "Q1,Q2,Q3,Q4");
|
|
261
|
-
var values = numberList(data.values || "12,19,7,14");
|
|
262
|
-
if (!values.length) values = [12, 19, 7, 14];
|
|
263
|
-
var count = Math.max(labels.length, values.length);
|
|
264
|
-
for (var fillIndex = 0; fillIndex < count; fillIndex += 1) {
|
|
265
|
-
if (!labels[fillIndex]) labels[fillIndex] = "Item " + (fillIndex + 1);
|
|
266
|
-
if (!Number.isFinite(values[fillIndex])) values[fillIndex] = 0;
|
|
267
|
-
}
|
|
268
|
-
var color = data.color || "#2563eb";
|
|
269
|
-
var max = Math.max.apply(null, values.map(function (value) { return Math.max(0, value); }).concat([1]));
|
|
270
|
-
var width = 640;
|
|
271
|
-
var height = 300;
|
|
272
|
-
if (type === "pie") {
|
|
273
|
-
var total = values.reduce(function (sum, item) { return sum + Math.max(0, item); }, 0) || 1;
|
|
274
|
-
var start = -Math.PI / 2;
|
|
275
|
-
var colors = chartColorList(data.colors, values.length);
|
|
276
|
-
var slices = values.map(function (value, index) {
|
|
277
|
-
var angle = (Math.max(0, value) / total) * Math.PI * 2;
|
|
278
|
-
var end = start + angle;
|
|
279
|
-
var mid = start + angle / 2;
|
|
280
|
-
var x1 = 320 + Math.cos(start) * 105;
|
|
281
|
-
var y1 = 145 + Math.sin(start) * 105;
|
|
282
|
-
var x2 = 320 + Math.cos(end) * 105;
|
|
283
|
-
var y2 = 145 + Math.sin(end) * 105;
|
|
284
|
-
var labelX = 320 + Math.cos(mid) * 64;
|
|
285
|
-
var labelY = 145 + Math.sin(mid) * 64;
|
|
286
|
-
var large = angle > Math.PI ? 1 : 0;
|
|
287
|
-
var path = "M320 145 L" + x1 + " " + y1 + " A105 105 0 " + large + " 1 " + x2 + " " + y2 + " Z";
|
|
288
|
-
start = end;
|
|
289
|
-
return '<g><path d="' + path + '" fill="' + esc(colors[index % colors.length]) + '"><title>' + esc((labels[index] || "") + ": " + value) + '</title></path>' + (value > 0 ? '<text x="' + labelX + '" y="' + labelY + '" text-anchor="middle" dominant-baseline="central" fill="#fff" stroke="#0f172a" stroke-opacity=".35" stroke-width="3" paint-order="stroke fill" font-size="15" font-weight="800">' + esc(chartValueLabel(value)) + "</text>" : "") + "</g>";
|
|
290
|
-
}).join("");
|
|
291
|
-
return '<svg viewBox="0 0 640 300" role="img" aria-label="' + esc(data.title || "Pie chart") + '">' + slices + "</svg>";
|
|
292
|
-
}
|
|
293
|
-
var padLeft = 58;
|
|
294
|
-
var padRight = 28;
|
|
295
|
-
var padTop = 30;
|
|
296
|
-
var padBottom = 48;
|
|
297
|
-
var plotWidth = width - padLeft - padRight;
|
|
298
|
-
var plotHeight = height - padTop - padBottom;
|
|
299
|
-
var axisBottom = height - padBottom;
|
|
300
|
-
var step = plotWidth / values.length;
|
|
301
|
-
var yFor = function (value) {
|
|
302
|
-
return axisBottom - (Math.max(0, value) / max) * plotHeight;
|
|
303
|
-
};
|
|
304
|
-
var points = values.map(function (value, index) {
|
|
305
|
-
var x = padLeft + step * index + step / 2;
|
|
306
|
-
var y = yFor(value);
|
|
307
|
-
return [x, y];
|
|
308
|
-
});
|
|
309
|
-
var axis =
|
|
310
|
-
'<path d="M' + padLeft + " " + axisBottom + "H" + (width - padRight) + "M" + padLeft + " " + padTop + "V" + axisBottom + '" stroke="#cbd5e1" fill="none"/>' +
|
|
311
|
-
chartTickValues(max).map(function (tick) {
|
|
312
|
-
var y = yFor(tick);
|
|
313
|
-
return '<g><path d="M' + padLeft + " " + y + "H" + (width - padRight) + '" stroke="#e8eef6" fill="none"/><text x="' + (padLeft - 10) + '" y="' + (y + 4) + '" text-anchor="end" font-size="12" fill="#64748b">' + esc(chartValueLabel(tick)) + "</text></g>";
|
|
314
|
-
}).join("") +
|
|
315
|
-
labels.map(function (label, index) {
|
|
316
|
-
var x = padLeft + step * index + step / 2;
|
|
317
|
-
return '<text x="' + x + '" y="' + (height - 18) + '" text-anchor="middle" font-size="12" fill="#64748b">' + esc(label) + "</text>";
|
|
318
|
-
}).join("");
|
|
319
|
-
if (type === "line") {
|
|
320
|
-
return '<svg viewBox="0 0 640 300" role="img" aria-label="' + esc(data.title || "Line chart") + '">' + axis + '<polyline points="' + points.map(function (point) { return point.join(","); }).join(" ") + '" fill="none" stroke="' + esc(normalizeChartColor(color, "#2563eb")) + '" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>' + points.map(function (point, index) { return '<g><circle cx="' + point[0] + '" cy="' + point[1] + '" r="5" fill="' + esc(normalizeChartColor(color, "#2563eb")) + '"><title>' + esc((labels[index] || "") + ": " + values[index]) + '</title></circle><text x="' + point[0] + '" y="' + (point[1] - 10) + '" text-anchor="middle" font-size="12" fill="#344054" font-weight="700">' + esc(chartValueLabel(values[index])) + "</text></g>"; }).join("") + "</svg>";
|
|
321
|
-
}
|
|
322
|
-
return '<svg viewBox="0 0 640 300" role="img" aria-label="' + esc(data.title || "Bar chart") + '">' + axis + values.map(function (value, index) {
|
|
323
|
-
var barHeight = (Math.max(0, value) / max) * plotHeight;
|
|
324
|
-
var x = padLeft + step * index + step * 0.18;
|
|
325
|
-
var y = axisBottom - barHeight;
|
|
326
|
-
var barWidth = step * 0.64;
|
|
327
|
-
var centerY = y + barHeight / 2 + 5;
|
|
328
|
-
return '<g><rect x="' + x + '" y="' + y + '" width="' + barWidth + '" height="' + barHeight + '" rx="5" fill="' + esc(normalizeChartColor(color, "#2563eb")) + '"><title>' + esc((labels[index] || "") + ": " + value) + '</title></rect><text x="' + (x + barWidth / 2) + '" y="' + centerY + '" text-anchor="middle" font-size="13" fill="#fff" stroke="#0f172a" stroke-opacity=".25" stroke-width="2" paint-order="stroke fill" font-weight="800">' + esc(chartValueLabel(value)) + "</text></g>";
|
|
329
|
-
}).join("") + "</svg>";
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function loadScriptOnce(src, key, callback) {
|
|
333
|
-
var existing = document.querySelector("script[data-blockwriteai-lib='" + key + "']");
|
|
334
|
-
if (existing) {
|
|
335
|
-
if (existing.dataset.loaded === "true") callback();
|
|
336
|
-
else existing.addEventListener("load", callback, { once: true });
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
var script = document.createElement("script");
|
|
340
|
-
script.src = src;
|
|
341
|
-
script.dataset.blockwriteaiLib = key;
|
|
342
|
-
script.onload = function () {
|
|
343
|
-
script.dataset.loaded = "true";
|
|
344
|
-
callback();
|
|
345
|
-
};
|
|
346
|
-
script.onerror = callback;
|
|
347
|
-
document.head.appendChild(script);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function loadStyleOnce(href, key) {
|
|
351
|
-
if (document.querySelector("link[data-blockwriteai-lib='" + key + "']")) return;
|
|
352
|
-
var link = document.createElement("link");
|
|
353
|
-
link.rel = "stylesheet";
|
|
354
|
-
link.href = href;
|
|
355
|
-
link.dataset.blockwriteaiLib = key;
|
|
356
|
-
document.head.appendChild(link);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function renderMermaidPreview(target, code) {
|
|
360
|
-
target.innerHTML = '<pre>' + esc(code || "") + "</pre>";
|
|
361
|
-
if (!code || !code.trim()) return;
|
|
362
|
-
loadScriptOnce("https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js", "mermaid", function () {
|
|
363
|
-
if (!global.mermaid) return;
|
|
364
|
-
try {
|
|
365
|
-
global.mermaid.initialize({ startOnLoad: false, securityLevel: "strict" });
|
|
366
|
-
var render = function () {
|
|
367
|
-
global.mermaid.render("rbe-mermaid-" + Math.random().toString(36).slice(2), code).then(function (result) {
|
|
368
|
-
target.innerHTML = result.svg;
|
|
369
|
-
}).catch(function () {
|
|
370
|
-
target.innerHTML = '<pre class="rbe-output-mermaid-error">' + esc(code || "") + "</pre>";
|
|
371
|
-
});
|
|
372
|
-
};
|
|
373
|
-
if (global.mermaid.parse) {
|
|
374
|
-
Promise.resolve(global.mermaid.parse(code)).then(render).catch(function () {
|
|
375
|
-
target.innerHTML = '<pre class="rbe-output-mermaid-error">' + esc(code || "") + "</pre>";
|
|
376
|
-
});
|
|
377
|
-
} else {
|
|
378
|
-
render();
|
|
379
|
-
}
|
|
380
|
-
} catch (error) {}
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function latexFallbackHTML(code) {
|
|
385
|
-
var html = esc(code || "");
|
|
386
|
-
html = html
|
|
387
|
-
.replace(/\\int/g, "∫")
|
|
388
|
-
.replace(/\\sum/g, "∑")
|
|
389
|
-
.replace(/\\sqrt\{([^}]*)\}/g, "√<span style=\"text-decoration:overline\">$1</span>")
|
|
390
|
-
.replace(/\\frac\{([^}]*)\}\{([^}]*)\}/g, '<span class="rbe-latex-frac"><span>$1</span><span>$2</span></span>')
|
|
391
|
-
.replace(/\^\{([^}]*)\}/g, "<sup>$1</sup>")
|
|
392
|
-
.replace(/\^([A-Za-z0-9+\-=]+)/g, "<sup>$1</sup>")
|
|
393
|
-
.replace(/_\{([^}]*)\}/g, "<sub>$1</sub>")
|
|
394
|
-
.replace(/_([A-Za-z0-9+\-=]+)/g, "<sub>$1</sub>")
|
|
395
|
-
.replace(/\\,/g, " ")
|
|
396
|
-
.replace(/\\ /g, " ");
|
|
397
|
-
return html;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
function renderLatexPreview(target, code, displayMode) {
|
|
401
|
-
target.innerHTML = latexFallbackHTML(code || "");
|
|
402
|
-
if (!code || !code.trim()) return;
|
|
403
|
-
loadStyleOnce("https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css", "katex-css");
|
|
404
|
-
loadScriptOnce("https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js", "katex", function () {
|
|
405
|
-
if (!global.katex) return;
|
|
406
|
-
try {
|
|
407
|
-
global.katex.render(code, target, { throwOnError: false, displayMode: !!displayMode });
|
|
408
|
-
} catch (error) {}
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
var DIAGRAM_LINE_TYPES = /^(line|arrow|leftArrow|rightArrow|upArrow|downArrow|biArrow|elbow|curved|curve|polyline|scribble)$/;
|
|
413
|
-
var DIAGRAM_SHAPE_TYPES = /^(rect|roundedRect|circle|oval|triangle|diamond|pentagon|hexagon|parallelogram|trapezoid|octagon|heart|cloud|cylinder|cube|callout|roundCallout|thought|plus|minus|multiply|divide|equal|brackets|text|wordart|image)$/;
|
|
414
|
-
|
|
415
|
-
function defaultMermaidWorkspace() {
|
|
416
|
-
return { width: 1100, height: 620, zoom: 1 };
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
var MERMAID_WORKSPACE_MAX = 6000;
|
|
420
|
-
var MERMAID_WORKSPACE_GROW_PADDING = 260;
|
|
421
|
-
var MERMAID_WORKSPACE_GROW_STEP = 240;
|
|
422
|
-
|
|
423
|
-
function defaultMermaidDiagram() {
|
|
424
|
-
return [
|
|
425
|
-
{ id: "shape-start", type: "roundedRect", x: 120, y: 140, w: 170, h: 76, text: "Start", fill: "#eef5ff", stroke: "#111827", fontSize: 16, strokeWidth: 1 },
|
|
426
|
-
{ id: "shape-blockwriteai", type: "roundedRect", x: 560, y: 140, w: 190, h: 76, text: "BlockWriteAI", fill: "#ecfdf3", stroke: "#111827", fontSize: 16, strokeWidth: 1 },
|
|
427
|
-
{ id: "line-main", type: "arrow", x1: 290, y1: 178, x2: 560, y2: 178, stroke: "#475467", strokeWidth: 1 }
|
|
428
|
-
];
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
function simpleMermaidToDiagram(code) {
|
|
432
|
-
var match = String(code || "").match(/([A-Za-z0-9_]+)\[([^\]]+)\]\s*-+>\s*([A-Za-z0-9_]+)\[([^\]]+)\]/);
|
|
433
|
-
if (!match) return null;
|
|
434
|
-
return [
|
|
435
|
-
{ id: "shape-" + match[1], type: "roundedRect", x: 120, y: 140, w: 170, h: 76, text: match[2], fill: "#eef5ff", stroke: "#111827", fontSize: 16, strokeWidth: 1 },
|
|
436
|
-
{ id: "shape-" + match[3], type: "roundedRect", x: 560, y: 140, w: 190, h: 76, text: match[4], fill: "#ecfdf3", stroke: "#111827", fontSize: 16, strokeWidth: 1 },
|
|
437
|
-
{ id: "line-" + match[1] + "-" + match[3], type: "arrow", x1: 290, y1: 178, x2: 560, y2: 178, stroke: "#475467", strokeWidth: 1 }
|
|
438
|
-
];
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
function isLineType(type) {
|
|
442
|
-
return DIAGRAM_LINE_TYPES.test(type || "");
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
function isTextDiagramType(type) {
|
|
446
|
-
return type === "text" || type === "wordart";
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
function clampNumber(value, min, max, fallback) {
|
|
450
|
-
value = Number(value);
|
|
451
|
-
if (!Number.isFinite(value)) value = fallback;
|
|
452
|
-
return Math.min(max, Math.max(min, value));
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
function normalizeDiagramWorkspace(data) {
|
|
456
|
-
var workspace = data && data.diagram && data.diagram.workspace ? data.diagram.workspace : data && data.workspace ? data.workspace : {};
|
|
457
|
-
return {
|
|
458
|
-
width: clampNumber(workspace.width, 640, MERMAID_WORKSPACE_MAX, 1100),
|
|
459
|
-
height: clampNumber(workspace.height, 360, MERMAID_WORKSPACE_MAX, 620),
|
|
460
|
-
zoom: clampNumber(workspace.zoom, 0.35, 2.5, 1)
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
function normalizeDiagramDash(value) {
|
|
465
|
-
return value === "dotted" || value === "dashed" || value === "longDash" || value === "dashDot" ? value : "solid";
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
function dashArray(value) {
|
|
469
|
-
value = normalizeDiagramDash(value);
|
|
470
|
-
if (value === "dotted") return "2 8";
|
|
471
|
-
if (value === "dashed") return "10 8";
|
|
472
|
-
if (value === "longDash") return "18 10";
|
|
473
|
-
if (value === "dashDot") return "14 7 2 7";
|
|
474
|
-
return "";
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function normalizeDiagramLineHeight(value) {
|
|
478
|
-
value = Number(value);
|
|
479
|
-
if (!Number.isFinite(value)) value = 1.25;
|
|
480
|
-
return clampNumber(value, 1, 2.5, 1.25);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
function normalizeDiagramListType(value) {
|
|
484
|
-
return value === "bullet" || value === "number" ? value : "none";
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
function normalizeDiagramListStyle(type, value) {
|
|
488
|
-
if (type === "bullet") {
|
|
489
|
-
return value === "circle" || value === "square" || value === "none" ? value : "disc";
|
|
490
|
-
}
|
|
491
|
-
if (type === "number") {
|
|
492
|
-
return value === "lower-alpha" || value === "upper-alpha" || value === "lower-roman" || value === "upper-roman" || value === "none" ? value : "decimal";
|
|
493
|
-
}
|
|
494
|
-
return "none";
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
function normalizeDiagramElement(item, index) {
|
|
498
|
-
item = item || {};
|
|
499
|
-
var type = DIAGRAM_SHAPE_TYPES.test(item.type) || DIAGRAM_LINE_TYPES.test(item.type) ? item.type : "roundedRect";
|
|
500
|
-
var isLine = isLineType(type);
|
|
501
|
-
var text = item.text || "";
|
|
502
|
-
if (!text && type === "wordart") text = "WordArt";
|
|
503
|
-
if (!text && /^(plus|minus|multiply|divide|equal|brackets)$/.test(type)) {
|
|
504
|
-
text = { plus: "+", minus: "-", multiply: "x", divide: "/", equal: "=", brackets: "[ ]" }[type] || "";
|
|
505
|
-
}
|
|
506
|
-
var fillValue = String(item.fill || "").trim();
|
|
507
|
-
var fillFallback = type === "wordart" ? "#f59e0b" : type === "text" ? "transparent" : "#eef5ff";
|
|
508
|
-
return {
|
|
509
|
-
id: item.id || "diagram-" + index + "-" + Math.random().toString(36).slice(2),
|
|
510
|
-
type: type,
|
|
511
|
-
x: clampNumber(item.x, -500, 4000, 80),
|
|
512
|
-
y: clampNumber(item.y, -500, 4000, 80),
|
|
513
|
-
w: clampNumber(item.w, 20, 2000, isTextDiagramType(type) ? 180 : 150),
|
|
514
|
-
h: clampNumber(item.h, 20, 2000, isTextDiagramType(type) ? 70 : 80),
|
|
515
|
-
x1: clampNumber(item.x1 == null ? item.x : item.x1, -500, 4000, 80),
|
|
516
|
-
y1: clampNumber(item.y1 == null ? item.y : item.y1, -500, 4000, 80),
|
|
517
|
-
x2: clampNumber(item.x2 == null ? Number(item.x || 80) + 160 : item.x2, -500, 4000, 240),
|
|
518
|
-
y2: clampNumber(item.y2 == null ? item.y : item.y2, -500, 4000, 80),
|
|
519
|
-
text: text,
|
|
520
|
-
fill: isLine ? "transparent" : fillValue === "transparent" ? "transparent" : normalizeChartColor(fillValue, fillFallback),
|
|
521
|
-
stroke: normalizeChartColor(item.stroke, isLine ? "#475467" : "#111827"),
|
|
522
|
-
strokeWidth: clampNumber(item.strokeWidth, 1, 16, 1),
|
|
523
|
-
dash: normalizeDiagramDash(item.dash),
|
|
524
|
-
opacity: clampNumber(item.opacity, 0.1, 1, 1),
|
|
525
|
-
fontFamily: item.fontFamily || "Arial",
|
|
526
|
-
fontSize: clampNumber(item.fontSize, 8, 96, type === "wordart" ? 36 : 16),
|
|
527
|
-
bold: !!item.bold || type === "wordart",
|
|
528
|
-
italic: !!item.italic,
|
|
529
|
-
underline: !!item.underline,
|
|
530
|
-
textColor: normalizeChartColor(item.textColor, "#172033"),
|
|
531
|
-
highlightColor: String(item.highlightColor || "").trim() === "transparent" ? "transparent" : normalizeChartColor(item.highlightColor, "transparent"),
|
|
532
|
-
textAlign: item.textAlign === "left" || item.textAlign === "right" || item.textAlign === "justify" ? item.textAlign : "center",
|
|
533
|
-
lineHeight: normalizeDiagramLineHeight(item.lineHeight),
|
|
534
|
-
spacingBefore: clampNumber(item.spacingBefore, 0, 48, 0),
|
|
535
|
-
spacingAfter: clampNumber(item.spacingAfter, 0, 48, 0),
|
|
536
|
-
indent: clampNumber(item.indent, 0, 8, 0),
|
|
537
|
-
listType: normalizeDiagramListType(item.listType),
|
|
538
|
-
listStyle: normalizeDiagramListStyle(normalizeDiagramListType(item.listType), item.listStyle),
|
|
539
|
-
rotation: clampNumber(item.rotation, -360, 360, 0),
|
|
540
|
-
group: item.group || "",
|
|
541
|
-
flipX: !!item.flipX,
|
|
542
|
-
flipY: !!item.flipY,
|
|
543
|
-
image: item.image || "",
|
|
544
|
-
name: item.name || ""
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
function diagramElements(data) {
|
|
549
|
-
var source = data && data.diagram && Array.isArray(data.diagram.elements) ? data.diagram.elements : Array.isArray(data && data.diagram) ? data.diagram : null;
|
|
550
|
-
if (!source && data && data.code) source = simpleMermaidToDiagram(data.code);
|
|
551
|
-
return (source ? source : defaultMermaidDiagram()).map(normalizeDiagramElement);
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
function selectedIdList(selectedIds) {
|
|
555
|
-
return String(selectedIds || "").split(",").map(function (id) { return id.trim(); }).filter(Boolean);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
function polygonPoints(cx, cy, rx, ry, count, startAngle) {
|
|
559
|
-
var points = [];
|
|
560
|
-
for (var i = 0; i < count; i += 1) {
|
|
561
|
-
var angle = (startAngle || -Math.PI / 2) + (i / count) * Math.PI * 2;
|
|
562
|
-
points.push((cx + Math.cos(angle) * rx) + "," + (cy + Math.sin(angle) * ry));
|
|
563
|
-
}
|
|
564
|
-
return points.join(" ");
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
function shapeMarkup(elm) {
|
|
568
|
-
var x = elm.x;
|
|
569
|
-
var y = elm.y;
|
|
570
|
-
var w = elm.w;
|
|
571
|
-
var h = elm.h;
|
|
572
|
-
var cx = x + w / 2;
|
|
573
|
-
var cy = y + h / 2;
|
|
574
|
-
var fill = esc(elm.fill);
|
|
575
|
-
var stroke = esc(elm.stroke);
|
|
576
|
-
var sw = esc(elm.strokeWidth);
|
|
577
|
-
var dash = dashArray(elm.dash);
|
|
578
|
-
var common = ' fill="' + fill + '" stroke="' + stroke + '" stroke-width="' + sw + '"' + (dash ? ' stroke-dasharray="' + dash + '"' : "") + ' opacity="' + esc(elm.opacity) + '"';
|
|
579
|
-
if (elm.type === "circle") return '<circle cx="' + cx + '" cy="' + cy + '" r="' + Math.min(w, h) / 2 + '"' + common + "></circle>";
|
|
580
|
-
if (elm.type === "oval") return '<ellipse cx="' + cx + '" cy="' + cy + '" rx="' + w / 2 + '" ry="' + h / 2 + '"' + common + "></ellipse>";
|
|
581
|
-
if (elm.type === "triangle") return '<polygon points="' + cx + "," + y + " " + (x + w) + "," + (y + h) + " " + x + "," + (y + h) + '"' + common + "></polygon>";
|
|
582
|
-
if (elm.type === "diamond") return '<polygon points="' + cx + "," + y + " " + (x + w) + "," + cy + " " + cx + "," + (y + h) + " " + x + "," + cy + '"' + common + "></polygon>";
|
|
583
|
-
if (elm.type === "pentagon") return '<polygon points="' + polygonPoints(cx, cy, w / 2, h / 2, 5) + '"' + common + "></polygon>";
|
|
584
|
-
if (elm.type === "hexagon") return '<polygon points="' + polygonPoints(cx, cy, w / 2, h / 2, 6, 0) + '"' + common + "></polygon>";
|
|
585
|
-
if (elm.type === "octagon") return '<polygon points="' + polygonPoints(cx, cy, w / 2, h / 2, 8, Math.PI / 8) + '"' + common + "></polygon>";
|
|
586
|
-
if (elm.type === "parallelogram") return '<polygon points="' + (x + w * .18) + "," + y + " " + (x + w) + "," + y + " " + (x + w * .82) + "," + (y + h) + " " + x + "," + (y + h) + '"' + common + "></polygon>";
|
|
587
|
-
if (elm.type === "trapezoid") return '<polygon points="' + (x + w * .18) + "," + y + " " + (x + w * .82) + "," + y + " " + (x + w) + "," + (y + h) + " " + x + "," + (y + h) + '"' + common + "></polygon>";
|
|
588
|
-
if (elm.type === "heart") return '<path d="M' + cx + " " + (y + h * .86) + " C" + (x - w * .1) + " " + (y + h * .35) + " " + (x + w * .12) + " " + y + " " + cx + " " + (y + h * .28) + " C" + (x + w * .88) + " " + y + " " + (x + w * 1.1) + " " + (y + h * .35) + " " + cx + " " + (y + h * .86) + ' Z"' + common + "></path>";
|
|
589
|
-
if (elm.type === "cloud") return '<path d="M' + (x + w * .22) + " " + (y + h * .72) + " C" + (x + w * .02) + " " + (y + h * .68) + " " + (x + w * .04) + " " + (y + h * .37) + " " + (x + w * .28) + " " + (y + h * .4) + " C" + (x + w * .34) + " " + (y + h * .12) + " " + (x + w * .68) + " " + (y + h * .1) + " " + (x + w * .74) + " " + (y + h * .38) + " C" + (x + w * 1.02) + " " + (y + h * .36) + " " + (x + w * 1.02) + " " + (y + h * .72) + " " + (x + w * .78) + " " + (y + h * .72) + ' Z"' + common + "></path>";
|
|
590
|
-
if (elm.type === "cylinder") return '<path d="M' + x + " " + (y + h * .18) + " C" + x + " " + y + " " + (x + w) + " " + y + " " + (x + w) + " " + (y + h * .18) + " V" + (y + h * .82) + " C" + (x + w) + " " + (y + h) + " " + x + " " + (y + h) + " " + x + " " + (y + h * .82) + ' Z"' + common + "></path>" + '<ellipse cx="' + cx + '" cy="' + (y + h * .18) + '" rx="' + w / 2 + '" ry="' + h * .18 + '"' + common + "></ellipse>";
|
|
591
|
-
if (elm.type === "cube") return '<path d="M' + x + " " + (y + h * .2) + " L" + (x + w * .2) + " " + y + " H" + (x + w) + " V" + (y + h * .8) + " L" + (x + w * .8) + " " + (y + h) + " H" + x + ' Z"' + common + "></path>" + '<path d="M' + (x + w * .2) + " " + y + " V" + (y + h * .8) + " H" + (x + w) + '" stroke="' + stroke + '" stroke-width="' + sw + '" fill="none" opacity="' + esc(elm.opacity) + '"></path>';
|
|
592
|
-
if (elm.type === "callout") return '<polygon points="' + x + "," + y + " " + (x + w) + "," + y + " " + (x + w) + "," + (y + h * .75) + " " + (x + w * .62) + "," + (y + h * .75) + " " + (x + w * .5) + "," + (y + h) + " " + (x + w * .38) + "," + (y + h * .75) + " " + x + "," + (y + h * .75) + '"' + common + "></polygon>";
|
|
593
|
-
if (elm.type === "roundCallout") return '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + (h * .78) + '" rx="18"' + common + "></rect>" + '<path d="M' + (x + w * .44) + " " + (y + h * .78) + " L" + (x + w * .5) + " " + (y + h) + " L" + (x + w * .58) + " " + (y + h * .78) + ' Z"' + common + "></path>";
|
|
594
|
-
if (elm.type === "thought") return '<ellipse cx="' + cx + '" cy="' + (y + h * .42) + '" rx="' + w / 2 + '" ry="' + h * .36 + '"' + common + "></ellipse>" + '<circle cx="' + (x + w * .62) + '" cy="' + (y + h * .82) + '" r="' + Math.min(w, h) * .08 + '"' + common + "></circle>" + '<circle cx="' + (x + w * .72) + '" cy="' + (y + h * .96) + '" r="' + Math.min(w, h) * .05 + '"' + common + "></circle>";
|
|
595
|
-
if (elm.type === "text") return '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" rx="4"' + common + "></rect>";
|
|
596
|
-
if (elm.type === "wordart") return '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" fill="transparent" stroke="transparent"></rect>';
|
|
597
|
-
if (elm.type === "image") return '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" rx="8" fill="#f8fafc" stroke="#d7dee8"></rect>' + (elm.image ? '<image href="' + esc(elm.image) + '" xlink:href="' + esc(elm.image) + '" x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" preserveAspectRatio="xMidYMid slice"></image>' : diagramText(elm));
|
|
598
|
-
return '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" rx="' + (elm.type === "roundedRect" ? 14 : 6) + '"' + common + "></rect>";
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
function diagramTextContent(elm) {
|
|
602
|
-
var lines = String(elm.text || "").split(/\r?\n/);
|
|
603
|
-
var highlight = elm.highlightColor && elm.highlightColor !== "transparent" ? 'background-color:' + esc(elm.highlightColor) + ";" : "";
|
|
604
|
-
var lineStyle = highlight ? ' style="' + highlight + 'box-decoration-break:clone;-webkit-box-decoration-break:clone;"' : "";
|
|
605
|
-
var items = lines.map(function (line) {
|
|
606
|
-
return '<span' + lineStyle + ">" + (line ? esc(line) : " ") + "</span>";
|
|
607
|
-
});
|
|
608
|
-
var listStyle = esc(normalizeDiagramListStyle(elm.listType, elm.listStyle));
|
|
609
|
-
if (elm.listType === "bullet") {
|
|
610
|
-
return '<ul style="margin:0;list-style-type:' + listStyle + ';padding-left:' + (18 + elm.indent * 18) + 'px;">' + items.map(function (item) { return "<li>" + item + "</li>"; }).join("") + "</ul>";
|
|
611
|
-
}
|
|
612
|
-
if (elm.listType === "number") {
|
|
613
|
-
return '<ol style="margin:0;list-style-type:' + listStyle + ';padding-left:' + (22 + elm.indent * 18) + 'px;">' + items.map(function (item) { return "<li>" + item + "</li>"; }).join("") + "</ol>";
|
|
614
|
-
}
|
|
615
|
-
return items.map(function (item, index) {
|
|
616
|
-
var margin = "margin:0;";
|
|
617
|
-
if (index === 0 && elm.spacingBefore) margin += "padding-top:" + esc(elm.spacingBefore) + "px;";
|
|
618
|
-
if (index === lines.length - 1 && elm.spacingAfter) margin += "padding-bottom:" + esc(elm.spacingAfter) + "px;";
|
|
619
|
-
return '<div style="' + margin + '">' + item + "</div>";
|
|
620
|
-
}).join("");
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
function diagramText(elm) {
|
|
624
|
-
if (!elm.text) return "";
|
|
625
|
-
if (elm.type === "wordart") {
|
|
626
|
-
var anchor = elm.textAlign === "left" ? "start" : elm.textAlign === "right" ? "end" : "middle";
|
|
627
|
-
var x = elm.textAlign === "left" ? elm.x + 12 : elm.textAlign === "right" ? elm.x + elm.w - 12 : elm.x + elm.w / 2;
|
|
628
|
-
var y = elm.y + elm.h / 2;
|
|
629
|
-
var decoration = elm.underline ? ' text-decoration="underline"' : "";
|
|
630
|
-
var stroke = ' stroke="' + esc(elm.stroke) + '" stroke-width="' + Math.max(1, elm.strokeWidth) + '" paint-order="stroke fill"';
|
|
631
|
-
return '<text x="' + x + '" y="' + y + '" text-anchor="' + anchor + '" dominant-baseline="middle" font-family="' + esc(elm.fontFamily) + ', Arial, sans-serif" font-size="' + esc(elm.fontSize) + '" font-weight="' + (elm.bold ? "800" : "400") + '" font-style="' + (elm.italic ? "italic" : "normal") + '"' + decoration + stroke + ' fill="' + esc(elm.textColor) + '">' + esc(elm.text || "") + "</text>";
|
|
632
|
-
}
|
|
633
|
-
var textBox = { x: elm.x, y: elm.y, w: elm.w, h: elm.h };
|
|
634
|
-
if (elm.type === "callout") textBox.h = elm.h * .72;
|
|
635
|
-
if (elm.type === "roundCallout") textBox.h = elm.h * .7;
|
|
636
|
-
if (elm.type === "thought") textBox.h = elm.h * .72;
|
|
637
|
-
var align = elm.textAlign || "center";
|
|
638
|
-
var justify = align === "left" ? "flex-start" : align === "right" ? "flex-end" : "center";
|
|
639
|
-
var decorationStyle = elm.underline ? "text-decoration:underline;" : "";
|
|
640
|
-
var contentStyle = "box-sizing:border-box;width:100%;height:100%;display:flex;align-items:center;justify-content:" + justify + ";overflow:hidden;padding:4px 8px 4px " + (8 + elm.indent * 10) + "px;color:" + esc(elm.textColor) + ";font-family:" + esc(elm.fontFamily) + ",Arial,sans-serif;font-size:" + esc(elm.fontSize) + "px;font-weight:" + (elm.bold ? "800" : "400") + ";font-style:" + (elm.italic ? "italic" : "normal") + ";" + decorationStyle + "text-align:" + esc(align) + ";line-height:" + esc(elm.lineHeight) + ";white-space:normal;overflow-wrap:anywhere;word-break:break-word;";
|
|
641
|
-
var innerStyle = "max-width:100%;";
|
|
642
|
-
if (align === "justify") innerStyle += "text-align:justify;";
|
|
643
|
-
return '<foreignObject class="rbe-mermaid-text-layer" x="' + esc(textBox.x) + '" y="' + esc(textBox.y) + '" width="' + esc(textBox.w) + '" height="' + esc(textBox.h) + '"><div xmlns="http://www.w3.org/1999/xhtml" style="' + contentStyle + '"><div style="' + innerStyle + '">' + diagramTextContent(elm) + "</div></div></foreignObject>";
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
function linePath(elm) {
|
|
647
|
-
if (elm.type === "elbow") return "M" + elm.x1 + " " + elm.y1 + " L" + elm.x2 + " " + elm.y1 + " L" + elm.x2 + " " + elm.y2;
|
|
648
|
-
if (elm.type === "curved" || elm.type === "curve") {
|
|
649
|
-
var midX = (elm.x1 + elm.x2) / 2;
|
|
650
|
-
return "M" + elm.x1 + " " + elm.y1 + " C" + midX + " " + elm.y1 + " " + midX + " " + elm.y2 + " " + elm.x2 + " " + elm.y2;
|
|
651
|
-
}
|
|
652
|
-
if (elm.type === "polyline") return "M" + elm.x1 + " " + elm.y1 + " L" + ((elm.x1 + elm.x2) / 2) + " " + (elm.y1 - 45) + " L" + elm.x2 + " " + elm.y2;
|
|
653
|
-
if (elm.type === "scribble") {
|
|
654
|
-
var d = "M" + elm.x1 + " " + elm.y1;
|
|
655
|
-
for (var i = 1; i <= 8; i += 1) {
|
|
656
|
-
var t = i / 8;
|
|
657
|
-
d += " L" + (elm.x1 + (elm.x2 - elm.x1) * t) + " " + (elm.y1 + (elm.y2 - elm.y1) * t + (i % 2 ? 8 : -8));
|
|
658
|
-
}
|
|
659
|
-
return d;
|
|
660
|
-
}
|
|
661
|
-
return "M" + elm.x1 + " " + elm.y1 + " L" + elm.x2 + " " + elm.y2;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
function elementBounds(elm) {
|
|
665
|
-
if (isLineType(elm.type)) {
|
|
666
|
-
return { x: Math.min(elm.x1, elm.x2), y: Math.min(elm.y1, elm.y2), w: Math.abs(elm.x2 - elm.x1), h: Math.abs(elm.y2 - elm.y1) };
|
|
667
|
-
}
|
|
668
|
-
return { x: elm.x, y: elm.y, w: elm.w, h: elm.h };
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
function rectsIntersect(a, b) {
|
|
672
|
-
return a.x <= b.x + b.w && a.x + a.w >= b.x && a.y <= b.y + b.h && a.y + a.h >= b.y;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
function selectionMarkup(elm, isSingle) {
|
|
676
|
-
var b = elementBounds(elm);
|
|
677
|
-
var markup = '<rect class="rbe-mermaid-selected-stroke" x="' + b.x + '" y="' + b.y + '" width="' + b.w + '" height="' + b.h + '" rx="6"></rect>';
|
|
678
|
-
var handleStyle = ' style="--rbe-handle-color:#2563eb"';
|
|
679
|
-
if (!isSingle || isLineType(elm.type)) {
|
|
680
|
-
if (isSingle && isLineType(elm.type)) {
|
|
681
|
-
markup += '<circle class="rbe-mermaid-handle" data-handle="start" cx="' + elm.x1 + '" cy="' + elm.y1 + '" r="5"' + handleStyle + '></circle><circle class="rbe-mermaid-handle" data-handle="end" cx="' + elm.x2 + '" cy="' + elm.y2 + '" r="5"' + handleStyle + '></circle>';
|
|
682
|
-
}
|
|
683
|
-
return markup;
|
|
684
|
-
}
|
|
685
|
-
[["nw", b.x, b.y], ["ne", b.x + b.w, b.y], ["se", b.x + b.w, b.y + b.h], ["sw", b.x, b.y + b.h]].forEach(function (handle) {
|
|
686
|
-
markup += '<circle class="rbe-mermaid-handle" data-handle="' + handle[0] + '" cx="' + handle[1] + '" cy="' + handle[2] + '" r="5"' + handleStyle + '></circle>';
|
|
687
|
-
});
|
|
688
|
-
[
|
|
689
|
-
["n", b.x + b.w / 2, b.y, 24, 6],
|
|
690
|
-
["e", b.x + b.w, b.y + b.h / 2, 6, 24],
|
|
691
|
-
["s", b.x + b.w / 2, b.y + b.h, 24, 6],
|
|
692
|
-
["w", b.x, b.y + b.h / 2, 6, 24]
|
|
693
|
-
].forEach(function (handle) {
|
|
694
|
-
markup += '<rect class="rbe-mermaid-handle" data-handle="' + handle[0] + '" x="' + (handle[1] - handle[3] / 2) + '" y="' + (handle[2] - handle[4] / 2) + '" width="' + handle[3] + '" height="' + handle[4] + '" rx="3"' + handleStyle + '></rect>';
|
|
695
|
-
});
|
|
696
|
-
var rotateX = b.x + b.w / 2;
|
|
697
|
-
var rotateY = b.y - 28;
|
|
698
|
-
markup += '<g class="rbe-mermaid-rotate" data-handle="rotate"><circle cx="' + rotateX + '" cy="' + rotateY + '" r="9"></circle><path d="M' + (rotateX + 2) + " " + (rotateY - 3) + " A4 4 0 1 0 " + (rotateX + 4) + " " + (rotateY + 2) + '" fill="none" stroke="#fff" stroke-width="1.6" stroke-linecap="round"></path><path d="M' + (rotateX + 3) + " " + (rotateY - 6) + " L" + (rotateX + 7) + " " + (rotateY - 3) + " L" + (rotateX + 3) + " " + rotateY + ' Z" fill="#fff"></path></g>';
|
|
699
|
-
return markup;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
function diagramSvg(elements, selectedIds, workspace, marquee) {
|
|
703
|
-
elements = (elements || []).map(normalizeDiagramElement);
|
|
704
|
-
workspace = workspace || defaultMermaidWorkspace();
|
|
705
|
-
var selected = selectedIdList(selectedIds);
|
|
706
|
-
var body = elements.map(function (elm) {
|
|
707
|
-
var isSelected = selected.indexOf(elm.id) !== -1;
|
|
708
|
-
var selectMarkup = isSelected ? selectionMarkup(elm, selected.length === 1) : "";
|
|
709
|
-
var transform = "";
|
|
710
|
-
if (!isLineType(elm.type) && (elm.rotation || elm.flipX || elm.flipY)) {
|
|
711
|
-
var tx = elm.x + elm.w / 2;
|
|
712
|
-
var ty = elm.y + elm.h / 2;
|
|
713
|
-
transform = ' transform="' + (elm.rotation ? "rotate(" + esc(elm.rotation) + " " + tx + " " + ty + ") " : "") + ((elm.flipX || elm.flipY) ? "translate(" + tx + " " + ty + ") scale(" + (elm.flipX ? -1 : 1) + " " + (elm.flipY ? -1 : 1) + ") translate(" + (-tx) + " " + (-ty) + ")" : "") + '"';
|
|
714
|
-
}
|
|
715
|
-
if (isLineType(elm.type)) {
|
|
716
|
-
var markerStart = elm.type === "leftArrow" || elm.type === "biArrow" ? ' marker-start="url(#rbe-arrow-head-start)"' : "";
|
|
717
|
-
var markerEnd = /^(arrow|rightArrow|upArrow|downArrow|biArrow|elbow|curved)$/.test(elm.type) ? ' marker-end="url(#rbe-arrow-head)"' : "";
|
|
718
|
-
var dash = dashArray(elm.dash);
|
|
719
|
-
var originDot = isSelected && (markerStart || markerEnd) ? '<circle class="rbe-mermaid-arrow-origin" cx="' + esc(elm.x1) + '" cy="' + esc(elm.y1) + '" r="4"></circle>' : "";
|
|
720
|
-
return '<g data-el-id="' + esc(elm.id) + '">' + selectMarkup + originDot + '<path d="' + linePath(elm) + '" fill="none" stroke="' + esc(elm.stroke) + '" stroke-width="' + esc(elm.strokeWidth) + '" stroke-linecap="round" stroke-linejoin="round"' + (dash ? ' stroke-dasharray="' + dash + '"' : "") + ' opacity="' + esc(elm.opacity) + '"' + markerStart + markerEnd + "></path></g>";
|
|
721
|
-
}
|
|
722
|
-
return '<g data-el-id="' + esc(elm.id) + '"' + transform + ">" + selectMarkup + shapeMarkup(elm) + (elm.type !== "image" ? diagramText(elm) : "") + "</g>";
|
|
723
|
-
}).join("");
|
|
724
|
-
if (marquee) body += '<rect class="rbe-mermaid-marquee" x="' + marquee.x + '" y="' + marquee.y + '" width="' + marquee.w + '" height="' + marquee.h + '"></rect>';
|
|
725
|
-
return '<svg class="rbe-mermaid-canvas" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="' + workspace.width * workspace.zoom + '" height="' + workspace.height * workspace.zoom + '" viewBox="0 0 ' + workspace.width + " " + workspace.height + '" role="img" aria-label="Diagram" tabindex="0"><defs><marker id="rbe-arrow-head" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#475467"></path></marker><marker id="rbe-arrow-head-start" markerWidth="10" markerHeight="10" refX="1" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M9,0 L9,6 L0,3 z" fill="#475467"></path></marker></defs>' + body + "</svg>";
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
function renderDiagramCanvas(wrap) {
|
|
729
|
-
var hidden = wrap.querySelector(".rbe-mermaid-diagram-json");
|
|
730
|
-
var elements = [];
|
|
731
|
-
try {
|
|
732
|
-
elements = JSON.parse(hidden.value || "[]");
|
|
733
|
-
} catch (error) {
|
|
734
|
-
elements = defaultMermaidDiagram();
|
|
735
|
-
}
|
|
736
|
-
var workspace = readWorkspaceFromBlock(wrap);
|
|
737
|
-
var marquee = null;
|
|
738
|
-
try {
|
|
739
|
-
marquee = wrap.dataset.marquee ? JSON.parse(wrap.dataset.marquee) : null;
|
|
740
|
-
} catch (error) {}
|
|
741
|
-
wrap.querySelector(".rbe-mermaid-stage").innerHTML = diagramSvg(elements, wrap.dataset.selectedIds || "", workspace, marquee);
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
function readWorkspaceFromBlock(wrap) {
|
|
745
|
-
return {
|
|
746
|
-
width: clampNumber((wrap.querySelector(".rbe-mermaid-workspace-w") || {}).value, 640, MERMAID_WORKSPACE_MAX, 1100),
|
|
747
|
-
height: clampNumber((wrap.querySelector(".rbe-mermaid-workspace-h") || {}).value, 360, MERMAID_WORKSPACE_MAX, 620),
|
|
748
|
-
zoom: clampNumber((wrap.querySelector(".rbe-mermaid-zoom") || {}).value, 0.35, 2.5, 1)
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
function bindMermaidDesigner(editor, wrap) {
|
|
753
|
-
var drag = null;
|
|
754
|
-
var lastShapePointer = { id: "", time: 0 };
|
|
755
|
-
|
|
756
|
-
function elements() {
|
|
757
|
-
try {
|
|
758
|
-
return JSON.parse(wrap.querySelector(".rbe-mermaid-diagram-json").value || "[]");
|
|
759
|
-
} catch (error) {
|
|
760
|
-
return defaultMermaidDiagram();
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
function resizeWorkspaceToFit(items, point) {
|
|
765
|
-
var workspace = readWorkspaceFromBlock(wrap);
|
|
766
|
-
var base = defaultMermaidWorkspace();
|
|
767
|
-
var maxX = point ? point.x : 0;
|
|
768
|
-
var maxY = point ? point.y : 0;
|
|
769
|
-
(items || []).forEach(function (elm) {
|
|
770
|
-
var bounds = elementBounds(elm);
|
|
771
|
-
maxX = Math.max(maxX, bounds.x + bounds.w);
|
|
772
|
-
maxY = Math.max(maxY, bounds.y + bounds.h);
|
|
773
|
-
});
|
|
774
|
-
var width = Math.min(MERMAID_WORKSPACE_MAX, Math.max(base.width, Math.ceil((maxX + MERMAID_WORKSPACE_GROW_PADDING) / MERMAID_WORKSPACE_GROW_STEP) * MERMAID_WORKSPACE_GROW_STEP));
|
|
775
|
-
var height = Math.min(MERMAID_WORKSPACE_MAX, Math.max(base.height, Math.ceil((maxY + MERMAID_WORKSPACE_GROW_PADDING) / MERMAID_WORKSPACE_GROW_STEP) * MERMAID_WORKSPACE_GROW_STEP));
|
|
776
|
-
if (width !== workspace.width) wrap.querySelector(".rbe-mermaid-workspace-w").value = width;
|
|
777
|
-
if (height !== workspace.height) wrap.querySelector(".rbe-mermaid-workspace-h").value = height;
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
function setElements(next, skipRender, growPoint) {
|
|
781
|
-
var normalized = next.map(normalizeDiagramElement);
|
|
782
|
-
resizeWorkspaceToFit(normalized, growPoint || null);
|
|
783
|
-
wrap.querySelector(".rbe-mermaid-diagram-json").value = JSON.stringify(normalized);
|
|
784
|
-
if (!skipRender) {
|
|
785
|
-
renderDiagramCanvas(wrap);
|
|
786
|
-
updateOptions();
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
function historyStack(name) {
|
|
791
|
-
try {
|
|
792
|
-
return JSON.parse(wrap.dataset[name] || "[]");
|
|
793
|
-
} catch (error) {
|
|
794
|
-
return [];
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
function writeHistory(name, stack) {
|
|
799
|
-
wrap.dataset[name] = JSON.stringify(stack.slice(-60));
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
function snapshot() {
|
|
803
|
-
return JSON.stringify({ elements: elements(), workspace: readWorkspaceFromBlock(wrap) });
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
function restoreSnapshot(value) {
|
|
807
|
-
var state = JSON.parse(value);
|
|
808
|
-
setElements(state.elements || []);
|
|
809
|
-
if (state.workspace) {
|
|
810
|
-
wrap.querySelector(".rbe-mermaid-workspace-w").value = state.workspace.width || 1100;
|
|
811
|
-
wrap.querySelector(".rbe-mermaid-workspace-h").value = state.workspace.height || 620;
|
|
812
|
-
wrap.querySelector(".rbe-mermaid-zoom").value = state.workspace.zoom || 1;
|
|
813
|
-
}
|
|
814
|
-
renderDiagramCanvas(wrap);
|
|
815
|
-
updateOptions();
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
function pushUndo() {
|
|
819
|
-
var undo = historyStack("undoStack");
|
|
820
|
-
undo.push(snapshot());
|
|
821
|
-
writeHistory("undoStack", undo);
|
|
822
|
-
writeHistory("redoStack", []);
|
|
823
|
-
refreshHistoryButtons();
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
function refreshHistoryButtons() {
|
|
827
|
-
var undo = wrap.querySelector("[data-diagram-action='undo']");
|
|
828
|
-
var redo = wrap.querySelector("[data-diagram-action='redo']");
|
|
829
|
-
if (undo) undo.disabled = !historyStack("undoStack").length;
|
|
830
|
-
if (redo) redo.disabled = !historyStack("redoStack").length;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
function undo() {
|
|
834
|
-
var undoStack = historyStack("undoStack");
|
|
835
|
-
if (!undoStack.length) return;
|
|
836
|
-
var redoStack = historyStack("redoStack");
|
|
837
|
-
redoStack.push(snapshot());
|
|
838
|
-
restoreSnapshot(undoStack.pop());
|
|
839
|
-
writeHistory("undoStack", undoStack);
|
|
840
|
-
writeHistory("redoStack", redoStack);
|
|
841
|
-
refreshHistoryButtons();
|
|
842
|
-
editor.changed(true);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
function redo() {
|
|
846
|
-
var redoStack = historyStack("redoStack");
|
|
847
|
-
if (!redoStack.length) return;
|
|
848
|
-
var undoStack = historyStack("undoStack");
|
|
849
|
-
undoStack.push(snapshot());
|
|
850
|
-
restoreSnapshot(redoStack.pop());
|
|
851
|
-
writeHistory("undoStack", undoStack);
|
|
852
|
-
writeHistory("redoStack", redoStack);
|
|
853
|
-
refreshHistoryButtons();
|
|
854
|
-
editor.changed(true);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
function selectedIds() {
|
|
858
|
-
return selectedIdList(wrap.dataset.selectedIds || "");
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
function setSelected(ids) {
|
|
862
|
-
wrap.dataset.selectedIds = (ids || []).filter(Boolean).join(",");
|
|
863
|
-
renderDiagramCanvas(wrap);
|
|
864
|
-
updateOptions();
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
function selectedElements() {
|
|
868
|
-
var ids = selectedIds();
|
|
869
|
-
return elements().filter(function (elm) { return ids.indexOf(elm.id) !== -1; });
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
function setTool(tool, sourceSelect) {
|
|
873
|
-
wrap.dataset.tool = tool;
|
|
874
|
-
Array.prototype.slice.call(wrap.querySelectorAll(".rbe-mermaid-tool[data-tool]")).forEach(function (button) {
|
|
875
|
-
button.classList.toggle("is-active", button.dataset.tool === tool);
|
|
876
|
-
});
|
|
877
|
-
Array.prototype.slice.call(wrap.querySelectorAll(".rbe-mermaid-menu-select")).forEach(function (select) {
|
|
878
|
-
if (select !== sourceSelect) select.value = "";
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
function point(event) {
|
|
883
|
-
var svg = wrap.querySelector(".rbe-mermaid-canvas");
|
|
884
|
-
var rect = svg.getBoundingClientRect();
|
|
885
|
-
var workspace = readWorkspaceFromBlock(wrap);
|
|
886
|
-
var raw = { x: ((event.clientX - rect.left) / rect.width) * workspace.width, y: ((event.clientY - rect.top) / rect.height) * workspace.height };
|
|
887
|
-
return event.altKey ? raw : { x: Math.round(raw.x / 10) * 10, y: Math.round(raw.y / 10) * 10 };
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
function autoScrollStage(event) {
|
|
891
|
-
var stage = wrap.querySelector(".rbe-mermaid-stage");
|
|
892
|
-
if (!stage) return;
|
|
893
|
-
var rect = stage.getBoundingClientRect();
|
|
894
|
-
var edge = 56;
|
|
895
|
-
var step = 30;
|
|
896
|
-
var dx = 0;
|
|
897
|
-
var dy = 0;
|
|
898
|
-
if (event.clientX > rect.right - edge) dx = step;
|
|
899
|
-
else if (event.clientX < rect.left + edge) dx = -step;
|
|
900
|
-
if (event.clientY > rect.bottom - edge) dy = step;
|
|
901
|
-
else if (event.clientY < rect.top + edge) dy = -step;
|
|
902
|
-
if (dx || dy) {
|
|
903
|
-
stage.scrollLeft += dx;
|
|
904
|
-
stage.scrollTop += dy;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
function constrainLinePoint(start, current) {
|
|
909
|
-
var dx = current.x - start.x;
|
|
910
|
-
var dy = current.y - start.y;
|
|
911
|
-
if (!dx && !dy) return current;
|
|
912
|
-
var length = Math.sqrt(dx * dx + dy * dy);
|
|
913
|
-
var snappedAngle = Math.round(Math.atan2(dy, dx) / (Math.PI / 4)) * (Math.PI / 4);
|
|
914
|
-
return {
|
|
915
|
-
x: Math.round((start.x + Math.cos(snappedAngle) * length) / 10) * 10,
|
|
916
|
-
y: Math.round((start.y + Math.sin(snappedAngle) * length) / 10) * 10
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
function selectedBounds() {
|
|
921
|
-
var list = selectedElements();
|
|
922
|
-
if (!list.length) return null;
|
|
923
|
-
var bounds = list.map(elementBounds);
|
|
924
|
-
var minX = Math.min.apply(null, bounds.map(function (b) { return b.x; }));
|
|
925
|
-
var minY = Math.min.apply(null, bounds.map(function (b) { return b.y; }));
|
|
926
|
-
var maxX = Math.max.apply(null, bounds.map(function (b) { return b.x + b.w; }));
|
|
927
|
-
var maxY = Math.max.apply(null, bounds.map(function (b) { return b.y + b.h; }));
|
|
928
|
-
return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
function updateOptions() {
|
|
932
|
-
var selected = selectedElements();
|
|
933
|
-
var panel = wrap.querySelector(".rbe-mermaid-stylebar");
|
|
934
|
-
if (!panel || !wrap.querySelector(".rbe-mermaid-option-text")) return;
|
|
935
|
-
panel.hidden = !selected.length;
|
|
936
|
-
if (!selected.length) return;
|
|
937
|
-
var first = selected[0];
|
|
938
|
-
var isLineSelection = selected.every(function (elm) { return isLineType(elm.type); });
|
|
939
|
-
var isTextCapable = selected.some(function (elm) { return !isLineType(elm.type) && elm.type !== "image"; });
|
|
940
|
-
panel.classList.toggle("is-line-selection", isLineSelection);
|
|
941
|
-
panel.classList.toggle("is-text-capable", isTextCapable);
|
|
942
|
-
wrap.querySelector(".rbe-mermaid-option-text").value = selected.length === 1 ? first.text || "" : selected.length + " objects selected";
|
|
943
|
-
wrap.querySelector(".rbe-mermaid-option-text").disabled = selected.length !== 1;
|
|
944
|
-
wrap.querySelector(".rbe-mermaid-option-font").value = first.fontFamily || "Arial";
|
|
945
|
-
wrap.querySelector(".rbe-mermaid-option-size").value = first.fontSize || 16;
|
|
946
|
-
var fillColor = first.fill === "transparent" ? "#ffffff" : normalizeChartColor(first.fill, "#eef5ff");
|
|
947
|
-
var strokeColor = normalizeChartColor(first.stroke, "#111827");
|
|
948
|
-
var textColor = normalizeChartColor(first.textColor, "#172033");
|
|
949
|
-
var highlightColor = first.highlightColor === "transparent" ? "#fff3b0" : normalizeChartColor(first.highlightColor, "#fff3b0");
|
|
950
|
-
wrap.querySelector(".rbe-mermaid-option-fill").value = fillColor;
|
|
951
|
-
wrap.querySelector(".rbe-mermaid-option-stroke").value = strokeColor;
|
|
952
|
-
wrap.querySelector(".rbe-mermaid-option-text-color").value = textColor;
|
|
953
|
-
wrap.querySelector(".rbe-mermaid-option-highlight").value = highlightColor;
|
|
954
|
-
wrap.querySelector(".rbe-mermaid-option-align").value = first.textAlign || "center";
|
|
955
|
-
wrap.querySelector(".rbe-mermaid-option-line-height").value = String(normalizeDiagramLineHeight(first.lineHeight));
|
|
956
|
-
wrap.querySelector(".rbe-mermaid-option-bullet").value = first.listType === "bullet" ? normalizeDiagramListStyle("bullet", first.listStyle) : "none";
|
|
957
|
-
wrap.querySelector(".rbe-mermaid-option-number").value = first.listType === "number" ? normalizeDiagramListStyle("number", first.listStyle) : "none";
|
|
958
|
-
panel.style.setProperty("--rbe-mermaid-fill", fillColor);
|
|
959
|
-
panel.style.setProperty("--rbe-mermaid-stroke", strokeColor);
|
|
960
|
-
panel.style.setProperty("--rbe-mermaid-text", textColor);
|
|
961
|
-
panel.style.setProperty("--rbe-mermaid-highlight", first.highlightColor === "transparent" ? "transparent" : highlightColor);
|
|
962
|
-
wrap.querySelector(".rbe-mermaid-option-weight").value = first.strokeWidth || 1;
|
|
963
|
-
wrap.querySelector(".rbe-mermaid-option-dash").value = normalizeDiagramDash(first.dash);
|
|
964
|
-
wrap.querySelector(".rbe-mermaid-option-opacity").value = first.opacity || 1;
|
|
965
|
-
Array.prototype.slice.call(wrap.querySelectorAll("[data-format-toggle]")).forEach(function (button) {
|
|
966
|
-
var prop = button.dataset.formatToggle;
|
|
967
|
-
button.classList.toggle("is-active", !!first[prop]);
|
|
968
|
-
});
|
|
969
|
-
var activeControls = [
|
|
970
|
-
[".rbe-mermaid-bullet-control", first.listType === "bullet"],
|
|
971
|
-
[".rbe-mermaid-number-control", first.listType === "number"],
|
|
972
|
-
[".rbe-mermaid-spacing-before", !!first.spacingBefore],
|
|
973
|
-
[".rbe-mermaid-spacing-after", !!first.spacingAfter]
|
|
974
|
-
];
|
|
975
|
-
activeControls.forEach(function (item) {
|
|
976
|
-
var node = wrap.querySelector(item[0]);
|
|
977
|
-
if (node) node.classList.toggle("is-active", !!item[1]);
|
|
978
|
-
});
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
function updateSelected(mutator, skipUndo) {
|
|
982
|
-
var ids = selectedIds();
|
|
983
|
-
if (!ids.length) return;
|
|
984
|
-
if (!skipUndo) pushUndo();
|
|
985
|
-
setElements(elements().map(function (elm) {
|
|
986
|
-
if (ids.indexOf(elm.id) !== -1) mutator(elm);
|
|
987
|
-
return elm;
|
|
988
|
-
}));
|
|
989
|
-
editor.changed(true);
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
function applyStylebarChange(event) {
|
|
993
|
-
if (!event.target.closest(".rbe-mermaid-stylebar")) return false;
|
|
994
|
-
var bulletChanged = event.target.classList.contains("rbe-mermaid-option-bullet");
|
|
995
|
-
var numberChanged = event.target.classList.contains("rbe-mermaid-option-number");
|
|
996
|
-
updateSelected(function (elm) {
|
|
997
|
-
if (event.target.classList.contains("rbe-mermaid-option-text")) elm.text = event.target.value;
|
|
998
|
-
elm.fontFamily = wrap.querySelector(".rbe-mermaid-option-font").value || "Arial";
|
|
999
|
-
elm.fontSize = Number(wrap.querySelector(".rbe-mermaid-option-size").value || 16);
|
|
1000
|
-
if (!isLineType(elm.type)) elm.fill = wrap.querySelector(".rbe-mermaid-option-fill").value;
|
|
1001
|
-
elm.stroke = wrap.querySelector(".rbe-mermaid-option-stroke").value;
|
|
1002
|
-
elm.textColor = wrap.querySelector(".rbe-mermaid-option-text-color").value;
|
|
1003
|
-
elm.highlightColor = event.target.classList.contains("rbe-mermaid-option-highlight") ? wrap.querySelector(".rbe-mermaid-option-highlight").value : elm.highlightColor;
|
|
1004
|
-
elm.textAlign = wrap.querySelector(".rbe-mermaid-option-align").value || "center";
|
|
1005
|
-
elm.lineHeight = normalizeDiagramLineHeight(wrap.querySelector(".rbe-mermaid-option-line-height").value);
|
|
1006
|
-
if (bulletChanged) {
|
|
1007
|
-
var bulletValue = wrap.querySelector(".rbe-mermaid-option-bullet").value || "none";
|
|
1008
|
-
elm.listType = bulletValue === "none" ? "none" : "bullet";
|
|
1009
|
-
elm.listStyle = bulletValue === "none" ? "none" : bulletValue;
|
|
1010
|
-
wrap.querySelector(".rbe-mermaid-option-number").value = "none";
|
|
1011
|
-
}
|
|
1012
|
-
if (numberChanged) {
|
|
1013
|
-
var numberValue = wrap.querySelector(".rbe-mermaid-option-number").value || "none";
|
|
1014
|
-
elm.listType = numberValue === "none" ? "none" : "number";
|
|
1015
|
-
elm.listStyle = numberValue === "none" ? "none" : numberValue;
|
|
1016
|
-
wrap.querySelector(".rbe-mermaid-option-bullet").value = "none";
|
|
1017
|
-
}
|
|
1018
|
-
elm.strokeWidth = Number(wrap.querySelector(".rbe-mermaid-option-weight").value || 1);
|
|
1019
|
-
elm.dash = wrap.querySelector(".rbe-mermaid-option-dash").value;
|
|
1020
|
-
elm.opacity = Number(wrap.querySelector(".rbe-mermaid-option-opacity").value || 1);
|
|
1021
|
-
}, true);
|
|
1022
|
-
return true;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
function createElement(type, p, fileData) {
|
|
1026
|
-
var line = isLineType(type);
|
|
1027
|
-
var text = "";
|
|
1028
|
-
if (type === "wordart") text = "WordArt";
|
|
1029
|
-
else if (/^(plus|minus|multiply|divide|equal|brackets)$/.test(type)) text = { plus: "+", minus: "-", multiply: "x", divide: "/", equal: "=", brackets: "[ ]" }[type] || "";
|
|
1030
|
-
return normalizeDiagramElement({
|
|
1031
|
-
id: "diagram-" + Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 6),
|
|
1032
|
-
type: type,
|
|
1033
|
-
x: p.x,
|
|
1034
|
-
y: p.y,
|
|
1035
|
-
w: type === "image" ? 220 : type === "wordart" ? 240 : type === "text" ? 190 : 10,
|
|
1036
|
-
h: type === "image" ? 150 : type === "wordart" ? 78 : type === "text" ? 70 : 10,
|
|
1037
|
-
x1: p.x,
|
|
1038
|
-
y1: p.y,
|
|
1039
|
-
x2: p.x,
|
|
1040
|
-
y2: p.y,
|
|
1041
|
-
text: text,
|
|
1042
|
-
image: fileData && fileData.url ? fileData.url : "",
|
|
1043
|
-
name: fileData && fileData.name ? fileData.name : "",
|
|
1044
|
-
fill: line || type === "text" ? "transparent" : type === "wordart" ? "#f59e0b" : "#eef5ff",
|
|
1045
|
-
stroke: line ? "#475467" : "#111827",
|
|
1046
|
-
strokeWidth: 1,
|
|
1047
|
-
fontSize: type === "wordart" ? 36 : 16
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
function editableDiagramElement(item) {
|
|
1052
|
-
return item && !isLineType(item.type) && item.type !== "image";
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
function restoreTextEditorTargets() {
|
|
1056
|
-
Array.prototype.slice.call(wrap.querySelectorAll(".rbe-mermaid-hidden-text")).forEach(function (node) {
|
|
1057
|
-
node.classList.remove("rbe-mermaid-hidden-text");
|
|
1058
|
-
});
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
function hideTextForEditor(id) {
|
|
1062
|
-
restoreTextEditorTargets();
|
|
1063
|
-
var group = Array.prototype.slice.call(wrap.querySelectorAll(".rbe-mermaid-canvas [data-el-id]")).filter(function (node) {
|
|
1064
|
-
return node.getAttribute("data-el-id") === id;
|
|
1065
|
-
})[0];
|
|
1066
|
-
if (!group) return;
|
|
1067
|
-
Array.prototype.slice.call(group.querySelectorAll("text,.rbe-mermaid-text-layer")).forEach(function (node) {
|
|
1068
|
-
node.classList.add("rbe-mermaid-hidden-text");
|
|
1069
|
-
});
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
function placeTextEditorCaretAtEnd(node) {
|
|
1073
|
-
if (!node) return;
|
|
1074
|
-
node.focus();
|
|
1075
|
-
try {
|
|
1076
|
-
node.setSelectionRange(node.value.length, node.value.length, "none");
|
|
1077
|
-
} catch (error) {}
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
function scheduleTextEditorCaretAtEnd(node) {
|
|
1081
|
-
if (!node) return;
|
|
1082
|
-
node.dataset.forceCaretEnd = "true";
|
|
1083
|
-
placeTextEditorCaretAtEnd(node);
|
|
1084
|
-
if (window.requestAnimationFrame) {
|
|
1085
|
-
window.requestAnimationFrame(function () { placeTextEditorCaretAtEnd(node); });
|
|
1086
|
-
}
|
|
1087
|
-
[0, 40, 120].forEach(function (delay) {
|
|
1088
|
-
setTimeout(function () { placeTextEditorCaretAtEnd(node); }, delay);
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
function closeTextEditor(save) {
|
|
1093
|
-
var active = wrap.querySelector(".rbe-mermaid-text-editor");
|
|
1094
|
-
if (!active) return;
|
|
1095
|
-
var id = active.dataset.editId || "";
|
|
1096
|
-
var nextText = active.value || active.textContent || "";
|
|
1097
|
-
restoreTextEditorTargets();
|
|
1098
|
-
active.remove();
|
|
1099
|
-
if (!save || !id) return;
|
|
1100
|
-
pushUndo();
|
|
1101
|
-
setElements(elements().map(function (elm) {
|
|
1102
|
-
if (elm.id === id) elm.text = nextText.trim();
|
|
1103
|
-
return elm;
|
|
1104
|
-
}));
|
|
1105
|
-
setSelected([id]);
|
|
1106
|
-
editor.changed(true);
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
function openTextEditor(id, seedText) {
|
|
1110
|
-
var item = elements().filter(function (elm) { return elm.id === id; })[0];
|
|
1111
|
-
if (!editableDiagramElement(item)) return;
|
|
1112
|
-
closeTextEditor(true);
|
|
1113
|
-
var stage = wrap.querySelector(".rbe-mermaid-stage");
|
|
1114
|
-
var workspace = readWorkspaceFromBlock(wrap);
|
|
1115
|
-
var svg = wrap.querySelector(".rbe-mermaid-canvas");
|
|
1116
|
-
var svgRect = svg ? svg.getBoundingClientRect() : null;
|
|
1117
|
-
var scaleX = svgRect && svgRect.width ? svgRect.width / workspace.width : workspace.zoom;
|
|
1118
|
-
var scaleY = svgRect && svgRect.height ? svgRect.height / workspace.height : workspace.zoom;
|
|
1119
|
-
var scale = Math.min(scaleX, scaleY);
|
|
1120
|
-
var node = document.createElement("textarea");
|
|
1121
|
-
var initial = seedText != null ? seedText : item.text || "";
|
|
1122
|
-
node.className = "rbe-mermaid-text-editor";
|
|
1123
|
-
node.dataset.editId = id;
|
|
1124
|
-
node.spellcheck = false;
|
|
1125
|
-
node.wrap = "soft";
|
|
1126
|
-
node.setAttribute("role", "textbox");
|
|
1127
|
-
node.setAttribute("aria-label", "Shape text");
|
|
1128
|
-
if (item.type === "text") node.setAttribute("placeholder", "Text");
|
|
1129
|
-
var textBox = { x: item.x, y: item.y, w: item.w, h: item.h };
|
|
1130
|
-
if (item.type === "callout") textBox.h = item.h * .72;
|
|
1131
|
-
if (item.type === "roundCallout") textBox.h = item.h * .7;
|
|
1132
|
-
if (item.type === "thought") textBox.h = item.h * .72;
|
|
1133
|
-
var pixelX = textBox.x * scaleX;
|
|
1134
|
-
var pixelY = textBox.y * scaleY;
|
|
1135
|
-
var pixelW = Math.max(42, textBox.w * scaleX);
|
|
1136
|
-
var pixelH = Math.max(32, textBox.h * scaleY);
|
|
1137
|
-
node.style.left = pixelX + "px";
|
|
1138
|
-
node.style.top = pixelY + "px";
|
|
1139
|
-
node.style.width = pixelW + "px";
|
|
1140
|
-
node.style.height = pixelH + "px";
|
|
1141
|
-
node.style.fontFamily = item.fontFamily || "Arial";
|
|
1142
|
-
var fontSize = Math.max(18, (item.fontSize || 16) * scale);
|
|
1143
|
-
var lineHeight = Math.round(fontSize * 1.25);
|
|
1144
|
-
node.style.fontSize = fontSize + "px";
|
|
1145
|
-
lineHeight = Math.round(fontSize * normalizeDiagramLineHeight(item.lineHeight));
|
|
1146
|
-
node.style.lineHeight = lineHeight + "px";
|
|
1147
|
-
node.style.padding = Math.max(4, Math.floor((pixelH - lineHeight) / 2)) + "px 8px 4px";
|
|
1148
|
-
node.style.fontWeight = item.bold ? "800" : "700";
|
|
1149
|
-
node.style.fontStyle = item.italic ? "italic" : "normal";
|
|
1150
|
-
node.style.color = item.textColor || "#172033";
|
|
1151
|
-
node.style.textAlign = item.textAlign || "center";
|
|
1152
|
-
node.style.backgroundColor = item.highlightColor && item.highlightColor !== "transparent" ? item.highlightColor : "transparent";
|
|
1153
|
-
node.value = initial;
|
|
1154
|
-
hideTextForEditor(id);
|
|
1155
|
-
stage.appendChild(node);
|
|
1156
|
-
scheduleTextEditorCaretAtEnd(node);
|
|
1157
|
-
setTimeout(function () {
|
|
1158
|
-
node.dataset.allowPointerCaret = "true";
|
|
1159
|
-
}, 250);
|
|
1160
|
-
node.addEventListener("pointerdown", function () {
|
|
1161
|
-
if (node.dataset.allowPointerCaret === "true") node.dataset.forceCaretEnd = "";
|
|
1162
|
-
});
|
|
1163
|
-
node.addEventListener("keydown", function (event) {
|
|
1164
|
-
event.stopPropagation();
|
|
1165
|
-
if (event.ctrlKey || event.metaKey || event.altKey) {
|
|
1166
|
-
node.dataset.forceCaretEnd = "";
|
|
1167
|
-
return;
|
|
1168
|
-
}
|
|
1169
|
-
if (node.dataset.forceCaretEnd === "true" && (event.key.length === 1 || event.key === "Backspace" || event.key === "Delete")) {
|
|
1170
|
-
placeTextEditorCaretAtEnd(node);
|
|
1171
|
-
node.dataset.forceCaretEnd = "";
|
|
1172
|
-
if (event.key.length === 1 && /^[A-Za-z0-9]$/.test(event.key) && node.value && !/\s$/.test(node.value)) {
|
|
1173
|
-
event.preventDefault();
|
|
1174
|
-
node.setRangeText(" " + event.key, node.value.length, node.value.length, "end");
|
|
1175
|
-
return;
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
if (event.key === "Enter" && !event.shiftKey) {
|
|
1179
|
-
event.preventDefault();
|
|
1180
|
-
closeTextEditor(true);
|
|
1181
|
-
}
|
|
1182
|
-
if (event.key === "Escape") {
|
|
1183
|
-
event.preventDefault();
|
|
1184
|
-
closeTextEditor(false);
|
|
1185
|
-
}
|
|
1186
|
-
});
|
|
1187
|
-
node.addEventListener("blur", function () {
|
|
1188
|
-
closeTextEditor(true);
|
|
1189
|
-
}, { once: true });
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
function applyAction(action) {
|
|
1193
|
-
var list = elements();
|
|
1194
|
-
var ids = selectedIds();
|
|
1195
|
-
if (action === "image") {
|
|
1196
|
-
wrap.querySelector(".rbe-mermaid-image-input").click();
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1199
|
-
if (!ids.length && !/^(paste|downloadSvg|downloadPng|downloadJpeg|downloadPdf|fit|zoomIn|zoomOut)$/.test(action)) return;
|
|
1200
|
-
if (action === "undo") return undo();
|
|
1201
|
-
if (action === "redo") return redo();
|
|
1202
|
-
if (action === "copy" || action === "cut") {
|
|
1203
|
-
wrap.dataset.clipboard = JSON.stringify(selectedElements());
|
|
1204
|
-
if (action === "cut") {
|
|
1205
|
-
pushUndo();
|
|
1206
|
-
setElements(list.filter(function (elm) { return ids.indexOf(elm.id) === -1; }));
|
|
1207
|
-
setSelected([]);
|
|
1208
|
-
editor.changed(true);
|
|
1209
|
-
}
|
|
1210
|
-
return;
|
|
1211
|
-
}
|
|
1212
|
-
if (action === "paste") {
|
|
1213
|
-
var clip = [];
|
|
1214
|
-
try { clip = JSON.parse(wrap.dataset.clipboard || "[]"); } catch (error) {}
|
|
1215
|
-
if (!clip.length) return;
|
|
1216
|
-
pushUndo();
|
|
1217
|
-
var pasted = clip.map(function (elm) {
|
|
1218
|
-
elm = normalizeDiagramElement(elm);
|
|
1219
|
-
elm.id = "diagram-" + Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 6);
|
|
1220
|
-
if (isLineType(elm.type)) {
|
|
1221
|
-
elm.x1 += 30; elm.x2 += 30; elm.y1 += 30; elm.y2 += 30;
|
|
1222
|
-
} else {
|
|
1223
|
-
elm.x += 30; elm.y += 30;
|
|
1224
|
-
}
|
|
1225
|
-
return elm;
|
|
1226
|
-
});
|
|
1227
|
-
setElements(list.concat(pasted));
|
|
1228
|
-
setSelected(pasted.map(function (elm) { return elm.id; }));
|
|
1229
|
-
editor.changed(true);
|
|
1230
|
-
return;
|
|
1231
|
-
}
|
|
1232
|
-
if (action === "duplicate") {
|
|
1233
|
-
wrap.dataset.clipboard = JSON.stringify(selectedElements());
|
|
1234
|
-
return applyAction("paste");
|
|
1235
|
-
}
|
|
1236
|
-
if (action === "delete") {
|
|
1237
|
-
pushUndo();
|
|
1238
|
-
setElements(list.filter(function (elm) { return ids.indexOf(elm.id) === -1; }));
|
|
1239
|
-
setSelected([]);
|
|
1240
|
-
editor.changed(true);
|
|
1241
|
-
return;
|
|
1242
|
-
}
|
|
1243
|
-
if (/^download/.test(action)) return downloadDiagram(wrap, action);
|
|
1244
|
-
if (action === "zoomIn" || action === "zoomOut" || action === "fit") {
|
|
1245
|
-
var zoom = wrap.querySelector(".rbe-mermaid-zoom");
|
|
1246
|
-
zoom.value = action === "fit" ? 1 : clampNumber(Number(zoom.value || 1) + (action === "zoomIn" ? .1 : -.1), .35, 2.5, 1);
|
|
1247
|
-
renderDiagramCanvas(wrap);
|
|
1248
|
-
editor.changed(true);
|
|
1249
|
-
return;
|
|
1250
|
-
}
|
|
1251
|
-
pushUndo();
|
|
1252
|
-
if (action === "bringFront") list = list.filter(function (elm) { return ids.indexOf(elm.id) === -1; }).concat(list.filter(function (elm) { return ids.indexOf(elm.id) !== -1; }));
|
|
1253
|
-
else if (action === "sendBack") list = list.filter(function (elm) { return ids.indexOf(elm.id) !== -1; }).concat(list.filter(function (elm) { return ids.indexOf(elm.id) === -1; }));
|
|
1254
|
-
else if (action === "bringForward" || action === "sendBackward") {
|
|
1255
|
-
var step = action === "bringForward" ? 1 : -1;
|
|
1256
|
-
ids.forEach(function (id) {
|
|
1257
|
-
var index = list.findIndex(function (elm) { return elm.id === id; });
|
|
1258
|
-
var nextIndex = index + step;
|
|
1259
|
-
if (index < 0 || nextIndex < 0 || nextIndex >= list.length) return;
|
|
1260
|
-
var item = list[index];
|
|
1261
|
-
list.splice(index, 1);
|
|
1262
|
-
list.splice(nextIndex, 0, item);
|
|
1263
|
-
});
|
|
1264
|
-
}
|
|
1265
|
-
else {
|
|
1266
|
-
var bounds = selectedBounds();
|
|
1267
|
-
if (action === "group") {
|
|
1268
|
-
var groupId = "group-" + Date.now().toString(36);
|
|
1269
|
-
list.forEach(function (elm) { if (ids.indexOf(elm.id) !== -1) elm.group = groupId; });
|
|
1270
|
-
}
|
|
1271
|
-
if (action === "ungroup") {
|
|
1272
|
-
list.forEach(function (elm) { if (ids.indexOf(elm.id) !== -1) elm.group = ""; });
|
|
1273
|
-
}
|
|
1274
|
-
if (action === "distributeH" && ids.length > 2) {
|
|
1275
|
-
var hItems = list.filter(function (elm) { return ids.indexOf(elm.id) !== -1 && !isLineType(elm.type); }).sort(function (a, b) { return a.x - b.x; });
|
|
1276
|
-
var firstX = hItems[0].x;
|
|
1277
|
-
var lastX = hItems[hItems.length - 1].x;
|
|
1278
|
-
var gapX = (lastX - firstX) / (hItems.length - 1);
|
|
1279
|
-
hItems.forEach(function (elm, index) { elm.x = firstX + gapX * index; });
|
|
1280
|
-
}
|
|
1281
|
-
if (action === "distributeV" && ids.length > 2) {
|
|
1282
|
-
var vItems = list.filter(function (elm) { return ids.indexOf(elm.id) !== -1 && !isLineType(elm.type); }).sort(function (a, b) { return a.y - b.y; });
|
|
1283
|
-
var firstY = vItems[0].y;
|
|
1284
|
-
var lastY = vItems[vItems.length - 1].y;
|
|
1285
|
-
var gapY = (lastY - firstY) / (vItems.length - 1);
|
|
1286
|
-
vItems.forEach(function (elm, index) { elm.y = firstY + gapY * index; });
|
|
1287
|
-
}
|
|
1288
|
-
list.forEach(function (elm) {
|
|
1289
|
-
if (ids.indexOf(elm.id) === -1) return;
|
|
1290
|
-
if (action === "rotateClockwise") elm.rotation = (elm.rotation || 0) + 15;
|
|
1291
|
-
if (action === "rotateCounter") elm.rotation = (elm.rotation || 0) - 15;
|
|
1292
|
-
if (action === "flipH" && !isLineType(elm.type)) elm.flipX = !elm.flipX;
|
|
1293
|
-
if (action === "flipV" && !isLineType(elm.type)) elm.flipY = !elm.flipY;
|
|
1294
|
-
if (!bounds || isLineType(elm.type)) return;
|
|
1295
|
-
if (action === "alignLeft") elm.x = bounds.x;
|
|
1296
|
-
if (action === "alignCenter") elm.x = bounds.x + bounds.w / 2 - elm.w / 2;
|
|
1297
|
-
if (action === "alignRight") elm.x = bounds.x + bounds.w - elm.w;
|
|
1298
|
-
if (action === "alignTop") elm.y = bounds.y;
|
|
1299
|
-
if (action === "alignMiddle") elm.y = bounds.y + bounds.h / 2 - elm.h / 2;
|
|
1300
|
-
if (action === "alignBottom") elm.y = bounds.y + bounds.h - elm.h;
|
|
1301
|
-
});
|
|
1302
|
-
}
|
|
1303
|
-
setElements(list);
|
|
1304
|
-
editor.changed(true);
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
function downloadDiagram(block, action) {
|
|
1308
|
-
var svg = diagramSvg(elements(), "", readWorkspaceFromBlock(block), null);
|
|
1309
|
-
var mime = "image/svg+xml";
|
|
1310
|
-
var ext = "svg";
|
|
1311
|
-
if (action === "downloadSvg") {
|
|
1312
|
-
triggerDownload("blockwriteai-diagram.svg", "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg));
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
|
-
if (action === "downloadPdf") {
|
|
1316
|
-
var popup = window.open("", "_blank");
|
|
1317
|
-
if (popup) {
|
|
1318
|
-
popup.document.write("<!doctype html><title>BlockWriteAI Diagram</title><style>body{margin:24px;font-family:Arial,sans-serif}svg{max-width:100%;height:auto}</style>" + svg + "<script>setTimeout(function(){window.print();},250);<\/script>");
|
|
1319
|
-
popup.document.close();
|
|
1320
|
-
}
|
|
1321
|
-
return;
|
|
1322
|
-
}
|
|
1323
|
-
var img = new Image();
|
|
1324
|
-
var url = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
|
|
1325
|
-
img.onload = function () {
|
|
1326
|
-
var workspace = readWorkspaceFromBlock(block);
|
|
1327
|
-
var canvas = document.createElement("canvas");
|
|
1328
|
-
canvas.width = workspace.width;
|
|
1329
|
-
canvas.height = workspace.height;
|
|
1330
|
-
var ctx = canvas.getContext("2d");
|
|
1331
|
-
ctx.fillStyle = "#ffffff";
|
|
1332
|
-
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
1333
|
-
ctx.drawImage(img, 0, 0);
|
|
1334
|
-
mime = action === "downloadJpeg" ? "image/jpeg" : "image/png";
|
|
1335
|
-
ext = action === "downloadJpeg" ? "jpg" : "png";
|
|
1336
|
-
triggerDownload("blockwriteai-diagram." + ext, canvas.toDataURL(mime, .92));
|
|
1337
|
-
};
|
|
1338
|
-
img.src = url;
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
function triggerDownload(name, href) {
|
|
1342
|
-
var link = document.createElement("a");
|
|
1343
|
-
link.href = href;
|
|
1344
|
-
link.download = name;
|
|
1345
|
-
document.body.appendChild(link);
|
|
1346
|
-
link.click();
|
|
1347
|
-
link.remove();
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
wrap.addEventListener("click", function (event) {
|
|
1351
|
-
var choiceButton = event.target.closest(".rbe-mermaid-choice[data-tool],.rbe-mermaid-line-choice[data-tool]");
|
|
1352
|
-
if (choiceButton) {
|
|
1353
|
-
event.preventDefault();
|
|
1354
|
-
setTool(choiceButton.dataset.tool || "select");
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
var toolButton = event.target.closest(".rbe-mermaid-tool[data-tool]");
|
|
1358
|
-
if (toolButton) {
|
|
1359
|
-
event.preventDefault();
|
|
1360
|
-
setTool(toolButton.dataset.tool || "select");
|
|
1361
|
-
return;
|
|
1362
|
-
}
|
|
1363
|
-
var textActionButton = event.target.closest("[data-text-action]");
|
|
1364
|
-
if (textActionButton) {
|
|
1365
|
-
event.preventDefault();
|
|
1366
|
-
var textAction = textActionButton.dataset.textAction || "";
|
|
1367
|
-
updateSelected(function (elm) {
|
|
1368
|
-
if (isLineType(elm.type) || elm.type === "image") return;
|
|
1369
|
-
if (textAction === "indent") elm.indent = clampNumber(Number(elm.indent || 0) + 1, 0, 8, 0);
|
|
1370
|
-
if (textAction === "outdent") elm.indent = clampNumber(Number(elm.indent || 0) - 1, 0, 8, 0);
|
|
1371
|
-
if (textAction === "spacing-before") elm.spacingBefore = elm.spacingBefore ? 0 : 10;
|
|
1372
|
-
if (textAction === "spacing-after") elm.spacingAfter = elm.spacingAfter ? 0 : 10;
|
|
1373
|
-
if (textAction === "reset-highlight") {
|
|
1374
|
-
elm.highlightColor = "transparent";
|
|
1375
|
-
}
|
|
1376
|
-
});
|
|
1377
|
-
updateOptions();
|
|
1378
|
-
return;
|
|
1379
|
-
}
|
|
1380
|
-
var alignButton = event.target.closest(".rbe-mermaid-align");
|
|
1381
|
-
if (alignButton) {
|
|
1382
|
-
event.preventDefault();
|
|
1383
|
-
wrap.querySelector(".rbe-mermaid-alignment").value = alignButton.dataset.align || "center";
|
|
1384
|
-
Array.prototype.slice.call(wrap.querySelectorAll(".rbe-mermaid-align")).forEach(function (button) {
|
|
1385
|
-
button.classList.toggle("is-active", button === alignButton);
|
|
1386
|
-
});
|
|
1387
|
-
editor.changed(true);
|
|
1388
|
-
return;
|
|
1389
|
-
}
|
|
1390
|
-
var styleButton = event.target.closest("[data-style-action]");
|
|
1391
|
-
if (styleButton) {
|
|
1392
|
-
event.preventDefault();
|
|
1393
|
-
var sizeInput = wrap.querySelector(".rbe-mermaid-option-size");
|
|
1394
|
-
var nextSize = Number(sizeInput.value || 16) + (styleButton.dataset.styleAction === "font-size-up" ? 2 : -2);
|
|
1395
|
-
sizeInput.value = clampNumber(nextSize, 8, 96, 16);
|
|
1396
|
-
applyStylebarChange({ target: sizeInput });
|
|
1397
|
-
updateOptions();
|
|
1398
|
-
return;
|
|
1399
|
-
}
|
|
1400
|
-
var actionButton = event.target.closest("[data-diagram-action]");
|
|
1401
|
-
if (actionButton) {
|
|
1402
|
-
event.preventDefault();
|
|
1403
|
-
applyAction(actionButton.dataset.diagramAction);
|
|
1404
|
-
}
|
|
1405
|
-
});
|
|
1406
|
-
|
|
1407
|
-
wrap.addEventListener("change", function (event) {
|
|
1408
|
-
if (applyStylebarChange(event)) return;
|
|
1409
|
-
var picker = event.target.closest(".rbe-mermaid-menu-select");
|
|
1410
|
-
if (picker && picker.value) {
|
|
1411
|
-
setTool(picker.value, picker);
|
|
1412
|
-
return;
|
|
1413
|
-
}
|
|
1414
|
-
var action = event.target.closest(".rbe-mermaid-action-select");
|
|
1415
|
-
if (action && action.value) {
|
|
1416
|
-
applyAction(action.value);
|
|
1417
|
-
action.value = "";
|
|
1418
|
-
return;
|
|
1419
|
-
}
|
|
1420
|
-
if (event.target.closest(".rbe-mermaid-workspace")) {
|
|
1421
|
-
pushUndo();
|
|
1422
|
-
renderDiagramCanvas(wrap);
|
|
1423
|
-
editor.changed(true);
|
|
1424
|
-
}
|
|
1425
|
-
});
|
|
1426
|
-
|
|
1427
|
-
wrap.addEventListener("input", function (event) {
|
|
1428
|
-
applyStylebarChange(event);
|
|
1429
|
-
});
|
|
1430
|
-
|
|
1431
|
-
wrap.addEventListener("click", function (event) {
|
|
1432
|
-
var formatButton = event.target.closest("[data-format-toggle]");
|
|
1433
|
-
if (!formatButton) return;
|
|
1434
|
-
event.preventDefault();
|
|
1435
|
-
var prop = formatButton.dataset.formatToggle;
|
|
1436
|
-
updateSelected(function (elm) { elm[prop] = !elm[prop]; });
|
|
1437
|
-
});
|
|
1438
|
-
|
|
1439
|
-
wrap.addEventListener("dblclick", function (event) {
|
|
1440
|
-
var target = event.target.closest("[data-el-id]");
|
|
1441
|
-
if (!target) return;
|
|
1442
|
-
var item = elements().filter(function (elm) { return elm.id === target.dataset.elId; })[0];
|
|
1443
|
-
if (!editableDiagramElement(item)) return;
|
|
1444
|
-
event.preventDefault();
|
|
1445
|
-
setSelected([item.id]);
|
|
1446
|
-
openTextEditor(item.id);
|
|
1447
|
-
});
|
|
1448
|
-
|
|
1449
|
-
wrap.addEventListener("pointerdown", function (event) {
|
|
1450
|
-
var svg = event.target.closest(".rbe-mermaid-canvas");
|
|
1451
|
-
if (!svg) return;
|
|
1452
|
-
if (wrap.querySelector(".rbe-mermaid-text-editor") && !event.target.closest(".rbe-mermaid-text-editor")) {
|
|
1453
|
-
closeTextEditor(true);
|
|
1454
|
-
svg = wrap.querySelector(".rbe-mermaid-canvas");
|
|
1455
|
-
if (!svg) return;
|
|
1456
|
-
}
|
|
1457
|
-
wrap.focus();
|
|
1458
|
-
event.preventDefault();
|
|
1459
|
-
var p = point(event);
|
|
1460
|
-
var handle = event.target.closest("[data-handle]");
|
|
1461
|
-
var target = event.target.closest("[data-el-id]");
|
|
1462
|
-
var tool = wrap.dataset.tool || "select";
|
|
1463
|
-
if (target && tool === "select" && !handle) {
|
|
1464
|
-
var targetId = target.dataset.elId;
|
|
1465
|
-
var now = Date.now();
|
|
1466
|
-
var isFastRepeat = lastShapePointer.id === targetId && now - lastShapePointer.time < 430;
|
|
1467
|
-
lastShapePointer = { id: targetId, time: now };
|
|
1468
|
-
if (Number(event.detail || 0) >= 2 || isFastRepeat) {
|
|
1469
|
-
var doubleClicked = elements().filter(function (elm) { return elm.id === targetId; })[0];
|
|
1470
|
-
if (editableDiagramElement(doubleClicked)) {
|
|
1471
|
-
drag = null;
|
|
1472
|
-
setSelected([doubleClicked.id]);
|
|
1473
|
-
openTextEditor(doubleClicked.id);
|
|
1474
|
-
return;
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
} else if (!target) {
|
|
1478
|
-
lastShapePointer = { id: "", time: 0 };
|
|
1479
|
-
}
|
|
1480
|
-
if (handle && selectedIds().length === 1) {
|
|
1481
|
-
pushUndo();
|
|
1482
|
-
drag = { mode: handle.dataset.handle === "rotate" ? "rotate" : "resize", handle: handle.dataset.handle, start: p, ids: selectedIds(), snapshot: elements() };
|
|
1483
|
-
svg.setPointerCapture(event.pointerId);
|
|
1484
|
-
return;
|
|
1485
|
-
}
|
|
1486
|
-
if (target && tool === "select") {
|
|
1487
|
-
var id = target.dataset.elId;
|
|
1488
|
-
var clicked = elements().filter(function (elm) { return elm.id === id; })[0];
|
|
1489
|
-
var groupIds = clicked && clicked.group ? elements().filter(function (elm) { return elm.group === clicked.group; }).map(function (elm) { return elm.id; }) : [id];
|
|
1490
|
-
var current = selectedIds();
|
|
1491
|
-
if (event.shiftKey || event.ctrlKey) {
|
|
1492
|
-
groupIds.forEach(function (groupId) {
|
|
1493
|
-
if (current.indexOf(groupId) === -1) current.push(groupId);
|
|
1494
|
-
else current = current.filter(function (item) { return item !== groupId; });
|
|
1495
|
-
});
|
|
1496
|
-
setSelected(current);
|
|
1497
|
-
} else if (current.indexOf(id) === -1) {
|
|
1498
|
-
setSelected(groupIds);
|
|
1499
|
-
}
|
|
1500
|
-
pushUndo();
|
|
1501
|
-
drag = { mode: "move", ids: selectedIds(), start: p, snapshot: elements() };
|
|
1502
|
-
svg.setPointerCapture(event.pointerId);
|
|
1503
|
-
return;
|
|
1504
|
-
}
|
|
1505
|
-
if (tool === "select") {
|
|
1506
|
-
setSelected([]);
|
|
1507
|
-
drag = { mode: "marquee", start: p };
|
|
1508
|
-
svg.setPointerCapture(event.pointerId);
|
|
1509
|
-
return;
|
|
1510
|
-
}
|
|
1511
|
-
var type = tool;
|
|
1512
|
-
if (!DIAGRAM_SHAPE_TYPES.test(type) && !DIAGRAM_LINE_TYPES.test(type)) return;
|
|
1513
|
-
pushUndo();
|
|
1514
|
-
var created = createElement(type, p);
|
|
1515
|
-
setElements(elements().concat([created]));
|
|
1516
|
-
setSelected([created.id]);
|
|
1517
|
-
drag = { mode: "draw", id: created.id, start: p };
|
|
1518
|
-
svg.setPointerCapture(event.pointerId);
|
|
1519
|
-
});
|
|
1520
|
-
|
|
1521
|
-
wrap.addEventListener("pointermove", function (event) {
|
|
1522
|
-
if (!drag) return;
|
|
1523
|
-
autoScrollStage(event);
|
|
1524
|
-
var p = point(event);
|
|
1525
|
-
resizeWorkspaceToFit(elements(), p);
|
|
1526
|
-
if (drag.mode === "marquee") {
|
|
1527
|
-
var marquee = { x: Math.min(drag.start.x, p.x), y: Math.min(drag.start.y, p.y), w: Math.abs(p.x - drag.start.x), h: Math.abs(p.y - drag.start.y) };
|
|
1528
|
-
wrap.dataset.marquee = JSON.stringify(marquee);
|
|
1529
|
-
renderDiagramCanvas(wrap);
|
|
1530
|
-
return;
|
|
1531
|
-
}
|
|
1532
|
-
var next = elements().map(function (elm) {
|
|
1533
|
-
if (drag.mode === "move" && drag.ids.indexOf(elm.id) !== -1) {
|
|
1534
|
-
var original = drag.snapshot.filter(function (item) { return item.id === elm.id; })[0] || elm;
|
|
1535
|
-
var dx = p.x - drag.start.x;
|
|
1536
|
-
var dy = p.y - drag.start.y;
|
|
1537
|
-
if (isLineType(elm.type)) {
|
|
1538
|
-
elm.x1 = original.x1 + dx;
|
|
1539
|
-
elm.y1 = original.y1 + dy;
|
|
1540
|
-
elm.x2 = original.x2 + dx;
|
|
1541
|
-
elm.y2 = original.y2 + dy;
|
|
1542
|
-
} else {
|
|
1543
|
-
elm.x = original.x + dx;
|
|
1544
|
-
elm.y = original.y + dy;
|
|
1545
|
-
}
|
|
1546
|
-
} else if (drag.mode === "draw" && elm.id === drag.id) {
|
|
1547
|
-
if (isLineType(elm.type)) {
|
|
1548
|
-
var linePoint = event.shiftKey ? constrainLinePoint(drag.start, p) : p;
|
|
1549
|
-
elm.x2 = linePoint.x;
|
|
1550
|
-
elm.y2 = linePoint.y;
|
|
1551
|
-
} else {
|
|
1552
|
-
elm.x = Math.min(drag.start.x, p.x);
|
|
1553
|
-
elm.y = Math.min(drag.start.y, p.y);
|
|
1554
|
-
elm.w = Math.max(40, Math.abs(p.x - drag.start.x));
|
|
1555
|
-
elm.h = Math.max(32, Math.abs(p.y - drag.start.y));
|
|
1556
|
-
}
|
|
1557
|
-
} else if ((drag.mode === "resize" || drag.mode === "rotate") && drag.ids.indexOf(elm.id) !== -1) {
|
|
1558
|
-
var base = drag.snapshot.filter(function (item) { return item.id === elm.id; })[0] || elm;
|
|
1559
|
-
if (isLineType(elm.type)) {
|
|
1560
|
-
if (drag.handle === "start") { elm.x1 = p.x; elm.y1 = p.y; }
|
|
1561
|
-
if (drag.handle === "end") { elm.x2 = p.x; elm.y2 = p.y; }
|
|
1562
|
-
} else if (drag.mode === "rotate") {
|
|
1563
|
-
var cx = base.x + base.w / 2;
|
|
1564
|
-
var cy = base.y + base.h / 2;
|
|
1565
|
-
elm.rotation = Math.round(Math.atan2(p.y - cy, p.x - cx) * 180 / Math.PI + 90);
|
|
1566
|
-
} else {
|
|
1567
|
-
var x2 = base.x + base.w;
|
|
1568
|
-
var y2 = base.y + base.h;
|
|
1569
|
-
if (/w/.test(drag.handle)) elm.x = p.x;
|
|
1570
|
-
if (/n/.test(drag.handle)) elm.y = p.y;
|
|
1571
|
-
if (/e/.test(drag.handle)) x2 = p.x;
|
|
1572
|
-
if (/s/.test(drag.handle)) y2 = p.y;
|
|
1573
|
-
elm.w = Math.max(24, x2 - elm.x);
|
|
1574
|
-
elm.h = Math.max(24, y2 - elm.y);
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
return elm;
|
|
1578
|
-
});
|
|
1579
|
-
setElements(next, false, p);
|
|
1580
|
-
});
|
|
1581
|
-
|
|
1582
|
-
wrap.addEventListener("pointerup", function () {
|
|
1583
|
-
if (!drag) return;
|
|
1584
|
-
var completedDrawId = drag.mode === "draw" ? drag.id : "";
|
|
1585
|
-
if (drag.mode === "marquee") {
|
|
1586
|
-
var marquee = JSON.parse(wrap.dataset.marquee || "{}");
|
|
1587
|
-
var ids = elements().filter(function (elm) { return rectsIntersect(elementBounds(elm), marquee); }).map(function (elm) { return elm.id; });
|
|
1588
|
-
wrap.dataset.marquee = "";
|
|
1589
|
-
setSelected(ids);
|
|
1590
|
-
}
|
|
1591
|
-
if (drag.mode === "draw") setTool("select");
|
|
1592
|
-
drag = null;
|
|
1593
|
-
refreshHistoryButtons();
|
|
1594
|
-
editor.changed(true);
|
|
1595
|
-
if (completedDrawId) {
|
|
1596
|
-
var item = elements().filter(function (elm) { return elm.id === completedDrawId; })[0];
|
|
1597
|
-
if (editableDiagramElement(item)) setTimeout(function () { openTextEditor(completedDrawId); }, 0);
|
|
1598
|
-
}
|
|
1599
|
-
});
|
|
1600
|
-
|
|
1601
|
-
wrap.addEventListener("keydown", function (event) {
|
|
1602
|
-
if (event.target.closest("input,textarea,select,[contenteditable='true']")) return;
|
|
1603
|
-
if (!event.ctrlKey && !event.metaKey && !event.altKey && event.key && event.key.length === 1) {
|
|
1604
|
-
var selected = selectedElements();
|
|
1605
|
-
if (selected.length === 1 && editableDiagramElement(selected[0])) {
|
|
1606
|
-
event.preventDefault();
|
|
1607
|
-
var existingText = String(selected[0].text || "").trim();
|
|
1608
|
-
var typedText = existingText ? existingText + (event.key === " " ? "" : " ") + event.key : event.key;
|
|
1609
|
-
openTextEditor(selected[0].id, typedText);
|
|
1610
|
-
return;
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
if (event.key === "Delete" || event.key === "Backspace") {
|
|
1614
|
-
event.preventDefault();
|
|
1615
|
-
applyAction("delete");
|
|
1616
|
-
}
|
|
1617
|
-
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "z") {
|
|
1618
|
-
event.preventDefault();
|
|
1619
|
-
if (event.shiftKey) redo();
|
|
1620
|
-
else undo();
|
|
1621
|
-
}
|
|
1622
|
-
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "y") {
|
|
1623
|
-
event.preventDefault();
|
|
1624
|
-
redo();
|
|
1625
|
-
}
|
|
1626
|
-
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "c") {
|
|
1627
|
-
event.preventDefault();
|
|
1628
|
-
applyAction("copy");
|
|
1629
|
-
}
|
|
1630
|
-
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "x") {
|
|
1631
|
-
event.preventDefault();
|
|
1632
|
-
applyAction("cut");
|
|
1633
|
-
}
|
|
1634
|
-
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "v") {
|
|
1635
|
-
event.preventDefault();
|
|
1636
|
-
applyAction("paste");
|
|
1637
|
-
}
|
|
1638
|
-
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "d") {
|
|
1639
|
-
event.preventDefault();
|
|
1640
|
-
applyAction("duplicate");
|
|
1641
|
-
}
|
|
1642
|
-
});
|
|
1643
|
-
|
|
1644
|
-
var imageInput = wrap.querySelector(".rbe-mermaid-image-input");
|
|
1645
|
-
function readMermaidImageAsDataURL(file) {
|
|
1646
|
-
return new Promise(function (resolve, reject) {
|
|
1647
|
-
var reader = new FileReader();
|
|
1648
|
-
reader.onload = function () { resolve({ url: reader.result, name: file.name }); };
|
|
1649
|
-
reader.onerror = function () { reject(reader.error || new Error("Image read failed")); };
|
|
1650
|
-
reader.readAsDataURL(file);
|
|
1651
|
-
});
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
function uploadMermaidImage(file) {
|
|
1655
|
-
if (editor && typeof editor.uploadFile === "function") {
|
|
1656
|
-
return editor.uploadFile(file, "image").catch(function () {
|
|
1657
|
-
return readMermaidImageAsDataURL(file);
|
|
1658
|
-
});
|
|
1659
|
-
}
|
|
1660
|
-
return readMermaidImageAsDataURL(file);
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
|
-
imageInput.addEventListener("change", function (event) {
|
|
1664
|
-
var file = event.target.files && event.target.files[0];
|
|
1665
|
-
if (!file || !/^image\//.test(file.type || "")) return;
|
|
1666
|
-
uploadMermaidImage(file).then(function (uploaded) {
|
|
1667
|
-
if (!uploaded || !uploaded.url) return;
|
|
1668
|
-
pushUndo();
|
|
1669
|
-
var workspace = readWorkspaceFromBlock(wrap);
|
|
1670
|
-
var created = createElement("image", { x: workspace.width / 2 - 140, y: 80 }, { url: uploaded.url, name: uploaded.name || file.name });
|
|
1671
|
-
created.w = 280;
|
|
1672
|
-
created.h = 190;
|
|
1673
|
-
setElements(elements().concat([created]));
|
|
1674
|
-
setSelected([created.id]);
|
|
1675
|
-
setTool("select");
|
|
1676
|
-
editor.changed(true);
|
|
1677
|
-
}).catch(function (error) {
|
|
1678
|
-
window.console && console.warn && console.warn("Mermaid image upload failed", error);
|
|
1679
|
-
});
|
|
1680
|
-
event.target.value = "";
|
|
1681
|
-
});
|
|
1682
|
-
|
|
1683
|
-
setTool("select");
|
|
1684
|
-
refreshHistoryButtons();
|
|
1685
|
-
updateOptions();
|
|
1686
|
-
}
|
|
1687
|
-
|
|
1688
|
-
function mermaidChoice(tool, icon, label) {
|
|
1689
|
-
return '<button type="button" class="rbe-mermaid-choice" data-tool="' + esc(tool) + '" title="' + esc(label) + '"><span aria-hidden="true">' + icon + '</span><span class="rbe-sr-only">' + esc(label) + "</span></button>";
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
function mermaidChoiceGrid(items) {
|
|
1693
|
-
return '<div class="rbe-mermaid-choice-grid">' + items.map(function (item) {
|
|
1694
|
-
return mermaidChoice(item[0], item[1], item[2]);
|
|
1695
|
-
}).join("") + "</div>";
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
function mermaidShapeMenuRow(label, icon, grid) {
|
|
1699
|
-
return '<div class="rbe-mermaid-menu-row"><span class="rbe-mermaid-menu-row-icon">' + faIcon(icon, label) + '</span><span>' + esc(label) + '</span><div class="rbe-mermaid-submenu">' + grid + "</div></div>";
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
function mermaidShapeMenu() {
|
|
1703
|
-
var basics = mermaidChoiceGrid([
|
|
1704
|
-
["rect", "□", "Rectangle"], ["roundedRect", "▢", "Rounded rectangle"], ["circle", "○", "Circle"], ["oval", "◯", "Oval"], ["triangle", "△", "Triangle"],
|
|
1705
|
-
["diamond", "◇", "Diamond"], ["pentagon", "⬟", "Pentagon"], ["hexagon", "⬡", "Hexagon"], ["parallelogram", "▱", "Parallelogram"], ["trapezoid", "⌂", "Trapezoid"],
|
|
1706
|
-
["octagon", "⬢", "Octagon"], ["heart", "♡", "Heart"], ["cloud", "☁", "Cloud"], ["cylinder", "◫", "Cylinder"], ["cube", "▣", "Cube"]
|
|
1707
|
-
]);
|
|
1708
|
-
var arrows = mermaidChoiceGrid([
|
|
1709
|
-
["arrow", "→", "Right arrow"], ["leftArrow", "←", "Left arrow"], ["upArrow", "↑", "Up arrow"], ["downArrow", "↓", "Down arrow"], ["biArrow", "↔", "Bidirectional arrow"]
|
|
1710
|
-
]);
|
|
1711
|
-
var callouts = mermaidChoiceGrid([
|
|
1712
|
-
["callout", "▱", "Callout"], ["roundCallout", "▢", "Rounded callout"], ["thought", "☁", "Thought bubble"]
|
|
1713
|
-
]);
|
|
1714
|
-
var equations = mermaidChoiceGrid([
|
|
1715
|
-
["plus", "+", "Plus"], ["minus", "−", "Minus"], ["multiply", "×", "Multiply"], ["divide", "÷", "Divide"], ["equal", "=", "Equal"], ["brackets", "[ ]", "Brackets"]
|
|
1716
|
-
]);
|
|
1717
|
-
return '<div class="rbe-mermaid-menu"><button type="button" class="rbe-mermaid-menu-btn" title="Shapes">' + faIcon("shapes", "Shapes") + '</button><div class="rbe-mermaid-popover">' + mermaidShapeMenuRow("Shapes", "square", basics) + mermaidShapeMenuRow("Arrows", "arrow-right", arrows) + mermaidShapeMenuRow("Callouts", "comment", callouts) + mermaidShapeMenuRow("Equation", "plus", equations) + "</div></div>";
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
function mermaidLineChoice(tool, icon, label) {
|
|
1721
|
-
return '<button type="button" class="rbe-mermaid-line-choice" data-tool="' + esc(tool) + '"><span class="rbe-mermaid-menu-row-icon">' + faIcon(icon, label) + '</span><span>' + esc(label) + "</span></button>";
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
function mermaidLineMenu() {
|
|
1725
|
-
return '<div class="rbe-mermaid-menu rbe-mermaid-line-menu"><button type="button" class="rbe-mermaid-menu-btn" title="Line options">' + faIcon("caret-down", "Line options") + '</button><div class="rbe-mermaid-popover">' +
|
|
1726
|
-
mermaidLineChoice("line", "minus", "Line") +
|
|
1727
|
-
mermaidLineChoice("arrow", "arrow-right-long", "Arrow") +
|
|
1728
|
-
mermaidLineChoice("elbow", "share-nodes", "Elbow Connector") +
|
|
1729
|
-
mermaidLineChoice("curved", "code-branch", "Curved Connector") +
|
|
1730
|
-
mermaidLineChoice("curve", "bezier-curve", "Curve") +
|
|
1731
|
-
mermaidLineChoice("polyline", "draw-polygon", "Polyline") +
|
|
1732
|
-
mermaidLineChoice("scribble", "signature", "Scribble") +
|
|
1733
|
-
"</div></div>";
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1736
|
-
function mermaidShapeStylebar() {
|
|
1737
|
-
return '<div class="rbe-mermaid-stylebar" hidden aria-label="Shape style controls">' +
|
|
1738
|
-
'<input class="rbe-mermaid-option-text rbe-mermaid-hidden-control" type="text" aria-hidden="true" tabindex="-1">' +
|
|
1739
|
-
'<input class="rbe-mermaid-option-opacity rbe-mermaid-hidden-control" type="hidden" value="1">' +
|
|
1740
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-fill-control" title="Fill color">' + faIcon("fill-drip", "Fill color") + '<span class="rbe-mermaid-control-swatch rbe-mermaid-fill-swatch"></span><input class="rbe-mermaid-option-fill" type="color" value="#eef5ff" aria-label="Fill color"></label>' +
|
|
1741
|
-
'<label class="rbe-mermaid-icon-control" title="Border color">' + faIcon("pen-nib", "Border color") + '<span class="rbe-mermaid-control-swatch rbe-mermaid-stroke-swatch"></span><input class="rbe-mermaid-option-stroke" type="color" value="#111827" aria-label="Border color"></label>' +
|
|
1742
|
-
'<label class="rbe-mermaid-icon-control" title="Border weight">' + faIcon("grip-lines", "Border weight") + '<select class="rbe-mermaid-option-weight" aria-label="Border weight"><option value="1">1px</option><option value="2">2px</option><option value="3">3px</option><option value="4">4px</option><option value="8">8px</option><option value="12">12px</option><option value="16">16px</option><option value="24">24px</option></select></label>' +
|
|
1743
|
-
'<label class="rbe-mermaid-icon-control" title="Border dash">' + faIcon("grip-lines-vertical", "Border dash") + '<select class="rbe-mermaid-option-dash" aria-label="Border dash"><option value="solid">Solid</option><option value="dotted">Dotted</option><option value="dashed">Dashed</option><option value="longDash">Long dash</option><option value="dashDot">Dash dot</option></select></label>' +
|
|
1744
|
-
'<span class="rbe-mermaid-toolbar-sep rbe-mermaid-text-control"></span>' +
|
|
1745
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-text-control" title="Font family">' + faIcon("font", "Font family") + '<select class="rbe-mermaid-option-font" aria-label="Font family"><option value="Arial">Arial</option><option value="Verdana">Verdana</option><option value="Tahoma">Tahoma</option><option value="Georgia">Georgia</option><option value="Times New Roman">Times New Roman</option><option value="Courier New">Courier New</option></select></label>' +
|
|
1746
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control" data-style-action="font-size-down" title="Decrease font size">' + faIcon("minus", "Decrease font size") + '</button>' +
|
|
1747
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-text-control" title="Font size">' + faIcon("text-height", "Font size") + '<select class="rbe-mermaid-option-size" aria-label="Font size"><option value="10">10</option><option value="12">12</option><option value="14">14</option><option value="16">16</option><option value="18">18</option><option value="20">20</option><option value="24">24</option><option value="28">28</option><option value="32">32</option><option value="40">40</option><option value="48">48</option><option value="64">64</option><option value="72">72</option></select></label>' +
|
|
1748
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control" data-style-action="font-size-up" title="Increase font size">' + faIcon("plus", "Increase font size") + '</button>' +
|
|
1749
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control" data-format-toggle="bold" title="Bold">' + faIcon("bold", "Bold") + '</button>' +
|
|
1750
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control" data-format-toggle="italic" title="Italic">' + faIcon("italic", "Italic") + '</button>' +
|
|
1751
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control" data-format-toggle="underline" title="Underline">' + faIcon("underline", "Underline") + '</button>' +
|
|
1752
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-text-control" title="Text color">' + faIcon("font", "Text color") + '<span class="rbe-mermaid-control-swatch rbe-mermaid-text-swatch"></span><input class="rbe-mermaid-option-text-color" type="color" value="#172033" aria-label="Text color"></label>' +
|
|
1753
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-text-control" title="Highlight color">' + faIcon("highlighter", "Highlight color") + '<span class="rbe-mermaid-control-swatch rbe-mermaid-highlight-swatch"></span><input class="rbe-mermaid-option-highlight" type="color" value="#fff3b0" aria-label="Highlight color"></label>' +
|
|
1754
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control" data-text-action="reset-highlight" title="Reset highlight">' + faIcon("rotate-left", "Reset highlight") + '</button>' +
|
|
1755
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-text-control" title="Text alignment">' + faIcon("align-center", "Text alignment") + '<select class="rbe-mermaid-option-align" aria-label="Text alignment"><option value="left">Left</option><option value="center">Center</option><option value="right">Right</option><option value="justify">Justify</option></select></label>' +
|
|
1756
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-text-control" title="Line spacing">' + faIcon("arrows-up-down", "Line spacing") + '<select class="rbe-mermaid-option-line-height" aria-label="Line spacing"><option value="1">Single</option><option value="1.15">1.15</option><option value="1.5">1.5</option><option value="2">Double</option></select></label>' +
|
|
1757
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-text-control rbe-mermaid-bullet-control" title="Bulleted list">' + faIcon("list-ul", "Bulleted list") + '<select class="rbe-mermaid-option-bullet" aria-label="Bulleted list"><option value="none">None</option><option value="disc">Disc</option><option value="circle">Circle</option><option value="square">Square</option></select></label>' +
|
|
1758
|
-
'<label class="rbe-mermaid-icon-control rbe-mermaid-text-control rbe-mermaid-number-control" title="Numbered list">' + faIcon("list-ol", "Numbered list") + '<select class="rbe-mermaid-option-number" aria-label="Numbered list"><option value="none">None</option><option value="decimal">1, 2, 3</option><option value="lower-alpha">a, b, c</option><option value="upper-alpha">A, B, C</option><option value="lower-roman">i, ii, iii</option><option value="upper-roman">I, II, III</option></select></label>' +
|
|
1759
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control" data-text-action="outdent" title="Decrease indent">' + faIcon("outdent", "Decrease indent") + '</button>' +
|
|
1760
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control" data-text-action="indent" title="Increase indent">' + faIcon("indent", "Increase indent") + '</button>' +
|
|
1761
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control rbe-mermaid-spacing-before" data-text-action="spacing-before" title="Add space before paragraph">' + faIcon("arrow-up", "Add space before paragraph") + '</button>' +
|
|
1762
|
-
'<button type="button" class="rbe-mermaid-style-btn rbe-mermaid-text-control rbe-mermaid-spacing-after" data-text-action="spacing-after" title="Add space after paragraph">' + faIcon("arrow-down", "Add space after paragraph") + '</button>' +
|
|
1763
|
-
"</div>";
|
|
1764
|
-
}
|
|
1765
|
-
|
|
1766
|
-
function mermaidDesignerToolbar() {
|
|
1767
|
-
return '<div class="rbe-mermaid-toolbar" role="toolbar" aria-label="Drawing tools">' +
|
|
1768
|
-
'<button type="button" class="rbe-mermaid-icon-btn" data-diagram-action="undo" title="Undo">' + faIcon("rotate-left", "Undo") + '</button>' +
|
|
1769
|
-
'<button type="button" class="rbe-mermaid-icon-btn" data-diagram-action="redo" title="Redo">' + faIcon("rotate-right", "Redo") + '</button>' +
|
|
1770
|
-
'<span class="rbe-mermaid-toolbar-sep"></span>' +
|
|
1771
|
-
'<button type="button" class="rbe-mermaid-tool" data-tool="select" title="Select">' + faIcon("arrow-pointer", "Select") + '</button>' +
|
|
1772
|
-
mermaidShapeMenu() +
|
|
1773
|
-
'<button type="button" class="rbe-mermaid-tool" data-tool="arrow" title="Arrow">' + faIcon("arrow-right-long", "Arrow") + '</button>' +
|
|
1774
|
-
mermaidLineMenu() +
|
|
1775
|
-
'<button type="button" class="rbe-mermaid-tool" data-tool="text" title="Text box">' + faIcon("font", "Text box") + '</button>' +
|
|
1776
|
-
'<button type="button" class="rbe-mermaid-icon-btn" data-diagram-action="image" title="Insert image">' + faIcon("image", "Insert image") + '</button>' +
|
|
1777
|
-
mermaidShapeStylebar() +
|
|
1778
|
-
"</div>";
|
|
1779
|
-
}
|
|
1780
|
-
|
|
1781
|
-
function refreshMermaidCardPreview(card) {
|
|
1782
|
-
var target = card.querySelector(".rbe-mermaid-card-preview");
|
|
1783
|
-
if (!target) return;
|
|
1784
|
-
var elements = [];
|
|
1785
|
-
try {
|
|
1786
|
-
elements = JSON.parse((card.querySelector(".rbe-mermaid-diagram-json") || {}).value || "[]").map(normalizeDiagramElement);
|
|
1787
|
-
} catch (error) {}
|
|
1788
|
-
if (!elements.length) {
|
|
1789
|
-
target.innerHTML = '<span class="rbe-mermaid-card-empty">Open the designer to draw a diagram.</span>';
|
|
1790
|
-
return;
|
|
1791
|
-
}
|
|
1792
|
-
target.innerHTML = '<div class="rbe-output-mermaid-diagram">' + diagramSvg(elements, "", readWorkspaceFromBlock(card), null) + "</div>";
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
function mermaidRulerMarkup() {
|
|
1796
|
-
var top = "";
|
|
1797
|
-
var side = "";
|
|
1798
|
-
for (var i = 1; i <= 10; i += 1) top += '<span style="left:' + (i * 100) + 'px">' + i + "</span>";
|
|
1799
|
-
for (var j = 1; j <= 7; j += 1) side += '<span style="top:' + (j * 100) + 'px">' + j + "</span>";
|
|
1800
|
-
return '<div class="rbe-mermaid-stage-shell"><div class="rbe-mermaid-ruler-corner"></div><div class="rbe-mermaid-top-ruler">' + top + '</div><div class="rbe-mermaid-side-ruler">' + side + '</div><div class="rbe-mermaid-stage"></div></div>';
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
function openMermaidDesignerModal(editor, card) {
|
|
1804
|
-
var existing = document.querySelector(".rbe-mermaid-modal");
|
|
1805
|
-
if (existing) {
|
|
1806
|
-
existing.remove();
|
|
1807
|
-
document.body.classList.remove("rbe-mermaid-modal-open");
|
|
1808
|
-
}
|
|
1809
|
-
var modal = document.createElement("div");
|
|
1810
|
-
modal.className = "rbe-mermaid-modal";
|
|
1811
|
-
modal.innerHTML =
|
|
1812
|
-
'<div class="rbe-mermaid-dialog" role="dialog" aria-modal="true" aria-label="Drawing">' +
|
|
1813
|
-
'<div class="rbe-mermaid-modal-head"><h2 class="rbe-mermaid-modal-title">Drawing</h2><button type="button" class="rbe-mermaid-close" data-modal-action="close" title="Close">' + faIcon("xmark", "Close") + '</button></div>' +
|
|
1814
|
-
'<div class="rbe-mermaid-modal-body"><div class="rbe-mermaid-block" tabindex="0">' +
|
|
1815
|
-
'<input type="hidden" class="rbe-mermaid-alignment"><input type="hidden" class="rbe-mermaid-diagram-json"><input class="rbe-mermaid-image-input" type="file" accept="image/*" hidden><textarea class="rbe-mermaid-code" hidden></textarea>' +
|
|
1816
|
-
mermaidDesignerToolbar() +
|
|
1817
|
-
'<input class="rbe-mermaid-workspace-w" type="hidden"><input class="rbe-mermaid-workspace-h" type="hidden"><input class="rbe-mermaid-zoom" type="hidden">' + mermaidRulerMarkup() +
|
|
1818
|
-
'</div></div>' +
|
|
1819
|
-
'<div class="rbe-mermaid-modal-foot"><button type="button" class="rbe-mermaid-modal-cancel" data-modal-action="close">Cancel</button><button type="button" class="rbe-mermaid-modal-save" data-modal-action="save">Save drawing</button></div>' +
|
|
1820
|
-
"</div>";
|
|
1821
|
-
function closeModal() {
|
|
1822
|
-
document.body.classList.remove("rbe-mermaid-modal-open");
|
|
1823
|
-
modal.remove();
|
|
1824
|
-
}
|
|
1825
|
-
document.body.classList.add("rbe-mermaid-modal-open");
|
|
1826
|
-
document.body.appendChild(modal);
|
|
1827
|
-
var designer = modal.querySelector(".rbe-mermaid-block");
|
|
1828
|
-
[".rbe-mermaid-alignment", ".rbe-mermaid-diagram-json", ".rbe-mermaid-code", ".rbe-mermaid-workspace-w", ".rbe-mermaid-workspace-h", ".rbe-mermaid-zoom"].forEach(function (selector) {
|
|
1829
|
-
var source = card.querySelector(selector);
|
|
1830
|
-
var target = designer.querySelector(selector);
|
|
1831
|
-
if (source && target) target.value = source.value || "";
|
|
1832
|
-
});
|
|
1833
|
-
renderDiagramCanvas(designer);
|
|
1834
|
-
bindMermaidDesigner(editor, designer);
|
|
1835
|
-
designer.focus();
|
|
1836
|
-
modal.addEventListener("click", function (event) {
|
|
1837
|
-
var actionButton = event.target.closest("[data-modal-action]");
|
|
1838
|
-
var action = actionButton ? actionButton.dataset.modalAction : "";
|
|
1839
|
-
if (!action) return;
|
|
1840
|
-
event.preventDefault();
|
|
1841
|
-
if (action === "save") {
|
|
1842
|
-
var textEditor = designer.querySelector(".rbe-mermaid-text-editor");
|
|
1843
|
-
if (textEditor && textEditor.dataset.editId) {
|
|
1844
|
-
var editId = textEditor.dataset.editId;
|
|
1845
|
-
var editedText = textEditor.value || textEditor.textContent || "";
|
|
1846
|
-
var current = [];
|
|
1847
|
-
try { current = JSON.parse((designer.querySelector(".rbe-mermaid-diagram-json") || {}).value || "[]"); } catch (error) {}
|
|
1848
|
-
designer.querySelector(".rbe-mermaid-diagram-json").value = JSON.stringify(current.map(function (elm) {
|
|
1849
|
-
elm = normalizeDiagramElement(elm);
|
|
1850
|
-
if (elm.id === editId) elm.text = editedText.trim();
|
|
1851
|
-
return elm;
|
|
1852
|
-
}));
|
|
1853
|
-
textEditor.remove();
|
|
1854
|
-
}
|
|
1855
|
-
[".rbe-mermaid-alignment", ".rbe-mermaid-diagram-json", ".rbe-mermaid-code", ".rbe-mermaid-workspace-w", ".rbe-mermaid-workspace-h", ".rbe-mermaid-zoom"].forEach(function (selector) {
|
|
1856
|
-
var source = designer.querySelector(selector);
|
|
1857
|
-
var target = card.querySelector(selector);
|
|
1858
|
-
if (source && target) target.value = source.value || "";
|
|
1859
|
-
});
|
|
1860
|
-
refreshMermaidCardPreview(card);
|
|
1861
|
-
editor.changed(true);
|
|
1862
|
-
}
|
|
1863
|
-
closeModal();
|
|
1864
|
-
});
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
function hydrateAdvancedOutput(root) {
|
|
1868
|
-
root = root || document;
|
|
1869
|
-
Array.prototype.slice.call(root.querySelectorAll(".rbe-output-latex")).forEach(function (node) {
|
|
1870
|
-
var code = node.dataset.latex || node.textContent || "";
|
|
1871
|
-
var display = node.dataset.display !== "false";
|
|
1872
|
-
if (node.dataset.renderedLatex === "true" && node.dataset.lastLatex === code && node.dataset.lastDisplay === String(display)) return;
|
|
1873
|
-
node.dataset.renderedLatex = "true";
|
|
1874
|
-
node.dataset.lastLatex = code;
|
|
1875
|
-
node.dataset.lastDisplay = String(display);
|
|
1876
|
-
renderLatexPreview(node, code, display);
|
|
1877
|
-
});
|
|
1878
|
-
Array.prototype.slice.call(root.querySelectorAll(".rbe-output-mermaid")).forEach(function (node) {
|
|
1879
|
-
var code = node.dataset.mermaid || node.textContent || "";
|
|
1880
|
-
if (node.dataset.renderedMermaid === "true" && node.dataset.lastMermaid === code) return;
|
|
1881
|
-
node.dataset.renderedMermaid = "true";
|
|
1882
|
-
node.dataset.lastMermaid = code;
|
|
1883
|
-
renderMermaidPreview(node, code);
|
|
1884
|
-
});
|
|
1885
|
-
}
|
|
1886
|
-
|
|
1887
|
-
function bootOutputHydration() {
|
|
1888
|
-
var run = function () { hydrateAdvancedOutput(document); };
|
|
1889
|
-
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", run, { once: true });
|
|
1890
|
-
else setTimeout(run, 0);
|
|
1891
|
-
if (!document.body) return;
|
|
1892
|
-
var timer = 0;
|
|
1893
|
-
new MutationObserver(function () {
|
|
1894
|
-
clearTimeout(timer);
|
|
1895
|
-
timer = setTimeout(run, 60);
|
|
1896
|
-
}).observe(document.body, { childList: true, subtree: true });
|
|
1897
|
-
}
|
|
1898
|
-
|
|
1899
|
-
function bindChange(editor, block, update) {
|
|
1900
|
-
block.addEventListener("input", function () {
|
|
1901
|
-
update();
|
|
1902
|
-
editor.changed();
|
|
1903
|
-
});
|
|
1904
|
-
block.addEventListener("change", function () {
|
|
1905
|
-
update();
|
|
1906
|
-
editor.changed();
|
|
1907
|
-
});
|
|
1908
|
-
}
|
|
1909
|
-
|
|
1910
|
-
function field(className, value) {
|
|
1911
|
-
return "." + className + " => " + value;
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
|
-
function chartCaptionAlignment(value) {
|
|
1915
|
-
value = String(value || "").toLowerCase();
|
|
1916
|
-
return value === "left" || value === "right" ? value : "center";
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
function plainTextFromHTML(value) {
|
|
1920
|
-
var template = document.createElement("template");
|
|
1921
|
-
template.innerHTML = sanitize(value || "");
|
|
1922
|
-
return template.content.textContent || "";
|
|
1923
|
-
}
|
|
1924
|
-
|
|
1925
|
-
BlockWriteAI.registerTool("chart", {
|
|
1926
|
-
label: "Chart",
|
|
1927
|
-
hint: "Bar, line, or pie chart",
|
|
1928
|
-
icon: "chart-column",
|
|
1929
|
-
defaultData: { type: "bar", title: "Chart", caption: "", labels: "Q1,Q2,Q3,Q4", values: "12,19,7,14", color: "#2563eb", colors: "#2563eb,#16a34a,#f59e0b,#dc2626" },
|
|
1930
|
-
render: function (body, data) {
|
|
1931
|
-
injectStyles();
|
|
1932
|
-
var editor = this;
|
|
1933
|
-
var wrap = el("div", "rbe-plugin-card rbe-chart-block");
|
|
1934
|
-
wrap.innerHTML =
|
|
1935
|
-
'<input class="rbe-chart-type" type="hidden">' +
|
|
1936
|
-
'<div class="rbe-plugin-toolbar"><input class="rbe-chart-title" placeholder="Chart title"><label class="rbe-chart-series-color">Color <input class="rbe-chart-color" type="color"></label><div class="rbe-chart-slice-colors" hidden><span class="rbe-chart-slice-label">Slice colors</span><div class="rbe-chart-slice-list"></div><input class="rbe-chart-colors" type="hidden"></div></div>' +
|
|
1937
|
-
'<div class="rbe-plugin-toolbar"><input class="rbe-chart-labels" placeholder="Labels: Q1,Q2,Q3"><input class="rbe-chart-values" placeholder="Values: 10,20,30"></div>' +
|
|
1938
|
-
'<div class="rbe-chart-preview-wrap"><div class="rbe-chart-type-bar" role="toolbar" aria-label="Chart type"><button type="button" class="rbe-chart-type-btn" data-chart-type="bar" title="Bar chart">' + faIcon("chart-column", "Bar chart") + '</button><button type="button" class="rbe-chart-type-btn" data-chart-type="line" title="Line chart">' + faIcon("chart-line", "Line chart") + '</button><button type="button" class="rbe-chart-type-btn" data-chart-type="pie" title="Pie chart">' + faIcon("chart-pie", "Pie chart") + '</button></div><div class="rbe-plugin-preview rbe-chart-preview"></div></div>' +
|
|
1939
|
-
'<div class="rbe-chart-caption rbe-editable" contenteditable="' + (!editor.readOnly) + '" data-placeholder="Chart caption"></div>';
|
|
1940
|
-
body.appendChild(wrap);
|
|
1941
|
-
wrap.querySelector(".rbe-chart-type").value = data.type === "line" || data.type === "pie" ? data.type : "bar";
|
|
1942
|
-
wrap.querySelector(".rbe-chart-title").value = data.title || "";
|
|
1943
|
-
wrap.querySelector(".rbe-chart-caption").innerHTML = sanitize(data.caption || "");
|
|
1944
|
-
wrap.querySelector(".rbe-chart-caption").style.textAlign = chartCaptionAlignment(data.captionAlignment || "center");
|
|
1945
|
-
wrap.querySelector(".rbe-chart-color").value = data.color || "#2563eb";
|
|
1946
|
-
wrap.querySelector(".rbe-chart-colors").value = data.colors || "#2563eb,#16a34a,#f59e0b,#dc2626";
|
|
1947
|
-
wrap.querySelector(".rbe-chart-labels").value = data.labels || "";
|
|
1948
|
-
wrap.querySelector(".rbe-chart-values").value = data.values || "";
|
|
1949
|
-
function syncSliceInputs() {
|
|
1950
|
-
var labels = labelList(wrap.querySelector(".rbe-chart-labels").value);
|
|
1951
|
-
var values = numberList(wrap.querySelector(".rbe-chart-values").value);
|
|
1952
|
-
var count = Math.max(1, labels.length, values.length);
|
|
1953
|
-
var hidden = wrap.querySelector(".rbe-chart-colors");
|
|
1954
|
-
var colors = chartColorList(hidden.value, count);
|
|
1955
|
-
var list = wrap.querySelector(".rbe-chart-slice-list");
|
|
1956
|
-
list.innerHTML = colors.map(function (item, index) {
|
|
1957
|
-
return '<label class="rbe-chart-slice-chip"><span>' + esc(labels[index] || "Q" + (index + 1)) + '</span><input type="color" value="' + esc(item) + '" data-slice-index="' + index + '"></label>';
|
|
1958
|
-
}).join("");
|
|
1959
|
-
hidden.value = colors.join(",");
|
|
1960
|
-
}
|
|
1961
|
-
function refreshTypeState() {
|
|
1962
|
-
var type = wrap.querySelector(".rbe-chart-type").value || "bar";
|
|
1963
|
-
Array.prototype.slice.call(wrap.querySelectorAll(".rbe-chart-type-btn")).forEach(function (button) {
|
|
1964
|
-
button.classList.toggle("is-active", button.dataset.chartType === type);
|
|
1965
|
-
});
|
|
1966
|
-
wrap.querySelector(".rbe-chart-series-color").hidden = type === "pie";
|
|
1967
|
-
wrap.querySelector(".rbe-chart-slice-colors").hidden = type !== "pie";
|
|
1968
|
-
if (type === "pie") syncSliceInputs();
|
|
1969
|
-
}
|
|
1970
|
-
var update = function () {
|
|
1971
|
-
refreshTypeState();
|
|
1972
|
-
wrap.querySelector(".rbe-chart-preview").innerHTML = chartSvg({
|
|
1973
|
-
type: wrap.querySelector(".rbe-chart-type").value,
|
|
1974
|
-
title: wrap.querySelector(".rbe-chart-title").value,
|
|
1975
|
-
color: wrap.querySelector(".rbe-chart-color").value,
|
|
1976
|
-
colors: wrap.querySelector(".rbe-chart-colors").value,
|
|
1977
|
-
labels: wrap.querySelector(".rbe-chart-labels").value,
|
|
1978
|
-
values: wrap.querySelector(".rbe-chart-values").value
|
|
1979
|
-
});
|
|
1980
|
-
};
|
|
1981
|
-
wrap.addEventListener("click", function (event) {
|
|
1982
|
-
var button = event.target.closest(".rbe-chart-type-btn");
|
|
1983
|
-
if (!button) return;
|
|
1984
|
-
event.preventDefault();
|
|
1985
|
-
wrap.querySelector(".rbe-chart-type").value = button.dataset.chartType || "bar";
|
|
1986
|
-
update();
|
|
1987
|
-
editor.changed(true);
|
|
1988
|
-
});
|
|
1989
|
-
wrap.addEventListener("input", function (event) {
|
|
1990
|
-
var color = event.target.closest(".rbe-chart-slice-chip input");
|
|
1991
|
-
if (!color) return;
|
|
1992
|
-
var inputs = Array.prototype.slice.call(wrap.querySelectorAll(".rbe-chart-slice-chip input"));
|
|
1993
|
-
wrap.querySelector(".rbe-chart-colors").value = inputs.map(function (input) { return input.value; }).join(",");
|
|
1994
|
-
});
|
|
1995
|
-
bindChange(editor, wrap, update);
|
|
1996
|
-
update();
|
|
1997
|
-
},
|
|
1998
|
-
serialize: function (block) {
|
|
1999
|
-
var caption = block.querySelector(".rbe-chart-caption");
|
|
2000
|
-
return {
|
|
2001
|
-
type: (block.querySelector(".rbe-chart-type") || {}).value || "bar",
|
|
2002
|
-
title: (block.querySelector(".rbe-chart-title") || {}).value || "",
|
|
2003
|
-
caption: caption ? sanitize(caption.innerHTML || "") : "",
|
|
2004
|
-
captionAlignment: chartCaptionAlignment(caption && caption.style ? caption.style.textAlign : "center"),
|
|
2005
|
-
color: (block.querySelector(".rbe-chart-color") || {}).value || "#2563eb",
|
|
2006
|
-
colors: (block.querySelector(".rbe-chart-colors") || {}).value || "",
|
|
2007
|
-
labels: (block.querySelector(".rbe-chart-labels") || {}).value || "",
|
|
2008
|
-
values: (block.querySelector(".rbe-chart-values") || {}).value || ""
|
|
2009
|
-
};
|
|
2010
|
-
},
|
|
2011
|
-
toHTML: function (data) {
|
|
2012
|
-
var captionAlignment = chartCaptionAlignment(data.captionAlignment || "center");
|
|
2013
|
-
return '<figure class="rbe-output-chart">' + (data.title ? '<figcaption class="rbe-output-chart-title">' + esc(data.title) + "</figcaption>" : "") + chartSvg(data) + (data.caption ? '<figcaption class="rbe-output-chart-caption" style="text-align:' + captionAlignment + '">' + inline(data.caption) + "</figcaption>" : "") + "</figure>";
|
|
2014
|
-
},
|
|
2015
|
-
toMarkdown: function (data) {
|
|
2016
|
-
return "Chart: " + (data.title || "") + (data.caption ? "\n" + plainTextFromHTML(data.caption) : "") + "\nLabels: " + (data.labels || "") + "\nValues: " + (data.values || "");
|
|
2017
|
-
}
|
|
2018
|
-
});
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
BlockWriteAI.registerTool("latex", {
|
|
2022
|
-
label: "LaTeX",
|
|
2023
|
-
hint: "Math formula block",
|
|
2024
|
-
icon: "square-root-variable",
|
|
2025
|
-
defaultData: { code: "\\\\int_a^b f(x) \\, dx", display: true },
|
|
2026
|
-
render: function (body, data) {
|
|
2027
|
-
injectStyles();
|
|
2028
|
-
var editor = this;
|
|
2029
|
-
var wrap = el("div", "rbe-plugin-card rbe-latex-block");
|
|
2030
|
-
wrap.innerHTML = '<textarea class="rbe-latex-code" spellcheck="false"></textarea><div class="rbe-plugin-preview rbe-latex-preview"></div>';
|
|
2031
|
-
body.appendChild(wrap);
|
|
2032
|
-
wrap.querySelector(".rbe-latex-code").value = data.code || "";
|
|
2033
|
-
var update = function () { renderLatexPreview(wrap.querySelector(".rbe-latex-preview"), wrap.querySelector(".rbe-latex-code").value, true); };
|
|
2034
|
-
bindChange(editor, wrap, update);
|
|
2035
|
-
update();
|
|
2036
|
-
},
|
|
2037
|
-
serialize: function (block) {
|
|
2038
|
-
return { code: (block.querySelector(".rbe-latex-code") || {}).value || "", display: true };
|
|
2039
|
-
},
|
|
2040
|
-
toHTML: function (data) {
|
|
2041
|
-
var code = data.code || "";
|
|
2042
|
-
return '<div class="rbe-output-latex" data-display="true" data-latex="' + esc(code) + '">' + latexFallbackHTML(code) + "</div>";
|
|
2043
|
-
},
|
|
2044
|
-
toMarkdown: function (data) {
|
|
2045
|
-
return "$$" + (data.code || "") + "$$";
|
|
2046
|
-
}
|
|
2047
|
-
});
|
|
2048
|
-
|
|
2049
|
-
BlockWriteAI.registerTool("audio", {
|
|
2050
|
-
label: "Audio",
|
|
2051
|
-
hint: "Upload or link audio",
|
|
2052
|
-
icon: "volume-high",
|
|
2053
|
-
defaultData: { url: "", title: "" },
|
|
2054
|
-
render: function (body, data) {
|
|
2055
|
-
injectStyles();
|
|
2056
|
-
var editor = this;
|
|
2057
|
-
var wrap = el("div", "rbe-plugin-card rbe-audio-block");
|
|
2058
|
-
wrap.innerHTML =
|
|
2059
|
-
'<input class="rbe-audio-title" type="hidden"><input class="rbe-audio-url" type="hidden">' +
|
|
2060
|
-
'<label class="rbe-upload-dropzone rbe-audio-dropzone"><input class="rbe-audio-file rbe-upload-input" type="file" accept="audio/*" ' + (editor.readOnly ? "disabled" : "") + '><span class="rbe-upload-icon">' + faIcon("cloud-arrow-up", "Upload audio") + '</span><strong>Drag and drop or click here</strong><span class="rbe-upload-main">to upload audio</span><small>MP3, WAV, OGG, M4A, AAC, and audio files only</small></label>' +
|
|
2061
|
-
'<div class="rbe-audio-preview"></div>';
|
|
2062
|
-
body.appendChild(wrap);
|
|
2063
|
-
wrap.querySelector(".rbe-audio-title").value = data.title || "";
|
|
2064
|
-
wrap.querySelector(".rbe-audio-url").value = data.url || "";
|
|
2065
|
-
var update = function () {
|
|
2066
|
-
var url = wrap.querySelector(".rbe-audio-url").value;
|
|
2067
|
-
var title = wrap.querySelector(".rbe-audio-title").value || "Audio";
|
|
2068
|
-
wrap.querySelector(".rbe-audio-preview").innerHTML = url ? '<div class="rbe-audio-card"><strong>' + esc(title) + '</strong><audio controls src="' + esc(url) + '"></audio><small>Drop or click above to replace audio</small></div>' : "";
|
|
2069
|
-
};
|
|
2070
|
-
function useFile(file) {
|
|
2071
|
-
var isAudio = !!file && (/^audio\//.test(file.type || "") || /\.(mp3|wav|ogg|m4a|aac|flac|webm)$/i.test(file.name || ""));
|
|
2072
|
-
if (!isAudio) {
|
|
2073
|
-
wrap.querySelector(".rbe-audio-preview").innerHTML = '<div class="rbe-audio-error">Please upload an audio file.</div>';
|
|
2074
|
-
return;
|
|
2075
|
-
}
|
|
2076
|
-
editor.uploadFile(file, "file").then(function (result) {
|
|
2077
|
-
wrap.querySelector(".rbe-audio-url").value = result.url || "";
|
|
2078
|
-
wrap.querySelector(".rbe-audio-title").value = result.name || file.name || "Audio";
|
|
2079
|
-
update();
|
|
2080
|
-
editor.changed(true);
|
|
2081
|
-
}).catch(function (error) {
|
|
2082
|
-
wrap.querySelector(".rbe-audio-preview").innerHTML = '<div class="rbe-audio-error">' + esc(error && error.message ? error.message : "Audio upload failed") + "</div>";
|
|
2083
|
-
});
|
|
2084
|
-
}
|
|
2085
|
-
wrap.querySelector(".rbe-audio-file").addEventListener("change", function (event) {
|
|
2086
|
-
var file = event.target.files && event.target.files[0];
|
|
2087
|
-
useFile(file);
|
|
2088
|
-
});
|
|
2089
|
-
wrap.querySelector(".rbe-audio-dropzone").addEventListener("dragover", function (event) {
|
|
2090
|
-
event.preventDefault();
|
|
2091
|
-
});
|
|
2092
|
-
wrap.querySelector(".rbe-audio-dropzone").addEventListener("drop", function (event) {
|
|
2093
|
-
event.preventDefault();
|
|
2094
|
-
useFile(event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]);
|
|
2095
|
-
});
|
|
2096
|
-
bindChange(editor, wrap, update);
|
|
2097
|
-
update();
|
|
2098
|
-
},
|
|
2099
|
-
serialize: function (block) {
|
|
2100
|
-
return { title: (block.querySelector(".rbe-audio-title") || {}).value || "", url: (block.querySelector(".rbe-audio-url") || {}).value || "" };
|
|
2101
|
-
},
|
|
2102
|
-
toHTML: function (data) {
|
|
2103
|
-
return '<figure class="rbe-output-audio">' + (data.url ? '<audio controls src="' + esc(data.url) + '"></audio>' : "") + "</figure>";
|
|
2104
|
-
},
|
|
2105
|
-
toMarkdown: function (data) {
|
|
2106
|
-
return "[" + (data.title || "Audio") + "](" + (data.url || "#") + ")";
|
|
2107
|
-
}
|
|
2108
|
-
});
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
BlockWriteAI.registerTool("columns", {
|
|
2112
|
-
label: "Columns",
|
|
2113
|
-
hint: "Multi-column layout",
|
|
2114
|
-
icon: "table-columns",
|
|
2115
|
-
defaultData: { count: 2, headers: ["Column 1", "Column 2"], columns: ["", ""] },
|
|
2116
|
-
render: function (body, data) {
|
|
2117
|
-
injectStyles();
|
|
2118
|
-
var editor = this;
|
|
2119
|
-
var maxColumns = 8;
|
|
2120
|
-
var count = Math.min(maxColumns, Math.max(2, Number(data.count || 2)));
|
|
2121
|
-
var headers = Array.isArray(data.headers) ? data.headers : [];
|
|
2122
|
-
var columns = Array.isArray(data.columns) ? data.columns : [];
|
|
2123
|
-
var headerAlignments = Array.isArray(data.headerAlignments) ? data.headerAlignments : [];
|
|
2124
|
-
var columnAlignments = Array.isArray(data.columnAlignments) ? data.columnAlignments : [];
|
|
2125
|
-
var wrap = el("div", "rbe-plugin-card rbe-columns-block");
|
|
2126
|
-
wrap.innerHTML = '<div class="rbe-plugin-toolbar"><label>Columns <select class="rbe-columns-count"></select></label></div><div class="rbe-columns-grid"></div>';
|
|
2127
|
-
body.appendChild(wrap);
|
|
2128
|
-
var select = wrap.querySelector(".rbe-columns-count");
|
|
2129
|
-
var grid = wrap.querySelector(".rbe-columns-grid");
|
|
2130
|
-
for (var optionCount = 2; optionCount <= maxColumns; optionCount += 1) {
|
|
2131
|
-
select.appendChild(el("option", "", { value: String(optionCount), text: String(optionCount) }));
|
|
2132
|
-
}
|
|
2133
|
-
select.value = String(count);
|
|
2134
|
-
function cleanAlign(value) {
|
|
2135
|
-
value = String(value || "").toLowerCase();
|
|
2136
|
-
return value === "center" || value === "right" ? value : "left";
|
|
2137
|
-
}
|
|
2138
|
-
function renderColumns() {
|
|
2139
|
-
var nextCount = Number(select.value || 2);
|
|
2140
|
-
var currentHeaders = Array.prototype.slice.call(grid.querySelectorAll(".rbe-column-header")).map(function (item) { return item.innerHTML; });
|
|
2141
|
-
var current = Array.prototype.slice.call(grid.querySelectorAll(".rbe-column-editor")).map(function (item) { return item.innerHTML; });
|
|
2142
|
-
var currentHeaderAlignments = Array.prototype.slice.call(grid.querySelectorAll(".rbe-column-header")).map(function (item) { return cleanAlign(item.style.textAlign); });
|
|
2143
|
-
var currentColumnAlignments = Array.prototype.slice.call(grid.querySelectorAll(".rbe-column-editor")).map(function (item) { return cleanAlign(item.style.textAlign); });
|
|
2144
|
-
grid.innerHTML = "";
|
|
2145
|
-
grid.style.gridTemplateColumns = "repeat(" + nextCount + ", minmax(220px, 1fr))";
|
|
2146
|
-
for (var i = 0; i < nextCount; i += 1) {
|
|
2147
|
-
var column = el("div", "rbe-column-field");
|
|
2148
|
-
var header = el("div", "rbe-column-header rbe-editable", {
|
|
2149
|
-
contentEditable: !editor.readOnly,
|
|
2150
|
-
html: sanitize(currentHeaders[i] || headers[i] || "Column " + (i + 1)),
|
|
2151
|
-
dataset: { placeholder: "Column " + (i + 1) + " header" }
|
|
2152
|
-
});
|
|
2153
|
-
header.style.textAlign = cleanAlign(currentHeaderAlignments[i] || headerAlignments[i]);
|
|
2154
|
-
column.appendChild(header);
|
|
2155
|
-
var field = el("div", "rbe-column-editor rbe-editable", {
|
|
2156
|
-
contentEditable: !editor.readOnly,
|
|
2157
|
-
html: sanitize(current[i] || columns[i] || ""),
|
|
2158
|
-
dataset: { placeholder: "Column " + (i + 1) }
|
|
2159
|
-
});
|
|
2160
|
-
field.style.textAlign = cleanAlign(currentColumnAlignments[i] || columnAlignments[i]);
|
|
2161
|
-
column.appendChild(field);
|
|
2162
|
-
grid.appendChild(column);
|
|
2163
|
-
}
|
|
2164
|
-
}
|
|
2165
|
-
select.addEventListener("change", function () {
|
|
2166
|
-
renderColumns();
|
|
2167
|
-
editor.changed(true);
|
|
2168
|
-
});
|
|
2169
|
-
grid.addEventListener("input", function () { editor.changed(); });
|
|
2170
|
-
renderColumns();
|
|
2171
|
-
},
|
|
2172
|
-
serialize: function (block) {
|
|
2173
|
-
function cleanAlign(value) {
|
|
2174
|
-
value = String(value || "").toLowerCase();
|
|
2175
|
-
return value === "center" || value === "right" ? value : "left";
|
|
2176
|
-
}
|
|
2177
|
-
return {
|
|
2178
|
-
count: Number((block.querySelector(".rbe-columns-count") || {}).value || 2),
|
|
2179
|
-
headers: Array.prototype.slice.call(block.querySelectorAll(".rbe-column-header")).map(function (item) { return sanitize(item.innerHTML || ""); }),
|
|
2180
|
-
columns: Array.prototype.slice.call(block.querySelectorAll(".rbe-column-editor")).map(function (item) { return sanitize(item.innerHTML || ""); }),
|
|
2181
|
-
headerAlignments: Array.prototype.slice.call(block.querySelectorAll(".rbe-column-header")).map(function (item) { return cleanAlign(item.style.textAlign); }),
|
|
2182
|
-
columnAlignments: Array.prototype.slice.call(block.querySelectorAll(".rbe-column-editor")).map(function (item) { return cleanAlign(item.style.textAlign); })
|
|
2183
|
-
};
|
|
2184
|
-
},
|
|
2185
|
-
toHTML: function (data) {
|
|
2186
|
-
function cleanAlign(value) {
|
|
2187
|
-
value = String(value || "").toLowerCase();
|
|
2188
|
-
return value === "center" || value === "right" ? value : "left";
|
|
2189
|
-
}
|
|
2190
|
-
var count = Math.min(8, Math.max(2, Number(data.count || 2)));
|
|
2191
|
-
var headers = Array.isArray(data.headers) ? data.headers : [];
|
|
2192
|
-
var columns = Array.isArray(data.columns) ? data.columns.slice(0, count) : [];
|
|
2193
|
-
var headerAlignments = Array.isArray(data.headerAlignments) ? data.headerAlignments : [];
|
|
2194
|
-
var columnAlignments = Array.isArray(data.columnAlignments) ? data.columnAlignments : [];
|
|
2195
|
-
while (columns.length < count) columns.push("");
|
|
2196
|
-
return '<div class="rbe-output-columns" style="--rbe-columns:' + count + '">' + columns.map(function (column, index) {
|
|
2197
|
-
var header = headers[index] || "Column " + (index + 1);
|
|
2198
|
-
var headerAlign = cleanAlign(headerAlignments[index]);
|
|
2199
|
-
var columnAlign = cleanAlign(columnAlignments[index]);
|
|
2200
|
-
return '<div class="rbe-output-column"><div class="rbe-output-column-header" style="text-align:' + headerAlign + '">' + inline(header) + '</div><div class="rbe-output-column-body" style="text-align:' + columnAlign + '">' + inline(column || "") + "</div></div>";
|
|
2201
|
-
}).join("") + "</div>";
|
|
2202
|
-
},
|
|
2203
|
-
toMarkdown: function (data, helpers) {
|
|
2204
|
-
return (data.columns || []).map(function (column, index) {
|
|
2205
|
-
var headers = Array.isArray(data.headers) ? data.headers : [];
|
|
2206
|
-
return (headers[index] || "Column " + (index + 1)) + "\n" + (helpers.text ? helpers.text(column) : column);
|
|
2207
|
-
}).join("\n\n");
|
|
2208
|
-
}
|
|
2209
|
-
});
|
|
2210
|
-
|
|
2211
|
-
function applyImageTransform(stage, editor) {
|
|
2212
|
-
if (!stage) return;
|
|
2213
|
-
var image = stage.querySelector(".rbe-image-preview");
|
|
2214
|
-
var rotation = Number(stage.dataset.rotation || 0);
|
|
2215
|
-
stage.dataset.rotation = String(rotation);
|
|
2216
|
-
if (editor && typeof editor.applyImageStageState === "function") editor.applyImageStageState(stage);
|
|
2217
|
-
else if (image) image.style.transform = "rotate(" + rotation + "deg)";
|
|
2218
|
-
}
|
|
2219
|
-
|
|
2220
|
-
function enhanceImageStages(editor, body, data) {
|
|
2221
|
-
var items = Array.isArray(data && data.items) ? data.items : data && data.url ? [data] : [];
|
|
2222
|
-
Array.prototype.slice.call(body.querySelectorAll(".rbe-image-stage")).forEach(function (stage, index) {
|
|
2223
|
-
var item = items[index] || {};
|
|
2224
|
-
stage.dataset.rotation = item.rotation || stage.dataset.rotation || "0";
|
|
2225
|
-
stage.dataset.crop = item.crop === "custom" ? "custom" : stage.dataset.crop || "free";
|
|
2226
|
-
applyImageTransform(stage, editor);
|
|
2227
|
-
var menu = stage.querySelector(".rbe-media-gear-menu");
|
|
2228
|
-
if (!menu || stage.querySelector(":scope > .rbe-image-transform-panel")) return;
|
|
2229
|
-
var panel = document.createElement("div");
|
|
2230
|
-
panel.className = "rbe-image-transform-panel";
|
|
2231
|
-
panel.innerHTML =
|
|
2232
|
-
'<button type="button" class="rbe-media-action rbe-image-transform" data-transform="rotate-left" title="Rotate left">' + faIcon("rotate-left", "Rotate left") + '</button>' +
|
|
2233
|
-
'<button type="button" class="rbe-media-action rbe-image-transform" data-transform="rotate-right" title="Rotate right">' + faIcon("rotate-right", "Rotate right") + '</button>';
|
|
2234
|
-
stage.appendChild(panel);
|
|
2235
|
-
});
|
|
2236
|
-
}
|
|
2237
|
-
|
|
2238
|
-
var originalRenderImage = BlockWriteAI.prototype.renderImage;
|
|
2239
|
-
BlockWriteAI.prototype.renderImage = function (body, data) {
|
|
2240
|
-
originalRenderImage.call(this, body, data || {});
|
|
2241
|
-
enhanceImageStages(this, body, data || {});
|
|
2242
|
-
};
|
|
2243
|
-
|
|
2244
|
-
var originalSerializeBlock = BlockWriteAI.prototype.serializeBlock;
|
|
2245
|
-
BlockWriteAI.prototype.serializeBlock = function (block) {
|
|
2246
|
-
var result = originalSerializeBlock.call(this, block);
|
|
2247
|
-
if (result && result.type === "image") {
|
|
2248
|
-
var stages = Array.prototype.slice.call(block.querySelectorAll(".rbe-image-stage"));
|
|
2249
|
-
result.data.items = (result.data.items || []).map(function (item, index) {
|
|
2250
|
-
var stage = stages[index];
|
|
2251
|
-
if (!stage) return item;
|
|
2252
|
-
item.rotation = Number(stage.dataset.rotation || 0);
|
|
2253
|
-
item.crop = stage.dataset.crop === "custom" ? "custom" : "free";
|
|
2254
|
-
return item;
|
|
2255
|
-
});
|
|
2256
|
-
}
|
|
2257
|
-
return result;
|
|
2258
|
-
};
|
|
2259
|
-
|
|
2260
|
-
document.addEventListener("click", function (event) {
|
|
2261
|
-
var button = event.target.closest(".rbe-image-transform");
|
|
2262
|
-
if (!button) return;
|
|
2263
|
-
var stage = button.closest(".rbe-image-stage");
|
|
2264
|
-
var block = button.closest(".rbe-block");
|
|
2265
|
-
if (!stage || !block) return;
|
|
2266
|
-
event.preventDefault();
|
|
2267
|
-
var action = button.dataset.transform || "";
|
|
2268
|
-
if (action === "rotate-left") stage.dataset.rotation = String((Number(stage.dataset.rotation || 0) - 90) % 360);
|
|
2269
|
-
if (action === "rotate-right") stage.dataset.rotation = String((Number(stage.dataset.rotation || 0) + 90) % 360);
|
|
2270
|
-
var root = block.closest(".rbe");
|
|
2271
|
-
if (root && root.__blockwriteaiInstance) {
|
|
2272
|
-
applyImageTransform(stage, root.__blockwriteaiInstance);
|
|
2273
|
-
root.__blockwriteaiInstance.updateMediaActionAvailability(stage.closest(".rbe-image-gallery") || block);
|
|
2274
|
-
root.__blockwriteaiInstance.changed(true);
|
|
2275
|
-
} else {
|
|
2276
|
-
applyImageTransform(stage);
|
|
2277
|
-
}
|
|
2278
|
-
});
|
|
2279
|
-
|
|
2280
|
-
injectStyles();
|
|
2281
|
-
bootOutputHydration();
|
|
2282
|
-
})(typeof window !== "undefined" ? window : this);
|