@zenuml/core 3.33.0 → 3.34.0
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/.kiro/hooks/README.md +38 -0
- package/.kiro/hooks/session-sound-notification.js +44 -0
- package/.kiro/hooks/session-sound-notification.json +23 -0
- package/DEPLOYMENT.md +62 -0
- package/dist/zenuml.esm.mjs +2 -2
- package/dist/zenuml.js +2 -2
- package/index.html +131 -42
- package/package.json +8 -3
- package/renderer.html +366 -0
- package/test-compression.html +274 -0
- package/test-url-params.html +192 -0
- package/vite.config.ts +1 -1
- package/wrangler.toml +12 -0
package/index.html
CHANGED
|
@@ -8,20 +8,14 @@
|
|
|
8
8
|
<link
|
|
9
9
|
rel="preload stylesheet"
|
|
10
10
|
as="style"
|
|
11
|
-
href="https://fonts.googleapis.com/css2?family=
|
|
11
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap"
|
|
12
12
|
/>
|
|
13
13
|
<style id="zenumlstyle">
|
|
14
|
-
/*
|
|
15
|
-
/*@import url('https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap');*/
|
|
16
|
-
/*!*@import url("https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@300;400;500;700&display=swap");*!*/
|
|
17
|
-
|
|
18
|
-
/*#diagram1 .sequence-diagram {*/
|
|
19
|
-
/* font-family: "Kalam", serif;*/
|
|
20
|
-
/*}*/
|
|
14
|
+
/* Custom styles for the diagram */
|
|
21
15
|
</style>
|
|
22
16
|
<link
|
|
23
17
|
rel="stylesheet"
|
|
24
|
-
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/
|
|
18
|
+
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github-dark.min.css"
|
|
25
19
|
crossorigin="anonymous"
|
|
26
20
|
/>
|
|
27
21
|
<script src="https://cdn.jsdelivr.net/npm/codemirror@5.65.1/lib/codemirror.min.js"></script>
|
|
@@ -32,61 +26,102 @@
|
|
|
32
26
|
crossorigin="anonymous"
|
|
33
27
|
referrerpolicy="no-referrer"
|
|
34
28
|
/>
|
|
35
|
-
<
|
|
29
|
+
<link
|
|
30
|
+
rel="stylesheet"
|
|
31
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.1/theme/material-darker.min.css"
|
|
32
|
+
crossorigin="anonymous"
|
|
33
|
+
/>
|
|
34
|
+
<title>ZenUML - Local Development</title>
|
|
36
35
|
<style>
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
* {
|
|
37
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
|
39
38
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
font-family: monospace;
|
|
43
|
-
font-size: 13px;
|
|
44
|
-
height: 100vh;
|
|
39
|
+
|
|
40
|
+
code, .CodeMirror {
|
|
41
|
+
font-family: 'JetBrains Mono', 'Monaco', 'Consolas', monospace;
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
.
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
.CodeMirror {
|
|
45
|
+
font-size: 14px;
|
|
46
|
+
height: 100%;
|
|
47
|
+
overflow: hidden;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
.
|
|
53
|
-
|
|
50
|
+
.CodeMirror-scroll {
|
|
51
|
+
padding: 1rem;
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
.
|
|
57
|
-
|
|
54
|
+
.zenuml .CodeMirror .CodeMirror-cursor {
|
|
55
|
+
border-color: #fff;
|
|
56
|
+
border-left-width: 2px;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
.
|
|
61
|
-
|
|
59
|
+
.gradient-text {
|
|
60
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
61
|
+
-webkit-background-clip: text;
|
|
62
|
+
-webkit-text-fill-color: transparent;
|
|
63
|
+
background-clip: text;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
|
|
67
|
+
.editor-shadow {
|
|
68
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
66
69
|
}
|
|
67
70
|
</style>
|
|
71
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
68
72
|
</head>
|
|
69
|
-
<body>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
73
|
+
<body class="bg-gray-50">
|
|
74
|
+
<!-- Main Editor Section -->
|
|
75
|
+
<div class="w-full h-screen p-4">
|
|
76
|
+
<div class="grid grid-cols-2 gap-4 h-full" id="diagram1">
|
|
77
|
+
<!-- Editor Panel -->
|
|
78
|
+
<div class="bg-white rounded-lg shadow-lg editor-shadow overflow-hidden h-full">
|
|
79
|
+
<div class="bg-gray-800 text-white px-4 py-3 flex items-center justify-between">
|
|
80
|
+
<h3 class="font-medium">Editor</h3>
|
|
81
|
+
<div class="flex space-x-2">
|
|
82
|
+
<button onclick="loadExample('basic')" class="text-sm bg-gray-700 hover:bg-gray-600 px-3 py-1 rounded transition-colors">
|
|
83
|
+
Basic
|
|
84
|
+
</button>
|
|
85
|
+
<button onclick="loadExample('advanced')" class="text-sm bg-gray-700 hover:bg-gray-600 px-3 py-1 rounded transition-colors">
|
|
86
|
+
Advanced
|
|
87
|
+
</button>
|
|
88
|
+
<button onclick="clearEditor()" class="text-sm bg-gray-700 hover:bg-gray-600 px-3 py-1 rounded transition-colors">
|
|
89
|
+
Clear
|
|
90
|
+
</button>
|
|
91
|
+
<button onclick="exportDiagram()" class="text-sm bg-blue-600 hover:bg-blue-700 px-3 py-1 rounded transition-colors">
|
|
92
|
+
Export PNG
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<div style="height: calc(100% - 52px);">
|
|
97
|
+
<textarea id="text" style="display: none;"></textarea>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Preview Panel -->
|
|
102
|
+
<div class="bg-white rounded-lg shadow-lg editor-shadow overflow-hidden h-full">
|
|
103
|
+
<div class="bg-gray-800 text-white px-4 py-3">
|
|
104
|
+
<h3 class="font-medium">Preview</h3>
|
|
105
|
+
</div>
|
|
106
|
+
<div style="height: calc(100% - 52px); overflow: auto;" class="p-4">
|
|
107
|
+
<pre class="zenuml" style="margin: 0"></pre>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
81
110
|
</div>
|
|
82
111
|
</div>
|
|
112
|
+
|
|
113
|
+
|
|
83
114
|
<script type="module">
|
|
84
115
|
import { waitUntil, debounce } from "./src/utils.ts";
|
|
85
116
|
import { createConfig } from "./src/config.ts";
|
|
117
|
+
import { toPng } from "html-to-image";
|
|
86
118
|
|
|
87
119
|
const editor = CodeMirror.fromTextArea(document.getElementById("text"), {
|
|
88
120
|
lineNumbers: true,
|
|
89
121
|
singleCursorHeightPerLine: false,
|
|
122
|
+
theme: "material-darker",
|
|
123
|
+
mode: "text/plain",
|
|
124
|
+
autofocus: true,
|
|
90
125
|
});
|
|
91
126
|
|
|
92
127
|
const updateDiagram = debounce((content) => {
|
|
@@ -112,12 +147,66 @@
|
|
|
112
147
|
);
|
|
113
148
|
});
|
|
114
149
|
|
|
115
|
-
//
|
|
150
|
+
// Example data
|
|
151
|
+
const examples = {
|
|
152
|
+
basic: `Alice -> Bob: Hello Bob!
|
|
153
|
+
Bob -> Alice: Hello Alice!`,
|
|
154
|
+
advanced: `title Online Shopping
|
|
155
|
+
participant Customer
|
|
156
|
+
participant WebApp
|
|
157
|
+
participant PaymentService
|
|
158
|
+
participant Database
|
|
159
|
+
|
|
160
|
+
Customer -> WebApp: Browse products
|
|
161
|
+
WebApp -> Database: Query products
|
|
162
|
+
Database --> WebApp: Return products
|
|
163
|
+
WebApp --> Customer: Display products
|
|
164
|
+
|
|
165
|
+
Customer -> WebApp: Add to cart
|
|
166
|
+
WebApp -> Database: Update cart
|
|
167
|
+
Database --> WebApp: Cart updated
|
|
168
|
+
WebApp --> Customer: Show cart
|
|
169
|
+
|
|
170
|
+
Customer -> WebApp: Checkout
|
|
171
|
+
WebApp -> PaymentService: Process payment
|
|
172
|
+
PaymentService --> WebApp: Payment confirmed
|
|
173
|
+
WebApp -> Database: Create order
|
|
174
|
+
Database --> WebApp: Order created
|
|
175
|
+
WebApp --> Customer: Order confirmation`
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Global functions
|
|
179
|
+
window.loadExample = function(type) {
|
|
180
|
+
editor.setValue(examples[type] || examples.basic);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
window.clearEditor = function() {
|
|
184
|
+
editor.setValue('');
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
window.exportDiagram = async function() {
|
|
188
|
+
const element = document.querySelector('.zenuml');
|
|
189
|
+
if (element) {
|
|
190
|
+
try {
|
|
191
|
+
const dataUrl = await toPng(element);
|
|
192
|
+
const link = document.createElement('a');
|
|
193
|
+
link.download = 'sequence-diagram.png';
|
|
194
|
+
link.href = dataUrl;
|
|
195
|
+
link.click();
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.error('Failed to export diagram:', error);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Load saved code from localStorage or default example
|
|
116
203
|
const savedCode = localStorage.getItem("zenuml-cm-code");
|
|
117
204
|
if (savedCode) {
|
|
118
205
|
editor.setValue(savedCode);
|
|
206
|
+
} else {
|
|
207
|
+
editor.setValue(examples.basic);
|
|
119
208
|
}
|
|
120
209
|
</script>
|
|
121
210
|
<script type="module" src="/src/main.tsx"></script>
|
|
122
211
|
</body>
|
|
123
|
-
</html>
|
|
212
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenuml/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.34.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,7 +36,10 @@
|
|
|
36
36
|
"git:forget": "git rm -r --cached . && git add . && git commit -m \"Forget all ignored files\"",
|
|
37
37
|
"test:specs": "echo \"Error: test:specs is not supported\"",
|
|
38
38
|
"storybook": "storybook dev -p 6006",
|
|
39
|
-
"build-storybook": "storybook build"
|
|
39
|
+
"build-storybook": "storybook build",
|
|
40
|
+
"worker:dev": "pnpm build:site && wrangler dev",
|
|
41
|
+
"worker:deploy": "pnpm build:site && wrangler deploy",
|
|
42
|
+
"worker:deploy:staging": "pnpm build:site && wrangler deploy --env staging"
|
|
40
43
|
},
|
|
41
44
|
"main": "./dist/zenuml.js",
|
|
42
45
|
"module": "./dist/zenuml.esm.mjs",
|
|
@@ -70,6 +73,7 @@
|
|
|
70
73
|
"immer": "^10.1.1",
|
|
71
74
|
"jotai": "^2.12.2",
|
|
72
75
|
"marked": "^4.3.0",
|
|
76
|
+
"pako": "^2.1.0",
|
|
73
77
|
"pino": "^8.8.0",
|
|
74
78
|
"radash": "^12.1.0",
|
|
75
79
|
"ramda": "^0.28.0",
|
|
@@ -115,6 +119,7 @@
|
|
|
115
119
|
"vite-plugin-css-injected-by-js": "^3.5.2",
|
|
116
120
|
"vite-plugin-svgr": "^4.3.0",
|
|
117
121
|
"vite-svg-loader": "^5.1.0",
|
|
118
|
-
"vitest": "^3.1.1"
|
|
122
|
+
"vitest": "^3.1.1",
|
|
123
|
+
"wrangler": "^4.25.0"
|
|
119
124
|
}
|
|
120
125
|
}
|
package/renderer.html
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" style="height: 100%; width: 100%">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
7
|
+
<title>ZenUML Web Renderer</title>
|
|
8
|
+
<meta name="description" content="ZenUML Web Renderer - Render sequence diagrams from URL parameters" />
|
|
9
|
+
<meta name="keywords" content="zenuml, sequence diagram, uml, renderer, web" />
|
|
10
|
+
|
|
11
|
+
<!-- Favicon -->
|
|
12
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
13
|
+
|
|
14
|
+
<!-- Fonts -->
|
|
15
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
16
|
+
<link
|
|
17
|
+
rel="preload stylesheet"
|
|
18
|
+
as="style"
|
|
19
|
+
href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@300;400;500;700&display=swap"
|
|
20
|
+
/>
|
|
21
|
+
|
|
22
|
+
<!-- Basic styles for the renderer -->
|
|
23
|
+
<style>
|
|
24
|
+
* {
|
|
25
|
+
box-sizing: border-box;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
body {
|
|
29
|
+
margin: 0;
|
|
30
|
+
padding: 0;
|
|
31
|
+
font-family: 'Roboto Slab', serif, system-ui, -apple-system, sans-serif;
|
|
32
|
+
background-color: white;
|
|
33
|
+
height: 100vh;
|
|
34
|
+
width: 100vw;
|
|
35
|
+
overflow: auto;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.zenuml {
|
|
39
|
+
width: 100%;
|
|
40
|
+
height: 100%;
|
|
41
|
+
margin: 0;
|
|
42
|
+
padding: 0;
|
|
43
|
+
overflow: auto;
|
|
44
|
+
text-align: center;
|
|
45
|
+
}
|
|
46
|
+
</style>
|
|
47
|
+
</head>
|
|
48
|
+
<body>
|
|
49
|
+
<!-- ZenUML diagram container -->
|
|
50
|
+
<pre class="zenuml" id="zenuml-diagram"></pre>
|
|
51
|
+
|
|
52
|
+
<!-- Initialize the renderer -->
|
|
53
|
+
<script type="module">
|
|
54
|
+
import pako from 'pako';
|
|
55
|
+
// ZenUML Web Renderer initialization
|
|
56
|
+
console.log('ZenUML Web Renderer initializing...');
|
|
57
|
+
|
|
58
|
+
// Default empty ZenUML code to display when no URL parameters are provided
|
|
59
|
+
const DEFAULT_ZENUML_CODE = `title ZenUML Web Renderer
|
|
60
|
+
A.method() {
|
|
61
|
+
B.process()
|
|
62
|
+
return result
|
|
63
|
+
}`;
|
|
64
|
+
|
|
65
|
+
// URL parameter extraction functionality
|
|
66
|
+
function extractCodeFromURL() {
|
|
67
|
+
try {
|
|
68
|
+
console.log('Extracting code parameter from URL...');
|
|
69
|
+
|
|
70
|
+
// Get current URL
|
|
71
|
+
const currentUrl = new URL(window.location.href);
|
|
72
|
+
console.log('Current URL:', currentUrl.href);
|
|
73
|
+
|
|
74
|
+
// Extract the 'code' parameter
|
|
75
|
+
const codeParam = currentUrl.searchParams.get('code');
|
|
76
|
+
|
|
77
|
+
if (codeParam) {
|
|
78
|
+
console.log('Code parameter found:', codeParam.substring(0, 50) + '...');
|
|
79
|
+
return codeParam;
|
|
80
|
+
} else {
|
|
81
|
+
console.log('No code parameter found in URL');
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('Error extracting code from URL:', error);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Check if URL parameter exists
|
|
91
|
+
function hasCodeParameter() {
|
|
92
|
+
try {
|
|
93
|
+
const currentUrl = new URL(window.location.href);
|
|
94
|
+
return currentUrl.searchParams.has('code');
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('Error checking for code parameter:', error);
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Base64 decoding functionality
|
|
102
|
+
function decodeBase64(encodedString) {
|
|
103
|
+
try {
|
|
104
|
+
console.log('Attempting to decode Base64 string...');
|
|
105
|
+
|
|
106
|
+
// Check if the string is valid Base64
|
|
107
|
+
if (!encodedString || typeof encodedString !== 'string') {
|
|
108
|
+
throw new Error('Invalid input: string is null, undefined, or not a string');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Remove any whitespace
|
|
112
|
+
const cleanedString = encodedString.trim();
|
|
113
|
+
|
|
114
|
+
// Check if string looks like Base64 (basic validation)
|
|
115
|
+
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
116
|
+
if (!base64Regex.test(cleanedString)) {
|
|
117
|
+
throw new Error('Invalid Base64 format');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Attempt to decode
|
|
121
|
+
const decodedString = atob(cleanedString);
|
|
122
|
+
console.log('Base64 decoding successful');
|
|
123
|
+
|
|
124
|
+
return decodedString;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('Base64 decoding failed:', error);
|
|
127
|
+
throw new Error(`Base64 decoding failed: ${error.message}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Gzip decompression functionality
|
|
132
|
+
function decompressGzip(compressedData) {
|
|
133
|
+
try {
|
|
134
|
+
console.log('Attempting to decompress gzip data...');
|
|
135
|
+
|
|
136
|
+
// Convert base64 decoded string to Uint8Array
|
|
137
|
+
const binaryString = compressedData;
|
|
138
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
139
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
140
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Decompress using pako
|
|
144
|
+
const decompressed = pako.ungzip(bytes, { to: 'string' });
|
|
145
|
+
console.log('Gzip decompression successful');
|
|
146
|
+
|
|
147
|
+
return decompressed;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error('Gzip decompression failed:', error);
|
|
150
|
+
throw new Error(`Gzip decompression failed: ${error.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Process URL code parameter with Base64 decoding and optional gzip decompression
|
|
155
|
+
function processURLCodeParameter(encodedCode) {
|
|
156
|
+
try {
|
|
157
|
+
console.log('Processing URL code parameter...');
|
|
158
|
+
|
|
159
|
+
if (!encodedCode) {
|
|
160
|
+
console.log('No encoded code provided');
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let processedCode = encodedCode;
|
|
165
|
+
|
|
166
|
+
// Step 1: Try to decode as Base64
|
|
167
|
+
try {
|
|
168
|
+
const base64Decoded = decodeBase64(encodedCode);
|
|
169
|
+
console.log('Base64 decoding successful');
|
|
170
|
+
processedCode = base64Decoded;
|
|
171
|
+
|
|
172
|
+
// Step 2: Check if the decoded data is gzipped and decompress if needed
|
|
173
|
+
// Gzip files start with magic numbers: 1f 8b
|
|
174
|
+
if (processedCode.length >= 2 &&
|
|
175
|
+
processedCode.charCodeAt(0) === 0x1f &&
|
|
176
|
+
processedCode.charCodeAt(1) === 0x8b) {
|
|
177
|
+
console.log('Gzip signature detected, attempting decompression...');
|
|
178
|
+
processedCode = decompressGzip(processedCode);
|
|
179
|
+
console.log('Successfully decompressed gzipped data');
|
|
180
|
+
} else {
|
|
181
|
+
console.log('No gzip signature found, using Base64 decoded data');
|
|
182
|
+
}
|
|
183
|
+
} catch (base64Error) {
|
|
184
|
+
console.warn('Base64 decoding failed, trying direct gzip decompression:', base64Error);
|
|
185
|
+
|
|
186
|
+
// If Base64 fails, maybe it's already raw text or needs different handling
|
|
187
|
+
// Try to see if it's URL encoded
|
|
188
|
+
try {
|
|
189
|
+
const urlDecoded = decodeURIComponent(encodedCode);
|
|
190
|
+
if (urlDecoded !== encodedCode) {
|
|
191
|
+
console.log('URL decoding applied');
|
|
192
|
+
processedCode = urlDecoded;
|
|
193
|
+
}
|
|
194
|
+
} catch (urlError) {
|
|
195
|
+
console.warn('URL decoding failed:', urlError);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return processedCode;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error('Failed to process URL code parameter:', error);
|
|
202
|
+
|
|
203
|
+
// Return the original code as fallback (might be plain text)
|
|
204
|
+
console.log('All decoding attempts failed, using raw parameter value');
|
|
205
|
+
return encodedCode;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Initialize the renderer
|
|
210
|
+
async function initRenderer() {
|
|
211
|
+
try {
|
|
212
|
+
console.log('Waiting for ZenUML core to load...');
|
|
213
|
+
|
|
214
|
+
// Wait for ZenUML to be available
|
|
215
|
+
await waitForZenUML();
|
|
216
|
+
|
|
217
|
+
console.log('ZenUML core loaded successfully');
|
|
218
|
+
|
|
219
|
+
// Get the ZenUML instance that was created by main.ts
|
|
220
|
+
const zenUmlInstance = window.zenUml;
|
|
221
|
+
|
|
222
|
+
if (!zenUmlInstance) {
|
|
223
|
+
throw new Error('ZenUML instance not found');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Verify ZenUML version
|
|
227
|
+
console.log('ZenUML Version:', window.ZENUML_VERSION);
|
|
228
|
+
|
|
229
|
+
// Extract and process code from URL parameters
|
|
230
|
+
const urlCodeParam = extractCodeFromURL();
|
|
231
|
+
let codeToRender = DEFAULT_ZENUML_CODE;
|
|
232
|
+
|
|
233
|
+
if (urlCodeParam) {
|
|
234
|
+
console.log('URL code parameter detected, processing...');
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
// Process the URL code parameter (includes Base64 decoding)
|
|
238
|
+
const processedCode = processURLCodeParameter(urlCodeParam);
|
|
239
|
+
|
|
240
|
+
if (processedCode) {
|
|
241
|
+
codeToRender = processedCode;
|
|
242
|
+
addStatusIndicator('success', 'Code decoded and ready to render');
|
|
243
|
+
} else {
|
|
244
|
+
console.log('Processed code is empty, using default diagram');
|
|
245
|
+
addStatusIndicator('warning', 'Empty code parameter, using default');
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error('Failed to process URL code parameter:', error);
|
|
249
|
+
addStatusIndicator('error', 'Failed to decode code parameter');
|
|
250
|
+
// Keep using default code
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
console.log('No URL code parameter, using default diagram');
|
|
254
|
+
addStatusIndicator('info', 'Using default diagram');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Render the diagram
|
|
258
|
+
console.log('Rendering diagram...');
|
|
259
|
+
await zenUmlInstance.render(codeToRender);
|
|
260
|
+
|
|
261
|
+
console.log('Diagram rendered successfully');
|
|
262
|
+
|
|
263
|
+
console.log('ZenUML Web Renderer initialized successfully');
|
|
264
|
+
|
|
265
|
+
// Add success indicator to the page
|
|
266
|
+
addStatusIndicator('success', 'ZenUML Web Renderer Ready');
|
|
267
|
+
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error('Failed to initialize renderer:', error);
|
|
270
|
+
addStatusIndicator('error', `Initialization failed: ${error.message}`);
|
|
271
|
+
|
|
272
|
+
// Show error in the diagram container
|
|
273
|
+
const diagramContainer = document.getElementById('zenuml-diagram');
|
|
274
|
+
if (diagramContainer) {
|
|
275
|
+
diagramContainer.innerHTML = `
|
|
276
|
+
<div style="padding: 20px; color: #dc2626; text-align: center;">
|
|
277
|
+
<h3>ZenUML Renderer Error</h3>
|
|
278
|
+
<p>Failed to initialize: ${error.message}</p>
|
|
279
|
+
<button onclick="location.reload()" style="margin-top: 10px; padding: 8px 16px; background: #dc2626; color: white; border: none; border-radius: 4px; cursor: pointer;">
|
|
280
|
+
Retry
|
|
281
|
+
</button>
|
|
282
|
+
</div>
|
|
283
|
+
`;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Wait for ZenUML to be available with timeout
|
|
289
|
+
function waitForZenUML(timeout = 10000) {
|
|
290
|
+
return new Promise((resolve, reject) => {
|
|
291
|
+
const startTime = Date.now();
|
|
292
|
+
|
|
293
|
+
const checkZenUml = () => {
|
|
294
|
+
if (typeof window.zenUml !== 'undefined') {
|
|
295
|
+
resolve();
|
|
296
|
+
} else if (Date.now() - startTime > timeout) {
|
|
297
|
+
reject(new Error('ZenUML loading timeout'));
|
|
298
|
+
} else {
|
|
299
|
+
setTimeout(checkZenUml, 100);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
checkZenUml();
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Add status indicator to show initialization status
|
|
308
|
+
function addStatusIndicator(type, message) {
|
|
309
|
+
const indicator = document.createElement('div');
|
|
310
|
+
indicator.id = 'status-indicator';
|
|
311
|
+
|
|
312
|
+
let backgroundColor;
|
|
313
|
+
switch (type) {
|
|
314
|
+
case 'success':
|
|
315
|
+
backgroundColor = '#10b981';
|
|
316
|
+
break;
|
|
317
|
+
case 'error':
|
|
318
|
+
backgroundColor = '#dc2626';
|
|
319
|
+
break;
|
|
320
|
+
case 'info':
|
|
321
|
+
backgroundColor = '#3b82f6';
|
|
322
|
+
break;
|
|
323
|
+
case 'warning':
|
|
324
|
+
backgroundColor = '#f59e0b';
|
|
325
|
+
break;
|
|
326
|
+
default:
|
|
327
|
+
backgroundColor = '#6b7280';
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
indicator.style.cssText = `
|
|
331
|
+
position: fixed;
|
|
332
|
+
top: 10px;
|
|
333
|
+
right: 10px;
|
|
334
|
+
padding: 8px 12px;
|
|
335
|
+
border-radius: 4px;
|
|
336
|
+
font-size: 12px;
|
|
337
|
+
font-weight: 500;
|
|
338
|
+
z-index: 1000;
|
|
339
|
+
background: ${backgroundColor};
|
|
340
|
+
color: white;
|
|
341
|
+
`;
|
|
342
|
+
indicator.textContent = message;
|
|
343
|
+
document.body.appendChild(indicator);
|
|
344
|
+
|
|
345
|
+
// Auto-hide success and info messages after 3 seconds
|
|
346
|
+
if (type === 'success' || type === 'info') {
|
|
347
|
+
setTimeout(() => {
|
|
348
|
+
if (indicator.parentNode) {
|
|
349
|
+
indicator.parentNode.removeChild(indicator);
|
|
350
|
+
}
|
|
351
|
+
}, 3000);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Start initialization when DOM is ready
|
|
356
|
+
if (document.readyState === 'loading') {
|
|
357
|
+
document.addEventListener('DOMContentLoaded', initRenderer);
|
|
358
|
+
} else {
|
|
359
|
+
initRenderer();
|
|
360
|
+
}
|
|
361
|
+
</script>
|
|
362
|
+
|
|
363
|
+
<!-- Load ZenUML core -->
|
|
364
|
+
<script type="module" src="/src/main.ts"></script>
|
|
365
|
+
</body>
|
|
366
|
+
</html>
|