@qarakash/blockwriteai 1.0.7 → 1.0.9
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 +166 -130
- package/dist/blockwriteai.js +1 -1
- package/dist/plugins/blockwriteai-advanced-blocks.js +1 -181
- package/dist/plugins/blockwriteai-ai.js +58 -24
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -15,8 +15,8 @@ All public assets, package entry points, and browser globals use the `BlockWrite
|
|
|
15
15
|
- Multi-image upload, drag and drop, resize, crop, rotate, and gallery layout.
|
|
16
16
|
- Attachment blocks for documents and videos.
|
|
17
17
|
- Code block with formatting, syntax help, language detection, and suggestions.
|
|
18
|
-
-
|
|
19
|
-
-
|
|
18
|
+
- Charts, LaTeX, audio, layout columns, code assistance, and optional history plugins in the free plugin set.
|
|
19
|
+
- Premium plugins for Drawing, Mermaid, Signature, Signature Flow, and AI writing, delivered after server-side license verification.
|
|
20
20
|
- Undo, redo, autosave, block actions, drag reordering, and optional JSON save/export buttons.
|
|
21
21
|
- JSON-powered preview mounting for public document pages.
|
|
22
22
|
- JSON save API examples for future database storage.
|
|
@@ -65,49 +65,51 @@ BlockWriteAI can be consumed as a CDN/script-link package, an npm package, a Pyt
|
|
|
65
65
|
|
|
66
66
|
### Script Link
|
|
67
67
|
|
|
68
|
-
Use the
|
|
69
|
-
|
|
70
|
-
```html
|
|
71
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/
|
|
72
|
-
|
|
73
|
-
<script src="https://cdn.jsdelivr.net/
|
|
74
|
-
<script src="https://cdn.jsdelivr.net/
|
|
75
|
-
<script src="https://cdn.jsdelivr.net/
|
|
76
|
-
<script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-ai.js"></script>
|
|
77
|
-
<script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-signature.js"></script>
|
|
78
|
-
<script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-signature-flow.js"></script>
|
|
68
|
+
Use the npm CDN for a locked release build:
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/blockwriteai.css">
|
|
72
|
+
|
|
73
|
+
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/blockwriteai.js"></script>
|
|
74
|
+
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/plugins/blockwriteai-code-assist.js"></script>
|
|
75
|
+
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/plugins/blockwriteai-advanced-blocks.js"></script>
|
|
79
76
|
```
|
|
80
77
|
|
|
81
|
-
`blockwriteai-advanced-blocks.js` is
|
|
82
|
-
|
|
78
|
+
`blockwriteai-advanced-blocks.js` is the free advanced bundle. It includes Chart,
|
|
79
|
+
LaTeX, Audio, and Columns/Layout. Drawing, Mermaid, Signature, Signature Flow,
|
|
80
|
+
and AI are premium plugins and should not be loaded directly in production.
|
|
81
|
+
|
|
82
|
+
Load History only when a project needs the history dropdown:
|
|
83
83
|
|
|
84
84
|
```html
|
|
85
|
-
<script src="https://cdn.jsdelivr.net/
|
|
86
|
-
<script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-mermaid.js"></script>
|
|
85
|
+
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/plugins/blockwriteai-history.js"></script>
|
|
87
86
|
```
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
```html
|
|
92
|
-
<script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-history.js"></script>
|
|
93
|
-
```
|
|
88
|
+
For development against the current GitHub branch, replace the npm URLs with the
|
|
89
|
+
GitHub CDN form:
|
|
94
90
|
|
|
95
|
-
|
|
91
|
+
```html
|
|
92
|
+
https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/...
|
|
93
|
+
```
|
|
96
94
|
|
|
97
95
|
### Premium License Gating
|
|
98
96
|
|
|
99
97
|
Drawing, Mermaid drawing, Signature, Signature Flow, and AI can be licensed through
|
|
100
98
|
the BlockWriteAI Platform. Normal editor blocks continue to work without a license.
|
|
101
|
-
Premium
|
|
102
|
-
or subscription.
|
|
99
|
+
Premium plugin scripts are delivered only after the license endpoint returns an
|
|
100
|
+
active trial or subscription. Without a valid license, those tools are not
|
|
101
|
+
registered and do not appear in the insert-block menu.
|
|
103
102
|
|
|
104
103
|
```js
|
|
105
104
|
const editor = new BlockWriteAI({
|
|
106
105
|
holder: "#editor",
|
|
107
|
-
licenseKey: "bwai_live_xxxxx",
|
|
108
106
|
premium: {
|
|
107
|
+
licenseKey: "bwai_live_xxxxx",
|
|
109
108
|
verifyEndpoint: "http://localhost/blockwriteai-platform/api/license_verify.php",
|
|
110
|
-
|
|
109
|
+
pluginEndpoint: "http://localhost/blockwriteai-platform/api/premium_plugins.php",
|
|
110
|
+
usageEndpoint: "http://localhost/blockwriteai-platform/api/ai_usage.php",
|
|
111
|
+
autoLoadPlugins: true,
|
|
112
|
+
features: ["drawing", "mermaid", "signature", "signature_flow", "ai"]
|
|
111
113
|
},
|
|
112
114
|
ai: {
|
|
113
115
|
endpoint: "/api/ai.php"
|
|
@@ -127,19 +129,20 @@ The verify endpoint must return a `features` object with these keys when enabled
|
|
|
127
129
|
}
|
|
128
130
|
```
|
|
129
131
|
|
|
130
|
-
The AI plugin calls `premium.usageEndpoint` before each AI request so the
|
|
131
|
-
can enforce the 7-day trial and daily prompt limits.
|
|
132
|
+
The AI plugin calls `premium.usageEndpoint` before each AI request so the
|
|
133
|
+
platform can enforce the 7-day trial and daily prompt limits.
|
|
132
134
|
|
|
133
|
-
For stronger production security, do not load premium plugin files directly from
|
|
134
|
-
public CDN. Load the free core first, request the premium plugins from your
|
|
135
|
+
For stronger production security, do not load premium plugin files directly from
|
|
136
|
+
a public CDN. Load the free core first, request the premium plugins from your
|
|
135
137
|
BlockWriteAI Platform, and create the editor only after the server has verified
|
|
136
138
|
the license. The platform serves Drawing, Mermaid, Signature, Signature Flow,
|
|
137
|
-
and AI as
|
|
139
|
+
and AI as a verified bundle after checking the requested feature flags:
|
|
138
140
|
|
|
139
141
|
```html
|
|
140
|
-
<link rel="stylesheet" href="/
|
|
141
|
-
<script src="/
|
|
142
|
-
<script src="/
|
|
142
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/blockwriteai.css">
|
|
143
|
+
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/blockwriteai.js"></script>
|
|
144
|
+
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/plugins/blockwriteai-code-assist.js"></script>
|
|
145
|
+
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/plugins/blockwriteai-advanced-blocks.js"></script>
|
|
143
146
|
<script>
|
|
144
147
|
async function boot() {
|
|
145
148
|
await BlockWriteAI.loadPremiumPlugins({
|
|
@@ -150,8 +153,8 @@ and AI as separate plugin files after checking the requested feature flags:
|
|
|
150
153
|
|
|
151
154
|
window.editor = new BlockWriteAI({
|
|
152
155
|
holder: "#editor",
|
|
153
|
-
licenseKey: "bwai_live_xxxxx",
|
|
154
156
|
premium: {
|
|
157
|
+
licenseKey: "bwai_live_xxxxx",
|
|
155
158
|
verifyEndpoint: "http://localhost/blockwriteai-platform/api/license_verify.php",
|
|
156
159
|
usageEndpoint: "http://localhost/blockwriteai-platform/api/ai_usage.php"
|
|
157
160
|
}
|
|
@@ -182,22 +185,19 @@ npm install @qarakash/blockwriteai
|
|
|
182
185
|
Bundler entry points:
|
|
183
186
|
|
|
184
187
|
```js
|
|
185
|
-
import BlockWriteAI from "@qarakash/blockwriteai";
|
|
186
|
-
import "@qarakash/blockwriteai/css";
|
|
187
|
-
import "@qarakash/blockwriteai/plugins/code-assist";
|
|
188
|
-
import "@qarakash/blockwriteai/plugins/advanced";
|
|
189
|
-
import "@qarakash/blockwriteai/plugins/
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
```
|
|
198
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.7/dist/blockwriteai.css">
|
|
199
|
-
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.7/dist/blockwriteai.js"></script>
|
|
200
|
-
```
|
|
188
|
+
import BlockWriteAI from "@qarakash/blockwriteai";
|
|
189
|
+
import "@qarakash/blockwriteai/css";
|
|
190
|
+
import "@qarakash/blockwriteai/plugins/code-assist";
|
|
191
|
+
import "@qarakash/blockwriteai/plugins/advanced";
|
|
192
|
+
import "@qarakash/blockwriteai/plugins/history";
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
After npm publishing, the same package is also available through npm CDNs:
|
|
196
|
+
|
|
197
|
+
```html
|
|
198
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/blockwriteai.css">
|
|
199
|
+
<script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.9/dist/blockwriteai.js"></script>
|
|
200
|
+
```
|
|
201
201
|
|
|
202
202
|
### Python
|
|
203
203
|
|
|
@@ -221,16 +221,21 @@ from blockwriteai_editor import copy_static
|
|
|
221
221
|
copy_static("static/blockwriteai")
|
|
222
222
|
```
|
|
223
223
|
|
|
224
|
-
Python helpers are also available for generating asset tags.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
print(
|
|
232
|
-
print(script_tags("/static/blockwriteai"
|
|
233
|
-
|
|
224
|
+
Python helpers are also available for generating asset tags. `script_tags()` loads
|
|
225
|
+
only core/free plugins by default. Pass `history=True` only on pages where you want
|
|
226
|
+
the optional History dropdown:
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from blockwriteai_editor import premium_script_tags, stylesheet_tag, script_tags
|
|
230
|
+
|
|
231
|
+
print(stylesheet_tag("/static/blockwriteai"))
|
|
232
|
+
print(script_tags("/static/blockwriteai"))
|
|
233
|
+
print(script_tags("/static/blockwriteai", history=True))
|
|
234
|
+
|
|
235
|
+
# Only for private/licensed deployments. Public apps should prefer the platform
|
|
236
|
+
# premium bundle endpoint shown in the Premium License Gating section.
|
|
237
|
+
print(premium_script_tags("/static/blockwriteai", ["signature", "ai"]))
|
|
238
|
+
```
|
|
234
239
|
|
|
235
240
|
### PHP / Composer
|
|
236
241
|
|
|
@@ -252,15 +257,20 @@ Publish assets into your public folder:
|
|
|
252
257
|
cp -R vendor/qarakash/blockwriteai/dist public/blockwriteai
|
|
253
258
|
```
|
|
254
259
|
|
|
255
|
-
PHP helper.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
echo BlockWriteAIAssets::
|
|
262
|
-
echo BlockWriteAIAssets::scriptTags('/blockwriteai'
|
|
263
|
-
|
|
260
|
+
PHP helper. `scriptTags()` loads only core/free plugins by default. Pass
|
|
261
|
+
`history: true` only on pages where you want the optional History dropdown:
|
|
262
|
+
|
|
263
|
+
```php
|
|
264
|
+
use QarAkash\BlockWriteAI\BlockWriteAIAssets;
|
|
265
|
+
|
|
266
|
+
echo BlockWriteAIAssets::stylesheetTag('/blockwriteai');
|
|
267
|
+
echo BlockWriteAIAssets::scriptTags('/blockwriteai');
|
|
268
|
+
echo BlockWriteAIAssets::scriptTags('/blockwriteai', plugins: true, history: true);
|
|
269
|
+
|
|
270
|
+
// Only for private/licensed deployments. Public apps should prefer the platform
|
|
271
|
+
// premium bundle endpoint shown in the Premium License Gating section.
|
|
272
|
+
echo BlockWriteAIAssets::premiumScriptTags('/blockwriteai', ['signature', 'ai']);
|
|
273
|
+
```
|
|
264
274
|
|
|
265
275
|
## Local XAMPP Demo
|
|
266
276
|
|
|
@@ -283,40 +293,38 @@ http://localhost/BlockWriteAI/examples/
|
|
|
283
293
|
|
|
284
294
|
<div id="editor"></div>
|
|
285
295
|
|
|
286
|
-
<script src="/BlockWriteAI/dist/blockwriteai.js"></script>
|
|
287
|
-
<script src="/BlockWriteAI/dist/plugins/blockwriteai-code-assist.js"></script>
|
|
288
|
-
<script src="/BlockWriteAI/dist/plugins/blockwriteai-advanced-blocks.js"></script>
|
|
289
|
-
|
|
290
|
-
<script
|
|
291
|
-
|
|
292
|
-
<script>
|
|
296
|
+
<script src="/BlockWriteAI/dist/blockwriteai.js"></script>
|
|
297
|
+
<script src="/BlockWriteAI/dist/plugins/blockwriteai-code-assist.js"></script>
|
|
298
|
+
<script src="/BlockWriteAI/dist/plugins/blockwriteai-advanced-blocks.js"></script>
|
|
299
|
+
|
|
300
|
+
<script>
|
|
293
301
|
const editor = new BlockWriteAI({
|
|
294
302
|
holder: "#editor",
|
|
295
303
|
maxWidth: "960px", // optional; omit for full-width editor shell
|
|
296
304
|
placeholder: "Write something, or press / for blocks",
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
305
|
+
data: {
|
|
306
|
+
blocks: [
|
|
307
|
+
{
|
|
308
|
+
type: "paragraph",
|
|
309
|
+
data: {
|
|
310
|
+
text: "Hello from BlockWriteAI",
|
|
311
|
+
alignment: "left"
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
onChange(data) {
|
|
317
|
+
console.log("Changed document", data);
|
|
318
|
+
},
|
|
319
|
+
async onSave(data) {
|
|
320
|
+
await fetch("/save-document.php", {
|
|
321
|
+
method: "POST",
|
|
322
|
+
headers: {
|
|
323
|
+
"Content-Type": "application/json"
|
|
324
|
+
},
|
|
325
|
+
body: JSON.stringify(data)
|
|
326
|
+
});
|
|
327
|
+
}
|
|
320
328
|
});
|
|
321
329
|
</script>
|
|
322
330
|
```
|
|
@@ -364,23 +372,38 @@ const editor = new BlockWriteAI({
|
|
|
364
372
|
});
|
|
365
373
|
```
|
|
366
374
|
|
|
367
|
-
## AI Plugin
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
375
|
+
## AI Plugin
|
|
376
|
+
|
|
377
|
+
AI is a premium plugin. Load it through the platform premium bundle after license
|
|
378
|
+
verification. The browser plugin never receives your OpenAI API key; it calls
|
|
379
|
+
your own server endpoint.
|
|
380
|
+
|
|
381
|
+
```html
|
|
382
|
+
<script src="/blockwriteai/blockwriteai.js"></script>
|
|
383
|
+
|
|
384
|
+
<script>
|
|
385
|
+
async function boot() {
|
|
386
|
+
await BlockWriteAI.loadPremiumPlugins({
|
|
387
|
+
licenseKey: "bwai_live_xxxxx",
|
|
388
|
+
endpoint: "/blockwriteai-platform/api/premium_plugins.php",
|
|
389
|
+
features: ["ai"]
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
window.editor = new BlockWriteAI({
|
|
393
|
+
holder: "#editor",
|
|
394
|
+
premium: {
|
|
395
|
+
licenseKey: "bwai_live_xxxxx",
|
|
396
|
+
verifyEndpoint: "/blockwriteai-platform/api/license_verify.php",
|
|
397
|
+
usageEndpoint: "/blockwriteai-platform/api/ai_usage.php"
|
|
398
|
+
},
|
|
399
|
+
ai: {
|
|
400
|
+
endpoint: "/api/blockwriteai-ai.php"
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
boot();
|
|
405
|
+
</script>
|
|
406
|
+
```
|
|
384
407
|
|
|
385
408
|
The included demo endpoint is `examples/api/ai.php`. For local development, copy `examples/api/openai.local.example.php` to `examples/api/openai.local.php` and add a development key, or set `OPENAI_API_KEY` in the server environment. Do not expose the key in browser JavaScript.
|
|
386
409
|
|
|
@@ -404,14 +427,27 @@ Create any page in your application and add a preview container. BlockWriteAI wi
|
|
|
404
427
|
|
|
405
428
|
<div class="blockwriteai-preview" data-source="/documents/123.json"></div>
|
|
406
429
|
|
|
407
|
-
<script src="/blockwriteai/blockwriteai.js"></script>
|
|
408
|
-
<script src="/blockwriteai/plugins/blockwriteai-advanced-blocks.js"></script>
|
|
409
|
-
<script
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
430
|
+
<script src="/blockwriteai/blockwriteai.js"></script>
|
|
431
|
+
<script src="/blockwriteai/plugins/blockwriteai-advanced-blocks.js"></script>
|
|
432
|
+
<script>
|
|
433
|
+
BlockWriteAI.mountPreviews();
|
|
434
|
+
</script>
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
If the preview page must render premium blocks, load the licensed premium bundle
|
|
438
|
+
before `BlockWriteAI.mountPreviews()`:
|
|
439
|
+
|
|
440
|
+
```js
|
|
441
|
+
async function mountDocumentPreview() {
|
|
442
|
+
await BlockWriteAI.loadPremiumPlugins({
|
|
443
|
+
licenseKey: "bwai_live_xxxxx",
|
|
444
|
+
endpoint: "/blockwriteai-platform/api/premium_plugins.php",
|
|
445
|
+
features: ["drawing", "mermaid", "signature", "signature_flow", "ai"]
|
|
446
|
+
});
|
|
447
|
+
BlockWriteAI.mountPreviews();
|
|
448
|
+
}
|
|
449
|
+
mountDocumentPreview();
|
|
450
|
+
```
|
|
415
451
|
|
|
416
452
|
The JSON endpoint can return either a BlockWriteAI document directly or an API wrapper such as:
|
|
417
453
|
|
|
@@ -420,7 +456,7 @@ The JSON endpoint can return either a BlockWriteAI document directly or an API w
|
|
|
420
456
|
"ok": true,
|
|
421
457
|
"data": {
|
|
422
458
|
"time": 1779540000000,
|
|
423
|
-
"version": "1.0.
|
|
459
|
+
"version": "1.0.9",
|
|
424
460
|
"blocks": []
|
|
425
461
|
}
|
|
426
462
|
}
|
|
@@ -524,7 +560,7 @@ BlockWriteAI.mountPreviews(); // Render JSON into .blockwriteai-preview containe
|
|
|
524
560
|
```json
|
|
525
561
|
{
|
|
526
562
|
"time": 1779540000000,
|
|
527
|
-
"version": "1.0.
|
|
563
|
+
"version": "1.0.9",
|
|
528
564
|
"blocks": [
|
|
529
565
|
{
|
|
530
566
|
"id": "block-title",
|
|
@@ -614,8 +650,8 @@ After a release is ready, publish each package from the repository root.
|
|
|
614
650
|
Create a Git release tag for script-link/CDN users:
|
|
615
651
|
|
|
616
652
|
```bash
|
|
617
|
-
git tag v1.0.
|
|
618
|
-
git push origin v1.0.
|
|
653
|
+
git tag v1.0.9
|
|
654
|
+
git push origin v1.0.9
|
|
619
655
|
```
|
|
620
656
|
|
|
621
657
|
Publish npm:
|
package/dist/blockwriteai.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* BlockWriteAI Advanced Blocks Plugin
|
|
3
|
-
* Adds chart,
|
|
3
|
+
* Adds chart, LaTeX, audio, and columns/layout blocks.
|
|
4
4
|
*/
|
|
5
5
|
(function (global) {
|
|
6
6
|
"use strict";
|
|
@@ -2017,63 +2017,6 @@
|
|
|
2017
2017
|
}
|
|
2018
2018
|
});
|
|
2019
2019
|
|
|
2020
|
-
BlockWriteAI.registerTool("mermaid", {
|
|
2021
|
-
label: "Mermaid",
|
|
2022
|
-
hint: "Visual diagrams and flowcharts",
|
|
2023
|
-
icon: "diagram-project",
|
|
2024
|
-
premiumFeature: "mermaid",
|
|
2025
|
-
defaultData: { code: "", alignment: "center", openOnInsert: true, diagram: { elements: [], workspace: defaultMermaidWorkspace() } },
|
|
2026
|
-
render: function (body, data) {
|
|
2027
|
-
injectStyles();
|
|
2028
|
-
var editor = this;
|
|
2029
|
-
var wrap = el("div", "rbe-plugin-card rbe-mermaid-block rbe-mermaid-card");
|
|
2030
|
-
wrap.tabIndex = 0;
|
|
2031
|
-
var alignment = data.alignment === "left" || data.alignment === "right" ? data.alignment : "center";
|
|
2032
|
-
var workspace = normalizeDiagramWorkspace(data);
|
|
2033
|
-
wrap.innerHTML =
|
|
2034
|
-
'<input type="hidden" class="rbe-mermaid-alignment" value="' + esc(alignment) + '">' +
|
|
2035
|
-
'<input type="hidden" class="rbe-mermaid-diagram-json">' +
|
|
2036
|
-
'<textarea class="rbe-mermaid-code" hidden></textarea>' +
|
|
2037
|
-
'<input class="rbe-mermaid-workspace-w" type="hidden" value="' + esc(workspace.width) + '">' +
|
|
2038
|
-
'<input class="rbe-mermaid-workspace-h" type="hidden" value="' + esc(workspace.height) + '">' +
|
|
2039
|
-
'<input class="rbe-mermaid-zoom" type="hidden" value="' + esc(workspace.zoom) + '">' +
|
|
2040
|
-
'<div class="rbe-mermaid-card-head"><span class="rbe-mermaid-card-title">Mermaid drawing</span><button type="button" class="rbe-mermaid-edit-btn" title="Edit drawing"' + (editor.readOnly ? " hidden" : "") + '>' + faIcon("pen-to-square", "Edit drawing") + '</button></div>' +
|
|
2041
|
-
'<div class="rbe-mermaid-card-preview"></div>';
|
|
2042
|
-
body.appendChild(wrap);
|
|
2043
|
-
var input = wrap.querySelector(".rbe-mermaid-code");
|
|
2044
|
-
input.value = data.code || "";
|
|
2045
|
-
wrap.querySelector(".rbe-mermaid-diagram-json").value = JSON.stringify(diagramElements(data));
|
|
2046
|
-
refreshMermaidCardPreview(wrap);
|
|
2047
|
-
wrap.addEventListener("click", function (event) {
|
|
2048
|
-
if (!event.target.closest(".rbe-mermaid-edit-btn")) return;
|
|
2049
|
-
event.preventDefault();
|
|
2050
|
-
if (!editor.readOnly) openMermaidDesignerModal(editor, wrap);
|
|
2051
|
-
});
|
|
2052
|
-
if (!editor.readOnly && data.openOnInsert === true) {
|
|
2053
|
-
setTimeout(function () { openMermaidDesignerModal(editor, wrap); }, 80);
|
|
2054
|
-
}
|
|
2055
|
-
},
|
|
2056
|
-
serialize: function (block) {
|
|
2057
|
-
var diagram = [];
|
|
2058
|
-
try {
|
|
2059
|
-
diagram = JSON.parse((block.querySelector(".rbe-mermaid-diagram-json") || {}).value || "[]");
|
|
2060
|
-
} catch (error) {}
|
|
2061
|
-
return {
|
|
2062
|
-
code: (block.querySelector(".rbe-mermaid-code") || {}).value || "",
|
|
2063
|
-
alignment: (block.querySelector(".rbe-mermaid-alignment") || {}).value || "center",
|
|
2064
|
-
openOnInsert: false,
|
|
2065
|
-
diagram: { elements: diagram.map(normalizeDiagramElement), workspace: readWorkspaceFromBlock(block) }
|
|
2066
|
-
};
|
|
2067
|
-
},
|
|
2068
|
-
toHTML: function (data) {
|
|
2069
|
-
var alignment = data.alignment === "left" || data.alignment === "right" ? data.alignment : "center";
|
|
2070
|
-
var elements = diagramElements(data);
|
|
2071
|
-
return '<figure class="rbe-output-mermaid-wrap rbe-output-align-' + esc(alignment) + '"><div class="rbe-output-mermaid-diagram">' + diagramSvg(elements, "", normalizeDiagramWorkspace(data), null) + "</div></figure>";
|
|
2072
|
-
},
|
|
2073
|
-
toMarkdown: function (data) {
|
|
2074
|
-
return "```mermaid\n" + (data.code || "") + "\n```";
|
|
2075
|
-
}
|
|
2076
|
-
});
|
|
2077
2020
|
|
|
2078
2021
|
BlockWriteAI.registerTool("latex", {
|
|
2079
2022
|
label: "LaTeX",
|
|
@@ -2164,129 +2107,6 @@
|
|
|
2164
2107
|
}
|
|
2165
2108
|
});
|
|
2166
2109
|
|
|
2167
|
-
function drawingTextSvgDataUri(text, color) {
|
|
2168
|
-
var safeColor = /^#[0-9a-f]{3}([0-9a-f]{3})?$/i.test(color || "") ? color : "#2f1830";
|
|
2169
|
-
var words = String(text || "Signature text").trim().split(/\s+/);
|
|
2170
|
-
var lineOne = words.slice(0, Math.ceil(words.length / 2)).join(" ");
|
|
2171
|
-
var lineTwo = words.slice(Math.ceil(words.length / 2)).join(" ");
|
|
2172
|
-
var hasTwoLines = !!lineTwo;
|
|
2173
|
-
var svg = [
|
|
2174
|
-
'<svg xmlns="http://www.w3.org/2000/svg" width="900" height="320" viewBox="0 0 900 320">',
|
|
2175
|
-
'<rect width="900" height="320" rx="16" fill="#ffffff"/>',
|
|
2176
|
-
'<text x="450" y="' + (hasTwoLines ? "138" : "176") + '" text-anchor="middle" font-family="Mabriella, \'Brush Script MT\', \'Segoe Script\', \'Lucida Handwriting\', cursive" font-size="' + (hasTwoLines ? "104" : "118") + '" font-weight="400" fill="' + esc(safeColor) + '">' + esc(lineOne) + "</text>",
|
|
2177
|
-
hasTwoLines ? '<text x="450" y="244" text-anchor="middle" font-family="Mabriella, \'Brush Script MT\', \'Segoe Script\', \'Lucida Handwriting\', cursive" font-size="104" font-weight="400" fill="' + esc(safeColor) + '">' + esc(lineTwo) + "</text>" : "",
|
|
2178
|
-
"</svg>"
|
|
2179
|
-
].join("");
|
|
2180
|
-
return "data:image/svg+xml;charset=UTF-8," + encodeURIComponent(svg);
|
|
2181
|
-
}
|
|
2182
|
-
|
|
2183
|
-
BlockWriteAI.registerTool("drawing", {
|
|
2184
|
-
label: "Drawing",
|
|
2185
|
-
hint: "Freehand sketch canvas",
|
|
2186
|
-
icon: "pen-nib",
|
|
2187
|
-
premiumFeature: "drawing",
|
|
2188
|
-
defaultData: { image: "", color: "#172033", size: 4, text: "" },
|
|
2189
|
-
render: function (body, data) {
|
|
2190
|
-
injectStyles();
|
|
2191
|
-
var editor = this;
|
|
2192
|
-
var wrap = el("div", "rbe-plugin-card rbe-drawing-block");
|
|
2193
|
-
wrap.dataset.initialImage = data.image || data.url || data.src || "";
|
|
2194
|
-
if (!wrap.dataset.initialImage && data.text) {
|
|
2195
|
-
wrap.dataset.initialImage = drawingTextSvgDataUri(data.text, data.color || "#2f1830");
|
|
2196
|
-
}
|
|
2197
|
-
wrap.dataset.drawingDirty = "false";
|
|
2198
|
-
wrap.innerHTML = '<div class="rbe-plugin-toolbar"><label>Pen <input class="rbe-drawing-color" type="color"></label><label>Size <input class="rbe-drawing-size" type="range" min="1" max="24"></label><input class="rbe-drawing-text-input" type="text" placeholder="Type name or text"><button type="button" class="rbe-small-btn rbe-drawing-text-apply" title="Convert text to Mabriella style" aria-label="Convert text to Mabriella style">' + faIcon("wand-magic-sparkles", "Convert text") + '</button><button type="button" class="rbe-small-btn rbe-drawing-clear">' + faIcon("eraser", "Clear drawing") + '</button></div><div class="rbe-drawing-shell"><canvas class="rbe-drawing-canvas" width="900" height="320"></canvas></div>';
|
|
2199
|
-
body.appendChild(wrap);
|
|
2200
|
-
var canvas = wrap.querySelector("canvas");
|
|
2201
|
-
var ctx = canvas.getContext("2d");
|
|
2202
|
-
wrap.querySelector(".rbe-drawing-color").value = data.color || "#172033";
|
|
2203
|
-
wrap.querySelector(".rbe-drawing-size").value = data.size || 4;
|
|
2204
|
-
wrap.querySelector(".rbe-drawing-text-input").value = data.text || "";
|
|
2205
|
-
function loadImage(source) {
|
|
2206
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
2207
|
-
if (!source) return;
|
|
2208
|
-
var image = new Image();
|
|
2209
|
-
image.onload = function () { ctx.drawImage(image, 0, 0, canvas.width, canvas.height); };
|
|
2210
|
-
image.src = source;
|
|
2211
|
-
}
|
|
2212
|
-
if (wrap.dataset.initialImage) {
|
|
2213
|
-
loadImage(wrap.dataset.initialImage);
|
|
2214
|
-
}
|
|
2215
|
-
var drawing = false;
|
|
2216
|
-
function point(event) {
|
|
2217
|
-
var rect = canvas.getBoundingClientRect();
|
|
2218
|
-
return { x: ((event.clientX - rect.left) / rect.width) * canvas.width, y: ((event.clientY - rect.top) / rect.height) * canvas.height };
|
|
2219
|
-
}
|
|
2220
|
-
canvas.addEventListener("pointerdown", function (event) {
|
|
2221
|
-
drawing = true;
|
|
2222
|
-
wrap.dataset.drawingDirty = "true";
|
|
2223
|
-
canvas.setPointerCapture(event.pointerId);
|
|
2224
|
-
var p = point(event);
|
|
2225
|
-
ctx.beginPath();
|
|
2226
|
-
ctx.moveTo(p.x, p.y);
|
|
2227
|
-
});
|
|
2228
|
-
canvas.addEventListener("pointermove", function (event) {
|
|
2229
|
-
if (!drawing) return;
|
|
2230
|
-
var p = point(event);
|
|
2231
|
-
ctx.strokeStyle = wrap.querySelector(".rbe-drawing-color").value;
|
|
2232
|
-
ctx.lineWidth = Number(wrap.querySelector(".rbe-drawing-size").value || 4);
|
|
2233
|
-
ctx.lineCap = "round";
|
|
2234
|
-
ctx.lineJoin = "round";
|
|
2235
|
-
ctx.lineTo(p.x, p.y);
|
|
2236
|
-
ctx.stroke();
|
|
2237
|
-
});
|
|
2238
|
-
canvas.addEventListener("pointerup", function () {
|
|
2239
|
-
drawing = false;
|
|
2240
|
-
editor.changed(true);
|
|
2241
|
-
});
|
|
2242
|
-
wrap.querySelector(".rbe-drawing-text-apply").addEventListener("click", function () {
|
|
2243
|
-
var input = wrap.querySelector(".rbe-drawing-text-input");
|
|
2244
|
-
var text = (input.value || "").trim();
|
|
2245
|
-
if (!text) {
|
|
2246
|
-
input.focus();
|
|
2247
|
-
return;
|
|
2248
|
-
}
|
|
2249
|
-
wrap.dataset.initialImage = drawingTextSvgDataUri(text, wrap.querySelector(".rbe-drawing-color").value || "#2f1830");
|
|
2250
|
-
wrap.dataset.drawingDirty = "false";
|
|
2251
|
-
loadImage(wrap.dataset.initialImage);
|
|
2252
|
-
editor.changed(true);
|
|
2253
|
-
});
|
|
2254
|
-
wrap.querySelector(".rbe-drawing-clear").addEventListener("click", function () {
|
|
2255
|
-
wrap.dataset.initialImage = "";
|
|
2256
|
-
wrap.dataset.drawingDirty = "true";
|
|
2257
|
-
wrap.querySelector(".rbe-drawing-text-input").value = "";
|
|
2258
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
2259
|
-
editor.changed(true);
|
|
2260
|
-
});
|
|
2261
|
-
},
|
|
2262
|
-
serialize: function (block) {
|
|
2263
|
-
var canvas = block.querySelector(".rbe-drawing-canvas");
|
|
2264
|
-
var drawingBlock = block.querySelector(".rbe-drawing-block") || block;
|
|
2265
|
-
var initialImage = drawingBlock.dataset.initialImage || "";
|
|
2266
|
-
if (initialImage && drawingBlock.dataset.drawingDirty !== "true") {
|
|
2267
|
-
return {
|
|
2268
|
-
image: initialImage,
|
|
2269
|
-
color: (block.querySelector(".rbe-drawing-color") || {}).value || "#172033",
|
|
2270
|
-
size: Number((block.querySelector(".rbe-drawing-size") || {}).value || 4),
|
|
2271
|
-
text: (block.querySelector(".rbe-drawing-text-input") || {}).value || ""
|
|
2272
|
-
};
|
|
2273
|
-
}
|
|
2274
|
-
return {
|
|
2275
|
-
image: canvas ? canvas.toDataURL("image/png") : "",
|
|
2276
|
-
color: (block.querySelector(".rbe-drawing-color") || {}).value || "#172033",
|
|
2277
|
-
size: Number((block.querySelector(".rbe-drawing-size") || {}).value || 4),
|
|
2278
|
-
text: (block.querySelector(".rbe-drawing-text-input") || {}).value || ""
|
|
2279
|
-
};
|
|
2280
|
-
},
|
|
2281
|
-
toHTML: function (data) {
|
|
2282
|
-
var image = data.image || data.url || data.src || (data.diagram && data.diagram.image) || "";
|
|
2283
|
-
if (!image && data.text) image = drawingTextSvgDataUri(data.text, data.color || "#2f1830");
|
|
2284
|
-
return image ? '<figure class="rbe-output-drawing"><img src="' + esc(image) + '" alt="Drawing"></figure>' : "";
|
|
2285
|
-
},
|
|
2286
|
-
toMarkdown: function () {
|
|
2287
|
-
return "";
|
|
2288
|
-
}
|
|
2289
|
-
});
|
|
2290
2110
|
|
|
2291
2111
|
BlockWriteAI.registerTool("columns", {
|
|
2292
2112
|
label: "Columns",
|
|
@@ -533,38 +533,70 @@
|
|
|
533
533
|
});
|
|
534
534
|
}
|
|
535
535
|
|
|
536
|
+
function ensureAIRefreshListener(editor) {
|
|
537
|
+
if (!editor || !editor.root || editor.__blockwriteaiAIRefreshBound) return;
|
|
538
|
+
editor.root.addEventListener("rbe:premium-change", refreshAIAvailability.bind(null, editor));
|
|
539
|
+
editor.__blockwriteaiAIRefreshBound = true;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function ensureTopToolbarAIButton(editor, toolbar) {
|
|
543
|
+
toolbar = toolbar || (editor && editor.topToolbar);
|
|
544
|
+
if (!editor || editor.options.ai === false || !toolbar) return toolbar;
|
|
545
|
+
injectStyles();
|
|
546
|
+
if (!toolbar.querySelector(".rbe-ai-toolbar-btn")) {
|
|
547
|
+
toolbar.appendChild(
|
|
548
|
+
el("button", "rbe-history-btn rbe-ai-toolbar-btn", {
|
|
549
|
+
type: "button",
|
|
550
|
+
title: "BlockWriteAI",
|
|
551
|
+
html: faIcon("wand-magic-sparkles", "BlockWriteAI"),
|
|
552
|
+
dataset: { aiToolbar: "true", premiumFeature: "ai", unlockedTitle: "BlockWriteAI" }
|
|
553
|
+
})
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
ensureAIRefreshListener(editor);
|
|
557
|
+
refreshAIAvailability(editor);
|
|
558
|
+
return toolbar;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function ensureInlineAIButton(editor, toolbar) {
|
|
562
|
+
toolbar = toolbar || (editor && editor.inlineToolbar);
|
|
563
|
+
if (!editor || editor.options.ai === false || !toolbar) return toolbar;
|
|
564
|
+
injectStyles();
|
|
565
|
+
if (!toolbar.querySelector(".rbe-ai-inline-btn")) {
|
|
566
|
+
toolbar.appendChild(
|
|
567
|
+
el("button", "rbe-ai-inline-btn", {
|
|
568
|
+
type: "button",
|
|
569
|
+
title: "BlockWriteAI",
|
|
570
|
+
html: faIcon("wand-magic-sparkles", "AI"),
|
|
571
|
+
dataset: { aiInline: "true", premiumFeature: "ai", unlockedTitle: "BlockWriteAI" }
|
|
572
|
+
})
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
ensureAIRefreshListener(editor);
|
|
576
|
+
refreshAIAvailability(editor);
|
|
577
|
+
return toolbar;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function hydrateExistingEditors() {
|
|
581
|
+
if (typeof document === "undefined") return;
|
|
582
|
+
Array.prototype.slice.call(document.querySelectorAll(".rbe")).forEach(function (root) {
|
|
583
|
+
var editor = root.__blockwriteaiInstance;
|
|
584
|
+
if (!editor) return;
|
|
585
|
+
ensureTopToolbarAIButton(editor);
|
|
586
|
+
ensureInlineAIButton(editor);
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
536
590
|
var originalCreateTopToolbar = BlockWriteAI.prototype.createTopToolbar;
|
|
537
591
|
BlockWriteAI.prototype.createTopToolbar = function () {
|
|
538
592
|
var toolbar = originalCreateTopToolbar.call(this);
|
|
539
|
-
|
|
540
|
-
injectStyles();
|
|
541
|
-
toolbar.appendChild(
|
|
542
|
-
el("button", "rbe-history-btn rbe-ai-toolbar-btn", {
|
|
543
|
-
type: "button",
|
|
544
|
-
title: "BlockWriteAI",
|
|
545
|
-
html: faIcon("wand-magic-sparkles", "BlockWriteAI"),
|
|
546
|
-
dataset: { aiToolbar: "true", premiumFeature: "ai", unlockedTitle: "BlockWriteAI" }
|
|
547
|
-
})
|
|
548
|
-
);
|
|
549
|
-
refreshAIAvailability(this);
|
|
550
|
-
this.root.addEventListener("rbe:premium-change", refreshAIAvailability.bind(null, this));
|
|
551
|
-
return toolbar;
|
|
593
|
+
return ensureTopToolbarAIButton(this, toolbar);
|
|
552
594
|
};
|
|
553
595
|
|
|
554
596
|
var originalCreateInlineToolbar = BlockWriteAI.prototype.createInlineToolbar;
|
|
555
597
|
BlockWriteAI.prototype.createInlineToolbar = function () {
|
|
556
598
|
var toolbar = originalCreateInlineToolbar.call(this);
|
|
557
|
-
|
|
558
|
-
injectStyles();
|
|
559
|
-
var button = el("button", "rbe-ai-inline-btn", {
|
|
560
|
-
type: "button",
|
|
561
|
-
title: "BlockWriteAI",
|
|
562
|
-
html: faIcon("wand-magic-sparkles", "AI"),
|
|
563
|
-
dataset: { aiInline: "true", premiumFeature: "ai", unlockedTitle: "BlockWriteAI" }
|
|
564
|
-
});
|
|
565
|
-
toolbar.appendChild(button);
|
|
566
|
-
refreshAIAvailability(this);
|
|
567
|
-
return toolbar;
|
|
599
|
+
return ensureInlineAIButton(this, toolbar);
|
|
568
600
|
};
|
|
569
601
|
|
|
570
602
|
BlockWriteAI.prototype.openAI = function () {
|
|
@@ -633,5 +665,7 @@
|
|
|
633
665
|
return BlockWriteAI;
|
|
634
666
|
};
|
|
635
667
|
|
|
668
|
+
hydrateExistingEditors();
|
|
669
|
+
|
|
636
670
|
return BlockWriteAI;
|
|
637
671
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qarakash/blockwriteai",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "BlockWriteAI JSON-first drop-in block writing editor with
|
|
3
|
+
"version": "1.0.9",
|
|
4
|
+
"description": "BlockWriteAI JSON-first drop-in block writing editor with free core blocks, preview mounting, and license-gated premium plugins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"blockwriteai",
|
|
7
7
|
"editor",
|