djm-ui 0.67.3 → 0.72.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/CHANGELOG.md +108 -0
- package/README.md +38 -2
- package/dist/djm-ui.cjs +1051 -356
- package/dist/djm-ui.cjs.map +4 -4
- package/dist/djm-ui.css +752 -17
- package/dist/djm-ui.esm.js +1127 -432
- package/dist/djm-ui.esm.js.map +4 -4
- package/dist/djm-ui.esm.min.js +375 -229
- package/dist/djm-ui.min.cjs +375 -229
- package/dist/djm-ui.min.css +2 -2
- package/dist/djm-ui.umd.js +967 -272
- package/dist/djm-ui.umd.min.js +375 -229
- package/dist/mcp/manifest.json +12195 -0
- package/dist/mcp/server.js +90 -0
- package/package.json +12 -4
- package/src/components/icon/index.js +13 -1
- package/src/components/input/index.js +17 -6
- package/src/components/rich-editor/index.js +724 -61
- package/src/index.js +1 -1
- package/src/locale/en-US.js +33 -1
- package/src/locale/zh-CN.js +33 -1
- package/src/styles/base.css +2 -3
- package/src/styles/components/button.css +2 -1
- package/src/styles/components/console.css +5 -0
- package/src/styles/components/content.css +517 -0
- package/src/styles/components/form.css +5 -0
- package/src/styles/components/layout.css +327 -1
- package/src/styles/components/media-picker.css +3 -3
- package/src/styles/components/menu.css +2 -1
- package/src/styles/components/org-picker.css +1 -1
- package/src/styles/components/responsive.css +86 -0
- package/src/styles/components/rich-editor.css +206 -7
- package/src/styles/components/skin.css +54 -0
- package/src/styles/components/template.css +5 -0
- package/src/styles/index.css +1 -0
- package/src/styles/theme-dark.css +2 -0
- package/src/styles/tokens.css +8 -0
- package/src/theme/index.js +40 -0
- package/src/utils/sanitize-html.js +44 -6
- package/types/index.d.ts +8 -0
package/dist/djm-ui.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! DJM UI v0.
|
|
1
|
+
/*! DJM UI v0.72.0 · MIT · 2026-10-26 */
|
|
2
2
|
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -1119,7 +1119,19 @@ var PATHS = {
|
|
|
1119
1119
|
activity: "M22 12h-4l-3 9L9 3l-3 9H2",
|
|
1120
1120
|
database: "M12 8c4.42 0 8-1.34 8-3s-3.58-3-8-3-8 1.34-8 3 3.58 3 8 3zM4 5v14c0 1.66 3.58 3 8 3s8-1.34 8-3V5M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3",
|
|
1121
1121
|
sun: "M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10zM12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42",
|
|
1122
|
-
moon: "M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"
|
|
1122
|
+
moon: "M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z",
|
|
1123
|
+
undo: "M3 10h11a5 5 0 1 1 0 10H8M3 10l4-4M3 10l4 4",
|
|
1124
|
+
redo: "M21 10H10a5 5 0 1 0 0 10h6M21 10l-4-4M21 10l-4 4",
|
|
1125
|
+
"align-left": "M4 6h16M4 12h10M4 18h13",
|
|
1126
|
+
"align-center": "M4 6h16M7 12h10M6 18h12",
|
|
1127
|
+
"align-right": "M4 6h16M10 12h10M7 18h13",
|
|
1128
|
+
"align-justify": "M4 6h16M4 12h16M4 18h16",
|
|
1129
|
+
list: "M9 6h11M9 12h11M9 18h11M4.5 6h.01M4.5 12h.01M4.5 18h.01",
|
|
1130
|
+
"list-ordered": "M10 6h10M10 12h10M10 18h10M4 6h1v4M4 12h2M4 16h2v2H4",
|
|
1131
|
+
outdent: "M4 6h16M10 12h10M10 18h10M8 9l-3 3 3 3",
|
|
1132
|
+
indent: "M4 6h16M10 12h10M10 18h10M5 9l3 3-3 3",
|
|
1133
|
+
unlink: "M10 13a5 5 0 0 0 7.5.5M14 11a5 5 0 0 0-7.5-.5M2 2l20 20",
|
|
1134
|
+
images: "M8 3h12v12M4 7h12v12H4zM7 15l3-3 3 3"
|
|
1123
1135
|
};
|
|
1124
1136
|
var icon_default = {
|
|
1125
1137
|
name: "DjmIcon",
|
|
@@ -1249,19 +1261,29 @@ var input_default = {
|
|
|
1249
1261
|
this.focus();
|
|
1250
1262
|
},
|
|
1251
1263
|
focus() {
|
|
1264
|
+
this.clearStaleValue();
|
|
1252
1265
|
if (this.$refs.input) this.$refs.input.focus();
|
|
1253
1266
|
},
|
|
1267
|
+
onFocus(event) {
|
|
1268
|
+
this.clearStaleValue();
|
|
1269
|
+
this.$emit("focus", event);
|
|
1270
|
+
},
|
|
1254
1271
|
blur() {
|
|
1255
1272
|
if (this.$refs.input) this.$refs.input.blur();
|
|
1256
1273
|
}
|
|
1257
1274
|
},
|
|
1258
1275
|
mounted() {
|
|
1259
|
-
this.
|
|
1260
|
-
|
|
1276
|
+
this.staleTimers = [null, 200, 600, 1200, 2400].map((delay) => {
|
|
1277
|
+
if (delay === null) {
|
|
1278
|
+
this.clearStaleValue();
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
return setTimeout(() => this.clearStaleValue(), delay);
|
|
1282
|
+
});
|
|
1261
1283
|
window.addEventListener("pageshow", this.clearStaleValue);
|
|
1262
1284
|
},
|
|
1263
1285
|
beforeUnmount() {
|
|
1264
|
-
|
|
1286
|
+
this.staleTimers.forEach((timer) => clearTimeout(timer));
|
|
1265
1287
|
window.removeEventListener("pageshow", this.clearStaleValue);
|
|
1266
1288
|
},
|
|
1267
1289
|
template: `
|
|
@@ -1281,7 +1303,7 @@ var input_default = {
|
|
|
1281
1303
|
@input="onInput"
|
|
1282
1304
|
@change="$emit('change', $event)"
|
|
1283
1305
|
@keyup.enter="$emit('enter', $event)"
|
|
1284
|
-
@focus="
|
|
1306
|
+
@focus="onFocus"
|
|
1285
1307
|
@blur="$emit('blur', $event)"
|
|
1286
1308
|
/>
|
|
1287
1309
|
<button
|
|
@@ -1311,7 +1333,7 @@ var input_default = {
|
|
|
1311
1333
|
@input="onInput"
|
|
1312
1334
|
@change="$emit('change', $event)"
|
|
1313
1335
|
@keyup.enter="$emit('enter', $event)"
|
|
1314
|
-
@focus="
|
|
1336
|
+
@focus="onFocus"
|
|
1315
1337
|
@blur="$emit('blur', $event)"
|
|
1316
1338
|
/>
|
|
1317
1339
|
`
|
|
@@ -1436,7 +1458,6 @@ var zh_CN_default = {
|
|
|
1436
1458
|
"richEditor.italic": "\u659C\u4F53",
|
|
1437
1459
|
"richEditor.underline": "\u4E0B\u5212\u7EBF",
|
|
1438
1460
|
"richEditor.strike": "\u5220\u9664\u7EBF",
|
|
1439
|
-
"richEditor.heading": "\u4E8C\u7EA7\u6807\u9898",
|
|
1440
1461
|
"richEditor.paragraph": "\u6B63\u6587",
|
|
1441
1462
|
"richEditor.bulletList": "\u65E0\u5E8F\u5217\u8868",
|
|
1442
1463
|
"richEditor.numberList": "\u6709\u5E8F\u5217\u8868",
|
|
@@ -1447,6 +1468,39 @@ var zh_CN_default = {
|
|
|
1447
1468
|
"richEditor.redo": "\u91CD\u505A",
|
|
1448
1469
|
"richEditor.source": "\u6E90\u7801",
|
|
1449
1470
|
"richEditor.visual": "\u53EF\u89C6\u5316",
|
|
1471
|
+
"richEditor.toolbar": "\u7F16\u8F91\u5DE5\u5177\u680F",
|
|
1472
|
+
"richEditor.block": "\u6BB5\u843D\u683C\u5F0F",
|
|
1473
|
+
"richEditor.heading1": "\u6807\u9898 1",
|
|
1474
|
+
"richEditor.heading2": "\u6807\u9898 2",
|
|
1475
|
+
"richEditor.heading3": "\u6807\u9898 3",
|
|
1476
|
+
"richEditor.quote": "\u5F15\u7528",
|
|
1477
|
+
"richEditor.codeBlock": "\u4EE3\u7801\u5757",
|
|
1478
|
+
"richEditor.fontSize": "\u5B57\u53F7",
|
|
1479
|
+
"richEditor.defaultSize": "\u9ED8\u8BA4",
|
|
1480
|
+
"richEditor.inlineCode": "\u884C\u5185\u4EE3\u7801",
|
|
1481
|
+
"richEditor.textColor": "\u6587\u5B57\u989C\u8272",
|
|
1482
|
+
"richEditor.bgColor": "\u80CC\u666F\u8272",
|
|
1483
|
+
"richEditor.alignLeft": "\u5DE6\u5BF9\u9F50",
|
|
1484
|
+
"richEditor.alignCenter": "\u5C45\u4E2D",
|
|
1485
|
+
"richEditor.alignRight": "\u53F3\u5BF9\u9F50",
|
|
1486
|
+
"richEditor.alignJustify": "\u4E24\u7AEF\u5BF9\u9F50",
|
|
1487
|
+
"richEditor.outdent": "\u51CF\u5C11\u7F29\u8FDB",
|
|
1488
|
+
"richEditor.indent": "\u589E\u52A0\u7F29\u8FDB",
|
|
1489
|
+
"richEditor.unlink": "\u53D6\u6D88\u94FE\u63A5",
|
|
1490
|
+
"richEditor.image": "\u63D2\u5165\u56FE\u7247",
|
|
1491
|
+
"richEditor.singleImage": "\u63D2\u5165\u5355\u56FE",
|
|
1492
|
+
"richEditor.multiImage": "\u63D2\u5165\u591A\u56FE",
|
|
1493
|
+
"richEditor.mediaLibrary": "\u4ECE\u7D20\u6750\u5E93\u9009\u62E9",
|
|
1494
|
+
"richEditor.hr": "\u5206\u5272\u7EBF",
|
|
1495
|
+
"richEditor.fullscreen": "\u5168\u5C4F",
|
|
1496
|
+
"richEditor.exitFullscreen": "\u9000\u51FA\u5168\u5C4F",
|
|
1497
|
+
"richEditor.wordCount": "\u5171 {count} \u5B57",
|
|
1498
|
+
"richEditor.uploading": "\u6B63\u5728\u4E0A\u4F20 {count} \u5F20\u56FE\u7247\u2026",
|
|
1499
|
+
"richEditor.uploadFailed": "\u56FE\u7247\u4E0A\u4F20\u5931\u8D25",
|
|
1500
|
+
"richEditor.imageTypeError": "\u53EA\u80FD\u4E0A\u4F20\u56FE\u7247\u6587\u4EF6",
|
|
1501
|
+
"richEditor.imageSizeError": "\u56FE\u7247\u4E0D\u80FD\u8D85\u8FC7 {size}MB",
|
|
1502
|
+
"richEditor.imageUrlInvalid": "\u56FE\u7247\u5730\u5740\u4E0D\u5408\u6CD5\uFF0C\u5DF2\u62D2\u7EDD\u63D2\u5165",
|
|
1503
|
+
"richEditor.linkInvalid": "\u94FE\u63A5\u53EA\u652F\u6301 http(s)\u3001mailto\u3001tel \u6216\u7AD9\u5185\u76F8\u5BF9\u5730\u5740",
|
|
1450
1504
|
"approval.start": "\u53D1\u8D77",
|
|
1451
1505
|
"approval.cc": "\u6284\u9001",
|
|
1452
1506
|
"approval.approved": "\u5DF2\u901A\u8FC7",
|
|
@@ -1655,7 +1709,6 @@ var en_US_default = {
|
|
|
1655
1709
|
"richEditor.italic": "Italic",
|
|
1656
1710
|
"richEditor.underline": "Underline",
|
|
1657
1711
|
"richEditor.strike": "Strikethrough",
|
|
1658
|
-
"richEditor.heading": "Heading 2",
|
|
1659
1712
|
"richEditor.paragraph": "Paragraph",
|
|
1660
1713
|
"richEditor.bulletList": "Bullet list",
|
|
1661
1714
|
"richEditor.numberList": "Numbered list",
|
|
@@ -1666,6 +1719,39 @@ var en_US_default = {
|
|
|
1666
1719
|
"richEditor.redo": "Redo",
|
|
1667
1720
|
"richEditor.source": "Source",
|
|
1668
1721
|
"richEditor.visual": "Visual",
|
|
1722
|
+
"richEditor.toolbar": "Formatting toolbar",
|
|
1723
|
+
"richEditor.block": "Paragraph style",
|
|
1724
|
+
"richEditor.heading1": "Heading 1",
|
|
1725
|
+
"richEditor.heading2": "Heading 2",
|
|
1726
|
+
"richEditor.heading3": "Heading 3",
|
|
1727
|
+
"richEditor.quote": "Quote",
|
|
1728
|
+
"richEditor.codeBlock": "Code block",
|
|
1729
|
+
"richEditor.fontSize": "Font size",
|
|
1730
|
+
"richEditor.defaultSize": "Default",
|
|
1731
|
+
"richEditor.inlineCode": "Inline code",
|
|
1732
|
+
"richEditor.textColor": "Text color",
|
|
1733
|
+
"richEditor.bgColor": "Background color",
|
|
1734
|
+
"richEditor.alignLeft": "Align left",
|
|
1735
|
+
"richEditor.alignCenter": "Align center",
|
|
1736
|
+
"richEditor.alignRight": "Align right",
|
|
1737
|
+
"richEditor.alignJustify": "Justify",
|
|
1738
|
+
"richEditor.outdent": "Decrease indent",
|
|
1739
|
+
"richEditor.indent": "Increase indent",
|
|
1740
|
+
"richEditor.unlink": "Remove link",
|
|
1741
|
+
"richEditor.image": "Insert image",
|
|
1742
|
+
"richEditor.singleImage": "Insert single image",
|
|
1743
|
+
"richEditor.multiImage": "Insert multiple images",
|
|
1744
|
+
"richEditor.mediaLibrary": "Choose from media library",
|
|
1745
|
+
"richEditor.hr": "Divider",
|
|
1746
|
+
"richEditor.fullscreen": "Fullscreen",
|
|
1747
|
+
"richEditor.exitFullscreen": "Exit fullscreen",
|
|
1748
|
+
"richEditor.wordCount": "{count} characters",
|
|
1749
|
+
"richEditor.uploading": "Uploading {count} image(s)\u2026",
|
|
1750
|
+
"richEditor.uploadFailed": "Image upload failed",
|
|
1751
|
+
"richEditor.imageTypeError": "Only image files are allowed",
|
|
1752
|
+
"richEditor.imageSizeError": "Image must be smaller than {size}MB",
|
|
1753
|
+
"richEditor.imageUrlInvalid": "Invalid image URL, insertion rejected",
|
|
1754
|
+
"richEditor.linkInvalid": "Only http(s), mailto, tel or relative URLs are allowed",
|
|
1669
1755
|
"approval.start": "Started",
|
|
1670
1756
|
"approval.cc": "CC",
|
|
1671
1757
|
"approval.approved": "Approved",
|
|
@@ -9484,7 +9570,199 @@ var tree_select_default = {
|
|
|
9484
9570
|
};
|
|
9485
9571
|
|
|
9486
9572
|
// src/components/rich-editor/index.js
|
|
9573
|
+
var import_vue33 = require("vue");
|
|
9574
|
+
|
|
9575
|
+
// src/components/media-picker/index.js
|
|
9487
9576
|
var import_vue32 = require("vue");
|
|
9577
|
+
var media_picker_default = {
|
|
9578
|
+
name: "DjmMediaPicker",
|
|
9579
|
+
components: { DjmModal: modal_default, DjmPagination: pagination_default, DjmIcon: icon_default },
|
|
9580
|
+
props: {
|
|
9581
|
+
modelValue: { type: [Array, String, Number], default: "" },
|
|
9582
|
+
items: { type: Array, default: () => [] },
|
|
9583
|
+
multiple: { type: Boolean, default: false },
|
|
9584
|
+
// 最多选几个,0 表示不限
|
|
9585
|
+
limit: { type: Number, default: 0 },
|
|
9586
|
+
// image 只显示图片,file 只显示非图片,空串不过滤
|
|
9587
|
+
accept: { type: String, default: "" },
|
|
9588
|
+
title: { type: String, default: "" },
|
|
9589
|
+
triggerText: { type: String, default: "" },
|
|
9590
|
+
pageSize: { type: Number, default: 12 },
|
|
9591
|
+
disabled: { type: Boolean, default: false }
|
|
9592
|
+
},
|
|
9593
|
+
emits: ["update:modelValue", "change"],
|
|
9594
|
+
setup(props, { emit }) {
|
|
9595
|
+
const open = (0, import_vue32.ref)(false);
|
|
9596
|
+
const keyword = (0, import_vue32.ref)("");
|
|
9597
|
+
const page = (0, import_vue32.ref)(1);
|
|
9598
|
+
const temp = (0, import_vue32.ref)([]);
|
|
9599
|
+
const selectedIds = (0, import_vue32.computed)(() => {
|
|
9600
|
+
if (props.multiple) return Array.isArray(props.modelValue) ? props.modelValue : [];
|
|
9601
|
+
if (props.modelValue === "" || props.modelValue === null || props.modelValue === void 0) return [];
|
|
9602
|
+
return [props.modelValue];
|
|
9603
|
+
});
|
|
9604
|
+
function isImage(item) {
|
|
9605
|
+
if (item.type) return item.type === "image";
|
|
9606
|
+
return /\.(png|jpe?g|gif|webp|svg|avif)$/i.test(item.url || "");
|
|
9607
|
+
}
|
|
9608
|
+
const filtered = (0, import_vue32.computed)(() => {
|
|
9609
|
+
const key = keyword.value.trim().toLowerCase();
|
|
9610
|
+
return props.items.filter((item) => {
|
|
9611
|
+
if (props.accept === "image" && !isImage(item)) return false;
|
|
9612
|
+
if (props.accept === "file" && isImage(item)) return false;
|
|
9613
|
+
if (key && !String(item.name || "").toLowerCase().includes(key)) return false;
|
|
9614
|
+
return true;
|
|
9615
|
+
});
|
|
9616
|
+
});
|
|
9617
|
+
const paged = (0, import_vue32.computed)(() => {
|
|
9618
|
+
const start = (page.value - 1) * props.pageSize;
|
|
9619
|
+
return filtered.value.slice(start, start + props.pageSize);
|
|
9620
|
+
});
|
|
9621
|
+
(0, import_vue32.watch)(keyword, () => {
|
|
9622
|
+
page.value = 1;
|
|
9623
|
+
});
|
|
9624
|
+
(0, import_vue32.watch)(
|
|
9625
|
+
() => filtered.value.length,
|
|
9626
|
+
() => {
|
|
9627
|
+
const max = Math.max(1, Math.ceil(filtered.value.length / props.pageSize));
|
|
9628
|
+
if (page.value > max) page.value = max;
|
|
9629
|
+
}
|
|
9630
|
+
);
|
|
9631
|
+
function isChecked(id) {
|
|
9632
|
+
return temp.value.includes(id);
|
|
9633
|
+
}
|
|
9634
|
+
function atLimit() {
|
|
9635
|
+
return props.limit > 0 && temp.value.length >= props.limit;
|
|
9636
|
+
}
|
|
9637
|
+
function toggle(item) {
|
|
9638
|
+
if (props.multiple) {
|
|
9639
|
+
if (isChecked(item.id)) {
|
|
9640
|
+
temp.value = temp.value.filter((id) => id !== item.id);
|
|
9641
|
+
return;
|
|
9642
|
+
}
|
|
9643
|
+
if (atLimit()) return;
|
|
9644
|
+
temp.value = [...temp.value, item.id];
|
|
9645
|
+
return;
|
|
9646
|
+
}
|
|
9647
|
+
temp.value = [item.id];
|
|
9648
|
+
}
|
|
9649
|
+
function openPanel() {
|
|
9650
|
+
if (props.disabled) return;
|
|
9651
|
+
temp.value = [...selectedIds.value];
|
|
9652
|
+
keyword.value = "";
|
|
9653
|
+
page.value = 1;
|
|
9654
|
+
open.value = true;
|
|
9655
|
+
}
|
|
9656
|
+
function commit() {
|
|
9657
|
+
const next = props.multiple ? [...temp.value] : temp.value[0] !== void 0 ? temp.value[0] : "";
|
|
9658
|
+
emit("update:modelValue", next);
|
|
9659
|
+
emit("change", next);
|
|
9660
|
+
open.value = false;
|
|
9661
|
+
}
|
|
9662
|
+
function cancel() {
|
|
9663
|
+
temp.value = [...selectedIds.value];
|
|
9664
|
+
open.value = false;
|
|
9665
|
+
}
|
|
9666
|
+
return {
|
|
9667
|
+
open,
|
|
9668
|
+
keyword,
|
|
9669
|
+
page,
|
|
9670
|
+
temp,
|
|
9671
|
+
selectedIds,
|
|
9672
|
+
filtered,
|
|
9673
|
+
paged,
|
|
9674
|
+
isImage,
|
|
9675
|
+
isChecked,
|
|
9676
|
+
atLimit,
|
|
9677
|
+
toggle,
|
|
9678
|
+
openPanel,
|
|
9679
|
+
commit,
|
|
9680
|
+
cancel,
|
|
9681
|
+
t
|
|
9682
|
+
};
|
|
9683
|
+
},
|
|
9684
|
+
template: `
|
|
9685
|
+
<span class="djm-media-picker">
|
|
9686
|
+
<slot name="trigger" :open="openPanel" :count="selectedIds.length">
|
|
9687
|
+
<button
|
|
9688
|
+
class="djm-btn"
|
|
9689
|
+
type="button"
|
|
9690
|
+
:disabled="disabled"
|
|
9691
|
+
@click="openPanel"
|
|
9692
|
+
>{{ triggerText || t('mediaPicker.select') }}<span v-if="selectedIds.length" class="djm-media-picker-count">{{ selectedIds.length }}</span></button>
|
|
9693
|
+
</slot>
|
|
9694
|
+
|
|
9695
|
+
<DjmModal
|
|
9696
|
+
:model-value="open"
|
|
9697
|
+
:title="title || t('mediaPicker.title')"
|
|
9698
|
+
width="760px"
|
|
9699
|
+
@update:model-value="cancel"
|
|
9700
|
+
>
|
|
9701
|
+
<div class="djm-media-toolbar">
|
|
9702
|
+
<label class="djm-media-search">
|
|
9703
|
+
<DjmIcon name="search" :size="13" />
|
|
9704
|
+
<input
|
|
9705
|
+
v-model="keyword"
|
|
9706
|
+
class="djm-media-search-input"
|
|
9707
|
+
type="text"
|
|
9708
|
+
:placeholder="t('mediaPicker.search')"
|
|
9709
|
+
:aria-label="t('mediaPicker.search')"
|
|
9710
|
+
/>
|
|
9711
|
+
</label>
|
|
9712
|
+
<span class="djm-media-toolbar-slot">
|
|
9713
|
+
<slot name="toolbar"></slot>
|
|
9714
|
+
</span>
|
|
9715
|
+
</div>
|
|
9716
|
+
|
|
9717
|
+
<div class="djm-media-grid" role="listbox" :aria-multiselectable="multiple ? 'true' : 'false'">
|
|
9718
|
+
<div
|
|
9719
|
+
v-for="item in paged"
|
|
9720
|
+
:key="item.id"
|
|
9721
|
+
class="djm-media-item"
|
|
9722
|
+
:class="{
|
|
9723
|
+
'djm-is-checked': isChecked(item.id),
|
|
9724
|
+
'djm-is-disabled': multiple && atLimit() && !isChecked(item.id)
|
|
9725
|
+
}"
|
|
9726
|
+
role="option"
|
|
9727
|
+
tabindex="0"
|
|
9728
|
+
:aria-selected="String(isChecked(item.id))"
|
|
9729
|
+
@click="toggle(item)"
|
|
9730
|
+
@keydown.enter.prevent="toggle(item)"
|
|
9731
|
+
@keydown.space.prevent="toggle(item)"
|
|
9732
|
+
>
|
|
9733
|
+
<div class="djm-media-thumb">
|
|
9734
|
+
<img v-if="isImage(item)" :src="item.url" :alt="item.name" loading="lazy" />
|
|
9735
|
+
<DjmIcon v-else name="folder" :size="26" />
|
|
9736
|
+
<span v-if="isChecked(item.id)" class="djm-media-check">
|
|
9737
|
+
<DjmIcon name="check" :size="11" />
|
|
9738
|
+
</span>
|
|
9739
|
+
</div>
|
|
9740
|
+
<div class="djm-media-name" :title="item.name">{{ item.name }}</div>
|
|
9741
|
+
</div>
|
|
9742
|
+
<div v-if="!paged.length" class="djm-media-empty">{{ t('mediaPicker.empty') }}</div>
|
|
9743
|
+
</div>
|
|
9744
|
+
|
|
9745
|
+
<div class="djm-media-foot">
|
|
9746
|
+
<span class="djm-media-total">
|
|
9747
|
+
{{ t('mediaPicker.total', { total: filtered.length }) }}
|
|
9748
|
+
<em v-if="multiple && limit > 0">{{ t('mediaPicker.limit', { limit }) }}</em>
|
|
9749
|
+
</span>
|
|
9750
|
+
<DjmPagination
|
|
9751
|
+
v-if="filtered.length > pageSize"
|
|
9752
|
+
v-model:page="page"
|
|
9753
|
+
:page-size="pageSize"
|
|
9754
|
+
:total="filtered.length"
|
|
9755
|
+
/>
|
|
9756
|
+
</div>
|
|
9757
|
+
|
|
9758
|
+
<template #footer>
|
|
9759
|
+
<button class="djm-btn" type="button" @click="cancel">{{ t('common.cancel') }}</button>
|
|
9760
|
+
<button class="djm-btn djm-btn-primary" type="button" @click="commit">{{ t('common.confirm') }}</button>
|
|
9761
|
+
</template>
|
|
9762
|
+
</DjmModal>
|
|
9763
|
+
</span>
|
|
9764
|
+
`
|
|
9765
|
+
};
|
|
9488
9766
|
|
|
9489
9767
|
// src/utils/sanitize-html.js
|
|
9490
9768
|
var TAGS = /* @__PURE__ */ new Set([
|
|
@@ -9524,7 +9802,18 @@ var TAGS = /* @__PURE__ */ new Set([
|
|
|
9524
9802
|
"th",
|
|
9525
9803
|
"td"
|
|
9526
9804
|
]);
|
|
9527
|
-
var GLOBAL_ATTRS = /* @__PURE__ */ new Set(["class", "title"]);
|
|
9805
|
+
var GLOBAL_ATTRS = /* @__PURE__ */ new Set(["class", "title", "style"]);
|
|
9806
|
+
var STYLE_PROPS = /* @__PURE__ */ new Set([
|
|
9807
|
+
"color",
|
|
9808
|
+
"background-color",
|
|
9809
|
+
"font-size",
|
|
9810
|
+
"font-weight",
|
|
9811
|
+
"font-style",
|
|
9812
|
+
"text-decoration",
|
|
9813
|
+
"text-align",
|
|
9814
|
+
"text-indent",
|
|
9815
|
+
"line-height"
|
|
9816
|
+
]);
|
|
9528
9817
|
var TAG_ATTRS = {
|
|
9529
9818
|
a: /* @__PURE__ */ new Set(["href", "target", "rel"]),
|
|
9530
9819
|
img: /* @__PURE__ */ new Set(["src", "alt", "width", "height"]),
|
|
@@ -9532,11 +9821,29 @@ var TAG_ATTRS = {
|
|
|
9532
9821
|
th: /* @__PURE__ */ new Set(["colspan", "rowspan", "scope"]),
|
|
9533
9822
|
td: /* @__PURE__ */ new Set(["colspan", "rowspan"])
|
|
9534
9823
|
};
|
|
9824
|
+
function cleanStyle(value) {
|
|
9825
|
+
return String(value || "").split(";").map((item) => {
|
|
9826
|
+
const index = item.indexOf(":");
|
|
9827
|
+
if (index === -1) return "";
|
|
9828
|
+
const name = item.slice(0, index).trim().toLowerCase();
|
|
9829
|
+
const val = item.slice(index + 1).trim();
|
|
9830
|
+
if (!STYLE_PROPS.has(name)) return "";
|
|
9831
|
+
if (/url\s*\(|expression\s*\(|javascript:/i.test(val)) return "";
|
|
9832
|
+
return name + ": " + val;
|
|
9833
|
+
}).filter(Boolean).join("; ");
|
|
9834
|
+
}
|
|
9835
|
+
var SAFE_SCHEMES = /* @__PURE__ */ new Set(["http", "https", "mailto", "tel"]);
|
|
9535
9836
|
function safeUrl(value, tag) {
|
|
9536
|
-
const url = String(value || "").replace(/[\u0000-\u0020]+/g, "")
|
|
9537
|
-
|
|
9538
|
-
if (
|
|
9539
|
-
|
|
9837
|
+
const url = String(value || "").replace(/[\u0000-\u0020]+/g, "");
|
|
9838
|
+
const scheme = url.match(/^([a-z][a-z0-9+.-]*):/i);
|
|
9839
|
+
if (!scheme) return true;
|
|
9840
|
+
const name = scheme[1].toLowerCase();
|
|
9841
|
+
if (SAFE_SCHEMES.has(name)) return true;
|
|
9842
|
+
if (tag === "img") {
|
|
9843
|
+
if (name === "blob") return true;
|
|
9844
|
+
if (name === "data" && /^data:image\//i.test(url)) return true;
|
|
9845
|
+
}
|
|
9846
|
+
return false;
|
|
9540
9847
|
}
|
|
9541
9848
|
function cleanNode(node) {
|
|
9542
9849
|
const children = [...node.childNodes];
|
|
@@ -9559,6 +9866,12 @@ function cleanNode(node) {
|
|
|
9559
9866
|
child.removeAttribute(attr.name);
|
|
9560
9867
|
return;
|
|
9561
9868
|
}
|
|
9869
|
+
if (name === "style") {
|
|
9870
|
+
const style = cleanStyle(attr.value);
|
|
9871
|
+
if (style) child.setAttribute("style", style);
|
|
9872
|
+
else child.removeAttribute("style");
|
|
9873
|
+
return;
|
|
9874
|
+
}
|
|
9562
9875
|
if ((name === "href" || name === "src") && !safeUrl(attr.value, tag)) {
|
|
9563
9876
|
child.removeAttribute(attr.name);
|
|
9564
9877
|
}
|
|
@@ -9579,79 +9892,475 @@ function sanitizeHtml(html) {
|
|
|
9579
9892
|
}
|
|
9580
9893
|
|
|
9581
9894
|
// src/components/rich-editor/index.js
|
|
9895
|
+
var BLOCKS = [
|
|
9896
|
+
{ value: "p", label: "paragraph" },
|
|
9897
|
+
{ value: "h1", label: "heading1" },
|
|
9898
|
+
{ value: "h2", label: "heading2" },
|
|
9899
|
+
{ value: "h3", label: "heading3" },
|
|
9900
|
+
{ value: "blockquote", label: "quote" },
|
|
9901
|
+
{ value: "pre", label: "codeBlock" }
|
|
9902
|
+
];
|
|
9903
|
+
var SIZES = [
|
|
9904
|
+
{ value: "", label: "defaultSize" },
|
|
9905
|
+
{ value: "12px", label: "12px" },
|
|
9906
|
+
{ value: "14px", label: "14px" },
|
|
9907
|
+
{ value: "16px", label: "16px" },
|
|
9908
|
+
{ value: "18px", label: "18px" },
|
|
9909
|
+
{ value: "24px", label: "24px" }
|
|
9910
|
+
];
|
|
9911
|
+
var COLORS = ["#1f2d3d", "#5a6b7d", "#2b86d9", "#2fa36b", "#d97706", "#dc2626", "#7c3aed", "#ffffff"];
|
|
9912
|
+
var TOOLBAR_PRESETS = {
|
|
9913
|
+
simple: ["history", "inline", "list", "insert"],
|
|
9914
|
+
basic: ["history", "format", "inline", "align", "list", "insert", "view"],
|
|
9915
|
+
full: ["history", "format", "inline", "color", "align", "list", "insert", "view"]
|
|
9916
|
+
};
|
|
9917
|
+
function isSafeImageUrl(url) {
|
|
9918
|
+
const value = String(url || "").replace(/[\u0000-\u0020]+/g, "");
|
|
9919
|
+
if (!value) return false;
|
|
9920
|
+
const scheme = value.match(/^([a-z][a-z0-9+.-]*):/i);
|
|
9921
|
+
if (!scheme) return true;
|
|
9922
|
+
const name = scheme[1].toLowerCase();
|
|
9923
|
+
if (name === "http" || name === "https" || name === "blob") return true;
|
|
9924
|
+
return name === "data" && /^data:image\//i.test(value);
|
|
9925
|
+
}
|
|
9926
|
+
function isSafeLink(url) {
|
|
9927
|
+
const value = String(url || "").trim();
|
|
9928
|
+
if (!value) return false;
|
|
9929
|
+
const scheme = value.replace(/[\u0000-\u0020]+/g, "").match(/^([a-z][a-z0-9+.-]*):/i);
|
|
9930
|
+
if (!scheme) return true;
|
|
9931
|
+
return ["http", "https", "mailto", "tel"].indexOf(scheme[1].toLowerCase()) > -1;
|
|
9932
|
+
}
|
|
9582
9933
|
var rich_editor_default = {
|
|
9583
9934
|
name: "DjmRichEditor",
|
|
9584
|
-
components: { Icon: icon_default },
|
|
9935
|
+
components: { Icon: icon_default, MediaPicker: media_picker_default },
|
|
9585
9936
|
props: {
|
|
9586
9937
|
modelValue: { type: String, default: "" },
|
|
9587
9938
|
placeholder: { type: String, default: "" },
|
|
9588
9939
|
minHeight: { type: Number, default: 200 },
|
|
9589
|
-
//
|
|
9590
|
-
sanitize: { type: Boolean, default:
|
|
9591
|
-
disabled: { type: Boolean, default: false }
|
|
9940
|
+
// 默认开启:对外输出的 HTML 走白名单清洗,内容里不会带出脚本
|
|
9941
|
+
sanitize: { type: Boolean, default: true },
|
|
9942
|
+
disabled: { type: Boolean, default: false },
|
|
9943
|
+
// 工具条:simple / basic / full,或传分组数组(history / format / inline / color / align / list / insert / view)
|
|
9944
|
+
toolbar: { type: [String, Array], default: "full" },
|
|
9945
|
+
// 自定义上传:接收 File,返回图片地址(或 { url }),不传则转成 dataURL 本地预览
|
|
9946
|
+
uploadImage: { type: Function, default: null },
|
|
9947
|
+
// 已上传图片,提供后工具栏出现「从素材库选择」:字符串或 { url, name }
|
|
9948
|
+
media: { type: Array, default: () => [] },
|
|
9949
|
+
accept: { type: String, default: "image/*" },
|
|
9950
|
+
// 单张图片大小上限(MB)
|
|
9951
|
+
maxImageSize: { type: Number, default: 5 },
|
|
9952
|
+
// 是否允许一次选多张
|
|
9953
|
+
multiple: { type: Boolean, default: true },
|
|
9954
|
+
showCount: { type: Boolean, default: true }
|
|
9592
9955
|
},
|
|
9593
|
-
emits: ["update:modelValue"],
|
|
9956
|
+
emits: ["update:modelValue", "upload-error"],
|
|
9594
9957
|
setup(props, { emit }) {
|
|
9595
|
-
const editor = (0,
|
|
9596
|
-
const
|
|
9597
|
-
const
|
|
9598
|
-
const
|
|
9958
|
+
const editor = (0, import_vue33.ref)(null);
|
|
9959
|
+
const fileInput = (0, import_vue33.ref)(null);
|
|
9960
|
+
const sourceMode = (0, import_vue33.ref)(false);
|
|
9961
|
+
const source = (0, import_vue33.ref)(props.modelValue);
|
|
9962
|
+
const fullscreen = (0, import_vue33.ref)(false);
|
|
9963
|
+
const panel = (0, import_vue33.ref)("");
|
|
9964
|
+
const uploadCount = (0, import_vue33.ref)(0);
|
|
9965
|
+
const textColor = (0, import_vue33.ref)(COLORS[0]);
|
|
9966
|
+
const bgColor = (0, import_vue33.ref)("#fdf3c4");
|
|
9967
|
+
const fontSize = (0, import_vue33.ref)("");
|
|
9968
|
+
const count2 = (0, import_vue33.ref)(0);
|
|
9969
|
+
const formats = (0, import_vue33.ref)({
|
|
9970
|
+
bold: false,
|
|
9971
|
+
italic: false,
|
|
9972
|
+
underline: false,
|
|
9973
|
+
strike: false,
|
|
9974
|
+
code: false,
|
|
9975
|
+
block: "p",
|
|
9976
|
+
align: "",
|
|
9977
|
+
list: ""
|
|
9978
|
+
});
|
|
9979
|
+
let savedRange = null;
|
|
9980
|
+
const ready = (0, import_vue33.computed)(() => !props.disabled && !sourceMode.value);
|
|
9981
|
+
const toolbarGroups = (0, import_vue33.computed)(() => {
|
|
9982
|
+
const list = Array.isArray(props.toolbar) ? props.toolbar : TOOLBAR_PRESETS[props.toolbar] || TOOLBAR_PRESETS.full;
|
|
9983
|
+
return new Set(list);
|
|
9984
|
+
});
|
|
9985
|
+
function has(group) {
|
|
9986
|
+
return toolbarGroups.value.has(group);
|
|
9987
|
+
}
|
|
9988
|
+
const mediaLibrary = (0, import_vue33.computed)(
|
|
9989
|
+
() => (props.media || []).map((item, index) => {
|
|
9990
|
+
if (typeof item === "string") {
|
|
9991
|
+
return { id: "media-" + index, url: item, name: "", type: "image" };
|
|
9992
|
+
}
|
|
9993
|
+
return {
|
|
9994
|
+
id: item && item.id !== void 0 ? String(item.id) : "media-" + index,
|
|
9995
|
+
url: item && (item.url || item.src) || "",
|
|
9996
|
+
name: item && (item.name || item.alt) || "",
|
|
9997
|
+
type: "image"
|
|
9998
|
+
};
|
|
9999
|
+
}).filter((item) => !!item.url)
|
|
10000
|
+
);
|
|
9599
10001
|
function clean(html) {
|
|
9600
10002
|
return props.sanitize ? sanitizeHtml(html) : html;
|
|
9601
10003
|
}
|
|
10004
|
+
function plainText(html) {
|
|
10005
|
+
return String(html || "").replace(/<[^>]*>/g, "").replace(/ /g, " ").replace(/&[a-z]+;/gi, " ");
|
|
10006
|
+
}
|
|
9602
10007
|
function syncFromDom() {
|
|
9603
10008
|
if (!editor.value) return;
|
|
9604
|
-
|
|
10009
|
+
const html = clean(editor.value.innerHTML);
|
|
10010
|
+
count2.value = plainText(html).trim().length;
|
|
10011
|
+
emit("update:modelValue", html);
|
|
9605
10012
|
}
|
|
9606
|
-
function
|
|
9607
|
-
const
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
10013
|
+
function currentRange() {
|
|
10014
|
+
const selection = window.getSelection();
|
|
10015
|
+
if (!selection || !selection.rangeCount || !editor.value) return null;
|
|
10016
|
+
const range = selection.getRangeAt(0);
|
|
10017
|
+
return editor.value.contains(range.commonAncestorContainer) ? range : null;
|
|
10018
|
+
}
|
|
10019
|
+
function rememberRange() {
|
|
10020
|
+
const range = currentRange();
|
|
10021
|
+
savedRange = range ? range.cloneRange() : null;
|
|
10022
|
+
}
|
|
10023
|
+
function focusAt(range) {
|
|
10024
|
+
if (!editor.value) return;
|
|
10025
|
+
editor.value.focus();
|
|
10026
|
+
const selection = window.getSelection();
|
|
10027
|
+
selection.removeAllRanges();
|
|
10028
|
+
if (range) {
|
|
10029
|
+
selection.addRange(range);
|
|
10030
|
+
return;
|
|
10031
|
+
}
|
|
10032
|
+
const end = document.createRange();
|
|
10033
|
+
end.selectNodeContents(editor.value);
|
|
10034
|
+
end.collapse(false);
|
|
10035
|
+
selection.addRange(end);
|
|
10036
|
+
}
|
|
10037
|
+
function insertNodeAt(range, node) {
|
|
10038
|
+
if (!editor.value) return;
|
|
10039
|
+
focusAt(range);
|
|
10040
|
+
const selection = window.getSelection();
|
|
10041
|
+
if (selection.rangeCount) selection.getRangeAt(0).insertNode(node);
|
|
10042
|
+
else editor.value.appendChild(node);
|
|
9612
10043
|
syncFromDom();
|
|
10044
|
+
syncFormats();
|
|
10045
|
+
}
|
|
10046
|
+
function ensureRange() {
|
|
10047
|
+
const range = currentRange();
|
|
10048
|
+
if (range) return range;
|
|
10049
|
+
if (!savedRange) return null;
|
|
10050
|
+
focusAt(savedRange);
|
|
10051
|
+
return currentRange();
|
|
9613
10052
|
}
|
|
9614
10053
|
function exec(command, value = null) {
|
|
9615
|
-
if (
|
|
10054
|
+
if (!ready.value) return;
|
|
10055
|
+
if (typeof document.execCommand !== "function") return;
|
|
10056
|
+
ensureRange();
|
|
10057
|
+
document.execCommand("styleWithCSS", false, true);
|
|
9616
10058
|
document.execCommand(command, false, value);
|
|
9617
10059
|
if (editor.value) editor.value.focus();
|
|
9618
10060
|
syncFromDom();
|
|
9619
10061
|
syncFormats();
|
|
9620
10062
|
}
|
|
9621
|
-
function
|
|
9622
|
-
|
|
10063
|
+
function setBlock(value) {
|
|
10064
|
+
panel.value = "";
|
|
10065
|
+
exec("formatBlock", "<" + value + ">");
|
|
10066
|
+
}
|
|
10067
|
+
function setFontSize(size) {
|
|
10068
|
+
panel.value = "";
|
|
10069
|
+
if (!ready.value || !editor.value) return;
|
|
10070
|
+
fontSize.value = size;
|
|
10071
|
+
const range = ensureRange();
|
|
10072
|
+
if (!range || range.collapsed) return;
|
|
10073
|
+
if (!size) {
|
|
10074
|
+
const walker = document.createTreeWalker(editor.value, NodeFilter.SHOW_ELEMENT);
|
|
10075
|
+
const targets = [];
|
|
10076
|
+
while (walker.nextNode()) {
|
|
10077
|
+
const el = walker.currentNode;
|
|
10078
|
+
if (el.style && el.style.fontSize && range.intersectsNode(el)) targets.push(el);
|
|
10079
|
+
}
|
|
10080
|
+
targets.forEach((el) => {
|
|
10081
|
+
el.style.fontSize = "";
|
|
10082
|
+
});
|
|
10083
|
+
syncFromDom();
|
|
10084
|
+
return;
|
|
10085
|
+
}
|
|
10086
|
+
const span = document.createElement("span");
|
|
10087
|
+
span.style.fontSize = size;
|
|
10088
|
+
span.appendChild(range.extractContents());
|
|
10089
|
+
range.insertNode(span);
|
|
10090
|
+
const selection = window.getSelection();
|
|
10091
|
+
const after = document.createRange();
|
|
10092
|
+
after.setStartAfter(span);
|
|
10093
|
+
after.collapse(true);
|
|
10094
|
+
selection.removeAllRanges();
|
|
10095
|
+
selection.addRange(after);
|
|
10096
|
+
syncFromDom();
|
|
10097
|
+
syncFormats();
|
|
10098
|
+
}
|
|
10099
|
+
function applyColor(kind, color) {
|
|
10100
|
+
panel.value = "";
|
|
10101
|
+
if (kind === "text") textColor.value = color;
|
|
10102
|
+
else bgColor.value = color;
|
|
10103
|
+
if (!ready.value) return;
|
|
10104
|
+
if (typeof document.execCommand !== "function") return;
|
|
10105
|
+
document.execCommand("styleWithCSS", false, true);
|
|
10106
|
+
const command = kind === "text" ? "foreColor" : "hiliteColor";
|
|
10107
|
+
if (!document.execCommand(command, false, color) && kind === "bg") {
|
|
10108
|
+
document.execCommand("backColor", false, color);
|
|
10109
|
+
}
|
|
10110
|
+
if (editor.value) editor.value.focus();
|
|
10111
|
+
syncFromDom();
|
|
10112
|
+
syncFormats();
|
|
10113
|
+
}
|
|
10114
|
+
function togglePanel(name) {
|
|
10115
|
+
if (!ready.value) return;
|
|
10116
|
+
panel.value = panel.value === name ? "" : name;
|
|
10117
|
+
}
|
|
10118
|
+
function toggleInlineCode() {
|
|
10119
|
+
if (!ready.value || !editor.value) return;
|
|
10120
|
+
const range = currentRange();
|
|
10121
|
+
if (!range) return;
|
|
10122
|
+
const anchor = range.commonAncestorContainer;
|
|
10123
|
+
const node = anchor.nodeType === 1 ? anchor : anchor.parentElement;
|
|
10124
|
+
const code = node && node.closest ? node.closest("code") : null;
|
|
10125
|
+
if (code && editor.value.contains(code)) {
|
|
10126
|
+
const parent = code.parentNode;
|
|
10127
|
+
while (code.firstChild) parent.insertBefore(code.firstChild, code);
|
|
10128
|
+
parent.removeChild(code);
|
|
10129
|
+
syncFromDom();
|
|
10130
|
+
return;
|
|
10131
|
+
}
|
|
10132
|
+
if (range.collapsed) return;
|
|
10133
|
+
const wrapper = document.createElement("code");
|
|
10134
|
+
wrapper.appendChild(range.extractContents());
|
|
10135
|
+
range.insertNode(wrapper);
|
|
10136
|
+
const selection = window.getSelection();
|
|
10137
|
+
const after = document.createRange();
|
|
10138
|
+
after.setStartAfter(wrapper);
|
|
10139
|
+
after.collapse(true);
|
|
10140
|
+
selection.removeAllRanges();
|
|
10141
|
+
selection.addRange(after);
|
|
10142
|
+
syncFromDom();
|
|
10143
|
+
syncFormats();
|
|
9623
10144
|
}
|
|
9624
10145
|
function addLink() {
|
|
10146
|
+
if (!ready.value) return;
|
|
9625
10147
|
const url = window.prompt(t("richEditor.linkPrompt"), "https://");
|
|
9626
|
-
if (url)
|
|
10148
|
+
if (!url) return;
|
|
10149
|
+
if (!isSafeLink(url)) {
|
|
10150
|
+
window.alert(t("richEditor.linkInvalid"));
|
|
10151
|
+
return;
|
|
10152
|
+
}
|
|
10153
|
+
const range = currentRange();
|
|
10154
|
+
if (range && range.collapsed) {
|
|
10155
|
+
const link = document.createElement("a");
|
|
10156
|
+
link.href = url;
|
|
10157
|
+
link.target = "_blank";
|
|
10158
|
+
link.rel = "noopener noreferrer";
|
|
10159
|
+
link.textContent = url;
|
|
10160
|
+
insertNodeAt(range, link);
|
|
10161
|
+
return;
|
|
10162
|
+
}
|
|
10163
|
+
exec("createLink", url);
|
|
10164
|
+
if (editor.value) {
|
|
10165
|
+
editor.value.querySelectorAll("a[href]").forEach((link) => {
|
|
10166
|
+
if (!link.getAttribute("target")) link.setAttribute("target", "_blank");
|
|
10167
|
+
link.setAttribute("rel", "noopener noreferrer");
|
|
10168
|
+
});
|
|
10169
|
+
}
|
|
10170
|
+
syncFromDom();
|
|
9627
10171
|
}
|
|
9628
|
-
function
|
|
9629
|
-
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
10172
|
+
function readAsDataUrl(file) {
|
|
10173
|
+
return new Promise((resolve, reject) => {
|
|
10174
|
+
const reader = new FileReader();
|
|
10175
|
+
reader.onload = () => resolve(reader.result);
|
|
10176
|
+
reader.onerror = () => reject(reader.error || new Error("read failed"));
|
|
10177
|
+
reader.readAsDataURL(file);
|
|
10178
|
+
});
|
|
10179
|
+
}
|
|
10180
|
+
async function uploadOne(file) {
|
|
10181
|
+
if (props.uploadImage) {
|
|
10182
|
+
const result = await props.uploadImage(file);
|
|
10183
|
+
const url = typeof result === "string" ? result : result && result.url;
|
|
10184
|
+
if (!url) throw new Error(t("richEditor.imageUrlInvalid"));
|
|
10185
|
+
if (!isSafeImageUrl(url)) throw new Error(t("richEditor.imageUrlInvalid"));
|
|
10186
|
+
return String(url).trim();
|
|
10187
|
+
}
|
|
10188
|
+
return readAsDataUrl(file);
|
|
10189
|
+
}
|
|
10190
|
+
function isImage(file) {
|
|
10191
|
+
return file && /^image\//.test(file.type);
|
|
10192
|
+
}
|
|
10193
|
+
function pickImage(allowMultiple) {
|
|
10194
|
+
if (!ready.value || !fileInput.value) return;
|
|
10195
|
+
rememberRange();
|
|
10196
|
+
fileInput.value.multiple = !!allowMultiple && props.multiple;
|
|
10197
|
+
fileInput.value.click();
|
|
10198
|
+
}
|
|
10199
|
+
function insertMedia(ids) {
|
|
10200
|
+
if (!ready.value) return;
|
|
10201
|
+
const picked = (Array.isArray(ids) ? ids : [ids]).map((id) => mediaLibrary.value.find((item) => item.id === String(id))).filter(Boolean);
|
|
10202
|
+
const safe = picked.filter((item) => {
|
|
10203
|
+
if (isSafeImageUrl(item.url)) return true;
|
|
10204
|
+
emit("upload-error", { file: null, message: t("richEditor.imageUrlInvalid") });
|
|
10205
|
+
return false;
|
|
10206
|
+
});
|
|
10207
|
+
if (!safe.length) return;
|
|
10208
|
+
focusAt(savedRange);
|
|
10209
|
+
const fragment = document.createDocumentFragment();
|
|
10210
|
+
safe.forEach((item) => {
|
|
10211
|
+
const img = document.createElement("img");
|
|
10212
|
+
img.src = item.url;
|
|
10213
|
+
img.alt = item.name || "image";
|
|
10214
|
+
img.className = "djm-rich-editor-img";
|
|
10215
|
+
fragment.appendChild(img);
|
|
10216
|
+
});
|
|
10217
|
+
const selection = window.getSelection();
|
|
10218
|
+
if (selection.rangeCount) selection.getRangeAt(0).insertNode(fragment);
|
|
10219
|
+
else editor.value.appendChild(fragment);
|
|
10220
|
+
syncFromDom();
|
|
10221
|
+
syncFormats();
|
|
10222
|
+
}
|
|
10223
|
+
function insertImages(files) {
|
|
10224
|
+
if (!files.length || !editor.value) return;
|
|
10225
|
+
uploadCount.value = files.length;
|
|
10226
|
+
const holder = document.createElement("span");
|
|
10227
|
+
holder.className = "djm-rich-editor-uploading";
|
|
10228
|
+
holder.textContent = t("richEditor.uploading", { count: files.length });
|
|
10229
|
+
const anchor = savedRange && editor.value.contains(savedRange.commonAncestorContainer) ? savedRange : null;
|
|
10230
|
+
focusAt(anchor);
|
|
10231
|
+
const selection = window.getSelection();
|
|
10232
|
+
if (selection.rangeCount) selection.getRangeAt(0).insertNode(holder);
|
|
10233
|
+
else editor.value.appendChild(holder);
|
|
10234
|
+
Promise.all(files.map(async (file) => {
|
|
10235
|
+
if (!isImage(file)) return { file, error: t("richEditor.imageTypeError") };
|
|
10236
|
+
if (props.maxImageSize > 0 && file.size > props.maxImageSize * 1024 * 1024) {
|
|
10237
|
+
return { file, error: t("richEditor.imageSizeError", { size: props.maxImageSize }) };
|
|
10238
|
+
}
|
|
10239
|
+
try {
|
|
10240
|
+
return { file, url: await uploadOne(file) };
|
|
10241
|
+
} catch (error) {
|
|
10242
|
+
return { file, error: error && error.message || t("richEditor.uploadFailed") };
|
|
10243
|
+
}
|
|
10244
|
+
})).then((results) => {
|
|
10245
|
+
uploadCount.value = 0;
|
|
10246
|
+
const done = results.filter((item) => item.url);
|
|
10247
|
+
const failed = results.filter((item) => item.error);
|
|
10248
|
+
const alive = editor.value && editor.value.contains(holder);
|
|
10249
|
+
if (done.length && editor.value) {
|
|
10250
|
+
done.forEach((item) => {
|
|
10251
|
+
const img = document.createElement("img");
|
|
10252
|
+
img.src = item.url;
|
|
10253
|
+
img.alt = item.file.name || "image";
|
|
10254
|
+
img.className = "djm-rich-editor-img";
|
|
10255
|
+
if (alive) holder.parentNode.insertBefore(img, holder);
|
|
10256
|
+
else editor.value.appendChild(img);
|
|
10257
|
+
});
|
|
10258
|
+
}
|
|
10259
|
+
if (alive) holder.remove();
|
|
10260
|
+
failed.forEach((item) => emit("upload-error", { file: item.file, message: item.error }));
|
|
10261
|
+
syncFromDom();
|
|
10262
|
+
});
|
|
10263
|
+
}
|
|
10264
|
+
function onFilesChange(event) {
|
|
10265
|
+
const files = Array.from(event.target.files || []);
|
|
10266
|
+
event.target.value = "";
|
|
10267
|
+
insertImages(files);
|
|
10268
|
+
}
|
|
10269
|
+
function onPaste(event) {
|
|
10270
|
+
const data = event.clipboardData;
|
|
10271
|
+
if (!data) return;
|
|
10272
|
+
const images = Array.from(data.files || []).filter(isImage);
|
|
10273
|
+
if (images.length) {
|
|
10274
|
+
event.preventDefault();
|
|
10275
|
+
insertImages(images);
|
|
10276
|
+
return;
|
|
10277
|
+
}
|
|
10278
|
+
const html = data.getData("text/html");
|
|
10279
|
+
if (!html) return;
|
|
10280
|
+
event.preventDefault();
|
|
10281
|
+
document.execCommand("insertHTML", false, sanitizeHtml(html));
|
|
10282
|
+
syncFromDom();
|
|
10283
|
+
}
|
|
10284
|
+
function onDragOver(event) {
|
|
10285
|
+
if (!ready.value) return;
|
|
10286
|
+
if (event.dataTransfer && Array.from(event.dataTransfer.types || []).includes("Files")) {
|
|
10287
|
+
event.preventDefault();
|
|
10288
|
+
}
|
|
10289
|
+
}
|
|
10290
|
+
function onDrop(event) {
|
|
10291
|
+
if (!ready.value) return;
|
|
10292
|
+
const files = Array.from(event.dataTransfer && event.dataTransfer.files || []).filter(isImage);
|
|
10293
|
+
if (!files.length) return;
|
|
10294
|
+
event.preventDefault();
|
|
10295
|
+
rememberRange();
|
|
10296
|
+
insertImages(files);
|
|
10297
|
+
}
|
|
10298
|
+
function closestTag(node, tag) {
|
|
10299
|
+
const el = node && (node.nodeType === 1 ? node : node.parentElement);
|
|
10300
|
+
return el && el.closest ? el.closest(tag) : null;
|
|
10301
|
+
}
|
|
10302
|
+
function detectBlock() {
|
|
10303
|
+
const selection = window.getSelection();
|
|
10304
|
+
if (!selection || !selection.anchorNode) return "p";
|
|
10305
|
+
let node = selection.anchorNode;
|
|
10306
|
+
if (node.nodeType !== 1) node = node.parentElement;
|
|
10307
|
+
while (node && node !== editor.value) {
|
|
10308
|
+
const tag = node.tagName.toLowerCase();
|
|
10309
|
+
if (["p", "h1", "h2", "h3", "blockquote", "pre"].includes(tag)) return tag;
|
|
10310
|
+
node = node.parentElement;
|
|
10311
|
+
}
|
|
10312
|
+
return "p";
|
|
10313
|
+
}
|
|
10314
|
+
function syncFormats() {
|
|
10315
|
+
if (props.disabled || sourceMode.value || !editor.value) return;
|
|
10316
|
+
if (!editor.value.contains(document.activeElement)) return;
|
|
10317
|
+
const selection = window.getSelection();
|
|
10318
|
+
formats.value = {
|
|
10319
|
+
bold: document.queryCommandState("bold"),
|
|
10320
|
+
italic: document.queryCommandState("italic"),
|
|
10321
|
+
underline: document.queryCommandState("underline"),
|
|
10322
|
+
strike: document.queryCommandState("strikeThrough"),
|
|
10323
|
+
code: !!closestTag(selection.anchorNode, "code"),
|
|
10324
|
+
block: detectBlock(),
|
|
10325
|
+
align: document.queryCommandState("justifyCenter") ? "center" : document.queryCommandState("justifyRight") ? "right" : document.queryCommandState("justifyFull") ? "justify" : "left",
|
|
10326
|
+
list: document.queryCommandState("insertOrderedList") ? "ol" : document.queryCommandState("insertUnorderedList") ? "ul" : ""
|
|
10327
|
+
};
|
|
9637
10328
|
}
|
|
9638
10329
|
function onSourceInput() {
|
|
10330
|
+
count2.value = plainText(source.value).trim().length;
|
|
9639
10331
|
emit("update:modelValue", clean(source.value));
|
|
9640
10332
|
}
|
|
9641
10333
|
function toggleSource() {
|
|
9642
10334
|
if (props.disabled) return;
|
|
10335
|
+
panel.value = "";
|
|
9643
10336
|
if (sourceMode.value) {
|
|
9644
10337
|
emit("update:modelValue", clean(source.value));
|
|
9645
10338
|
sourceMode.value = false;
|
|
9646
10339
|
requestAnimationFrame(() => {
|
|
9647
10340
|
if (editor.value) editor.value.innerHTML = clean(source.value);
|
|
10341
|
+
syncFromDom();
|
|
9648
10342
|
});
|
|
9649
10343
|
} else {
|
|
9650
10344
|
source.value = editor.value ? editor.value.innerHTML : props.modelValue;
|
|
9651
10345
|
sourceMode.value = true;
|
|
9652
10346
|
}
|
|
9653
10347
|
}
|
|
9654
|
-
(
|
|
10348
|
+
function toggleFullscreen() {
|
|
10349
|
+
if (props.disabled) return;
|
|
10350
|
+
fullscreen.value = !fullscreen.value;
|
|
10351
|
+
panel.value = "";
|
|
10352
|
+
}
|
|
10353
|
+
function onDocumentClick(event) {
|
|
10354
|
+
if (!panel.value) return;
|
|
10355
|
+
if (!(event.target.closest && event.target.closest(".djm-rich-editor-color"))) panel.value = "";
|
|
10356
|
+
}
|
|
10357
|
+
function onKeydown(event) {
|
|
10358
|
+
if (event.key === "Escape" && fullscreen.value) {
|
|
10359
|
+
fullscreen.value = false;
|
|
10360
|
+
panel.value = "";
|
|
10361
|
+
}
|
|
10362
|
+
}
|
|
10363
|
+
(0, import_vue33.watch)(
|
|
9655
10364
|
() => props.modelValue,
|
|
9656
10365
|
(value) => {
|
|
9657
10366
|
if (sourceMode.value) {
|
|
@@ -9660,40 +10369,117 @@ var rich_editor_default = {
|
|
|
9660
10369
|
}
|
|
9661
10370
|
const next = clean(value);
|
|
9662
10371
|
if (editor.value && editor.value.innerHTML !== next) editor.value.innerHTML = next;
|
|
10372
|
+
count2.value = plainText(next).trim().length;
|
|
9663
10373
|
}
|
|
9664
10374
|
);
|
|
9665
|
-
(0,
|
|
10375
|
+
(0, import_vue33.onMounted)(() => {
|
|
9666
10376
|
if (editor.value) editor.value.innerHTML = clean(props.modelValue);
|
|
10377
|
+
count2.value = plainText(props.modelValue).trim().length;
|
|
9667
10378
|
document.addEventListener("selectionchange", syncFormats);
|
|
10379
|
+
document.addEventListener("click", onDocumentClick);
|
|
10380
|
+
document.addEventListener("keydown", onKeydown);
|
|
10381
|
+
});
|
|
10382
|
+
(0, import_vue33.onBeforeUnmount)(() => {
|
|
10383
|
+
document.removeEventListener("selectionchange", syncFormats);
|
|
10384
|
+
document.removeEventListener("click", onDocumentClick);
|
|
10385
|
+
document.removeEventListener("keydown", onKeydown);
|
|
9668
10386
|
});
|
|
9669
|
-
(0, import_vue32.onBeforeUnmount)(() => document.removeEventListener("selectionchange", syncFormats));
|
|
9670
10387
|
return {
|
|
9671
10388
|
editor,
|
|
10389
|
+
fileInput,
|
|
9672
10390
|
sourceMode,
|
|
9673
10391
|
source,
|
|
10392
|
+
fullscreen,
|
|
10393
|
+
panel,
|
|
10394
|
+
uploadCount,
|
|
10395
|
+
textColor,
|
|
10396
|
+
bgColor,
|
|
10397
|
+
fontSize,
|
|
10398
|
+
count: count2,
|
|
9674
10399
|
formats,
|
|
10400
|
+
blocks: BLOCKS,
|
|
10401
|
+
sizes: SIZES,
|
|
10402
|
+
colors: COLORS,
|
|
10403
|
+
mediaLibrary,
|
|
10404
|
+
has,
|
|
9675
10405
|
exec,
|
|
9676
|
-
|
|
10406
|
+
setBlock,
|
|
10407
|
+
setFontSize,
|
|
10408
|
+
applyColor,
|
|
10409
|
+
togglePanel,
|
|
10410
|
+
toggleInlineCode,
|
|
9677
10411
|
addLink,
|
|
9678
|
-
|
|
10412
|
+
pickImage,
|
|
10413
|
+
insertMedia,
|
|
10414
|
+
onFilesChange,
|
|
9679
10415
|
onPaste,
|
|
10416
|
+
onDragOver,
|
|
10417
|
+
onDrop,
|
|
10418
|
+
rememberRange,
|
|
10419
|
+
onSourceInput,
|
|
9680
10420
|
toggleSource,
|
|
10421
|
+
toggleFullscreen,
|
|
9681
10422
|
syncFromDom,
|
|
9682
10423
|
syncFormats,
|
|
9683
10424
|
t
|
|
9684
10425
|
};
|
|
9685
10426
|
},
|
|
9686
10427
|
template: `
|
|
9687
|
-
<div
|
|
9688
|
-
|
|
9689
|
-
|
|
10428
|
+
<div
|
|
10429
|
+
class="djm-rich-editor"
|
|
10430
|
+
:class="{ 'djm-is-disabled': disabled, 'djm-is-fullscreen': fullscreen }"
|
|
10431
|
+
>
|
|
10432
|
+
<div class="djm-rich-editor-toolbar" role="toolbar" :aria-label="t('richEditor.toolbar')" @mousedown="rememberRange">
|
|
10433
|
+
<div class="djm-rich-editor-group" v-if="has('history')">
|
|
10434
|
+
<button
|
|
10435
|
+
class="djm-rich-editor-btn"
|
|
10436
|
+
type="button"
|
|
10437
|
+
:title="t('richEditor.undo')"
|
|
10438
|
+
:aria-label="t('richEditor.undo')"
|
|
10439
|
+
:disabled="disabled || sourceMode"
|
|
10440
|
+
@mousedown.prevent
|
|
10441
|
+
@click="exec('undo')"
|
|
10442
|
+
><Icon name="undo" :size="13" /></button>
|
|
10443
|
+
<button
|
|
10444
|
+
class="djm-rich-editor-btn"
|
|
10445
|
+
type="button"
|
|
10446
|
+
:title="t('richEditor.redo')"
|
|
10447
|
+
:aria-label="t('richEditor.redo')"
|
|
10448
|
+
:disabled="disabled || sourceMode"
|
|
10449
|
+
@mousedown.prevent
|
|
10450
|
+
@click="exec('redo')"
|
|
10451
|
+
><Icon name="redo" :size="13" /></button>
|
|
10452
|
+
</div>
|
|
10453
|
+
|
|
10454
|
+
<div class="djm-rich-editor-group" v-if="has('format')">
|
|
10455
|
+
<select
|
|
10456
|
+
class="djm-rich-editor-select"
|
|
10457
|
+
:value="formats.block"
|
|
10458
|
+
:aria-label="t('richEditor.block')"
|
|
10459
|
+
:disabled="disabled || sourceMode"
|
|
10460
|
+
@change="setBlock($event.target.value)"
|
|
10461
|
+
>
|
|
10462
|
+
<option v-for="item in blocks" :key="item.value" :value="item.value">{{ t('richEditor.' + item.label) }}</option>
|
|
10463
|
+
</select>
|
|
10464
|
+
<select
|
|
10465
|
+
class="djm-rich-editor-select djm-rich-editor-select-size"
|
|
10466
|
+
:value="fontSize"
|
|
10467
|
+
:aria-label="t('richEditor.fontSize')"
|
|
10468
|
+
:disabled="disabled || sourceMode"
|
|
10469
|
+
@change="setFontSize($event.target.value)"
|
|
10470
|
+
>
|
|
10471
|
+
<option v-for="item in sizes" :key="item.value" :value="item.value">{{ t('richEditor.' + item.label) }}</option>
|
|
10472
|
+
</select>
|
|
10473
|
+
</div>
|
|
10474
|
+
|
|
10475
|
+
<div class="djm-rich-editor-group" v-if="has('inline')">
|
|
9690
10476
|
<button
|
|
9691
10477
|
class="djm-rich-editor-btn djm-rich-editor-btn-bold"
|
|
9692
10478
|
type="button"
|
|
9693
10479
|
:title="t('richEditor.bold')"
|
|
9694
10480
|
:aria-label="t('richEditor.bold')"
|
|
9695
10481
|
:aria-pressed="String(formats.bold)"
|
|
9696
|
-
:disabled="disabled"
|
|
10482
|
+
:disabled="disabled || sourceMode"
|
|
9697
10483
|
@mousedown.prevent
|
|
9698
10484
|
@click="exec('bold')"
|
|
9699
10485
|
>B</button>
|
|
@@ -9703,7 +10489,7 @@ var rich_editor_default = {
|
|
|
9703
10489
|
:title="t('richEditor.italic')"
|
|
9704
10490
|
:aria-label="t('richEditor.italic')"
|
|
9705
10491
|
:aria-pressed="String(formats.italic)"
|
|
9706
|
-
:disabled="disabled"
|
|
10492
|
+
:disabled="disabled || sourceMode"
|
|
9707
10493
|
@mousedown.prevent
|
|
9708
10494
|
@click="exec('italic')"
|
|
9709
10495
|
>I</button>
|
|
@@ -9713,7 +10499,7 @@ var rich_editor_default = {
|
|
|
9713
10499
|
:title="t('richEditor.underline')"
|
|
9714
10500
|
:aria-label="t('richEditor.underline')"
|
|
9715
10501
|
:aria-pressed="String(formats.underline)"
|
|
9716
|
-
:disabled="disabled"
|
|
10502
|
+
:disabled="disabled || sourceMode"
|
|
9717
10503
|
@mousedown.prevent
|
|
9718
10504
|
@click="exec('underline')"
|
|
9719
10505
|
>U</button>
|
|
@@ -9723,46 +10509,130 @@ var rich_editor_default = {
|
|
|
9723
10509
|
:title="t('richEditor.strike')"
|
|
9724
10510
|
:aria-label="t('richEditor.strike')"
|
|
9725
10511
|
:aria-pressed="String(formats.strike)"
|
|
9726
|
-
:disabled="disabled"
|
|
10512
|
+
:disabled="disabled || sourceMode"
|
|
9727
10513
|
@mousedown.prevent
|
|
9728
10514
|
@click="exec('strikeThrough')"
|
|
9729
10515
|
>S</button>
|
|
10516
|
+
<button
|
|
10517
|
+
class="djm-rich-editor-btn"
|
|
10518
|
+
type="button"
|
|
10519
|
+
:title="t('richEditor.inlineCode')"
|
|
10520
|
+
:aria-label="t('richEditor.inlineCode')"
|
|
10521
|
+
:aria-pressed="String(formats.code)"
|
|
10522
|
+
:disabled="disabled || sourceMode"
|
|
10523
|
+
@mousedown.prevent
|
|
10524
|
+
@click="toggleInlineCode"
|
|
10525
|
+
><Icon name="code" :size="13" /></button>
|
|
9730
10526
|
</div>
|
|
9731
10527
|
|
|
9732
|
-
<div class="djm-rich-editor-group">
|
|
9733
|
-
<button
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
10528
|
+
<div class="djm-rich-editor-group djm-rich-editor-color" v-if="has('color')">
|
|
10529
|
+
<button
|
|
10530
|
+
class="djm-rich-editor-btn"
|
|
10531
|
+
type="button"
|
|
10532
|
+
:title="t('richEditor.textColor')"
|
|
10533
|
+
:aria-label="t('richEditor.textColor')"
|
|
10534
|
+
:aria-expanded="String(panel === 'text')"
|
|
10535
|
+
:disabled="disabled || sourceMode"
|
|
10536
|
+
@mousedown.prevent
|
|
10537
|
+
@click.stop="togglePanel('text')"
|
|
10538
|
+
>
|
|
10539
|
+
<span class="djm-rich-editor-letter" :style="{ borderBottomColor: textColor }">A</span>
|
|
9743
10540
|
</button>
|
|
9744
|
-
<button
|
|
9745
|
-
|
|
10541
|
+
<button
|
|
10542
|
+
class="djm-rich-editor-btn"
|
|
10543
|
+
type="button"
|
|
10544
|
+
:title="t('richEditor.bgColor')"
|
|
10545
|
+
:aria-label="t('richEditor.bgColor')"
|
|
10546
|
+
:aria-expanded="String(panel === 'bg')"
|
|
10547
|
+
:disabled="disabled || sourceMode"
|
|
10548
|
+
@mousedown.prevent
|
|
10549
|
+
@click.stop="togglePanel('bg')"
|
|
10550
|
+
>
|
|
10551
|
+
<span class="djm-rich-editor-letter djm-rich-editor-letter-bg" :style="{ background: bgColor }">A</span>
|
|
9746
10552
|
</button>
|
|
10553
|
+
<div v-if="panel === 'text' || panel === 'bg'" class="djm-rich-editor-panel" role="group" :aria-label="t('richEditor.textColor')">
|
|
10554
|
+
<button
|
|
10555
|
+
v-for="color in colors"
|
|
10556
|
+
:key="color"
|
|
10557
|
+
class="djm-rich-editor-swatch"
|
|
10558
|
+
type="button"
|
|
10559
|
+
:title="color"
|
|
10560
|
+
:aria-label="color"
|
|
10561
|
+
:style="{ background: color }"
|
|
10562
|
+
@mousedown.prevent
|
|
10563
|
+
@click="applyColor(panel, color)"
|
|
10564
|
+
></button>
|
|
10565
|
+
</div>
|
|
9747
10566
|
</div>
|
|
9748
10567
|
|
|
9749
|
-
<div class="djm-rich-editor-group">
|
|
9750
|
-
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.
|
|
9751
|
-
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.
|
|
9752
|
-
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.
|
|
10568
|
+
<div class="djm-rich-editor-group" v-if="has('align')">
|
|
10569
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.alignLeft')" :aria-label="t('richEditor.alignLeft')" :aria-pressed="String(formats.align === 'left')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('justifyLeft')"><Icon name="align-left" :size="13" /></button>
|
|
10570
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.alignCenter')" :aria-label="t('richEditor.alignCenter')" :aria-pressed="String(formats.align === 'center')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('justifyCenter')"><Icon name="align-center" :size="13" /></button>
|
|
10571
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.alignRight')" :aria-label="t('richEditor.alignRight')" :aria-pressed="String(formats.align === 'right')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('justifyRight')"><Icon name="align-right" :size="13" /></button>
|
|
10572
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.alignJustify')" :aria-label="t('richEditor.alignJustify')" :aria-pressed="String(formats.align === 'justify')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('justifyFull')"><Icon name="align-justify" :size="13" /></button>
|
|
9753
10573
|
</div>
|
|
9754
10574
|
|
|
9755
|
-
<div class="djm-rich-editor-
|
|
9756
|
-
|
|
9757
|
-
class="djm-rich-editor-btn"
|
|
9758
|
-
|
|
9759
|
-
type="button"
|
|
9760
|
-
|
|
9761
|
-
|
|
9762
|
-
|
|
9763
|
-
|
|
9764
|
-
<
|
|
9765
|
-
|
|
10575
|
+
<div class="djm-rich-editor-group" v-if="has('list')">
|
|
10576
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.bulletList')" :aria-label="t('richEditor.bulletList')" :aria-pressed="String(formats.list === 'ul')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('insertUnorderedList')"><Icon name="list" :size="13" /></button>
|
|
10577
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.numberList')" :aria-label="t('richEditor.numberList')" :aria-pressed="String(formats.list === 'ol')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('insertOrderedList')"><Icon name="list-ordered" :size="13" /></button>
|
|
10578
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.outdent')" :aria-label="t('richEditor.outdent')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('outdent')"><Icon name="outdent" :size="13" /></button>
|
|
10579
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.indent')" :aria-label="t('richEditor.indent')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('indent')"><Icon name="indent" :size="13" /></button>
|
|
10580
|
+
</div>
|
|
10581
|
+
|
|
10582
|
+
<div class="djm-rich-editor-group" v-if="has('insert')">
|
|
10583
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.link')" :aria-label="t('richEditor.link')" :disabled="disabled || sourceMode" @mousedown.prevent @click="addLink"><Icon name="link" :size="13" /></button>
|
|
10584
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.unlink')" :aria-label="t('richEditor.unlink')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('unlink')"><Icon name="unlink" :size="13" /></button>
|
|
10585
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.singleImage')" :aria-label="t('richEditor.singleImage')" :disabled="disabled || sourceMode" @mousedown.prevent @click="pickImage(false)"><Icon name="image" :size="13" /></button>
|
|
10586
|
+
<button v-if="multiple" class="djm-rich-editor-btn" type="button" :title="t('richEditor.multiImage')" :aria-label="t('richEditor.multiImage')" :disabled="disabled || sourceMode" @mousedown.prevent @click="pickImage(true)"><Icon name="images" :size="13" /></button>
|
|
10587
|
+
<MediaPicker
|
|
10588
|
+
v-if="mediaLibrary.length"
|
|
10589
|
+
class="djm-rich-editor-picker"
|
|
10590
|
+
multiple
|
|
10591
|
+
accept="image"
|
|
10592
|
+
:items="mediaLibrary"
|
|
10593
|
+
:title="t('richEditor.mediaLibrary')"
|
|
10594
|
+
:disabled="disabled || sourceMode"
|
|
10595
|
+
@change="insertMedia"
|
|
10596
|
+
>
|
|
10597
|
+
<template #trigger="{ open }">
|
|
10598
|
+
<button
|
|
10599
|
+
class="djm-rich-editor-btn"
|
|
10600
|
+
type="button"
|
|
10601
|
+
:title="t('richEditor.mediaLibrary')"
|
|
10602
|
+
:aria-label="t('richEditor.mediaLibrary')"
|
|
10603
|
+
:disabled="disabled || sourceMode"
|
|
10604
|
+
@mousedown.prevent="rememberRange"
|
|
10605
|
+
@click="open"
|
|
10606
|
+
><Icon name="grid" :size="13" /></button>
|
|
10607
|
+
</template>
|
|
10608
|
+
</MediaPicker>
|
|
10609
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.hr')" :aria-label="t('richEditor.hr')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('insertHorizontalRule')">\u2014</button>
|
|
10610
|
+
<button class="djm-rich-editor-btn" type="button" :title="t('richEditor.clearFormat')" :aria-label="t('richEditor.clearFormat')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('removeFormat')"><span class="djm-rich-editor-glyph">T\xD7</span></button>
|
|
10611
|
+
</div>
|
|
10612
|
+
|
|
10613
|
+
<div class="djm-rich-editor-spacer" v-if="has('view')"></div>
|
|
10614
|
+
<div class="djm-rich-editor-group djm-rich-editor-group-end" v-if="has('view')">
|
|
10615
|
+
<button
|
|
10616
|
+
class="djm-rich-editor-btn"
|
|
10617
|
+
:class="{ 'djm-is-active': sourceMode }"
|
|
10618
|
+
type="button"
|
|
10619
|
+
:title="sourceMode ? t('richEditor.visual') : t('richEditor.source')"
|
|
10620
|
+
:aria-label="sourceMode ? t('richEditor.visual') : t('richEditor.source')"
|
|
10621
|
+
:aria-pressed="String(sourceMode)"
|
|
10622
|
+
:disabled="disabled"
|
|
10623
|
+
@click="toggleSource"
|
|
10624
|
+
><Icon name="code" :size="13" /></button>
|
|
10625
|
+
<button
|
|
10626
|
+
class="djm-rich-editor-btn"
|
|
10627
|
+
:class="{ 'djm-is-active': fullscreen }"
|
|
10628
|
+
type="button"
|
|
10629
|
+
:title="fullscreen ? t('richEditor.exitFullscreen') : t('richEditor.fullscreen')"
|
|
10630
|
+
:aria-label="fullscreen ? t('richEditor.exitFullscreen') : t('richEditor.fullscreen')"
|
|
10631
|
+
:aria-pressed="String(fullscreen)"
|
|
10632
|
+
:disabled="disabled"
|
|
10633
|
+
@click="toggleFullscreen"
|
|
10634
|
+
><Icon :name="fullscreen ? 'minimize' : 'maximize'" :size="13" /></button>
|
|
10635
|
+
</div>
|
|
9766
10636
|
</div>
|
|
9767
10637
|
|
|
9768
10638
|
<div
|
|
@@ -9778,6 +10648,8 @@ var rich_editor_default = {
|
|
|
9778
10648
|
:style="{ minHeight: minHeight + 'px' }"
|
|
9779
10649
|
@input="syncFromDom"
|
|
9780
10650
|
@paste="onPaste"
|
|
10651
|
+
@dragover="onDragOver"
|
|
10652
|
+
@drop="onDrop"
|
|
9781
10653
|
></div>
|
|
9782
10654
|
|
|
9783
10655
|
<textarea
|
|
@@ -9790,12 +10662,27 @@ var rich_editor_default = {
|
|
|
9790
10662
|
spellcheck="false"
|
|
9791
10663
|
@input="onSourceInput"
|
|
9792
10664
|
></textarea>
|
|
10665
|
+
|
|
10666
|
+
<div v-if="showCount" class="djm-rich-editor-foot">
|
|
10667
|
+
<span v-if="uploadCount" class="djm-rich-editor-foot-item">{{ t('richEditor.uploading', { count: uploadCount }) }}</span>
|
|
10668
|
+
<span class="djm-rich-editor-foot-item">{{ t('richEditor.wordCount', { count }) }}</span>
|
|
10669
|
+
</div>
|
|
10670
|
+
|
|
10671
|
+
<input
|
|
10672
|
+
ref="fileInput"
|
|
10673
|
+
class="djm-rich-editor-file"
|
|
10674
|
+
type="file"
|
|
10675
|
+
:accept="accept"
|
|
10676
|
+
tabindex="-1"
|
|
10677
|
+
aria-hidden="true"
|
|
10678
|
+
@change="onFilesChange"
|
|
10679
|
+
/>
|
|
9793
10680
|
</div>
|
|
9794
10681
|
`
|
|
9795
10682
|
};
|
|
9796
10683
|
|
|
9797
10684
|
// src/components/floating-window/index.js
|
|
9798
|
-
var
|
|
10685
|
+
var import_vue34 = require("vue");
|
|
9799
10686
|
function clamp(value, min, max) {
|
|
9800
10687
|
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
9801
10688
|
}
|
|
@@ -9813,12 +10700,12 @@ var floating_window_default = {
|
|
|
9813
10700
|
},
|
|
9814
10701
|
emits: ["close", "focus"],
|
|
9815
10702
|
setup(props, { emit }) {
|
|
9816
|
-
const root = (0,
|
|
9817
|
-
const pos = (0,
|
|
9818
|
-
const size = (0,
|
|
9819
|
-
const minimized = (0,
|
|
9820
|
-
const maximized = (0,
|
|
9821
|
-
const saved = (0,
|
|
10703
|
+
const root = (0, import_vue34.ref)(null);
|
|
10704
|
+
const pos = (0, import_vue34.ref)({ x: props.initialX, y: props.initialY });
|
|
10705
|
+
const size = (0, import_vue34.ref)({ w: props.width, h: props.height });
|
|
10706
|
+
const minimized = (0, import_vue34.ref)(false);
|
|
10707
|
+
const maximized = (0, import_vue34.ref)(false);
|
|
10708
|
+
const saved = (0, import_vue34.ref)(null);
|
|
9822
10709
|
let drag = null;
|
|
9823
10710
|
let resize = null;
|
|
9824
10711
|
function stage() {
|
|
@@ -9906,7 +10793,7 @@ var floating_window_default = {
|
|
|
9906
10793
|
}
|
|
9907
10794
|
emit("focus");
|
|
9908
10795
|
}
|
|
9909
|
-
(0,
|
|
10796
|
+
(0, import_vue34.onBeforeUnmount)(() => {
|
|
9910
10797
|
window.removeEventListener("pointermove", onDrag);
|
|
9911
10798
|
window.removeEventListener("pointerup", endDrag);
|
|
9912
10799
|
window.removeEventListener("pointermove", onResize);
|
|
@@ -9954,7 +10841,7 @@ var floating_window_default = {
|
|
|
9954
10841
|
};
|
|
9955
10842
|
|
|
9956
10843
|
// src/components/upload/index.js
|
|
9957
|
-
var
|
|
10844
|
+
var import_vue35 = require("vue");
|
|
9958
10845
|
var uidSeed6 = 0;
|
|
9959
10846
|
function extension(name) {
|
|
9960
10847
|
const index = name.lastIndexOf(".");
|
|
@@ -10004,11 +10891,11 @@ var upload_default = {
|
|
|
10004
10891
|
},
|
|
10005
10892
|
emits: ["update:modelValue", "change", "success", "error", "remove", "exceed"],
|
|
10006
10893
|
setup(props, { emit }) {
|
|
10007
|
-
const files = (0,
|
|
10008
|
-
const dragActive = (0,
|
|
10009
|
-
const inputRef = (0,
|
|
10894
|
+
const files = (0, import_vue35.ref)([]);
|
|
10895
|
+
const dragActive = (0, import_vue35.ref)(false);
|
|
10896
|
+
const inputRef = (0, import_vue35.ref)(null);
|
|
10010
10897
|
const tasks = /* @__PURE__ */ new Map();
|
|
10011
|
-
(0,
|
|
10898
|
+
(0, import_vue35.watch)(
|
|
10012
10899
|
() => props.modelValue,
|
|
10013
10900
|
(list) => {
|
|
10014
10901
|
const next = list || [];
|
|
@@ -10102,7 +10989,7 @@ var upload_default = {
|
|
|
10102
10989
|
if (pass === false) continue;
|
|
10103
10990
|
}
|
|
10104
10991
|
uidSeed6 += 1;
|
|
10105
|
-
const item = (0,
|
|
10992
|
+
const item = (0, import_vue35.reactive)({
|
|
10106
10993
|
uid: uidSeed6,
|
|
10107
10994
|
name: raw.name,
|
|
10108
10995
|
size: raw.size,
|
|
@@ -10162,7 +11049,7 @@ var upload_default = {
|
|
|
10162
11049
|
files.value = [];
|
|
10163
11050
|
emitList();
|
|
10164
11051
|
}
|
|
10165
|
-
(0,
|
|
11052
|
+
(0, import_vue35.onBeforeUnmount)(() => {
|
|
10166
11053
|
files.value.forEach((item) => {
|
|
10167
11054
|
if (item.url) URL.revokeObjectURL(item.url);
|
|
10168
11055
|
});
|
|
@@ -10310,7 +11197,7 @@ var upload_default = {
|
|
|
10310
11197
|
};
|
|
10311
11198
|
|
|
10312
11199
|
// src/components/tree/index.js
|
|
10313
|
-
var
|
|
11200
|
+
var import_vue36 = require("vue");
|
|
10314
11201
|
var tree_default = {
|
|
10315
11202
|
name: "DjmTree",
|
|
10316
11203
|
components: { Icon: icon_default },
|
|
@@ -10342,17 +11229,17 @@ var tree_default = {
|
|
|
10342
11229
|
},
|
|
10343
11230
|
emits: ["update:checked", "update:expanded", "node-click", "check", "node-drop", "load-error"],
|
|
10344
11231
|
setup(props, { emit }) {
|
|
10345
|
-
const lazyChildren = (0,
|
|
10346
|
-
const loadingKeys = (0,
|
|
10347
|
-
const innerExpanded = (0,
|
|
10348
|
-
const innerChecked = (0,
|
|
10349
|
-
(0,
|
|
11232
|
+
const lazyChildren = (0, import_vue36.ref)({});
|
|
11233
|
+
const loadingKeys = (0, import_vue36.ref)([]);
|
|
11234
|
+
const innerExpanded = (0, import_vue36.ref)([...props.expanded]);
|
|
11235
|
+
const innerChecked = (0, import_vue36.ref)([...props.checked]);
|
|
11236
|
+
(0, import_vue36.watch)(
|
|
10350
11237
|
() => props.expanded,
|
|
10351
11238
|
(value) => {
|
|
10352
11239
|
if (Array.isArray(value)) innerExpanded.value = value;
|
|
10353
11240
|
}
|
|
10354
11241
|
);
|
|
10355
|
-
(0,
|
|
11242
|
+
(0, import_vue36.watch)(
|
|
10356
11243
|
() => props.checked,
|
|
10357
11244
|
(value) => {
|
|
10358
11245
|
if (Array.isArray(value)) innerChecked.value = value;
|
|
@@ -10390,7 +11277,7 @@ var tree_default = {
|
|
|
10390
11277
|
});
|
|
10391
11278
|
return out;
|
|
10392
11279
|
}
|
|
10393
|
-
(0,
|
|
11280
|
+
(0, import_vue36.watch)(
|
|
10394
11281
|
() => props.data,
|
|
10395
11282
|
() => {
|
|
10396
11283
|
if (props.defaultExpandAll) innerExpanded.value = collectExpandable(props.data);
|
|
@@ -10407,7 +11294,7 @@ var tree_default = {
|
|
|
10407
11294
|
const children = childrenOf(node);
|
|
10408
11295
|
return Boolean(children && children.some((child) => matchSubtree(child)));
|
|
10409
11296
|
}
|
|
10410
|
-
const rows = (0,
|
|
11297
|
+
const rows = (0, import_vue36.computed)(() => {
|
|
10411
11298
|
const result = [];
|
|
10412
11299
|
const walk = (nodes, level) => {
|
|
10413
11300
|
nodes.forEach((node) => {
|
|
@@ -10478,8 +11365,8 @@ var tree_default = {
|
|
|
10478
11365
|
function isActive(node) {
|
|
10479
11366
|
return props.activeKey !== "" && node[props.nodeKey] === props.activeKey;
|
|
10480
11367
|
}
|
|
10481
|
-
const rootEl = (0,
|
|
10482
|
-
const focusIndex = (0,
|
|
11368
|
+
const rootEl = (0, import_vue36.ref)(null);
|
|
11369
|
+
const focusIndex = (0, import_vue36.ref)(-1);
|
|
10483
11370
|
function tabIndexOf(index) {
|
|
10484
11371
|
return (focusIndex.value === -1 ? 0 : focusIndex.value) === index ? 0 : -1;
|
|
10485
11372
|
}
|
|
@@ -10536,9 +11423,9 @@ var tree_default = {
|
|
|
10536
11423
|
function rowClassOf(node, level) {
|
|
10537
11424
|
return typeof props.rowClass === "function" ? props.rowClass(node, level) : props.rowClass;
|
|
10538
11425
|
}
|
|
10539
|
-
const dragKey = (0,
|
|
10540
|
-
const dropKey = (0,
|
|
10541
|
-
const dropPosition = (0,
|
|
11426
|
+
const dragKey = (0, import_vue36.ref)("");
|
|
11427
|
+
const dropKey = (0, import_vue36.ref)("");
|
|
11428
|
+
const dropPosition = (0, import_vue36.ref)("");
|
|
10542
11429
|
function findNodeByKey(key, nodes = props.data) {
|
|
10543
11430
|
for (const node of nodes) {
|
|
10544
11431
|
if (node[props.nodeKey] === key) return node;
|
|
@@ -10650,7 +11537,7 @@ var tree_default = {
|
|
|
10650
11537
|
onDrop,
|
|
10651
11538
|
onDragEnd,
|
|
10652
11539
|
labelOf,
|
|
10653
|
-
emptyLabel: (0,
|
|
11540
|
+
emptyLabel: (0, import_vue36.computed)(() => props.emptyText || t("tree.empty")),
|
|
10654
11541
|
t
|
|
10655
11542
|
};
|
|
10656
11543
|
},
|
|
@@ -10719,7 +11606,7 @@ var tree_default = {
|
|
|
10719
11606
|
};
|
|
10720
11607
|
|
|
10721
11608
|
// src/components/editable-table/index.js
|
|
10722
|
-
var
|
|
11609
|
+
var import_vue37 = require("vue");
|
|
10723
11610
|
var ACTIONS_KEY = "__editable_actions";
|
|
10724
11611
|
function isEmpty(value) {
|
|
10725
11612
|
if (value === "" || value === null || value === void 0) return true;
|
|
@@ -10742,13 +11629,13 @@ var editable_table_default = {
|
|
|
10742
11629
|
},
|
|
10743
11630
|
emits: ["edit", "save", "cancel"],
|
|
10744
11631
|
setup(props, { emit }) {
|
|
10745
|
-
const slots = (0,
|
|
10746
|
-
const editingKey = (0,
|
|
10747
|
-
const draft = (0,
|
|
10748
|
-
const errors = (0,
|
|
10749
|
-
const tableRef = (0,
|
|
10750
|
-
const editableColumns = (0,
|
|
10751
|
-
const renderColumns = (0,
|
|
11632
|
+
const slots = (0, import_vue37.useSlots)();
|
|
11633
|
+
const editingKey = (0, import_vue37.ref)("");
|
|
11634
|
+
const draft = (0, import_vue37.reactive)({});
|
|
11635
|
+
const errors = (0, import_vue37.reactive)({});
|
|
11636
|
+
const tableRef = (0, import_vue37.ref)(null);
|
|
11637
|
+
const editableColumns = (0, import_vue37.computed)(() => props.columns.filter((column) => column.editor));
|
|
11638
|
+
const renderColumns = (0, import_vue37.computed)(() => {
|
|
10752
11639
|
if (!props.showActions) return props.columns;
|
|
10753
11640
|
return props.columns.concat({
|
|
10754
11641
|
key: ACTIONS_KEY,
|
|
@@ -10760,7 +11647,7 @@ var editable_table_default = {
|
|
|
10760
11647
|
exportable: false
|
|
10761
11648
|
});
|
|
10762
11649
|
});
|
|
10763
|
-
const forwardedSlotNames = (0,
|
|
11650
|
+
const forwardedSlotNames = (0, import_vue37.computed)(() => {
|
|
10764
11651
|
const taken = new Set(editableColumns.value.map((column) => "cell-" + column.key));
|
|
10765
11652
|
taken.add("cell-" + ACTIONS_KEY);
|
|
10766
11653
|
return Object.keys(slots).filter((name) => !taken.has(name));
|
|
@@ -10835,7 +11722,7 @@ var editable_table_default = {
|
|
|
10835
11722
|
return false;
|
|
10836
11723
|
}
|
|
10837
11724
|
if (!validate()) {
|
|
10838
|
-
(0,
|
|
11725
|
+
(0, import_vue37.nextTick)(() => {
|
|
10839
11726
|
const el = tableRef.value && tableRef.value.$el ? tableRef.value.$el.querySelector(".djm-cell-error") : null;
|
|
10840
11727
|
if (el) el.scrollIntoView({ block: "nearest" });
|
|
10841
11728
|
});
|
|
@@ -10855,7 +11742,7 @@ var editable_table_default = {
|
|
|
10855
11742
|
clearErrors();
|
|
10856
11743
|
return true;
|
|
10857
11744
|
}
|
|
10858
|
-
(0,
|
|
11745
|
+
(0, import_vue37.watch)(
|
|
10859
11746
|
() => props.rows,
|
|
10860
11747
|
() => {
|
|
10861
11748
|
if (editingKey.value && !findRow(editingKey.value)) {
|
|
@@ -10991,8 +11878,8 @@ var descriptions_default = {
|
|
|
10991
11878
|
};
|
|
10992
11879
|
|
|
10993
11880
|
// src/components/message/index.js
|
|
10994
|
-
var
|
|
10995
|
-
var djmMessages = (0,
|
|
11881
|
+
var import_vue38 = require("vue");
|
|
11882
|
+
var djmMessages = (0, import_vue38.reactive)([]);
|
|
10996
11883
|
var seq = 0;
|
|
10997
11884
|
function close(id) {
|
|
10998
11885
|
const index = djmMessages.findIndex((item) => item.id === id);
|
|
@@ -11037,7 +11924,7 @@ var message_default = {
|
|
|
11037
11924
|
};
|
|
11038
11925
|
|
|
11039
11926
|
// src/components/org-picker/index.js
|
|
11040
|
-
var
|
|
11927
|
+
var import_vue39 = require("vue");
|
|
11041
11928
|
var org_picker_default = {
|
|
11042
11929
|
name: "DjmOrgPicker",
|
|
11043
11930
|
components: { DjmIcon: icon_default },
|
|
@@ -11056,13 +11943,13 @@ var org_picker_default = {
|
|
|
11056
11943
|
},
|
|
11057
11944
|
emits: ["update:modelValue", "change", "visible-change"],
|
|
11058
11945
|
setup(props, { emit }) {
|
|
11059
|
-
const open = (0,
|
|
11060
|
-
const root = (0,
|
|
11061
|
-
const searchRef = (0,
|
|
11062
|
-
const keyword = (0,
|
|
11063
|
-
const activeDept = (0,
|
|
11064
|
-
const temp = (0,
|
|
11065
|
-
const expandedIds = (0,
|
|
11946
|
+
const open = (0, import_vue39.ref)(false);
|
|
11947
|
+
const root = (0, import_vue39.ref)(null);
|
|
11948
|
+
const searchRef = (0, import_vue39.ref)(null);
|
|
11949
|
+
const keyword = (0, import_vue39.ref)("");
|
|
11950
|
+
const activeDept = (0, import_vue39.ref)("");
|
|
11951
|
+
const temp = (0, import_vue39.ref)([]);
|
|
11952
|
+
const expandedIds = (0, import_vue39.ref)(/* @__PURE__ */ new Set());
|
|
11066
11953
|
let detachPanel = null;
|
|
11067
11954
|
function collectDeptIds(nodes, out = []) {
|
|
11068
11955
|
nodes.forEach((node) => {
|
|
@@ -11092,22 +11979,22 @@ var org_picker_default = {
|
|
|
11092
11979
|
walk([root2]);
|
|
11093
11980
|
return ids;
|
|
11094
11981
|
}
|
|
11095
|
-
const staffMap = (0,
|
|
11982
|
+
const staffMap = (0, import_vue39.computed)(() => {
|
|
11096
11983
|
const map = /* @__PURE__ */ new Map();
|
|
11097
11984
|
props.staff.forEach((item) => map.set(item.id, item));
|
|
11098
11985
|
return map;
|
|
11099
11986
|
});
|
|
11100
|
-
const appliedStaff = (0,
|
|
11987
|
+
const appliedStaff = (0, import_vue39.computed)(
|
|
11101
11988
|
() => props.modelValue.map((id) => staffMap.value.get(id)).filter(Boolean)
|
|
11102
11989
|
);
|
|
11103
|
-
const visibleTags = (0,
|
|
11990
|
+
const visibleTags = (0, import_vue39.computed)(() => {
|
|
11104
11991
|
if (props.maxTagCount <= 0) return appliedStaff.value;
|
|
11105
11992
|
return appliedStaff.value.slice(0, props.maxTagCount);
|
|
11106
11993
|
});
|
|
11107
|
-
const restTagCount = (0,
|
|
11994
|
+
const restTagCount = (0, import_vue39.computed)(
|
|
11108
11995
|
() => Math.max(0, appliedStaff.value.length - visibleTags.value.length)
|
|
11109
11996
|
);
|
|
11110
|
-
const visibleStaff = (0,
|
|
11997
|
+
const visibleStaff = (0, import_vue39.computed)(() => {
|
|
11111
11998
|
const key = keyword.value.trim().toLowerCase();
|
|
11112
11999
|
if (key) {
|
|
11113
12000
|
return props.staff.filter(
|
|
@@ -11118,7 +12005,7 @@ var org_picker_default = {
|
|
|
11118
12005
|
const scope = deptScope(activeDept.value);
|
|
11119
12006
|
return props.staff.filter((item) => scope.has(item.deptId));
|
|
11120
12007
|
});
|
|
11121
|
-
const deptRows = (0,
|
|
12008
|
+
const deptRows = (0, import_vue39.computed)(() => {
|
|
11122
12009
|
const rows = [];
|
|
11123
12010
|
const walk = (nodes, depth) => {
|
|
11124
12011
|
nodes.forEach((node) => {
|
|
@@ -11130,11 +12017,11 @@ var org_picker_default = {
|
|
|
11130
12017
|
walk(props.departments, 0);
|
|
11131
12018
|
return rows;
|
|
11132
12019
|
});
|
|
11133
|
-
const selectedCount = (0,
|
|
11134
|
-
const placeholderText = (0,
|
|
11135
|
-
const emptyLabel = (0,
|
|
11136
|
-
const panel = (0,
|
|
11137
|
-
const panelStyle = (0,
|
|
12020
|
+
const selectedCount = (0, import_vue39.computed)(() => temp.value.length);
|
|
12021
|
+
const placeholderText = (0, import_vue39.computed)(() => props.placeholder || t("orgPicker.placeholder"));
|
|
12022
|
+
const emptyLabel = (0, import_vue39.computed)(() => props.emptyText || t("orgPicker.empty"));
|
|
12023
|
+
const panel = (0, import_vue39.ref)(null);
|
|
12024
|
+
const panelStyle = (0, import_vue39.ref)({ ...PANEL_HIDDEN_STYLE });
|
|
11138
12025
|
const PANEL_HEIGHT = 342;
|
|
11139
12026
|
function updatePosition() {
|
|
11140
12027
|
if (!open.value || !root.value) return;
|
|
@@ -11151,7 +12038,7 @@ var org_picker_default = {
|
|
|
11151
12038
|
expandedIds.value = new Set(collectDeptIds(props.departments));
|
|
11152
12039
|
}
|
|
11153
12040
|
expandAll();
|
|
11154
|
-
(0,
|
|
12041
|
+
(0, import_vue39.watch)(() => props.departments, () => {
|
|
11155
12042
|
expandedIds.value = /* @__PURE__ */ new Set([...expandedIds.value, ...collectDeptIds(props.departments)]);
|
|
11156
12043
|
});
|
|
11157
12044
|
function initialOf(item) {
|
|
@@ -11240,7 +12127,7 @@ var org_picker_default = {
|
|
|
11240
12127
|
function clearTemp() {
|
|
11241
12128
|
temp.value = [];
|
|
11242
12129
|
}
|
|
11243
|
-
(0,
|
|
12130
|
+
(0, import_vue39.onBeforeUnmount)(() => {
|
|
11244
12131
|
if (detachPanel) {
|
|
11245
12132
|
detachPanel();
|
|
11246
12133
|
detachPanel = null;
|
|
@@ -11426,7 +12313,7 @@ var org_picker_default = {
|
|
|
11426
12313
|
};
|
|
11427
12314
|
|
|
11428
12315
|
// src/components/schema-form/index.js
|
|
11429
|
-
var
|
|
12316
|
+
var import_vue40 = require("vue");
|
|
11430
12317
|
var CONTROL_MAP = {
|
|
11431
12318
|
input: input_default,
|
|
11432
12319
|
number: input_number_default,
|
|
@@ -11462,26 +12349,26 @@ var schema_form_default = {
|
|
|
11462
12349
|
},
|
|
11463
12350
|
emits: ["update:modelValue", "change"],
|
|
11464
12351
|
setup(props, { emit }) {
|
|
11465
|
-
const innerForm = (0,
|
|
11466
|
-
const model = (0,
|
|
11467
|
-
(0,
|
|
12352
|
+
const innerForm = (0, import_vue40.ref)(null);
|
|
12353
|
+
const model = (0, import_vue40.reactive)({ ...props.modelValue });
|
|
12354
|
+
(0, import_vue40.watch)(() => props.fields, (fields) => {
|
|
11468
12355
|
fields.forEach((field) => {
|
|
11469
12356
|
if (model[field.key] === void 0 && field.default !== void 0) {
|
|
11470
12357
|
model[field.key] = typeof field.default === "function" ? field.default() : field.default;
|
|
11471
12358
|
}
|
|
11472
12359
|
});
|
|
11473
12360
|
}, { immediate: true, deep: true });
|
|
11474
|
-
(0,
|
|
12361
|
+
(0, import_vue40.watch)(() => props.modelValue, (value) => {
|
|
11475
12362
|
if (!value) return;
|
|
11476
12363
|
Object.keys(value).forEach((key) => {
|
|
11477
12364
|
if (model[key] !== value[key]) model[key] = value[key];
|
|
11478
12365
|
});
|
|
11479
12366
|
}, { deep: true });
|
|
11480
|
-
(0,
|
|
12367
|
+
(0, import_vue40.watch)(model, () => {
|
|
11481
12368
|
emit("update:modelValue", { ...model });
|
|
11482
12369
|
emit("change", { ...model });
|
|
11483
12370
|
}, { deep: true });
|
|
11484
|
-
const formRules = (0,
|
|
12371
|
+
const formRules = (0, import_vue40.computed)(() => {
|
|
11485
12372
|
const merged = { ...props.rules };
|
|
11486
12373
|
props.fields.forEach((field) => {
|
|
11487
12374
|
if (!field.required && !field.rules) return;
|
|
@@ -11494,7 +12381,7 @@ var schema_form_default = {
|
|
|
11494
12381
|
});
|
|
11495
12382
|
return merged;
|
|
11496
12383
|
});
|
|
11497
|
-
const visibleFields = (0,
|
|
12384
|
+
const visibleFields = (0, import_vue40.computed)(
|
|
11498
12385
|
() => props.fields.filter((field) => {
|
|
11499
12386
|
if (typeof field.visibleWhen !== "function") return true;
|
|
11500
12387
|
return Boolean(field.visibleWhen(model));
|
|
@@ -11688,7 +12575,7 @@ var approval_flow_default = {
|
|
|
11688
12575
|
};
|
|
11689
12576
|
|
|
11690
12577
|
// src/components/query-filter/index.js
|
|
11691
|
-
var
|
|
12578
|
+
var import_vue41 = require("vue");
|
|
11692
12579
|
var CONTROL_MAP2 = {
|
|
11693
12580
|
input: input_default,
|
|
11694
12581
|
number: input_number_default,
|
|
@@ -11713,26 +12600,26 @@ var query_filter_default = {
|
|
|
11713
12600
|
},
|
|
11714
12601
|
emits: ["update:modelValue", "search", "reset"],
|
|
11715
12602
|
setup(props, { emit }) {
|
|
11716
|
-
const expanded = (0,
|
|
11717
|
-
const model = (0,
|
|
11718
|
-
(0,
|
|
12603
|
+
const expanded = (0, import_vue41.ref)(false);
|
|
12604
|
+
const model = (0, import_vue41.reactive)({ ...props.modelValue });
|
|
12605
|
+
(0, import_vue41.watch)(() => props.fields, (fields) => {
|
|
11719
12606
|
fields.forEach((field) => {
|
|
11720
12607
|
if (model[field.key] === void 0 && field.default !== void 0) {
|
|
11721
12608
|
model[field.key] = typeof field.default === "function" ? field.default() : field.default;
|
|
11722
12609
|
}
|
|
11723
12610
|
});
|
|
11724
12611
|
}, { immediate: true, deep: true });
|
|
11725
|
-
(0,
|
|
12612
|
+
(0, import_vue41.watch)(() => props.modelValue, (value) => {
|
|
11726
12613
|
if (!value) return;
|
|
11727
12614
|
Object.keys(value).forEach((key) => {
|
|
11728
12615
|
if (model[key] !== value[key]) model[key] = value[key];
|
|
11729
12616
|
});
|
|
11730
12617
|
}, { deep: true });
|
|
11731
|
-
(0,
|
|
12618
|
+
(0, import_vue41.watch)(model, () => {
|
|
11732
12619
|
emit("update:modelValue", { ...model });
|
|
11733
12620
|
}, { deep: true });
|
|
11734
|
-
const collapsible = (0,
|
|
11735
|
-
const visibleFields = (0,
|
|
12621
|
+
const collapsible = (0, import_vue41.computed)(() => props.fields.length > props.visibleCount);
|
|
12622
|
+
const visibleFields = (0, import_vue41.computed)(() => {
|
|
11736
12623
|
if (!collapsible.value || expanded.value) return props.fields;
|
|
11737
12624
|
return props.fields.slice(0, props.visibleCount);
|
|
11738
12625
|
});
|
|
@@ -11861,198 +12748,6 @@ var filter_tags_default = {
|
|
|
11861
12748
|
`
|
|
11862
12749
|
};
|
|
11863
12750
|
|
|
11864
|
-
// src/components/media-picker/index.js
|
|
11865
|
-
var import_vue41 = require("vue");
|
|
11866
|
-
var media_picker_default = {
|
|
11867
|
-
name: "DjmMediaPicker",
|
|
11868
|
-
components: { DjmModal: modal_default, DjmPagination: pagination_default, DjmIcon: icon_default },
|
|
11869
|
-
props: {
|
|
11870
|
-
modelValue: { type: [Array, String, Number], default: "" },
|
|
11871
|
-
items: { type: Array, default: () => [] },
|
|
11872
|
-
multiple: { type: Boolean, default: false },
|
|
11873
|
-
// 最多选几个,0 表示不限
|
|
11874
|
-
limit: { type: Number, default: 0 },
|
|
11875
|
-
// image 只显示图片,file 只显示非图片,空串不过滤
|
|
11876
|
-
accept: { type: String, default: "" },
|
|
11877
|
-
title: { type: String, default: "" },
|
|
11878
|
-
triggerText: { type: String, default: "" },
|
|
11879
|
-
pageSize: { type: Number, default: 12 },
|
|
11880
|
-
disabled: { type: Boolean, default: false }
|
|
11881
|
-
},
|
|
11882
|
-
emits: ["update:modelValue", "change"],
|
|
11883
|
-
setup(props, { emit }) {
|
|
11884
|
-
const open = (0, import_vue41.ref)(false);
|
|
11885
|
-
const keyword = (0, import_vue41.ref)("");
|
|
11886
|
-
const page = (0, import_vue41.ref)(1);
|
|
11887
|
-
const temp = (0, import_vue41.ref)([]);
|
|
11888
|
-
const selectedIds = (0, import_vue41.computed)(() => {
|
|
11889
|
-
if (props.multiple) return Array.isArray(props.modelValue) ? props.modelValue : [];
|
|
11890
|
-
if (props.modelValue === "" || props.modelValue === null || props.modelValue === void 0) return [];
|
|
11891
|
-
return [props.modelValue];
|
|
11892
|
-
});
|
|
11893
|
-
function isImage(item) {
|
|
11894
|
-
if (item.type) return item.type === "image";
|
|
11895
|
-
return /\.(png|jpe?g|gif|webp|svg|avif)$/i.test(item.url || "");
|
|
11896
|
-
}
|
|
11897
|
-
const filtered = (0, import_vue41.computed)(() => {
|
|
11898
|
-
const key = keyword.value.trim().toLowerCase();
|
|
11899
|
-
return props.items.filter((item) => {
|
|
11900
|
-
if (props.accept === "image" && !isImage(item)) return false;
|
|
11901
|
-
if (props.accept === "file" && isImage(item)) return false;
|
|
11902
|
-
if (key && !String(item.name || "").toLowerCase().includes(key)) return false;
|
|
11903
|
-
return true;
|
|
11904
|
-
});
|
|
11905
|
-
});
|
|
11906
|
-
const paged = (0, import_vue41.computed)(() => {
|
|
11907
|
-
const start = (page.value - 1) * props.pageSize;
|
|
11908
|
-
return filtered.value.slice(start, start + props.pageSize);
|
|
11909
|
-
});
|
|
11910
|
-
(0, import_vue41.watch)(keyword, () => {
|
|
11911
|
-
page.value = 1;
|
|
11912
|
-
});
|
|
11913
|
-
(0, import_vue41.watch)(
|
|
11914
|
-
() => filtered.value.length,
|
|
11915
|
-
() => {
|
|
11916
|
-
const max = Math.max(1, Math.ceil(filtered.value.length / props.pageSize));
|
|
11917
|
-
if (page.value > max) page.value = max;
|
|
11918
|
-
}
|
|
11919
|
-
);
|
|
11920
|
-
function isChecked(id) {
|
|
11921
|
-
return temp.value.includes(id);
|
|
11922
|
-
}
|
|
11923
|
-
function atLimit() {
|
|
11924
|
-
return props.limit > 0 && temp.value.length >= props.limit;
|
|
11925
|
-
}
|
|
11926
|
-
function toggle(item) {
|
|
11927
|
-
if (props.multiple) {
|
|
11928
|
-
if (isChecked(item.id)) {
|
|
11929
|
-
temp.value = temp.value.filter((id) => id !== item.id);
|
|
11930
|
-
return;
|
|
11931
|
-
}
|
|
11932
|
-
if (atLimit()) return;
|
|
11933
|
-
temp.value = [...temp.value, item.id];
|
|
11934
|
-
return;
|
|
11935
|
-
}
|
|
11936
|
-
temp.value = [item.id];
|
|
11937
|
-
}
|
|
11938
|
-
function openPanel() {
|
|
11939
|
-
if (props.disabled) return;
|
|
11940
|
-
temp.value = [...selectedIds.value];
|
|
11941
|
-
keyword.value = "";
|
|
11942
|
-
page.value = 1;
|
|
11943
|
-
open.value = true;
|
|
11944
|
-
}
|
|
11945
|
-
function commit() {
|
|
11946
|
-
const next = props.multiple ? [...temp.value] : temp.value[0] !== void 0 ? temp.value[0] : "";
|
|
11947
|
-
emit("update:modelValue", next);
|
|
11948
|
-
emit("change", next);
|
|
11949
|
-
open.value = false;
|
|
11950
|
-
}
|
|
11951
|
-
function cancel() {
|
|
11952
|
-
temp.value = [...selectedIds.value];
|
|
11953
|
-
open.value = false;
|
|
11954
|
-
}
|
|
11955
|
-
return {
|
|
11956
|
-
open,
|
|
11957
|
-
keyword,
|
|
11958
|
-
page,
|
|
11959
|
-
temp,
|
|
11960
|
-
selectedIds,
|
|
11961
|
-
filtered,
|
|
11962
|
-
paged,
|
|
11963
|
-
isImage,
|
|
11964
|
-
isChecked,
|
|
11965
|
-
atLimit,
|
|
11966
|
-
toggle,
|
|
11967
|
-
openPanel,
|
|
11968
|
-
commit,
|
|
11969
|
-
cancel,
|
|
11970
|
-
t
|
|
11971
|
-
};
|
|
11972
|
-
},
|
|
11973
|
-
template: `
|
|
11974
|
-
<span class="djm-media-picker">
|
|
11975
|
-
<slot name="trigger" :open="openPanel" :count="selectedIds.length">
|
|
11976
|
-
<button
|
|
11977
|
-
class="djm-btn"
|
|
11978
|
-
type="button"
|
|
11979
|
-
:disabled="disabled"
|
|
11980
|
-
@click="openPanel"
|
|
11981
|
-
>{{ triggerText || t('mediaPicker.select') }}<span v-if="selectedIds.length" class="djm-media-picker-count">{{ selectedIds.length }}</span></button>
|
|
11982
|
-
</slot>
|
|
11983
|
-
|
|
11984
|
-
<DjmModal
|
|
11985
|
-
:model-value="open"
|
|
11986
|
-
:title="title || t('mediaPicker.title')"
|
|
11987
|
-
width="760px"
|
|
11988
|
-
@update:model-value="cancel"
|
|
11989
|
-
>
|
|
11990
|
-
<div class="djm-media-toolbar">
|
|
11991
|
-
<label class="djm-media-search">
|
|
11992
|
-
<DjmIcon name="search" :size="13" />
|
|
11993
|
-
<input
|
|
11994
|
-
v-model="keyword"
|
|
11995
|
-
class="djm-media-search-input"
|
|
11996
|
-
type="text"
|
|
11997
|
-
:placeholder="t('mediaPicker.search')"
|
|
11998
|
-
:aria-label="t('mediaPicker.search')"
|
|
11999
|
-
/>
|
|
12000
|
-
</label>
|
|
12001
|
-
<span class="djm-media-toolbar-slot">
|
|
12002
|
-
<slot name="toolbar"></slot>
|
|
12003
|
-
</span>
|
|
12004
|
-
</div>
|
|
12005
|
-
|
|
12006
|
-
<div class="djm-media-grid" role="listbox" :aria-multiselectable="multiple ? 'true' : 'false'">
|
|
12007
|
-
<div
|
|
12008
|
-
v-for="item in paged"
|
|
12009
|
-
:key="item.id"
|
|
12010
|
-
class="djm-media-item"
|
|
12011
|
-
:class="{
|
|
12012
|
-
'djm-is-checked': isChecked(item.id),
|
|
12013
|
-
'djm-is-disabled': multiple && atLimit() && !isChecked(item.id)
|
|
12014
|
-
}"
|
|
12015
|
-
role="option"
|
|
12016
|
-
tabindex="0"
|
|
12017
|
-
:aria-selected="String(isChecked(item.id))"
|
|
12018
|
-
@click="toggle(item)"
|
|
12019
|
-
@keydown.enter.prevent="toggle(item)"
|
|
12020
|
-
@keydown.space.prevent="toggle(item)"
|
|
12021
|
-
>
|
|
12022
|
-
<div class="djm-media-thumb">
|
|
12023
|
-
<img v-if="isImage(item)" :src="item.url" :alt="item.name" loading="lazy" />
|
|
12024
|
-
<DjmIcon v-else name="folder" :size="26" />
|
|
12025
|
-
<span v-if="isChecked(item.id)" class="djm-media-check">
|
|
12026
|
-
<DjmIcon name="check" :size="11" />
|
|
12027
|
-
</span>
|
|
12028
|
-
</div>
|
|
12029
|
-
<div class="djm-media-name" :title="item.name">{{ item.name }}</div>
|
|
12030
|
-
</div>
|
|
12031
|
-
<div v-if="!paged.length" class="djm-media-empty">{{ t('mediaPicker.empty') }}</div>
|
|
12032
|
-
</div>
|
|
12033
|
-
|
|
12034
|
-
<div class="djm-media-foot">
|
|
12035
|
-
<span class="djm-media-total">
|
|
12036
|
-
{{ t('mediaPicker.total', { total: filtered.length }) }}
|
|
12037
|
-
<em v-if="multiple && limit > 0">{{ t('mediaPicker.limit', { limit }) }}</em>
|
|
12038
|
-
</span>
|
|
12039
|
-
<DjmPagination
|
|
12040
|
-
v-if="filtered.length > pageSize"
|
|
12041
|
-
v-model:page="page"
|
|
12042
|
-
:page-size="pageSize"
|
|
12043
|
-
:total="filtered.length"
|
|
12044
|
-
/>
|
|
12045
|
-
</div>
|
|
12046
|
-
|
|
12047
|
-
<template #footer>
|
|
12048
|
-
<button class="djm-btn" type="button" @click="cancel">{{ t('common.cancel') }}</button>
|
|
12049
|
-
<button class="djm-btn djm-btn-primary" type="button" @click="commit">{{ t('common.confirm') }}</button>
|
|
12050
|
-
</template>
|
|
12051
|
-
</DjmModal>
|
|
12052
|
-
</span>
|
|
12053
|
-
`
|
|
12054
|
-
};
|
|
12055
|
-
|
|
12056
12751
|
// src/components/kanban/index.js
|
|
12057
12752
|
var import_vue42 = require("vue");
|
|
12058
12753
|
function cloneColumns(list) {
|
|
@@ -15393,7 +16088,7 @@ var components = [
|
|
|
15393
16088
|
org_chart_default,
|
|
15394
16089
|
page_tabs_default
|
|
15395
16090
|
];
|
|
15396
|
-
var version = "0.
|
|
16091
|
+
var version = "0.72.0";
|
|
15397
16092
|
function install(app, options = {}) {
|
|
15398
16093
|
if (options.locale) setLocale(options.locale);
|
|
15399
16094
|
components.forEach((component) => app.component(component.name, component));
|