@b9g/crank 0.4.1 → 0.4.4
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/crank.cjs +167 -169
- package/crank.cjs.map +1 -1
- package/crank.d.ts +0 -4
- package/crank.js +167 -169
- package/crank.js.map +1 -1
- package/dom.cjs +15 -7
- package/dom.cjs.map +1 -1
- package/dom.js +15 -7
- package/dom.js.map +1 -1
- package/html.cjs +8 -5
- package/html.cjs.map +1 -1
- package/html.js +8 -5
- package/html.js.map +1 -1
- package/package.json +13 -13
- package/umd.js +188 -177
- package/umd.js.map +1 -1
package/umd.js
CHANGED
|
@@ -960,13 +960,170 @@
|
|
|
960
960
|
provisions.set(key, value);
|
|
961
961
|
}
|
|
962
962
|
addEventListener(type, listener, options) {
|
|
963
|
-
|
|
963
|
+
const impl = this[$ContextImpl];
|
|
964
|
+
let listeners;
|
|
965
|
+
if (!isListenerOrListenerObject(listener)) {
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
else {
|
|
969
|
+
const listeners1 = listenersMap.get(impl);
|
|
970
|
+
if (listeners1) {
|
|
971
|
+
listeners = listeners1;
|
|
972
|
+
}
|
|
973
|
+
else {
|
|
974
|
+
listeners = [];
|
|
975
|
+
listenersMap.set(impl, listeners);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
options = normalizeListenerOptions(options);
|
|
979
|
+
let callback;
|
|
980
|
+
if (typeof listener === "object") {
|
|
981
|
+
callback = () => listener.handleEvent.apply(listener, arguments);
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
callback = listener;
|
|
985
|
+
}
|
|
986
|
+
const record = { type, callback, listener, options };
|
|
987
|
+
if (options.once) {
|
|
988
|
+
record.callback = function () {
|
|
989
|
+
const i = listeners.indexOf(record);
|
|
990
|
+
if (i !== -1) {
|
|
991
|
+
listeners.splice(i, 1);
|
|
992
|
+
}
|
|
993
|
+
return callback.apply(this, arguments);
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
if (listeners.some((record1) => record.type === record1.type &&
|
|
997
|
+
record.listener === record1.listener &&
|
|
998
|
+
!record.options.capture === !record1.options.capture)) {
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
listeners.push(record);
|
|
1002
|
+
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1003
|
+
for (const value of getChildValues(impl.ret)) {
|
|
1004
|
+
if (isEventTarget(value)) {
|
|
1005
|
+
value.addEventListener(record.type, record.callback, record.options);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
964
1008
|
}
|
|
965
1009
|
removeEventListener(type, listener, options) {
|
|
966
|
-
|
|
1010
|
+
const impl = this[$ContextImpl];
|
|
1011
|
+
const listeners = listenersMap.get(impl);
|
|
1012
|
+
if (listeners == null || !isListenerOrListenerObject(listener)) {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
const options1 = normalizeListenerOptions(options);
|
|
1016
|
+
const i = listeners.findIndex((record) => record.type === type &&
|
|
1017
|
+
record.listener === listener &&
|
|
1018
|
+
!record.options.capture === !options1.capture);
|
|
1019
|
+
if (i === -1) {
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
const record = listeners[i];
|
|
1023
|
+
listeners.splice(i, 1);
|
|
1024
|
+
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1025
|
+
for (const value of getChildValues(impl.ret)) {
|
|
1026
|
+
if (isEventTarget(value)) {
|
|
1027
|
+
value.removeEventListener(record.type, record.callback, record.options);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
967
1030
|
}
|
|
968
1031
|
dispatchEvent(ev) {
|
|
969
|
-
|
|
1032
|
+
const impl = this[$ContextImpl];
|
|
1033
|
+
const path = [];
|
|
1034
|
+
for (let parent = impl.parent; parent !== undefined; parent = parent.parent) {
|
|
1035
|
+
path.push(parent);
|
|
1036
|
+
}
|
|
1037
|
+
// We patch the stopImmediatePropagation method because ev.cancelBubble
|
|
1038
|
+
// only informs us if stopPropagation was called and there are no
|
|
1039
|
+
// properties which inform us if stopImmediatePropagation was called.
|
|
1040
|
+
let immediateCancelBubble = false;
|
|
1041
|
+
const stopImmediatePropagation = ev.stopImmediatePropagation;
|
|
1042
|
+
setEventProperty(ev, "stopImmediatePropagation", () => {
|
|
1043
|
+
immediateCancelBubble = true;
|
|
1044
|
+
return stopImmediatePropagation.call(ev);
|
|
1045
|
+
});
|
|
1046
|
+
setEventProperty(ev, "target", impl.ctx);
|
|
1047
|
+
// The only possible errors in this block are errors thrown by callbacks,
|
|
1048
|
+
// and dispatchEvent will only log these errors rather than throwing
|
|
1049
|
+
// them. Therefore, we place all code in a try block, log errors in the
|
|
1050
|
+
// catch block, and use an unsafe return statement in the finally block.
|
|
1051
|
+
//
|
|
1052
|
+
// Each early return within the try block returns true because while the
|
|
1053
|
+
// return value is overridden in the finally block, TypeScript
|
|
1054
|
+
// (justifiably) does not recognize the unsafe return statement.
|
|
1055
|
+
//
|
|
1056
|
+
// TODO: Run all callbacks even if one of them errors
|
|
1057
|
+
try {
|
|
1058
|
+
setEventProperty(ev, "eventPhase", CAPTURING_PHASE);
|
|
1059
|
+
for (let i = path.length - 1; i >= 0; i--) {
|
|
1060
|
+
const target = path[i];
|
|
1061
|
+
const listeners = listenersMap.get(target);
|
|
1062
|
+
if (listeners) {
|
|
1063
|
+
setEventProperty(ev, "currentTarget", target.ctx);
|
|
1064
|
+
for (const record of listeners) {
|
|
1065
|
+
if (record.type === ev.type && record.options.capture) {
|
|
1066
|
+
record.callback.call(target.ctx, ev);
|
|
1067
|
+
if (immediateCancelBubble) {
|
|
1068
|
+
return true;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
if (ev.cancelBubble) {
|
|
1074
|
+
return true;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
{
|
|
1078
|
+
const listeners = listenersMap.get(impl);
|
|
1079
|
+
if (listeners) {
|
|
1080
|
+
setEventProperty(ev, "eventPhase", AT_TARGET);
|
|
1081
|
+
setEventProperty(ev, "currentTarget", impl.ctx);
|
|
1082
|
+
for (const record of listeners) {
|
|
1083
|
+
if (record.type === ev.type) {
|
|
1084
|
+
record.callback.call(impl.ctx, ev);
|
|
1085
|
+
if (immediateCancelBubble) {
|
|
1086
|
+
return true;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
if (ev.cancelBubble) {
|
|
1091
|
+
return true;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
if (ev.bubbles) {
|
|
1096
|
+
setEventProperty(ev, "eventPhase", BUBBLING_PHASE);
|
|
1097
|
+
for (let i = 0; i < path.length; i++) {
|
|
1098
|
+
const target = path[i];
|
|
1099
|
+
const listeners = listenersMap.get(target);
|
|
1100
|
+
if (listeners) {
|
|
1101
|
+
setEventProperty(ev, "currentTarget", target.ctx);
|
|
1102
|
+
for (const record of listeners) {
|
|
1103
|
+
if (record.type === ev.type && !record.options.capture) {
|
|
1104
|
+
record.callback.call(target.ctx, ev);
|
|
1105
|
+
if (immediateCancelBubble) {
|
|
1106
|
+
return true;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
if (ev.cancelBubble) {
|
|
1112
|
+
return true;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
catch (err) {
|
|
1118
|
+
// TODO: Use setTimeout to rethrow the error.
|
|
1119
|
+
console.error(err);
|
|
1120
|
+
}
|
|
1121
|
+
finally {
|
|
1122
|
+
setEventProperty(ev, "eventPhase", NONE);
|
|
1123
|
+
setEventProperty(ev, "currentTarget", null);
|
|
1124
|
+
// eslint-disable-next-line no-unsafe-finally
|
|
1125
|
+
return !ev.defaultPrevented;
|
|
1126
|
+
}
|
|
970
1127
|
}
|
|
971
1128
|
}
|
|
972
1129
|
/*** PRIVATE CONTEXT FUNCTIONS ***/
|
|
@@ -1367,168 +1524,11 @@
|
|
|
1367
1524
|
const AT_TARGET = 2;
|
|
1368
1525
|
const BUBBLING_PHASE = 3;
|
|
1369
1526
|
const listenersMap = new WeakMap();
|
|
1370
|
-
function
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
else {
|
|
1376
|
-
const listeners1 = listenersMap.get(ctx);
|
|
1377
|
-
if (listeners1) {
|
|
1378
|
-
listeners = listeners1;
|
|
1379
|
-
}
|
|
1380
|
-
else {
|
|
1381
|
-
listeners = [];
|
|
1382
|
-
listenersMap.set(ctx, listeners);
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
options = normalizeListenerOptions(options);
|
|
1386
|
-
let callback;
|
|
1387
|
-
if (typeof listener === "object") {
|
|
1388
|
-
callback = () => listener.handleEvent.apply(listener, arguments);
|
|
1389
|
-
}
|
|
1390
|
-
else {
|
|
1391
|
-
callback = listener;
|
|
1392
|
-
}
|
|
1393
|
-
const record = { type, callback, listener, options };
|
|
1394
|
-
if (options.once) {
|
|
1395
|
-
record.callback = function () {
|
|
1396
|
-
const i = listeners.indexOf(record);
|
|
1397
|
-
if (i !== -1) {
|
|
1398
|
-
listeners.splice(i, 1);
|
|
1399
|
-
}
|
|
1400
|
-
return callback.apply(this, arguments);
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
if (listeners.some((record1) => record.type === record1.type &&
|
|
1404
|
-
record.listener === record1.listener &&
|
|
1405
|
-
!record.options.capture === !record1.options.capture)) {
|
|
1406
|
-
return;
|
|
1407
|
-
}
|
|
1408
|
-
listeners.push(record);
|
|
1409
|
-
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1410
|
-
for (const value of getChildValues(ctx.ret)) {
|
|
1411
|
-
if (isEventTarget(value)) {
|
|
1412
|
-
value.addEventListener(record.type, record.callback, record.options);
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
}
|
|
1416
|
-
function removeEventListener(ctx, type, listener, options) {
|
|
1417
|
-
const listeners = listenersMap.get(ctx);
|
|
1418
|
-
if (listener == null || listeners == null) {
|
|
1419
|
-
return;
|
|
1420
|
-
}
|
|
1421
|
-
const options1 = normalizeListenerOptions(options);
|
|
1422
|
-
const i = listeners.findIndex((record) => record.type === type &&
|
|
1423
|
-
record.listener === listener &&
|
|
1424
|
-
!record.options.capture === !options1.capture);
|
|
1425
|
-
if (i === -1) {
|
|
1426
|
-
return;
|
|
1427
|
-
}
|
|
1428
|
-
const record = listeners[i];
|
|
1429
|
-
listeners.splice(i, 1);
|
|
1430
|
-
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1431
|
-
for (const value of getChildValues(ctx.ret)) {
|
|
1432
|
-
if (isEventTarget(value)) {
|
|
1433
|
-
value.removeEventListener(record.type, record.callback, record.options);
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
function dispatchEvent(ctx, ev) {
|
|
1438
|
-
const path = [];
|
|
1439
|
-
for (let parent = ctx.parent; parent !== undefined; parent = parent.parent) {
|
|
1440
|
-
path.push(parent);
|
|
1441
|
-
}
|
|
1442
|
-
// We patch the stopImmediatePropagation method because ev.cancelBubble
|
|
1443
|
-
// only informs us if stopPropagation was called and there are no
|
|
1444
|
-
// properties which inform us if stopImmediatePropagation was called.
|
|
1445
|
-
let immediateCancelBubble = false;
|
|
1446
|
-
const stopImmediatePropagation = ev.stopImmediatePropagation;
|
|
1447
|
-
setEventProperty(ev, "stopImmediatePropagation", () => {
|
|
1448
|
-
immediateCancelBubble = true;
|
|
1449
|
-
return stopImmediatePropagation.call(ev);
|
|
1450
|
-
});
|
|
1451
|
-
setEventProperty(ev, "target", ctx.ctx);
|
|
1452
|
-
// The only possible errors in this block are errors thrown by callbacks,
|
|
1453
|
-
// and dispatchEvent will only log these errors rather than throwing
|
|
1454
|
-
// them. Therefore, we place all code in a try block, log errors in the
|
|
1455
|
-
// catch block, and use an unsafe return statement in the finally block.
|
|
1456
|
-
//
|
|
1457
|
-
// Each early return within the try block returns true because while the
|
|
1458
|
-
// return value is overridden in the finally block, TypeScript
|
|
1459
|
-
// (justifiably) does not recognize the unsafe return statement.
|
|
1460
|
-
//
|
|
1461
|
-
// TODO: Run all callbacks even if one of them errors
|
|
1462
|
-
try {
|
|
1463
|
-
setEventProperty(ev, "eventPhase", CAPTURING_PHASE);
|
|
1464
|
-
for (let i = path.length - 1; i >= 0; i--) {
|
|
1465
|
-
const target = path[i];
|
|
1466
|
-
const listeners = listenersMap.get(target);
|
|
1467
|
-
if (listeners) {
|
|
1468
|
-
setEventProperty(ev, "currentTarget", target.ctx);
|
|
1469
|
-
for (const record of listeners) {
|
|
1470
|
-
if (record.type === ev.type && record.options.capture) {
|
|
1471
|
-
record.callback.call(target.ctx, ev);
|
|
1472
|
-
if (immediateCancelBubble) {
|
|
1473
|
-
return true;
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
if (ev.cancelBubble) {
|
|
1479
|
-
return true;
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
{
|
|
1483
|
-
const listeners = listenersMap.get(ctx);
|
|
1484
|
-
if (listeners) {
|
|
1485
|
-
setEventProperty(ev, "eventPhase", AT_TARGET);
|
|
1486
|
-
setEventProperty(ev, "currentTarget", ctx.ctx);
|
|
1487
|
-
for (const record of listeners) {
|
|
1488
|
-
if (record.type === ev.type) {
|
|
1489
|
-
record.callback.call(ctx.ctx, ev);
|
|
1490
|
-
if (immediateCancelBubble) {
|
|
1491
|
-
return true;
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
if (ev.cancelBubble) {
|
|
1496
|
-
return true;
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
if (ev.bubbles) {
|
|
1501
|
-
setEventProperty(ev, "eventPhase", BUBBLING_PHASE);
|
|
1502
|
-
for (let i = 0; i < path.length; i++) {
|
|
1503
|
-
const target = path[i];
|
|
1504
|
-
const listeners = listenersMap.get(target);
|
|
1505
|
-
if (listeners) {
|
|
1506
|
-
setEventProperty(ev, "currentTarget", target.ctx);
|
|
1507
|
-
for (const record of listeners) {
|
|
1508
|
-
if (record.type === ev.type && !record.options.capture) {
|
|
1509
|
-
record.callback.call(target.ctx, ev);
|
|
1510
|
-
if (immediateCancelBubble) {
|
|
1511
|
-
return true;
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
if (ev.cancelBubble) {
|
|
1517
|
-
return true;
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
catch (err) {
|
|
1523
|
-
// TODO: Use setTimeout to rethrow the error.
|
|
1524
|
-
console.error(err);
|
|
1525
|
-
}
|
|
1526
|
-
finally {
|
|
1527
|
-
setEventProperty(ev, "eventPhase", NONE);
|
|
1528
|
-
setEventProperty(ev, "currentTarget", null);
|
|
1529
|
-
// eslint-disable-next-line no-unsafe-finally
|
|
1530
|
-
return !ev.defaultPrevented;
|
|
1531
|
-
}
|
|
1527
|
+
function isListenerOrListenerObject(value) {
|
|
1528
|
+
return (typeof value === "function" ||
|
|
1529
|
+
(value !== null &&
|
|
1530
|
+
typeof value === "object" &&
|
|
1531
|
+
typeof value.handleEvent === "function"));
|
|
1532
1532
|
}
|
|
1533
1533
|
function normalizeListenerOptions(options) {
|
|
1534
1534
|
if (typeof options === "boolean") {
|
|
@@ -1739,16 +1739,24 @@
|
|
|
1739
1739
|
// falsy properties, so we use attributes in this case.
|
|
1740
1740
|
!(typeof value === "string" &&
|
|
1741
1741
|
typeof node[name] === "boolean")) {
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1742
|
+
// walk up the object's prototype chain to find the owner of the
|
|
1743
|
+
// named property
|
|
1744
|
+
let obj = node;
|
|
1745
|
+
do {
|
|
1746
|
+
if (Object.prototype.hasOwnProperty.call(obj, name)) {
|
|
1747
|
+
break;
|
|
1745
1748
|
}
|
|
1749
|
+
} while ((obj = Object.getPrototypeOf(obj)));
|
|
1750
|
+
// get the descriptor for the named property and check whether it
|
|
1751
|
+
// implies that the property is writable
|
|
1752
|
+
const descriptor = Object.getOwnPropertyDescriptor(obj, name);
|
|
1753
|
+
if (descriptor != null &&
|
|
1754
|
+
(descriptor.writable === true || descriptor.set !== undefined)) {
|
|
1755
|
+
node[name] = value;
|
|
1746
1756
|
return;
|
|
1747
1757
|
}
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
// attributes
|
|
1751
|
-
}
|
|
1758
|
+
// if the property wasn't writable, fall through to the code below
|
|
1759
|
+
// which uses setAttribute() instead of assigning directly.
|
|
1752
1760
|
}
|
|
1753
1761
|
if (value === true) {
|
|
1754
1762
|
value = "";
|
|
@@ -1904,19 +1912,22 @@
|
|
|
1904
1912
|
case name === "children":
|
|
1905
1913
|
case name === "innerHTML":
|
|
1906
1914
|
break;
|
|
1907
|
-
case name === "style":
|
|
1915
|
+
case name === "style": {
|
|
1908
1916
|
if (typeof value === "string") {
|
|
1909
1917
|
attrs.push(`style="${escape(value)}"`);
|
|
1910
1918
|
}
|
|
1911
|
-
else {
|
|
1919
|
+
else if (typeof value === "object") {
|
|
1912
1920
|
attrs.push(`style="${escape(printStyleObject(value))}"`);
|
|
1913
1921
|
}
|
|
1914
1922
|
break;
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1923
|
+
}
|
|
1924
|
+
case name === "className": {
|
|
1925
|
+
if ("class" in props || typeof value !== "string") {
|
|
1926
|
+
continue;
|
|
1918
1927
|
}
|
|
1928
|
+
attrs.push(`class="${escape(value)}"`);
|
|
1919
1929
|
break;
|
|
1930
|
+
}
|
|
1920
1931
|
case typeof value === "string":
|
|
1921
1932
|
attrs.push(`${escape(name)}="${escape(value)}"`);
|
|
1922
1933
|
break;
|