@burger-editor/client 4.0.0-alpha.62 → 4.0.0-alpha.64
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/dist/client.js +595 -724
- package/dist/client.js.map +1 -1
- package/package.json +6 -6
package/dist/client.js
CHANGED
|
@@ -1266,7 +1266,6 @@ function setValue(el, name, datum, attr = 'field', filter, xssSanitize = true) {
|
|
|
1266
1266
|
if (filter) {
|
|
1267
1267
|
datum = filter(datum);
|
|
1268
1268
|
}
|
|
1269
|
-
// console.log({ name, field, fieldName, propName, datum, el: el.innerHTML });
|
|
1270
1269
|
if (!propName) {
|
|
1271
1270
|
setContent$1(el, datum, undefined, xssSanitize);
|
|
1272
1271
|
return;
|
|
@@ -1315,6 +1314,53 @@ function setValue(el, name, datum, attr = 'field', filter, xssSanitize = true) {
|
|
|
1315
1314
|
}
|
|
1316
1315
|
el.setAttribute(propName, `${datum}`);
|
|
1317
1316
|
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Set a boolean attribute on an element via its DOM property.
|
|
1319
|
+
* Empty string is treated as true (HTML boolean attribute convention).
|
|
1320
|
+
* Falls back to setAttribute if the element doesn't match any of the expected types.
|
|
1321
|
+
* @param el
|
|
1322
|
+
* @param datum
|
|
1323
|
+
* @param types
|
|
1324
|
+
* @param prop
|
|
1325
|
+
* @param emptyIsTrue
|
|
1326
|
+
* @returns true if handled
|
|
1327
|
+
*/
|
|
1328
|
+
function setBooleanAttr(el, datum, types, prop, emptyIsTrue = true) {
|
|
1329
|
+
if (types.some((T) => el instanceof T)) {
|
|
1330
|
+
// SAFETY: prop is always a hardcoded string literal from setBooleanAttrByName
|
|
1331
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1332
|
+
el[prop] = emptyIsTrue ? (datum === '' ? true : !!datum) : !!datum;
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
return false;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Set an integer attribute on an element via its DOM property.
|
|
1339
|
+
* Removes the attribute if the parsed value is NaN.
|
|
1340
|
+
* Falls back to setAttribute if the element doesn't match any of the expected types.
|
|
1341
|
+
* @param el
|
|
1342
|
+
* @param name
|
|
1343
|
+
* @param datum
|
|
1344
|
+
* @param types
|
|
1345
|
+
* @param prop
|
|
1346
|
+
* @param floor
|
|
1347
|
+
* @returns true if handled
|
|
1348
|
+
*/
|
|
1349
|
+
function setIntegerAttr(el, name, datum, types, prop, floor = false) {
|
|
1350
|
+
if (types.some((T) => el instanceof T)) {
|
|
1351
|
+
const val = toInt(datum);
|
|
1352
|
+
if (Number.isNaN(val)) {
|
|
1353
|
+
el.removeAttribute(name);
|
|
1354
|
+
}
|
|
1355
|
+
else {
|
|
1356
|
+
// SAFETY: prop is always a hardcoded string literal from setIntegerAttrByName
|
|
1357
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1358
|
+
el[prop] = floor ? Math.floor(val) : val;
|
|
1359
|
+
}
|
|
1360
|
+
return true;
|
|
1361
|
+
}
|
|
1362
|
+
return false;
|
|
1363
|
+
}
|
|
1318
1364
|
/**
|
|
1319
1365
|
*
|
|
1320
1366
|
* @param el
|
|
@@ -1374,6 +1420,25 @@ function set$1(el, prefix, name, datum, xssSanitize = true) {
|
|
|
1374
1420
|
}
|
|
1375
1421
|
return;
|
|
1376
1422
|
}
|
|
1423
|
+
if (setSpecialAttr(el, name, datum)) {
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
if (setBooleanAttrByName(el, name, datum)) {
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
if (setIntegerAttrByName(el, name, datum)) {
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
el.setAttribute(name, `${datum}`);
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Handle attributes with unique logic that doesn't fit boolean/integer patterns.
|
|
1436
|
+
* @param el
|
|
1437
|
+
* @param name
|
|
1438
|
+
* @param datum
|
|
1439
|
+
* @returns true if handled
|
|
1440
|
+
*/
|
|
1441
|
+
function setSpecialAttr(el, name, datum) {
|
|
1377
1442
|
switch (name) {
|
|
1378
1443
|
case 'contenteditable': {
|
|
1379
1444
|
switch (datum) {
|
|
@@ -1387,7 +1452,7 @@ function set$1(el, prefix, name, datum, xssSanitize = true) {
|
|
|
1387
1452
|
el.removeAttribute(name);
|
|
1388
1453
|
}
|
|
1389
1454
|
}
|
|
1390
|
-
return;
|
|
1455
|
+
return true;
|
|
1391
1456
|
}
|
|
1392
1457
|
case 'dir': {
|
|
1393
1458
|
switch (datum) {
|
|
@@ -1396,45 +1461,45 @@ function set$1(el, prefix, name, datum, xssSanitize = true) {
|
|
|
1396
1461
|
el.dir = datum;
|
|
1397
1462
|
break;
|
|
1398
1463
|
}
|
|
1399
|
-
// case 'auto':
|
|
1400
1464
|
default: {
|
|
1401
1465
|
el.removeAttribute(name);
|
|
1402
1466
|
}
|
|
1403
1467
|
}
|
|
1404
|
-
return;
|
|
1468
|
+
return true;
|
|
1405
1469
|
}
|
|
1406
1470
|
case 'draggable': {
|
|
1407
1471
|
if (typeof datum === 'boolean') {
|
|
1408
1472
|
el.draggable = datum;
|
|
1409
|
-
break;
|
|
1410
1473
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1474
|
+
else {
|
|
1475
|
+
switch (datum) {
|
|
1476
|
+
case 'true': {
|
|
1477
|
+
el.draggable = true;
|
|
1478
|
+
break;
|
|
1479
|
+
}
|
|
1480
|
+
case 'false': {
|
|
1481
|
+
el.draggable = false;
|
|
1482
|
+
break;
|
|
1483
|
+
}
|
|
1484
|
+
default: {
|
|
1485
|
+
el.removeAttribute(name);
|
|
1486
|
+
}
|
|
1423
1487
|
}
|
|
1424
1488
|
}
|
|
1425
|
-
return;
|
|
1489
|
+
return true;
|
|
1426
1490
|
}
|
|
1427
1491
|
case 'hidden': {
|
|
1428
1492
|
if (datum === 'until-found') {
|
|
1429
1493
|
el.setAttribute(name, datum);
|
|
1430
|
-
return;
|
|
1431
1494
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1495
|
+
else {
|
|
1496
|
+
el.hidden = !!datum;
|
|
1497
|
+
}
|
|
1498
|
+
return true;
|
|
1434
1499
|
}
|
|
1435
1500
|
case 'spellcheck': {
|
|
1436
1501
|
el.spellcheck = !!datum;
|
|
1437
|
-
return;
|
|
1502
|
+
return true;
|
|
1438
1503
|
}
|
|
1439
1504
|
case 'tabindex': {
|
|
1440
1505
|
let i;
|
|
@@ -1445,501 +1510,224 @@ function set$1(el, prefix, name, datum, xssSanitize = true) {
|
|
|
1445
1510
|
i = Number.parseInt(datum, 10);
|
|
1446
1511
|
}
|
|
1447
1512
|
else {
|
|
1448
|
-
i = datum;
|
|
1513
|
+
i = datum ?? -1;
|
|
1449
1514
|
}
|
|
1450
1515
|
el.tabIndex = Number.isNaN(i) ? -1 : Math.floor(i);
|
|
1451
|
-
return;
|
|
1452
|
-
}
|
|
1453
|
-
case 'async': {
|
|
1454
|
-
if (el instanceof HTMLScriptElement) {
|
|
1455
|
-
el.async = !!datum;
|
|
1456
|
-
}
|
|
1457
|
-
else {
|
|
1458
|
-
el.setAttribute(name, `${datum}`);
|
|
1459
|
-
}
|
|
1460
|
-
return;
|
|
1516
|
+
return true;
|
|
1461
1517
|
}
|
|
1462
1518
|
case 'autocomplete': {
|
|
1463
1519
|
if (el instanceof HTMLInputElement || el instanceof HTMLFormElement) {
|
|
1464
|
-
|
|
1465
|
-
el.autocomplete = datum ? `${datum}` : 'off';
|
|
1520
|
+
el.setAttribute(name, datum ? `${datum}` : 'off');
|
|
1466
1521
|
}
|
|
1467
1522
|
else {
|
|
1468
1523
|
el.setAttribute(name, `${datum}`);
|
|
1469
1524
|
}
|
|
1470
|
-
return;
|
|
1525
|
+
return true;
|
|
1471
1526
|
}
|
|
1472
|
-
case '
|
|
1473
|
-
if (el instanceof
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1527
|
+
case 'download': {
|
|
1528
|
+
if (el instanceof HTMLAnchorElement) {
|
|
1529
|
+
if (datum || datum === '') {
|
|
1530
|
+
el.download = `${datum}`;
|
|
1531
|
+
}
|
|
1532
|
+
else {
|
|
1533
|
+
el.removeAttribute(name);
|
|
1534
|
+
}
|
|
1478
1535
|
}
|
|
1479
1536
|
else {
|
|
1480
1537
|
el.setAttribute(name, `${datum}`);
|
|
1481
1538
|
}
|
|
1482
|
-
return;
|
|
1539
|
+
return true;
|
|
1483
1540
|
}
|
|
1484
|
-
case '
|
|
1541
|
+
case 'preload': {
|
|
1485
1542
|
if (el instanceof HTMLAudioElement || el instanceof HTMLVideoElement) {
|
|
1486
|
-
|
|
1543
|
+
switch (datum) {
|
|
1544
|
+
case '':
|
|
1545
|
+
case 'auto':
|
|
1546
|
+
case 'metadata': {
|
|
1547
|
+
el.preload = datum;
|
|
1548
|
+
break;
|
|
1549
|
+
}
|
|
1550
|
+
default: {
|
|
1551
|
+
el.preload = 'none';
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1487
1554
|
}
|
|
1488
1555
|
else {
|
|
1489
1556
|
el.setAttribute(name, `${datum}`);
|
|
1490
1557
|
}
|
|
1491
|
-
return;
|
|
1558
|
+
return true;
|
|
1492
1559
|
}
|
|
1493
|
-
case '
|
|
1560
|
+
case 'step': {
|
|
1494
1561
|
if (el instanceof HTMLInputElement) {
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
else {
|
|
1498
|
-
el.setAttribute(name, `${datum}`);
|
|
1499
|
-
}
|
|
1500
|
-
return;
|
|
1501
|
-
}
|
|
1502
|
-
case 'cols': {
|
|
1503
|
-
if (el instanceof HTMLTextAreaElement) {
|
|
1504
|
-
const cols = toInt(datum);
|
|
1505
|
-
if (Number.isNaN(cols)) {
|
|
1506
|
-
el.removeAttribute(name);
|
|
1562
|
+
if (datum === 'any') {
|
|
1563
|
+
el.step = datum;
|
|
1507
1564
|
}
|
|
1508
1565
|
else {
|
|
1509
|
-
|
|
1566
|
+
const step = toNum(datum);
|
|
1567
|
+
if (Number.isNaN(step)) {
|
|
1568
|
+
el.removeAttribute(name);
|
|
1569
|
+
}
|
|
1570
|
+
else {
|
|
1571
|
+
el.step = step.toString(10);
|
|
1572
|
+
}
|
|
1510
1573
|
}
|
|
1511
1574
|
}
|
|
1512
1575
|
else {
|
|
1513
1576
|
el.setAttribute(name, `${datum}`);
|
|
1514
1577
|
}
|
|
1515
|
-
return;
|
|
1578
|
+
return true;
|
|
1516
1579
|
}
|
|
1517
|
-
case '
|
|
1518
|
-
if (el instanceof
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1580
|
+
case 'target': {
|
|
1581
|
+
if (el instanceof HTMLAnchorElement ||
|
|
1582
|
+
el instanceof HTMLAreaElement ||
|
|
1583
|
+
el instanceof HTMLFormElement) {
|
|
1584
|
+
if (datum) {
|
|
1585
|
+
el.target = `${datum}`;
|
|
1522
1586
|
}
|
|
1523
1587
|
else {
|
|
1524
|
-
el.
|
|
1588
|
+
el.removeAttribute(name);
|
|
1525
1589
|
}
|
|
1526
1590
|
}
|
|
1527
1591
|
else {
|
|
1528
1592
|
el.setAttribute(name, `${datum}`);
|
|
1529
1593
|
}
|
|
1530
|
-
return;
|
|
1594
|
+
return true;
|
|
1595
|
+
}
|
|
1596
|
+
default: {
|
|
1597
|
+
return false;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* Handle boolean HTML attributes via their DOM properties.
|
|
1603
|
+
* @param el
|
|
1604
|
+
* @param name
|
|
1605
|
+
* @param datum
|
|
1606
|
+
* @returns true if handled
|
|
1607
|
+
*/
|
|
1608
|
+
function setBooleanAttrByName(el, name, datum) {
|
|
1609
|
+
switch (name) {
|
|
1610
|
+
case 'async': {
|
|
1611
|
+
return setBooleanAttr(el, datum, [HTMLScriptElement], 'async', false);
|
|
1612
|
+
}
|
|
1613
|
+
case 'autofocus': {
|
|
1614
|
+
return setBooleanAttr(el, datum, [HTMLButtonElement, HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement], 'autofocus');
|
|
1615
|
+
}
|
|
1616
|
+
case 'autoplay': {
|
|
1617
|
+
return setBooleanAttr(el, datum, [HTMLAudioElement, HTMLVideoElement], 'autoplay');
|
|
1618
|
+
}
|
|
1619
|
+
case 'checked': {
|
|
1620
|
+
return setBooleanAttr(el, datum, [HTMLInputElement], 'checked');
|
|
1531
1621
|
}
|
|
1532
1622
|
case 'controls': {
|
|
1533
|
-
|
|
1534
|
-
el.controls = datum === '' ? true : !!datum;
|
|
1535
|
-
}
|
|
1536
|
-
else {
|
|
1537
|
-
el.setAttribute(name, `${datum}`);
|
|
1538
|
-
}
|
|
1539
|
-
return;
|
|
1623
|
+
return setBooleanAttr(el, datum, [HTMLAudioElement, HTMLVideoElement], 'controls');
|
|
1540
1624
|
}
|
|
1541
1625
|
case 'default': {
|
|
1542
|
-
|
|
1543
|
-
el.default = datum === '' ? true : !!datum;
|
|
1544
|
-
}
|
|
1545
|
-
else {
|
|
1546
|
-
el.setAttribute(name, `${datum}`);
|
|
1547
|
-
}
|
|
1548
|
-
return;
|
|
1626
|
+
return setBooleanAttr(el, datum, [HTMLTrackElement], 'default');
|
|
1549
1627
|
}
|
|
1550
1628
|
case 'defer': {
|
|
1551
|
-
|
|
1552
|
-
el.defer = !!datum;
|
|
1553
|
-
}
|
|
1554
|
-
else {
|
|
1555
|
-
el.setAttribute(name, `${datum}`);
|
|
1556
|
-
}
|
|
1557
|
-
return;
|
|
1629
|
+
return setBooleanAttr(el, datum, [HTMLScriptElement], 'defer', false);
|
|
1558
1630
|
}
|
|
1559
1631
|
case 'disabled': {
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
else {
|
|
1570
|
-
el.setAttribute(name, `${datum}`);
|
|
1571
|
-
}
|
|
1572
|
-
return;
|
|
1573
|
-
}
|
|
1574
|
-
case 'download': {
|
|
1575
|
-
if (el instanceof HTMLAnchorElement) {
|
|
1576
|
-
if (datum || datum === '') {
|
|
1577
|
-
el.download = `${datum}`;
|
|
1578
|
-
}
|
|
1579
|
-
else {
|
|
1580
|
-
el.removeAttribute(name);
|
|
1581
|
-
}
|
|
1582
|
-
}
|
|
1583
|
-
else {
|
|
1584
|
-
el.setAttribute(name, `${datum}`);
|
|
1585
|
-
}
|
|
1586
|
-
return;
|
|
1587
|
-
}
|
|
1588
|
-
case 'high': {
|
|
1589
|
-
if (el instanceof HTMLMeterElement) {
|
|
1590
|
-
const high = toInt(datum);
|
|
1591
|
-
if (Number.isNaN(high)) {
|
|
1592
|
-
el.removeAttribute(name);
|
|
1593
|
-
}
|
|
1594
|
-
else {
|
|
1595
|
-
el.high = high;
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
else {
|
|
1599
|
-
el.setAttribute(name, `${datum}`);
|
|
1600
|
-
}
|
|
1601
|
-
return;
|
|
1632
|
+
return setBooleanAttr(el, datum, [
|
|
1633
|
+
HTMLButtonElement,
|
|
1634
|
+
HTMLFieldSetElement,
|
|
1635
|
+
HTMLInputElement,
|
|
1636
|
+
HTMLOptGroupElement,
|
|
1637
|
+
HTMLOptionElement,
|
|
1638
|
+
HTMLSelectElement,
|
|
1639
|
+
HTMLTextAreaElement,
|
|
1640
|
+
], 'disabled');
|
|
1602
1641
|
}
|
|
1603
1642
|
case 'ismap': {
|
|
1604
|
-
|
|
1605
|
-
el.isMap = datum === '' ? true : !!datum;
|
|
1606
|
-
}
|
|
1607
|
-
else {
|
|
1608
|
-
el.setAttribute(name, `${datum}`);
|
|
1609
|
-
}
|
|
1610
|
-
return;
|
|
1643
|
+
return setBooleanAttr(el, datum, [HTMLImageElement], 'isMap');
|
|
1611
1644
|
}
|
|
1612
1645
|
case 'loop': {
|
|
1613
|
-
|
|
1614
|
-
el.loop = datum === '' ? true : !!datum;
|
|
1615
|
-
}
|
|
1616
|
-
else {
|
|
1617
|
-
el.setAttribute(name, `${datum}`);
|
|
1618
|
-
}
|
|
1619
|
-
return;
|
|
1620
|
-
}
|
|
1621
|
-
case 'low': {
|
|
1622
|
-
if (el instanceof HTMLMeterElement) {
|
|
1623
|
-
const low = toInt(datum);
|
|
1624
|
-
if (Number.isNaN(low)) {
|
|
1625
|
-
el.removeAttribute(name);
|
|
1626
|
-
}
|
|
1627
|
-
else {
|
|
1628
|
-
el.low = low;
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
else {
|
|
1632
|
-
el.setAttribute(name, `${datum}`);
|
|
1633
|
-
}
|
|
1634
|
-
return;
|
|
1635
|
-
}
|
|
1636
|
-
case 'max': {
|
|
1637
|
-
if (el instanceof HTMLInputElement ||
|
|
1638
|
-
el instanceof HTMLMeterElement ||
|
|
1639
|
-
el instanceof HTMLProgressElement) {
|
|
1640
|
-
const max = toInt(datum);
|
|
1641
|
-
if (Number.isNaN(max)) {
|
|
1642
|
-
el.removeAttribute(name);
|
|
1643
|
-
}
|
|
1644
|
-
else {
|
|
1645
|
-
el.max = max;
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
else {
|
|
1649
|
-
el.setAttribute(name, `${datum}`);
|
|
1650
|
-
}
|
|
1651
|
-
return;
|
|
1652
|
-
}
|
|
1653
|
-
case 'maxlength': {
|
|
1654
|
-
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
|
|
1655
|
-
const maxLength = toInt(datum);
|
|
1656
|
-
if (Number.isNaN(maxLength)) {
|
|
1657
|
-
el.removeAttribute(name);
|
|
1658
|
-
}
|
|
1659
|
-
else {
|
|
1660
|
-
el.maxLength = Math.floor(maxLength);
|
|
1661
|
-
}
|
|
1662
|
-
}
|
|
1663
|
-
else {
|
|
1664
|
-
el.setAttribute(name, `${datum}`);
|
|
1665
|
-
}
|
|
1666
|
-
return;
|
|
1667
|
-
}
|
|
1668
|
-
case 'min': {
|
|
1669
|
-
if (el instanceof HTMLInputElement || el instanceof HTMLMeterElement) {
|
|
1670
|
-
const min = toInt(datum);
|
|
1671
|
-
if (Number.isNaN(min)) {
|
|
1672
|
-
el.removeAttribute(name);
|
|
1673
|
-
}
|
|
1674
|
-
else {
|
|
1675
|
-
el.min = min;
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
else {
|
|
1679
|
-
el.setAttribute(name, `${datum}`);
|
|
1680
|
-
}
|
|
1681
|
-
return;
|
|
1646
|
+
return setBooleanAttr(el, datum, [HTMLAudioElement, HTMLVideoElement], 'loop');
|
|
1682
1647
|
}
|
|
1683
1648
|
case 'multiple': {
|
|
1684
|
-
|
|
1685
|
-
el.multiple = datum === '' ? true : !!datum;
|
|
1686
|
-
}
|
|
1687
|
-
else {
|
|
1688
|
-
el.setAttribute(name, `${datum}`);
|
|
1689
|
-
}
|
|
1690
|
-
return;
|
|
1649
|
+
return setBooleanAttr(el, datum, [HTMLInputElement, HTMLSelectElement], 'multiple');
|
|
1691
1650
|
}
|
|
1692
1651
|
case 'novalidate': {
|
|
1693
|
-
|
|
1694
|
-
el.noValidate = datum === '' ? true : !!datum;
|
|
1695
|
-
}
|
|
1696
|
-
else {
|
|
1697
|
-
el.setAttribute(name, `${datum}`);
|
|
1698
|
-
}
|
|
1699
|
-
return;
|
|
1652
|
+
return setBooleanAttr(el, datum, [HTMLFormElement], 'noValidate');
|
|
1700
1653
|
}
|
|
1701
1654
|
case 'open': {
|
|
1702
|
-
|
|
1703
|
-
el.open = datum === '' ? true : !!datum;
|
|
1704
|
-
}
|
|
1705
|
-
else {
|
|
1706
|
-
el.setAttribute(name, `${datum}`);
|
|
1707
|
-
}
|
|
1708
|
-
break;
|
|
1709
|
-
}
|
|
1710
|
-
case 'optimum': {
|
|
1711
|
-
if (el instanceof HTMLMeterElement) {
|
|
1712
|
-
const optimum = toInt(datum);
|
|
1713
|
-
if (Number.isNaN(optimum)) {
|
|
1714
|
-
el.removeAttribute(name);
|
|
1715
|
-
}
|
|
1716
|
-
else {
|
|
1717
|
-
el.optimum = Math.floor(optimum);
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
else {
|
|
1721
|
-
el.setAttribute(name, `${datum}`);
|
|
1722
|
-
}
|
|
1723
|
-
return;
|
|
1724
|
-
}
|
|
1725
|
-
case 'preload': {
|
|
1726
|
-
if (el instanceof HTMLAudioElement || el instanceof HTMLVideoElement) {
|
|
1727
|
-
switch (datum) {
|
|
1728
|
-
case '':
|
|
1729
|
-
case 'auto':
|
|
1730
|
-
case 'metadata': {
|
|
1731
|
-
el.preload = datum;
|
|
1732
|
-
break;
|
|
1733
|
-
}
|
|
1734
|
-
default: {
|
|
1735
|
-
el.preload = 'none';
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
else {
|
|
1740
|
-
el.setAttribute(name, `${datum}`);
|
|
1741
|
-
}
|
|
1742
|
-
return;
|
|
1655
|
+
return setBooleanAttr(el, datum, [HTMLDetailsElement], 'open');
|
|
1743
1656
|
}
|
|
1744
1657
|
case 'readonly': {
|
|
1745
|
-
|
|
1746
|
-
el.readOnly = datum === '' ? true : !!datum;
|
|
1747
|
-
}
|
|
1748
|
-
else {
|
|
1749
|
-
el.setAttribute(name, `${datum}`);
|
|
1750
|
-
}
|
|
1751
|
-
return;
|
|
1658
|
+
return setBooleanAttr(el, datum, [HTMLInputElement, HTMLTextAreaElement], 'readOnly');
|
|
1752
1659
|
}
|
|
1753
1660
|
case 'required': {
|
|
1754
|
-
|
|
1755
|
-
el instanceof HTMLSelectElement ||
|
|
1756
|
-
el instanceof HTMLTextAreaElement) {
|
|
1757
|
-
el.required = datum === '' ? true : !!datum;
|
|
1758
|
-
}
|
|
1759
|
-
else {
|
|
1760
|
-
el.setAttribute(name, `${datum}`);
|
|
1761
|
-
}
|
|
1762
|
-
return;
|
|
1661
|
+
return setBooleanAttr(el, datum, [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement], 'required');
|
|
1763
1662
|
}
|
|
1764
1663
|
case 'reversed': {
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1664
|
+
return setBooleanAttr(el, datum, [HTMLOListElement], 'reversed');
|
|
1665
|
+
}
|
|
1666
|
+
default: {
|
|
1667
|
+
return false;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Handle integer HTML attributes via their DOM properties.
|
|
1673
|
+
* @param el
|
|
1674
|
+
* @param name
|
|
1675
|
+
* @param datum
|
|
1676
|
+
* @returns true if handled
|
|
1677
|
+
*/
|
|
1678
|
+
function setIntegerAttrByName(el, name, datum) {
|
|
1679
|
+
switch (name) {
|
|
1680
|
+
case 'cols': {
|
|
1681
|
+
return setIntegerAttr(el, name, datum, [HTMLTextAreaElement], 'cols');
|
|
1682
|
+
}
|
|
1683
|
+
case 'colspan': {
|
|
1684
|
+
return setIntegerAttr(el, name, datum, [HTMLTableCellElement], 'colSpan');
|
|
1685
|
+
}
|
|
1686
|
+
case 'high': {
|
|
1687
|
+
return setIntegerAttr(el, name, datum, [HTMLMeterElement], 'high');
|
|
1688
|
+
}
|
|
1689
|
+
case 'low': {
|
|
1690
|
+
return setIntegerAttr(el, name, datum, [HTMLMeterElement], 'low');
|
|
1691
|
+
}
|
|
1692
|
+
case 'max': {
|
|
1693
|
+
return setIntegerAttr(el, name, datum, [HTMLInputElement, HTMLMeterElement, HTMLProgressElement], 'max');
|
|
1694
|
+
}
|
|
1695
|
+
case 'maxlength': {
|
|
1696
|
+
return setIntegerAttr(el, name, datum, [HTMLInputElement, HTMLTextAreaElement], 'maxLength', true);
|
|
1697
|
+
}
|
|
1698
|
+
case 'min': {
|
|
1699
|
+
return setIntegerAttr(el, name, datum, [HTMLInputElement, HTMLMeterElement], 'min');
|
|
1700
|
+
}
|
|
1701
|
+
case 'optimum': {
|
|
1702
|
+
return setIntegerAttr(el, name, datum, [HTMLMeterElement], 'optimum', true);
|
|
1772
1703
|
}
|
|
1773
1704
|
case 'rows': {
|
|
1774
|
-
|
|
1775
|
-
const rows = toInt(datum);
|
|
1776
|
-
if (Number.isNaN(rows)) {
|
|
1777
|
-
el.removeAttribute(name);
|
|
1778
|
-
}
|
|
1779
|
-
else {
|
|
1780
|
-
el.rows = Math.floor(rows);
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
else {
|
|
1784
|
-
el.setAttribute(name, `${datum}`);
|
|
1785
|
-
}
|
|
1786
|
-
return;
|
|
1705
|
+
return setIntegerAttr(el, name, datum, [HTMLTextAreaElement], 'rows', true);
|
|
1787
1706
|
}
|
|
1788
1707
|
case 'rowspan': {
|
|
1789
|
-
|
|
1790
|
-
const rowSpan = toInt(datum);
|
|
1791
|
-
if (Number.isNaN(rowSpan)) {
|
|
1792
|
-
el.removeAttribute(name);
|
|
1793
|
-
}
|
|
1794
|
-
else {
|
|
1795
|
-
el.rowSpan = Math.floor(rowSpan);
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
else {
|
|
1799
|
-
el.setAttribute(name, `${datum}`);
|
|
1800
|
-
}
|
|
1801
|
-
return;
|
|
1708
|
+
return setIntegerAttr(el, name, datum, [HTMLTableCellElement], 'rowSpan', true);
|
|
1802
1709
|
}
|
|
1803
1710
|
case 'size': {
|
|
1804
|
-
|
|
1805
|
-
const size = toInt(datum);
|
|
1806
|
-
if (Number.isNaN(size)) {
|
|
1807
|
-
el.removeAttribute(name);
|
|
1808
|
-
}
|
|
1809
|
-
else {
|
|
1810
|
-
el.size = size;
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1813
|
-
else {
|
|
1814
|
-
el.setAttribute(name, `${datum}`);
|
|
1815
|
-
}
|
|
1816
|
-
return;
|
|
1711
|
+
return setIntegerAttr(el, name, datum, [HTMLInputElement, HTMLSelectElement], 'size');
|
|
1817
1712
|
}
|
|
1818
1713
|
case 'span': {
|
|
1819
|
-
|
|
1820
|
-
const span = toInt(datum);
|
|
1821
|
-
if (Number.isNaN(span)) {
|
|
1822
|
-
el.removeAttribute(name);
|
|
1823
|
-
}
|
|
1824
|
-
else {
|
|
1825
|
-
el.span = span;
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
|
-
else {
|
|
1829
|
-
el.setAttribute(name, `${datum}`);
|
|
1830
|
-
}
|
|
1831
|
-
return;
|
|
1714
|
+
return setIntegerAttr(el, name, datum, [HTMLTableColElement], 'span');
|
|
1832
1715
|
}
|
|
1833
1716
|
case 'start': {
|
|
1834
|
-
|
|
1835
|
-
const start = toInt(datum);
|
|
1836
|
-
if (Number.isNaN(start)) {
|
|
1837
|
-
el.removeAttribute(name);
|
|
1838
|
-
}
|
|
1839
|
-
else {
|
|
1840
|
-
el.start = start;
|
|
1841
|
-
}
|
|
1842
|
-
}
|
|
1843
|
-
else {
|
|
1844
|
-
el.setAttribute(name, `${datum}`);
|
|
1845
|
-
}
|
|
1846
|
-
return;
|
|
1847
|
-
}
|
|
1848
|
-
case 'step': {
|
|
1849
|
-
if (el instanceof HTMLInputElement) {
|
|
1850
|
-
if (datum === 'any') {
|
|
1851
|
-
el.step = datum;
|
|
1852
|
-
break;
|
|
1853
|
-
}
|
|
1854
|
-
const step = toNum(datum);
|
|
1855
|
-
if (Number.isNaN(step)) {
|
|
1856
|
-
el.removeAttribute(name);
|
|
1857
|
-
}
|
|
1858
|
-
else {
|
|
1859
|
-
el.step = step.toString(10);
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
else {
|
|
1863
|
-
el.setAttribute(name, `${datum}`);
|
|
1864
|
-
}
|
|
1865
|
-
return;
|
|
1866
|
-
}
|
|
1867
|
-
case 'target': {
|
|
1868
|
-
if (el instanceof HTMLAnchorElement ||
|
|
1869
|
-
el instanceof HTMLAreaElement ||
|
|
1870
|
-
el instanceof HTMLFormElement) {
|
|
1871
|
-
if (datum) {
|
|
1872
|
-
el.target = `${datum}`;
|
|
1873
|
-
}
|
|
1874
|
-
else {
|
|
1875
|
-
el.removeAttribute(name);
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
else {
|
|
1879
|
-
el.setAttribute(name, `${datum}`);
|
|
1880
|
-
}
|
|
1881
|
-
return;
|
|
1717
|
+
return setIntegerAttr(el, name, datum, [HTMLOListElement], 'start');
|
|
1882
1718
|
}
|
|
1883
|
-
// case 'accesskey':
|
|
1884
|
-
// case 'class':
|
|
1885
|
-
// case 'contextmenu':
|
|
1886
|
-
// case 'dropzone': // breakable support
|
|
1887
|
-
// case 'id':
|
|
1888
|
-
// case 'itemid':
|
|
1889
|
-
// case 'itemprop':
|
|
1890
|
-
// case 'itemref':
|
|
1891
|
-
// case 'itemscope':
|
|
1892
|
-
// case 'itemtype':
|
|
1893
|
-
// case 'lang':
|
|
1894
|
-
// case 'slot': // breakable support
|
|
1895
|
-
// case 'style':
|
|
1896
|
-
// case 'title':
|
|
1897
|
-
// case 'translate': // breakable support
|
|
1898
|
-
// case 'accept':
|
|
1899
|
-
// case 'accept-charset':
|
|
1900
|
-
// case 'action':
|
|
1901
|
-
// case 'align':
|
|
1902
|
-
// case 'alt':
|
|
1903
|
-
// case 'cite':
|
|
1904
|
-
// case 'coords':
|
|
1905
|
-
// case 'datetime':
|
|
1906
|
-
// case 'enctype':
|
|
1907
|
-
// case 'for':
|
|
1908
|
-
// case 'headers':
|
|
1909
|
-
// case 'href':
|
|
1910
|
-
// case 'hreflang':
|
|
1911
|
-
// case 'kind':
|
|
1912
|
-
// case 'label':
|
|
1913
|
-
// case 'list':
|
|
1914
|
-
// case 'media':
|
|
1915
|
-
// case 'method':
|
|
1916
|
-
// case 'name':
|
|
1917
|
-
// case 'pattern':
|
|
1918
|
-
// case 'placeholder':
|
|
1919
|
-
// case 'poster':
|
|
1920
|
-
// case 'pubdate':
|
|
1921
|
-
// case 'rel':
|
|
1922
|
-
// case 'sandbox':
|
|
1923
|
-
// case 'src':
|
|
1924
|
-
// case 'srcdoc':
|
|
1925
|
-
// case 'srclang':
|
|
1926
|
-
// case 'summary':
|
|
1927
|
-
// case 'type':
|
|
1928
|
-
// case 'usemap':
|
|
1929
|
-
// case 'value':
|
|
1930
|
-
// case 'wrap':
|
|
1931
|
-
// and Data-* attributes
|
|
1932
1719
|
default: {
|
|
1933
|
-
|
|
1720
|
+
return false;
|
|
1934
1721
|
}
|
|
1935
1722
|
}
|
|
1936
1723
|
}
|
|
1937
1724
|
/**
|
|
1938
|
-
*
|
|
1939
|
-
*
|
|
1940
|
-
* @param
|
|
1941
|
-
* @param
|
|
1942
|
-
* @param
|
|
1725
|
+
* Set content value on a form element or general element.
|
|
1726
|
+
* Handles checkbox/radio checked state, input values, and innerHTML/textContent.
|
|
1727
|
+
* @param el - The target element
|
|
1728
|
+
* @param datum - The value to set
|
|
1729
|
+
* @param asHtml - Whether to set as innerHTML (true) or textContent (false)
|
|
1730
|
+
* @param xssSanitize - Whether to sanitize HTML content for XSS protection
|
|
1943
1731
|
*/
|
|
1944
1732
|
function setContent$1(el, datum, asHtml = true, xssSanitize = true) {
|
|
1945
1733
|
if (el instanceof HTMLInputElement ||
|
|
@@ -2909,8 +2697,11 @@ class EditorUI {
|
|
|
2909
2697
|
show() {
|
|
2910
2698
|
this.#el.hidden = false;
|
|
2911
2699
|
}
|
|
2700
|
+
/**
|
|
2701
|
+
* @returns Whether the UI element is currently visible (not hidden)
|
|
2702
|
+
*/
|
|
2912
2703
|
visible() {
|
|
2913
|
-
return
|
|
2704
|
+
return !this.#el.hidden;
|
|
2914
2705
|
}
|
|
2915
2706
|
}
|
|
2916
2707
|
|
|
@@ -2963,10 +2754,11 @@ class EditorDialog extends EditorUI {
|
|
|
2963
2754
|
this.clearTemplate();
|
|
2964
2755
|
this.#onClosed();
|
|
2965
2756
|
}
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2757
|
+
/**
|
|
2758
|
+
* Handle form completion. Subclasses override to process form data before closing.
|
|
2759
|
+
* @param _formData - The submitted form data
|
|
2760
|
+
*/
|
|
2761
|
+
complete(_formData) {
|
|
2970
2762
|
this.close();
|
|
2971
2763
|
}
|
|
2972
2764
|
dispatchEvent(event) {
|
|
@@ -2981,17 +2773,18 @@ class EditorDialog extends EditorUI {
|
|
|
2981
2773
|
? elements.map((el) => el.shadowRoot?.querySelector(shadowSelector) ?? el)
|
|
2982
2774
|
: elements;
|
|
2983
2775
|
}
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2776
|
+
/**
|
|
2777
|
+
* Handle form submission. Subclasses override to add custom behavior.
|
|
2778
|
+
* Return `false` to cancel submission.
|
|
2779
|
+
* @param _e - The submit event
|
|
2780
|
+
* @param _submitter - The element that triggered submission
|
|
2781
|
+
*/
|
|
2782
|
+
onSubmit(_e, _submitter) { }
|
|
2783
|
+
/**
|
|
2784
|
+
* Open the dialog. Subclasses override to set up content before showing.
|
|
2785
|
+
* @param _args - Arguments passed by subclass overrides
|
|
2786
|
+
*/
|
|
2787
|
+
open(..._args) {
|
|
2995
2788
|
const cancel = this.#onOpen();
|
|
2996
2789
|
if (cancel === true) {
|
|
2997
2790
|
return;
|
|
@@ -3215,21 +3008,38 @@ class ComponentObserver {
|
|
|
3215
3008
|
constructor() {
|
|
3216
3009
|
this.#instanceId = instanceId++;
|
|
3217
3010
|
}
|
|
3011
|
+
/**
|
|
3012
|
+
* Dispatch a custom event on the window.
|
|
3013
|
+
* @template A - The action type key
|
|
3014
|
+
* @param name - The action name to dispatch
|
|
3015
|
+
* @param payload - The event payload matching the action type
|
|
3016
|
+
*/
|
|
3218
3017
|
notify(name, payload) {
|
|
3219
3018
|
window.dispatchEvent(new CustomEvent(`bge:_${this.#instanceId}_:${name}`, { detail: payload }));
|
|
3220
3019
|
}
|
|
3020
|
+
/**
|
|
3021
|
+
* Remove all registered event listeners and clear the internal map.
|
|
3022
|
+
*/
|
|
3221
3023
|
off() {
|
|
3222
|
-
for (const [
|
|
3223
|
-
|
|
3224
|
-
window.removeEventListener(`bge:_${this.#instanceId}_:${name}`, listener);
|
|
3024
|
+
for (const [wrapper, name] of this.#listeners) {
|
|
3025
|
+
window.removeEventListener(`bge:_${this.#instanceId}_:${name}`, wrapper);
|
|
3225
3026
|
}
|
|
3226
3027
|
this.#listeners.clear();
|
|
3227
3028
|
}
|
|
3029
|
+
/**
|
|
3030
|
+
* Register an event listener. Each call creates a separate wrapper,
|
|
3031
|
+
* so calling with the same listener multiple times will fire it
|
|
3032
|
+
* multiple times per event.
|
|
3033
|
+
* @template A - The action type key
|
|
3034
|
+
* @param name - The action name to listen for
|
|
3035
|
+
* @param listener - Callback receiving the typed payload
|
|
3036
|
+
*/
|
|
3228
3037
|
on(name, listener) {
|
|
3229
|
-
|
|
3230
|
-
window.addEventListener(`bge:_${this.#instanceId}_:${name}`, (e) => {
|
|
3038
|
+
const wrapper = (e) => {
|
|
3231
3039
|
listener(e.detail);
|
|
3232
|
-
}
|
|
3040
|
+
};
|
|
3041
|
+
this.#listeners.set(wrapper, name);
|
|
3042
|
+
window.addEventListener(`bge:_${this.#instanceId}_:${name}`, wrapper);
|
|
3233
3043
|
}
|
|
3234
3044
|
}
|
|
3235
3045
|
|
|
@@ -3387,11 +3197,17 @@ function getCustomProperties(scope, containerType) {
|
|
|
3387
3197
|
}
|
|
3388
3198
|
}
|
|
3389
3199
|
}
|
|
3390
|
-
// Merge nested defaults
|
|
3391
|
-
//
|
|
3392
|
-
for (const [category,
|
|
3393
|
-
|
|
3394
|
-
|
|
3200
|
+
// Merge nested defaults: use nested default when no direct default exists,
|
|
3201
|
+
// or when the nested default has higher cascade layer priority.
|
|
3202
|
+
for (const [category, nestedProperty] of nestedDefaultValues.entries()) {
|
|
3203
|
+
const directProperty = defaultValues.get(category);
|
|
3204
|
+
if (directProperty) {
|
|
3205
|
+
// Compare by layer priority; on equal priority, direct selector wins
|
|
3206
|
+
const winner = compareCustomPropertyByLayerPriority(nestedProperty, directProperty);
|
|
3207
|
+
defaultValues.set(category, winner);
|
|
3208
|
+
}
|
|
3209
|
+
else {
|
|
3210
|
+
defaultValues.set(category, nestedProperty);
|
|
3395
3211
|
}
|
|
3396
3212
|
}
|
|
3397
3213
|
for (const [category, property] of defaultValues.entries()) {
|
|
@@ -4250,9 +4066,21 @@ class ItemEditorDialog extends EditorDialog {
|
|
|
4250
4066
|
$ctrl.max = value.toString();
|
|
4251
4067
|
}
|
|
4252
4068
|
}
|
|
4069
|
+
/**
|
|
4070
|
+
* Register a change handler for a named form control.
|
|
4071
|
+
* When `runOnInit` is true, fires immediately with the current value
|
|
4072
|
+
* (oldValue is null) and stores the initial value for subsequent comparisons.
|
|
4073
|
+
* @template N - The item data property name
|
|
4074
|
+
* @template D - The data type for the property
|
|
4075
|
+
* @param name - The control name prefixed with `$`
|
|
4076
|
+
* @param handler - Callback receiving new value and previous value
|
|
4077
|
+
* @param runOnInit - Whether to invoke the handler immediately with the current value
|
|
4078
|
+
*/
|
|
4253
4079
|
onChange(name, handler, runOnInit = true) {
|
|
4254
4080
|
if (runOnInit) {
|
|
4255
|
-
|
|
4081
|
+
const initialValue = this.get(name);
|
|
4082
|
+
this.#values.set(name, initialValue);
|
|
4083
|
+
handler(initialValue, null);
|
|
4256
4084
|
}
|
|
4257
4085
|
for (const $ctrl of this.#findAll(name)) {
|
|
4258
4086
|
$ctrl.addEventListener('change', () => {
|
|
@@ -4757,12 +4585,10 @@ class BurgerEditorEngine {
|
|
|
4757
4585
|
const mainInitialContent = typeof options.initialContents === 'string'
|
|
4758
4586
|
? options.initialContents
|
|
4759
4587
|
: options.initialContents.main;
|
|
4760
|
-
// @ts-ignore force assign to readonly property
|
|
4761
4588
|
engine.#main =
|
|
4762
4589
|
//
|
|
4763
4590
|
await EditableArea.new('main', mainInitialContent, engine, options.blockMenu, options.initialInsertionButton, stylesheets, options.config.classList, options.editableAreaShell);
|
|
4764
4591
|
const draftInitialContent = typeof options.initialContents === 'string' ? null : options.initialContents.draft;
|
|
4765
|
-
// @ts-ignore force assign to readonly property
|
|
4766
4592
|
engine.#draft =
|
|
4767
4593
|
draftInitialContent == null
|
|
4768
4594
|
? null
|
|
@@ -33706,6 +33532,281 @@ function getCurrentEditorState(wysiwygElement) {
|
|
|
33706
33532
|
};
|
|
33707
33533
|
}
|
|
33708
33534
|
|
|
33535
|
+
const controlUIStyles = `
|
|
33536
|
+
:host {
|
|
33537
|
+
display: block;
|
|
33538
|
+
}
|
|
33539
|
+
|
|
33540
|
+
textarea,
|
|
33541
|
+
iframe {
|
|
33542
|
+
block-size: 50svh;
|
|
33543
|
+
inline-size: 100%;
|
|
33544
|
+
resize: vertical;
|
|
33545
|
+
overflow-y: auto;
|
|
33546
|
+
background: var(--bge-lightest-color);
|
|
33547
|
+
border: 1px solid var(--bge-border-color);
|
|
33548
|
+
border-radius: var(--border-radius);
|
|
33549
|
+
}
|
|
33550
|
+
|
|
33551
|
+
iframe[data-focus-within="true"],
|
|
33552
|
+
textarea:focus-visible {
|
|
33553
|
+
--bge-border-color: var(--bge-ui-primary-color);
|
|
33554
|
+
--bge-outline-color: var(--bge-ui-primary-color);
|
|
33555
|
+
outline: var(--bge-focus-outline-width) solid var(--bge-outline-color);
|
|
33556
|
+
}
|
|
33557
|
+
|
|
33558
|
+
textarea {
|
|
33559
|
+
font-family: var(--bge-font-family-monospace);
|
|
33560
|
+
}
|
|
33561
|
+
|
|
33562
|
+
[data-bge-mode="wysiwyg"] textarea {
|
|
33563
|
+
display: none;
|
|
33564
|
+
}
|
|
33565
|
+
|
|
33566
|
+
[data-bge-mode="html"] iframe {
|
|
33567
|
+
display: none;
|
|
33568
|
+
}
|
|
33569
|
+
|
|
33570
|
+
[data-text-only-editor] {
|
|
33571
|
+
block-size: 50svh;
|
|
33572
|
+
inline-size: 100%;
|
|
33573
|
+
resize: vertical;
|
|
33574
|
+
overflow-y: auto;
|
|
33575
|
+
background: var(--bge-lightest-color);
|
|
33576
|
+
border: 1px solid var(--bge-border-color);
|
|
33577
|
+
border-radius: var(--border-radius);
|
|
33578
|
+
padding: 1rem;
|
|
33579
|
+
box-sizing: border-box;
|
|
33580
|
+
}
|
|
33581
|
+
|
|
33582
|
+
[data-bge-mode="wysiwyg"] [data-text-only-editor],
|
|
33583
|
+
[data-bge-mode="html"] [data-text-only-editor] {
|
|
33584
|
+
display: none;
|
|
33585
|
+
}
|
|
33586
|
+
|
|
33587
|
+
[data-bge-mode="text-only"] iframe,
|
|
33588
|
+
[data-bge-mode="text-only"] textarea {
|
|
33589
|
+
display: none;
|
|
33590
|
+
}
|
|
33591
|
+
|
|
33592
|
+
[contenteditable="plaintext-only"] {
|
|
33593
|
+
outline: 1px dashed var(--bge-border-color);
|
|
33594
|
+
cursor: text;
|
|
33595
|
+
}
|
|
33596
|
+
|
|
33597
|
+
[contenteditable="plaintext-only"]:hover {
|
|
33598
|
+
outline-color: var(--bge-ui-primary-color);
|
|
33599
|
+
}
|
|
33600
|
+
|
|
33601
|
+
[contenteditable="plaintext-only"]:focus {
|
|
33602
|
+
outline: 2px solid var(--bge-ui-primary-color);
|
|
33603
|
+
outline-offset: 2px;
|
|
33604
|
+
}
|
|
33605
|
+
|
|
33606
|
+
[role="alert"] {
|
|
33607
|
+
margin-block-start: 0.5rem;
|
|
33608
|
+
padding: 0.5rem;
|
|
33609
|
+
background-color: var(--bge-error-color, #fee);
|
|
33610
|
+
border: 1px solid var(--bge-error-border-color, #fcc);
|
|
33611
|
+
border-radius: var(--border-radius);
|
|
33612
|
+
color: var(--bge-error-text-color, #c00);
|
|
33613
|
+
font-size: 0.875rem;
|
|
33614
|
+
}
|
|
33615
|
+
`;
|
|
33616
|
+
const editorContentStyles = (css) => `
|
|
33617
|
+
:where(html, body) {
|
|
33618
|
+
margin: 0;
|
|
33619
|
+
padding: 0;
|
|
33620
|
+
|
|
33621
|
+
:where(&, *) {
|
|
33622
|
+
box-sizing: border-box;
|
|
33623
|
+
}
|
|
33624
|
+
}
|
|
33625
|
+
|
|
33626
|
+
iframe,
|
|
33627
|
+
[contenteditable="true"] {
|
|
33628
|
+
padding: 1rem;
|
|
33629
|
+
block-size: 100%;
|
|
33630
|
+
box-sizing: border-box;
|
|
33631
|
+
}
|
|
33632
|
+
|
|
33633
|
+
[contenteditable="true"]:focus-visible {
|
|
33634
|
+
outline: none;
|
|
33635
|
+
}
|
|
33636
|
+
|
|
33637
|
+
${css}
|
|
33638
|
+
|
|
33639
|
+
a:any-link {
|
|
33640
|
+
pointer-events: none !important;
|
|
33641
|
+
}
|
|
33642
|
+
`;
|
|
33643
|
+
|
|
33644
|
+
var __typeError$2 = (msg) => {
|
|
33645
|
+
throw TypeError(msg);
|
|
33646
|
+
};
|
|
33647
|
+
var __accessCheck$2 = (obj, member, msg) => member.has(obj) || __typeError$2("Cannot " + msg);
|
|
33648
|
+
var __privateGet$2 = (obj, member, getter) => (__accessCheck$2(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
33649
|
+
var __privateAdd$2 = (obj, member, value) => member.has(obj) ? __typeError$2("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
33650
|
+
var __privateSet$2 = (obj, member, value, setter) => (__accessCheck$2(obj, member, "write to private field"), member.set(obj, value), value);
|
|
33651
|
+
var __privateMethod$1 = (obj, member, method) => (__accessCheck$2(obj, member, "access private method"), method);
|
|
33652
|
+
var _container, _setToTextarea, _preventEnterKey, _syncToTextarea, _TextOnlyModeController_instances, attachEventListeners_fn, identifyEditableElements_fn;
|
|
33653
|
+
class TextOnlyModeController {
|
|
33654
|
+
/**
|
|
33655
|
+
* @param setToTextarea - Callback to sync cleaned HTML back to the textarea
|
|
33656
|
+
*/
|
|
33657
|
+
constructor(setToTextarea) {
|
|
33658
|
+
__privateAdd$2(this, _TextOnlyModeController_instances);
|
|
33659
|
+
__privateAdd$2(this, _container, null);
|
|
33660
|
+
__privateAdd$2(this, _setToTextarea);
|
|
33661
|
+
/**
|
|
33662
|
+
* Enter キーを防止するハンドラー
|
|
33663
|
+
* @param event
|
|
33664
|
+
*/
|
|
33665
|
+
__privateAdd$2(this, _preventEnterKey, (event) => {
|
|
33666
|
+
if (event.key === "Enter") {
|
|
33667
|
+
event.preventDefault();
|
|
33668
|
+
}
|
|
33669
|
+
});
|
|
33670
|
+
/**
|
|
33671
|
+
* text-onlyコンテナからtextareaへ同期
|
|
33672
|
+
*/
|
|
33673
|
+
__privateAdd$2(this, _syncToTextarea, () => {
|
|
33674
|
+
if (!__privateGet$2(this, _container)) {
|
|
33675
|
+
return;
|
|
33676
|
+
}
|
|
33677
|
+
const cleanHTML = this.cleanHTML();
|
|
33678
|
+
__privateGet$2(this, _setToTextarea).call(this, cleanHTML);
|
|
33679
|
+
});
|
|
33680
|
+
__privateSet$2(this, _setToTextarea, setToTextarea);
|
|
33681
|
+
}
|
|
33682
|
+
/**
|
|
33683
|
+
* The text-only editing container element, or null if not yet activated.
|
|
33684
|
+
*/
|
|
33685
|
+
get container() {
|
|
33686
|
+
return __privateGet$2(this, _container);
|
|
33687
|
+
}
|
|
33688
|
+
/**
|
|
33689
|
+
* text-onlyモードを有効化
|
|
33690
|
+
* @param shadowRoot
|
|
33691
|
+
* @param currentHTML
|
|
33692
|
+
* @param structureChangeMessage
|
|
33693
|
+
* @param previewStyleContent
|
|
33694
|
+
*/
|
|
33695
|
+
activate(shadowRoot, currentHTML, structureChangeMessage, previewStyleContent) {
|
|
33696
|
+
if (!__privateGet$2(this, _container)) {
|
|
33697
|
+
__privateSet$2(this, _container, document.createElement("div"));
|
|
33698
|
+
__privateGet$2(this, _container).dataset.textOnlyEditor = "";
|
|
33699
|
+
const modeContainer = shadowRoot.querySelector("[data-bge-mode]");
|
|
33700
|
+
modeContainer.insertBefore(__privateGet$2(this, _container), structureChangeMessage);
|
|
33701
|
+
}
|
|
33702
|
+
const textOnlyStyle = document.createElement("style");
|
|
33703
|
+
textOnlyStyle.dataset.textOnlyStyle = "";
|
|
33704
|
+
if (previewStyleContent) {
|
|
33705
|
+
textOnlyStyle.textContent = previewStyleContent;
|
|
33706
|
+
}
|
|
33707
|
+
__privateGet$2(this, _container).innerHTML = currentHTML;
|
|
33708
|
+
__privateGet$2(this, _container).prepend(textOnlyStyle);
|
|
33709
|
+
__privateMethod$1(this, _TextOnlyModeController_instances, identifyEditableElements_fn).call(this, __privateGet$2(this, _container));
|
|
33710
|
+
__privateMethod$1(this, _TextOnlyModeController_instances, attachEventListeners_fn).call(this);
|
|
33711
|
+
shadowRoot.querySelector(`[data-bge-mode]`).dataset.bgeMode = "text-only";
|
|
33712
|
+
}
|
|
33713
|
+
/**
|
|
33714
|
+
* contenteditable属性を削除してクリーンなHTMLを返す
|
|
33715
|
+
*/
|
|
33716
|
+
cleanHTML() {
|
|
33717
|
+
if (!__privateGet$2(this, _container)) {
|
|
33718
|
+
return "";
|
|
33719
|
+
}
|
|
33720
|
+
const clone = __privateGet$2(this, _container).cloneNode(true);
|
|
33721
|
+
const editableElements = clone.querySelectorAll('[contenteditable="plaintext-only"]');
|
|
33722
|
+
for (const el of editableElements) {
|
|
33723
|
+
el.removeAttribute("contenteditable");
|
|
33724
|
+
}
|
|
33725
|
+
const styleElements = clone.querySelectorAll("[data-text-only-style]");
|
|
33726
|
+
for (const el of styleElements) {
|
|
33727
|
+
el.remove();
|
|
33728
|
+
}
|
|
33729
|
+
return clone.innerHTML;
|
|
33730
|
+
}
|
|
33731
|
+
/**
|
|
33732
|
+
* text-onlyモードを無効化
|
|
33733
|
+
*/
|
|
33734
|
+
deactivate() {
|
|
33735
|
+
if (!__privateGet$2(this, _container)) {
|
|
33736
|
+
return;
|
|
33737
|
+
}
|
|
33738
|
+
const editableElements = __privateGet$2(this, _container).querySelectorAll(
|
|
33739
|
+
'[contenteditable="plaintext-only"]'
|
|
33740
|
+
);
|
|
33741
|
+
for (const el of editableElements) {
|
|
33742
|
+
el.removeEventListener("keydown", __privateGet$2(this, _preventEnterKey));
|
|
33743
|
+
el.removeEventListener("input", __privateGet$2(this, _syncToTextarea));
|
|
33744
|
+
}
|
|
33745
|
+
__privateGet$2(this, _container).innerHTML = "";
|
|
33746
|
+
}
|
|
33747
|
+
/**
|
|
33748
|
+
* text-onlyモードの値を取得
|
|
33749
|
+
* @param textareaValue
|
|
33750
|
+
*/
|
|
33751
|
+
getValue(textareaValue) {
|
|
33752
|
+
if (!__privateGet$2(this, _container)) {
|
|
33753
|
+
return textareaValue;
|
|
33754
|
+
}
|
|
33755
|
+
return this.cleanHTML();
|
|
33756
|
+
}
|
|
33757
|
+
/**
|
|
33758
|
+
* text-onlyモードに値を設定
|
|
33759
|
+
* @param value
|
|
33760
|
+
* @param shadowRoot
|
|
33761
|
+
* @param structureChangeMessage
|
|
33762
|
+
* @param previewStyleContent
|
|
33763
|
+
*/
|
|
33764
|
+
setValue(value, shadowRoot, structureChangeMessage, previewStyleContent) {
|
|
33765
|
+
this.deactivate();
|
|
33766
|
+
__privateGet$2(this, _setToTextarea).call(this, value);
|
|
33767
|
+
this.activate(shadowRoot, value, structureChangeMessage, previewStyleContent);
|
|
33768
|
+
}
|
|
33769
|
+
}
|
|
33770
|
+
_container = new WeakMap();
|
|
33771
|
+
_setToTextarea = new WeakMap();
|
|
33772
|
+
_preventEnterKey = new WeakMap();
|
|
33773
|
+
_syncToTextarea = new WeakMap();
|
|
33774
|
+
_TextOnlyModeController_instances = new WeakSet();
|
|
33775
|
+
attachEventListeners_fn = function() {
|
|
33776
|
+
if (!__privateGet$2(this, _container)) {
|
|
33777
|
+
return;
|
|
33778
|
+
}
|
|
33779
|
+
const editableElements = __privateGet$2(this, _container).querySelectorAll(
|
|
33780
|
+
'[contenteditable="plaintext-only"]'
|
|
33781
|
+
);
|
|
33782
|
+
for (const el of editableElements) {
|
|
33783
|
+
el.addEventListener("keydown", __privateGet$2(this, _preventEnterKey));
|
|
33784
|
+
el.addEventListener("input", __privateGet$2(this, _syncToTextarea));
|
|
33785
|
+
}
|
|
33786
|
+
};
|
|
33787
|
+
identifyEditableElements_fn = function(container) {
|
|
33788
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
|
|
33789
|
+
acceptNode: (node) => {
|
|
33790
|
+
const element = node;
|
|
33791
|
+
const hasDirectTextChild = [...element.childNodes].some(
|
|
33792
|
+
(child) => child.nodeType === Node.TEXT_NODE && child.textContent?.trim()
|
|
33793
|
+
);
|
|
33794
|
+
if (hasDirectTextChild) {
|
|
33795
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
33796
|
+
}
|
|
33797
|
+
return NodeFilter.FILTER_SKIP;
|
|
33798
|
+
}
|
|
33799
|
+
});
|
|
33800
|
+
const editableElements = [];
|
|
33801
|
+
let currentNode;
|
|
33802
|
+
while (currentNode = walker.nextNode()) {
|
|
33803
|
+
editableElements.push(currentNode);
|
|
33804
|
+
}
|
|
33805
|
+
for (const el of editableElements) {
|
|
33806
|
+
el.setAttribute("contenteditable", "plaintext-only");
|
|
33807
|
+
}
|
|
33808
|
+
};
|
|
33809
|
+
|
|
33709
33810
|
var __defProp$1 = Object.defineProperty;
|
|
33710
33811
|
var __typeError$1 = (msg) => {
|
|
33711
33812
|
throw TypeError(msg);
|
|
@@ -33717,7 +33818,7 @@ var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "rea
|
|
|
33717
33818
|
var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
33718
33819
|
var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
|
|
33719
33820
|
var __privateMethod = (obj, member, method) => (__accessCheck$1(obj, member, "access private method"), method);
|
|
33720
|
-
var _editor, _editorRoot, _hasStructureChange, _isExpectingHTML, _isInitializing, _previewStyle, _structureChangeMessage, _textarea, _textareaDescriptor,
|
|
33821
|
+
var _editor, _editorRoot, _hasStructureChange, _isExpectingHTML, _isInitializing, _previewStyle, _structureChangeMessage, _textarea, _textareaDescriptor, _textOnlyMode, _BgeWysiwygElement_instances, checkStructureChange_fn, setStructureChange_fn, setToTextarea_fn, transaction_fn, updateStructureChangeMessage_fn;
|
|
33721
33822
|
function defineBgeWysiwygElement(options, global = window) {
|
|
33722
33823
|
if (options?.extensions) {
|
|
33723
33824
|
BgeWysiwygElement.extensions = options.extensions;
|
|
@@ -33746,26 +33847,7 @@ const _BgeWysiwygElement = class _BgeWysiwygElement extends HTMLElement {
|
|
|
33746
33847
|
__privateAdd$1(this, _structureChangeMessage, null);
|
|
33747
33848
|
__privateAdd$1(this, _textarea, null);
|
|
33748
33849
|
__privateAdd$1(this, _textareaDescriptor, null);
|
|
33749
|
-
__privateAdd$1(this,
|
|
33750
|
-
/**
|
|
33751
|
-
* Enter キーを防止するハンドラー
|
|
33752
|
-
* @param event
|
|
33753
|
-
*/
|
|
33754
|
-
__privateAdd$1(this, _preventEnterKey, (event) => {
|
|
33755
|
-
if (event.key === "Enter") {
|
|
33756
|
-
event.preventDefault();
|
|
33757
|
-
}
|
|
33758
|
-
});
|
|
33759
|
-
/**
|
|
33760
|
-
* text-onlyコンテナからtextareaへ同期
|
|
33761
|
-
*/
|
|
33762
|
-
__privateAdd$1(this, _syncTextOnlyToTextarea, () => {
|
|
33763
|
-
if (this.mode !== "text-only" || !__privateGet$1(this, _textOnlyContainer)) {
|
|
33764
|
-
return;
|
|
33765
|
-
}
|
|
33766
|
-
const cleanHTML = __privateMethod(this, _BgeWysiwygElement_instances, cleanTextOnlyHTML_fn).call(this, "");
|
|
33767
|
-
__privateMethod(this, _BgeWysiwygElement_instances, setToTextarea_fn).call(this, cleanHTML);
|
|
33768
|
-
});
|
|
33850
|
+
__privateAdd$1(this, _textOnlyMode, null);
|
|
33769
33851
|
this.attachShadow({ mode: "open" });
|
|
33770
33852
|
if (!this.shadowRoot) {
|
|
33771
33853
|
throw new Error("Not supported shadow DOM");
|
|
@@ -33776,7 +33858,7 @@ const _BgeWysiwygElement = class _BgeWysiwygElement extends HTMLElement {
|
|
|
33776
33858
|
throw new ReferenceError("<bge-wysiwyg> is not connected");
|
|
33777
33859
|
}
|
|
33778
33860
|
if (this.mode === "text-only") {
|
|
33779
|
-
return
|
|
33861
|
+
return __privateGet$1(this, _textOnlyMode)?.getValue(__privateGet$1(this, _textarea).value) ?? __privateGet$1(this, _textarea).value;
|
|
33780
33862
|
}
|
|
33781
33863
|
if (this.mode === "wysiwyg") {
|
|
33782
33864
|
if (!__privateGet$1(this, _editor)) {
|
|
@@ -33793,7 +33875,12 @@ const _BgeWysiwygElement = class _BgeWysiwygElement extends HTMLElement {
|
|
|
33793
33875
|
throw new ReferenceError("<bge-wysiwyg> is not connected");
|
|
33794
33876
|
}
|
|
33795
33877
|
if (this.mode === "text-only") {
|
|
33796
|
-
|
|
33878
|
+
__privateGet$1(this, _textOnlyMode)?.setValue(
|
|
33879
|
+
value,
|
|
33880
|
+
this.shadowRoot,
|
|
33881
|
+
__privateGet$1(this, _structureChangeMessage),
|
|
33882
|
+
__privateGet$1(this, _previewStyle)?.textContent ?? null
|
|
33883
|
+
);
|
|
33797
33884
|
return;
|
|
33798
33885
|
}
|
|
33799
33886
|
if (this.mode === "html") {
|
|
@@ -33828,14 +33915,20 @@ const _BgeWysiwygElement = class _BgeWysiwygElement extends HTMLElement {
|
|
|
33828
33915
|
return;
|
|
33829
33916
|
}
|
|
33830
33917
|
if (this.mode === "text-only") {
|
|
33831
|
-
|
|
33918
|
+
__privateGet$1(this, _textOnlyMode)?.deactivate();
|
|
33832
33919
|
}
|
|
33833
33920
|
if (mode === "wysiwyg" && this.mode === "html" && __privateMethod(this, _BgeWysiwygElement_instances, checkStructureChange_fn).call(this)) {
|
|
33834
33921
|
__privateMethod(this, _BgeWysiwygElement_instances, setStructureChange_fn).call(this, true);
|
|
33835
33922
|
return;
|
|
33836
33923
|
}
|
|
33837
33924
|
if (mode === "text-only") {
|
|
33838
|
-
|
|
33925
|
+
const currentHTML = this.mode === "wysiwyg" ? __privateGet$1(this, _editor).getHTML().replaceAll("<p></p>", "") : __privateGet$1(this, _textarea).value;
|
|
33926
|
+
__privateGet$1(this, _textOnlyMode)?.activate(
|
|
33927
|
+
this.shadowRoot,
|
|
33928
|
+
currentHTML,
|
|
33929
|
+
__privateGet$1(this, _structureChangeMessage),
|
|
33930
|
+
__privateGet$1(this, _previewStyle)?.textContent ?? null
|
|
33931
|
+
);
|
|
33839
33932
|
return;
|
|
33840
33933
|
}
|
|
33841
33934
|
this.shadowRoot.querySelector(`[data-bge-mode]`)?.setAttribute(
|
|
@@ -33880,87 +33973,7 @@ const _BgeWysiwygElement = class _BgeWysiwygElement extends HTMLElement {
|
|
|
33880
33973
|
const textarea = this.shadowRoot.querySelector("textarea");
|
|
33881
33974
|
const controlUIStyle = document.createElement("style");
|
|
33882
33975
|
this.shadowRoot.append(controlUIStyle);
|
|
33883
|
-
controlUIStyle.textContent =
|
|
33884
|
-
:host {
|
|
33885
|
-
display: block;
|
|
33886
|
-
}
|
|
33887
|
-
|
|
33888
|
-
textarea,
|
|
33889
|
-
iframe {
|
|
33890
|
-
block-size: 50svh;
|
|
33891
|
-
inline-size: 100%;
|
|
33892
|
-
resize: vertical;
|
|
33893
|
-
overflow-y: auto;
|
|
33894
|
-
background: var(--bge-lightest-color);
|
|
33895
|
-
border: 1px solid var(--bge-border-color);
|
|
33896
|
-
border-radius: var(--border-radius);
|
|
33897
|
-
}
|
|
33898
|
-
|
|
33899
|
-
iframe[data-focus-within="true"],
|
|
33900
|
-
textarea:focus-visible {
|
|
33901
|
-
--bge-border-color: var(--bge-ui-primary-color);
|
|
33902
|
-
--bge-outline-color: var(--bge-ui-primary-color);
|
|
33903
|
-
outline: var(--bge-focus-outline-width) solid var(--bge-outline-color);
|
|
33904
|
-
}
|
|
33905
|
-
|
|
33906
|
-
textarea {
|
|
33907
|
-
font-family: var(--bge-font-family-monospace);
|
|
33908
|
-
}
|
|
33909
|
-
|
|
33910
|
-
[data-bge-mode="wysiwyg"] textarea {
|
|
33911
|
-
display: none;
|
|
33912
|
-
}
|
|
33913
|
-
|
|
33914
|
-
[data-bge-mode="html"] iframe {
|
|
33915
|
-
display: none;
|
|
33916
|
-
}
|
|
33917
|
-
|
|
33918
|
-
[data-text-only-editor] {
|
|
33919
|
-
block-size: 50svh;
|
|
33920
|
-
inline-size: 100%;
|
|
33921
|
-
resize: vertical;
|
|
33922
|
-
overflow-y: auto;
|
|
33923
|
-
background: var(--bge-lightest-color);
|
|
33924
|
-
border: 1px solid var(--bge-border-color);
|
|
33925
|
-
border-radius: var(--border-radius);
|
|
33926
|
-
padding: 1rem;
|
|
33927
|
-
box-sizing: border-box;
|
|
33928
|
-
}
|
|
33929
|
-
|
|
33930
|
-
[data-bge-mode="wysiwyg"] [data-text-only-editor],
|
|
33931
|
-
[data-bge-mode="html"] [data-text-only-editor] {
|
|
33932
|
-
display: none;
|
|
33933
|
-
}
|
|
33934
|
-
|
|
33935
|
-
[data-bge-mode="text-only"] iframe,
|
|
33936
|
-
[data-bge-mode="text-only"] textarea {
|
|
33937
|
-
display: none;
|
|
33938
|
-
}
|
|
33939
|
-
|
|
33940
|
-
[contenteditable="plaintext-only"] {
|
|
33941
|
-
outline: 1px dashed var(--bge-border-color);
|
|
33942
|
-
cursor: text;
|
|
33943
|
-
}
|
|
33944
|
-
|
|
33945
|
-
[contenteditable="plaintext-only"]:hover {
|
|
33946
|
-
outline-color: var(--bge-ui-primary-color);
|
|
33947
|
-
}
|
|
33948
|
-
|
|
33949
|
-
[contenteditable="plaintext-only"]:focus {
|
|
33950
|
-
outline: 2px solid var(--bge-ui-primary-color);
|
|
33951
|
-
outline-offset: 2px;
|
|
33952
|
-
}
|
|
33953
|
-
|
|
33954
|
-
[role="alert"] {
|
|
33955
|
-
margin-block-start: 0.5rem;
|
|
33956
|
-
padding: 0.5rem;
|
|
33957
|
-
background-color: var(--bge-error-color, #fee);
|
|
33958
|
-
border: 1px solid var(--bge-error-border-color, #fcc);
|
|
33959
|
-
border-radius: var(--border-radius);
|
|
33960
|
-
color: var(--bge-error-text-color, #c00);
|
|
33961
|
-
font-size: 0.875rem;
|
|
33962
|
-
}
|
|
33963
|
-
`;
|
|
33976
|
+
controlUIStyle.textContent = controlUIStyles;
|
|
33964
33977
|
preview.contentDocument.body.addEventListener("focusin", () => {
|
|
33965
33978
|
preview.dataset.focusWithin = "true";
|
|
33966
33979
|
});
|
|
@@ -34021,6 +34034,9 @@ const _BgeWysiwygElement = class _BgeWysiwygElement extends HTMLElement {
|
|
|
34021
34034
|
HTMLTextAreaElement.prototype,
|
|
34022
34035
|
"value"
|
|
34023
34036
|
));
|
|
34037
|
+
__privateSet$1(this, _textOnlyMode, new TextOnlyModeController((html) => {
|
|
34038
|
+
__privateMethod(this, _BgeWysiwygElement_instances, setToTextarea_fn).call(this, html);
|
|
34039
|
+
}));
|
|
34024
34040
|
Object.defineProperty(__privateGet$1(this, _textarea), "value", {
|
|
34025
34041
|
get: () => {
|
|
34026
34042
|
return __privateGet$1(this, _textareaDescriptor)?.get?.call(__privateGet$1(this, _textarea)) ?? "";
|
|
@@ -34081,33 +34097,7 @@ const _BgeWysiwygElement = class _BgeWysiwygElement extends HTMLElement {
|
|
|
34081
34097
|
if (!__privateGet$1(this, _previewStyle)) {
|
|
34082
34098
|
throw new ReferenceError("<bge-wysiwyg> is not connected");
|
|
34083
34099
|
}
|
|
34084
|
-
__privateGet$1(this, _previewStyle).textContent =
|
|
34085
|
-
:where(html, body) {
|
|
34086
|
-
margin: 0;
|
|
34087
|
-
padding: 0;
|
|
34088
|
-
|
|
34089
|
-
:where(&, *) {
|
|
34090
|
-
box-sizing: border-box;
|
|
34091
|
-
}
|
|
34092
|
-
}
|
|
34093
|
-
|
|
34094
|
-
iframe,
|
|
34095
|
-
[contenteditable="true"] {
|
|
34096
|
-
padding: 1rem;
|
|
34097
|
-
block-size: 100%;
|
|
34098
|
-
box-sizing: border-box;
|
|
34099
|
-
}
|
|
34100
|
-
|
|
34101
|
-
[contenteditable="true"]:focus-visible {
|
|
34102
|
-
outline: none;
|
|
34103
|
-
}
|
|
34104
|
-
|
|
34105
|
-
${css}
|
|
34106
|
-
|
|
34107
|
-
a:any-link {
|
|
34108
|
-
pointer-events: none !important;
|
|
34109
|
-
}
|
|
34110
|
-
`;
|
|
34100
|
+
__privateGet$1(this, _previewStyle).textContent = editorContentStyles(css);
|
|
34111
34101
|
}
|
|
34112
34102
|
syncWysiwygToTextarea() {
|
|
34113
34103
|
if (__privateGet$1(this, _isExpectingHTML)) {
|
|
@@ -34178,47 +34168,8 @@ _previewStyle = new WeakMap();
|
|
|
34178
34168
|
_structureChangeMessage = new WeakMap();
|
|
34179
34169
|
_textarea = new WeakMap();
|
|
34180
34170
|
_textareaDescriptor = new WeakMap();
|
|
34181
|
-
|
|
34182
|
-
_preventEnterKey = new WeakMap();
|
|
34183
|
-
_syncTextOnlyToTextarea = new WeakMap();
|
|
34171
|
+
_textOnlyMode = new WeakMap();
|
|
34184
34172
|
_BgeWysiwygElement_instances = new WeakSet();
|
|
34185
|
-
/**
|
|
34186
|
-
* text-onlyモードを有効化
|
|
34187
|
-
*/
|
|
34188
|
-
activateTextOnlyMode_fn = function() {
|
|
34189
|
-
const currentHTML = this.mode === "wysiwyg" ? __privateGet$1(this, _editor).getHTML().replaceAll("<p></p>", "") : __privateGet$1(this, _textarea).value;
|
|
34190
|
-
if (!__privateGet$1(this, _textOnlyContainer)) {
|
|
34191
|
-
__privateSet$1(this, _textOnlyContainer, document.createElement("div"));
|
|
34192
|
-
__privateGet$1(this, _textOnlyContainer).dataset.textOnlyEditor = "";
|
|
34193
|
-
const modeContainer = this.shadowRoot.querySelector("[data-bge-mode]");
|
|
34194
|
-
modeContainer.insertBefore(__privateGet$1(this, _textOnlyContainer), __privateGet$1(this, _structureChangeMessage));
|
|
34195
|
-
}
|
|
34196
|
-
const textOnlyStyle = document.createElement("style");
|
|
34197
|
-
textOnlyStyle.dataset.textOnlyStyle = "";
|
|
34198
|
-
if (__privateGet$1(this, _previewStyle)) {
|
|
34199
|
-
textOnlyStyle.textContent = __privateGet$1(this, _previewStyle).textContent;
|
|
34200
|
-
}
|
|
34201
|
-
__privateGet$1(this, _textOnlyContainer).innerHTML = currentHTML;
|
|
34202
|
-
__privateGet$1(this, _textOnlyContainer).prepend(textOnlyStyle);
|
|
34203
|
-
__privateMethod(this, _BgeWysiwygElement_instances, identifyEditableElements_fn).call(this, __privateGet$1(this, _textOnlyContainer));
|
|
34204
|
-
__privateMethod(this, _BgeWysiwygElement_instances, attachTextOnlyEventListeners_fn).call(this);
|
|
34205
|
-
this.shadowRoot.querySelector(`[data-bge-mode]`).dataset.bgeMode = "text-only";
|
|
34206
|
-
};
|
|
34207
|
-
/**
|
|
34208
|
-
* text-onlyモード用のイベントリスナーを設定
|
|
34209
|
-
*/
|
|
34210
|
-
attachTextOnlyEventListeners_fn = function() {
|
|
34211
|
-
if (!__privateGet$1(this, _textOnlyContainer)) {
|
|
34212
|
-
return;
|
|
34213
|
-
}
|
|
34214
|
-
const editableElements = __privateGet$1(this, _textOnlyContainer).querySelectorAll(
|
|
34215
|
-
'[contenteditable="plaintext-only"]'
|
|
34216
|
-
);
|
|
34217
|
-
for (const el of editableElements) {
|
|
34218
|
-
el.addEventListener("keydown", __privateGet$1(this, _preventEnterKey));
|
|
34219
|
-
el.addEventListener("input", __privateGet$1(this, _syncTextOnlyToTextarea));
|
|
34220
|
-
}
|
|
34221
|
-
};
|
|
34222
34173
|
checkStructureChange_fn = function() {
|
|
34223
34174
|
if (!__privateGet$1(this, _editor) || !__privateGet$1(this, _textarea) || this.mode !== "html") {
|
|
34224
34175
|
return false;
|
|
@@ -34227,76 +34178,6 @@ checkStructureChange_fn = function() {
|
|
|
34227
34178
|
const isStructureSame = normalizeHtmlStructure(__privateGet$1(this, _textarea).value, expectedHTML);
|
|
34228
34179
|
return !isStructureSame;
|
|
34229
34180
|
};
|
|
34230
|
-
/**
|
|
34231
|
-
* contenteditable属性を削除してクリーンなHTMLを返す
|
|
34232
|
-
* @param html
|
|
34233
|
-
*/
|
|
34234
|
-
cleanTextOnlyHTML_fn = function(html) {
|
|
34235
|
-
if (!__privateGet$1(this, _textOnlyContainer)) {
|
|
34236
|
-
return html;
|
|
34237
|
-
}
|
|
34238
|
-
const clone = __privateGet$1(this, _textOnlyContainer).cloneNode(true);
|
|
34239
|
-
const editableElements = clone.querySelectorAll('[contenteditable="plaintext-only"]');
|
|
34240
|
-
for (const el of editableElements) {
|
|
34241
|
-
el.removeAttribute("contenteditable");
|
|
34242
|
-
}
|
|
34243
|
-
const styleElements = clone.querySelectorAll("[data-text-only-style]");
|
|
34244
|
-
for (const el of styleElements) {
|
|
34245
|
-
el.remove();
|
|
34246
|
-
}
|
|
34247
|
-
return clone.innerHTML;
|
|
34248
|
-
};
|
|
34249
|
-
/**
|
|
34250
|
-
* text-onlyモードを無効化
|
|
34251
|
-
*/
|
|
34252
|
-
deactivateTextOnlyMode_fn = function() {
|
|
34253
|
-
if (!__privateGet$1(this, _textOnlyContainer)) {
|
|
34254
|
-
return;
|
|
34255
|
-
}
|
|
34256
|
-
const editableElements = __privateGet$1(this, _textOnlyContainer).querySelectorAll(
|
|
34257
|
-
'[contenteditable="plaintext-only"]'
|
|
34258
|
-
);
|
|
34259
|
-
for (const el of editableElements) {
|
|
34260
|
-
el.removeEventListener("keydown", __privateGet$1(this, _preventEnterKey));
|
|
34261
|
-
el.removeEventListener("input", __privateGet$1(this, _syncTextOnlyToTextarea));
|
|
34262
|
-
}
|
|
34263
|
-
__privateGet$1(this, _textOnlyContainer).innerHTML = "";
|
|
34264
|
-
};
|
|
34265
|
-
/**
|
|
34266
|
-
* text-onlyモードの値を取得
|
|
34267
|
-
*/
|
|
34268
|
-
getTextOnlyValue_fn = function() {
|
|
34269
|
-
if (!__privateGet$1(this, _textOnlyContainer)) {
|
|
34270
|
-
return __privateGet$1(this, _textarea)?.value ?? "";
|
|
34271
|
-
}
|
|
34272
|
-
return __privateMethod(this, _BgeWysiwygElement_instances, cleanTextOnlyHTML_fn).call(this, "");
|
|
34273
|
-
};
|
|
34274
|
-
/**
|
|
34275
|
-
* 編集可能要素を特定してcontenteditable="plaintext-only"を付与
|
|
34276
|
-
* @param container
|
|
34277
|
-
*/
|
|
34278
|
-
identifyEditableElements_fn = function(container) {
|
|
34279
|
-
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
|
|
34280
|
-
acceptNode: (node) => {
|
|
34281
|
-
const element = node;
|
|
34282
|
-
const hasDirectTextChild = [...element.childNodes].some(
|
|
34283
|
-
(child) => child.nodeType === Node.TEXT_NODE && child.textContent?.trim()
|
|
34284
|
-
);
|
|
34285
|
-
if (hasDirectTextChild) {
|
|
34286
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
34287
|
-
}
|
|
34288
|
-
return NodeFilter.FILTER_SKIP;
|
|
34289
|
-
}
|
|
34290
|
-
});
|
|
34291
|
-
const editableElements = [];
|
|
34292
|
-
let currentNode;
|
|
34293
|
-
while (currentNode = walker.nextNode()) {
|
|
34294
|
-
editableElements.push(currentNode);
|
|
34295
|
-
}
|
|
34296
|
-
for (const el of editableElements) {
|
|
34297
|
-
el.setAttribute("contenteditable", "plaintext-only");
|
|
34298
|
-
}
|
|
34299
|
-
};
|
|
34300
34181
|
setStructureChange_fn = function(hasChange) {
|
|
34301
34182
|
if (__privateGet$1(this, _hasStructureChange) === hasChange) {
|
|
34302
34183
|
return;
|
|
@@ -34311,22 +34192,12 @@ setStructureChange_fn = function(hasChange) {
|
|
|
34311
34192
|
})
|
|
34312
34193
|
);
|
|
34313
34194
|
};
|
|
34314
|
-
/**
|
|
34315
|
-
* text-onlyモードに値を設定
|
|
34316
|
-
* @param value
|
|
34317
|
-
*/
|
|
34318
|
-
setTextOnlyValue_fn = function(value) {
|
|
34319
|
-
__privateMethod(this, _BgeWysiwygElement_instances, deactivateTextOnlyMode_fn).call(this);
|
|
34320
|
-
__privateMethod(this, _BgeWysiwygElement_instances, setToTextarea_fn).call(this, value);
|
|
34321
|
-
__privateMethod(this, _BgeWysiwygElement_instances, activateTextOnlyMode_fn).call(this);
|
|
34322
|
-
};
|
|
34323
34195
|
setToTextarea_fn = function(html) {
|
|
34324
34196
|
if (!__privateGet$1(this, _textarea) || !__privateGet$1(this, _textareaDescriptor)) {
|
|
34325
34197
|
throw new ReferenceError("<bge-wysiwyg> is not connected");
|
|
34326
34198
|
}
|
|
34327
34199
|
__privateGet$1(this, _textareaDescriptor).set?.call(__privateGet$1(this, _textarea), html);
|
|
34328
34200
|
};
|
|
34329
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
34330
34201
|
transaction_fn = function(_editor2) {
|
|
34331
34202
|
const data = {
|
|
34332
34203
|
state: getCurrentEditorState(this)
|
|
@@ -45099,7 +44970,7 @@ function parseConfig(config) {
|
|
|
45099
44970
|
}
|
|
45100
44971
|
}
|
|
45101
44972
|
|
|
45102
|
-
const version = "4.0.0-alpha.
|
|
44973
|
+
const version = "4.0.0-alpha.63";
|
|
45103
44974
|
function attachDraftSwitcher(engine) {
|
|
45104
44975
|
if (engine.hasDraft()) {
|
|
45105
44976
|
const container = document.createElement("div");
|