@b9g/crank 0.4.3 → 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/umd.js CHANGED
@@ -960,13 +960,170 @@
960
960
  provisions.set(key, value);
961
961
  }
962
962
  addEventListener(type, listener, options) {
963
- return addEventListener(this[$ContextImpl], type, listener, options);
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
- return removeEventListener(this[$ContextImpl], type, listener, options);
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
- return dispatchEvent(this[$ContextImpl], ev);
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 addEventListener(ctx, type, listener, options) {
1371
- let listeners;
1372
- if (listener == null) {
1373
- return;
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") {