@angular/core 18.0.0-rc.1 → 18.0.0-rc.3
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/esm2022/primitives/event-dispatch/contract_binary.mjs +3 -3
- package/esm2022/primitives/event-dispatch/index.mjs +2 -2
- package/esm2022/primitives/event-dispatch/src/action_resolver.mjs +8 -17
- package/esm2022/primitives/event-dispatch/src/attribute.mjs +52 -65
- package/esm2022/primitives/event-dispatch/src/cache.mjs +6 -39
- package/esm2022/primitives/event-dispatch/src/dispatcher.mjs +56 -200
- package/esm2022/primitives/event-dispatch/src/earlyeventcontract.mjs +4 -4
- package/esm2022/primitives/event-dispatch/src/event_contract_defines.mjs +1 -6
- package/esm2022/primitives/event-dispatch/src/event_info.mjs +16 -1
- package/esm2022/primitives/event-dispatch/src/eventcontract.mjs +13 -30
- package/esm2022/primitives/event-dispatch/src/key_code.mjs +11 -13
- package/esm2022/primitives/event-dispatch/src/property.mjs +24 -27
- package/esm2022/primitives/event-dispatch/src/register_events.mjs +5 -25
- package/esm2022/primitives/event-dispatch/src/restriction.mjs +2 -2
- package/esm2022/src/application/create_application.mjs +11 -4
- package/esm2022/src/change_detection/scheduling/exhaustive_check_no_changes.mjs +5 -5
- package/esm2022/src/change_detection/scheduling/ng_zone_scheduling.mjs +4 -16
- package/esm2022/src/change_detection/scheduling/zoneless_scheduling.mjs +3 -1
- package/esm2022/src/change_detection/scheduling/zoneless_scheduling_impl.mjs +12 -3
- package/esm2022/src/core_reactivity_export_internal.mjs +1 -3
- package/esm2022/src/core_render3_private_export.mjs +1 -3
- package/esm2022/src/errors.mjs +1 -1
- package/esm2022/src/hydration/event_replay.mjs +55 -82
- package/esm2022/src/hydration/utils.mjs +1 -2
- package/esm2022/src/metadata/directives.mjs +1 -1
- package/esm2022/src/platform/platform_ref.mjs +9 -10
- package/esm2022/src/render3/component_ref.mjs +1 -1
- package/esm2022/src/render3/index.mjs +1 -3
- package/esm2022/src/render3/instructions/change_detection.mjs +17 -6
- package/esm2022/src/render3/instructions/listener.mjs +3 -3
- package/esm2022/src/render3/interfaces/public_definitions.mjs +1 -1
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/testing/src/component_fixture.mjs +2 -2
- package/esm2022/testing/src/logger.mjs +3 -3
- package/esm2022/testing/src/test_bed.mjs +1 -3
- package/esm2022/testing/src/test_bed_compiler.mjs +1 -3
- package/event-dispatch-contract.min.js +1 -1
- package/fesm2022/core.mjs +108 -124
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/event-dispatch.mjs +250 -563
- package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
- package/fesm2022/primitives/signals.mjs +1 -1
- package/fesm2022/rxjs-interop.mjs +1 -1
- package/fesm2022/testing.mjs +2 -4
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +6 -3
- package/package.json +1 -1
- package/primitives/event-dispatch/index.d.ts +96 -132
- package/primitives/signals/index.d.ts +1 -1
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/migrations/http-providers/bundle.js +46 -29
- package/schematics/migrations/http-providers/bundle.js.map +3 -3
- package/schematics/migrations/invalid-two-way-bindings/bundle.js +163 -159
- package/schematics/migrations/invalid-two-way-bindings/bundle.js.map +3 -3
- package/schematics/ng-generate/control-flow-migration/bundle.js +171 -167
- package/schematics/ng-generate/control-flow-migration/bundle.js.map +3 -3
- package/schematics/ng-generate/standalone-migration/bundle.js +471 -452
- package/schematics/ng-generate/standalone-migration/bundle.js.map +3 -3
- package/testing/index.d.ts +1 -1
- package/esm2022/primitives/event-dispatch/src/base_dispatcher.mjs +0 -94
- package/esm2022/primitives/event-dispatch/src/custom_events.mjs +0 -102
- package/esm2022/primitives/event-dispatch/src/legacy_dispatcher.mjs +0 -9
- package/esm2022/primitives/event-dispatch/src/replay.mjs +0 -389
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v18.0.0-rc.
|
|
2
|
+
* @license Angular v18.0.0-rc.3
|
|
3
3
|
* (c) 2010-2024 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -80,6 +80,14 @@ function getA11yClickKey(eventInfo) {
|
|
|
80
80
|
function setA11yClickKey(eventInfo, a11yClickKey) {
|
|
81
81
|
eventInfo.eiack = a11yClickKey;
|
|
82
82
|
}
|
|
83
|
+
/** Added for readability when accessing stable property names. */
|
|
84
|
+
function getResolved(eventInfo) {
|
|
85
|
+
return eventInfo.eir;
|
|
86
|
+
}
|
|
87
|
+
/** Added for readability when accessing stable property names. */
|
|
88
|
+
function setResolved(eventInfo, resolved) {
|
|
89
|
+
eventInfo.eir = resolved;
|
|
90
|
+
}
|
|
83
91
|
/** Clones an `EventInfo` */
|
|
84
92
|
function cloneEventInfo(eventInfo) {
|
|
85
93
|
return {
|
|
@@ -91,6 +99,7 @@ function cloneEventInfo(eventInfo) {
|
|
|
91
99
|
timeStamp: eventInfo.timeStamp,
|
|
92
100
|
eirp: eventInfo.eirp,
|
|
93
101
|
eiack: eventInfo.eiack,
|
|
102
|
+
eir: eventInfo.eir,
|
|
94
103
|
};
|
|
95
104
|
}
|
|
96
105
|
/**
|
|
@@ -191,171 +200,15 @@ class EventInfoWrapper {
|
|
|
191
200
|
setIsReplay(replay) {
|
|
192
201
|
setIsReplay(this.eventInfo, replay);
|
|
193
202
|
}
|
|
194
|
-
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @fileoverview An enum to control who can call certain jsaction APIs.
|
|
201
|
-
*/
|
|
202
|
-
var Restriction;
|
|
203
|
-
(function (Restriction) {
|
|
204
|
-
Restriction[Restriction["I_AM_THE_JSACTION_FRAMEWORK"] = 1] = "I_AM_THE_JSACTION_FRAMEWORK";
|
|
205
|
-
})(Restriction || (Restriction = {}));
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Receives a DOM event, determines the jsaction associated with the source
|
|
209
|
-
* element of the DOM event, and invokes the handler associated with the
|
|
210
|
-
* jsaction.
|
|
211
|
-
*/
|
|
212
|
-
class BaseDispatcher {
|
|
213
|
-
/**
|
|
214
|
-
* Options are:
|
|
215
|
-
* 1. `eventReplayer`: When the event contract dispatches replay events
|
|
216
|
-
* to the Dispatcher, the Dispatcher collects them and in the next tick
|
|
217
|
-
* dispatches them to the `eventReplayer`.
|
|
218
|
-
* @param dispatchDelegate A function that should handle dispatching an `EventInfoWrapper` to handlers.
|
|
219
|
-
*/
|
|
220
|
-
constructor(dispatchDelegate, { eventReplayer = undefined } = {}) {
|
|
221
|
-
this.dispatchDelegate = dispatchDelegate;
|
|
222
|
-
/** The queue of events. */
|
|
223
|
-
this.queuedEventInfoWrappers = [];
|
|
224
|
-
/** Whether the event replay is scheduled. */
|
|
225
|
-
this.eventReplayScheduled = false;
|
|
226
|
-
this.eventReplayer = eventReplayer;
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Receives an event or the event queue from the EventContract. The event
|
|
230
|
-
* queue is copied and it attempts to replay.
|
|
231
|
-
* If event info is passed in it looks for an action handler that can handle
|
|
232
|
-
* the given event. If there is no handler registered queues the event and
|
|
233
|
-
* checks if a loader is registered for the given namespace. If so, calls it.
|
|
234
|
-
*
|
|
235
|
-
* Alternatively, if in global dispatch mode, calls all registered global
|
|
236
|
-
* handlers for the appropriate event type.
|
|
237
|
-
*
|
|
238
|
-
* The three functionalities of this call are deliberately not split into
|
|
239
|
-
* three methods (and then declared as an abstract interface), because the
|
|
240
|
-
* interface is used by EventContract, which lives in a different jsbinary.
|
|
241
|
-
* Therefore the interface between the three is defined entirely in terms that
|
|
242
|
-
* are invariant under jscompiler processing (Function and Array, as opposed
|
|
243
|
-
* to a custom type with method names).
|
|
244
|
-
*
|
|
245
|
-
* @param eventInfo The info for the event that triggered this call or the
|
|
246
|
-
* queue of events from EventContract.
|
|
247
|
-
*/
|
|
248
|
-
dispatch(eventInfo) {
|
|
249
|
-
const eventInfoWrapper = new EventInfoWrapper(eventInfo);
|
|
250
|
-
if (eventInfoWrapper.getIsReplay()) {
|
|
251
|
-
if (!this.eventReplayer) {
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
this.queueEventInfoWrapper(eventInfoWrapper);
|
|
255
|
-
this.scheduleEventReplay();
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
this.dispatchDelegate(eventInfoWrapper);
|
|
259
|
-
}
|
|
260
|
-
/** Queue an `EventInfoWrapper` for replay. */
|
|
261
|
-
queueEventInfoWrapper(eventInfoWrapper) {
|
|
262
|
-
this.queuedEventInfoWrappers.push(eventInfoWrapper);
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Replays queued events, if any. The replaying will happen in its own
|
|
266
|
-
* stack once the current flow cedes control. This is done to mimic
|
|
267
|
-
* browser event handling.
|
|
268
|
-
*/
|
|
269
|
-
scheduleEventReplay() {
|
|
270
|
-
if (this.eventReplayScheduled ||
|
|
271
|
-
!this.eventReplayer ||
|
|
272
|
-
this.queuedEventInfoWrappers.length === 0) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
this.eventReplayScheduled = true;
|
|
276
|
-
Promise.resolve().then(() => {
|
|
277
|
-
this.eventReplayScheduled = false;
|
|
278
|
-
this.eventReplayer(this.queuedEventInfoWrappers);
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Registers deferred functionality for an EventContract and a Jsaction
|
|
284
|
-
* Dispatcher.
|
|
285
|
-
*/
|
|
286
|
-
function registerDispatcher$1(eventContract, dispatcher) {
|
|
287
|
-
eventContract.ecrd((eventInfo) => {
|
|
288
|
-
dispatcher.dispatch(eventInfo);
|
|
289
|
-
}, Restriction.I_AM_THE_JSACTION_FRAMEWORK);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const Char = {
|
|
293
|
-
/**
|
|
294
|
-
* The separator between the namespace and the action name in the
|
|
295
|
-
* jsaction attribute value.
|
|
296
|
-
*/
|
|
297
|
-
NAMESPACE_ACTION_SEPARATOR: '.',
|
|
298
|
-
/**
|
|
299
|
-
* The separator between the event name and action in the jsaction
|
|
300
|
-
* attribute value.
|
|
301
|
-
*/
|
|
302
|
-
EVENT_ACTION_SEPARATOR: ':',
|
|
303
|
-
/**
|
|
304
|
-
* The separator between the logged oi attribute values in the &oi=
|
|
305
|
-
* URL parameter value.
|
|
306
|
-
*/
|
|
307
|
-
OI_SEPARATOR: '.',
|
|
308
|
-
/**
|
|
309
|
-
* The separator between the key and the value pairs in the &cad=
|
|
310
|
-
* URL parameter value.
|
|
311
|
-
*/
|
|
312
|
-
CAD_KEY_VALUE_SEPARATOR: ':',
|
|
313
|
-
/**
|
|
314
|
-
* The separator between the key-value pairs in the &cad= URL
|
|
315
|
-
* parameter value.
|
|
316
|
-
*/
|
|
317
|
-
CAD_SEPARATOR: ',',
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Determines if one node is contained within another. Adapted from
|
|
322
|
-
* {@see goog.dom.contains}.
|
|
323
|
-
* @param node Node that should contain otherNode.
|
|
324
|
-
* @param otherNode Node being contained.
|
|
325
|
-
* @return True if otherNode is contained within node.
|
|
326
|
-
*/
|
|
327
|
-
function contains(node, otherNode) {
|
|
328
|
-
if (otherNode === null) {
|
|
329
|
-
return false;
|
|
330
|
-
}
|
|
331
|
-
// We use browser specific methods for this if available since it is faster
|
|
332
|
-
// that way.
|
|
333
|
-
// IE DOM
|
|
334
|
-
if ('contains' in node && otherNode.nodeType === 1) {
|
|
335
|
-
return node.contains(otherNode);
|
|
336
|
-
}
|
|
337
|
-
// W3C DOM Level 3
|
|
338
|
-
if ('compareDocumentPosition' in node) {
|
|
339
|
-
return node === otherNode || Boolean(node.compareDocumentPosition(otherNode) & 16);
|
|
203
|
+
getResolved() {
|
|
204
|
+
return getResolved(this.eventInfo);
|
|
340
205
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
otherNode = otherNode.parentNode;
|
|
206
|
+
setResolved(resolved) {
|
|
207
|
+
setResolved(this.eventInfo, resolved);
|
|
344
208
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Helper method for broadcastCustomEvent. Returns true if any member of
|
|
349
|
-
* the set is an ancestor of element.
|
|
350
|
-
*/
|
|
351
|
-
function hasAncestorInNodeList(element, nodeList) {
|
|
352
|
-
for (let idx = 0; idx < nodeList.length; ++idx) {
|
|
353
|
-
const member = nodeList[idx];
|
|
354
|
-
if (member !== element && contains(member, element)) {
|
|
355
|
-
return true;
|
|
356
|
-
}
|
|
209
|
+
clone() {
|
|
210
|
+
return new EventInfoWrapper(cloneEventInfo(this.eventInfo));
|
|
357
211
|
}
|
|
358
|
-
return false;
|
|
359
212
|
}
|
|
360
213
|
|
|
361
214
|
/*
|
|
@@ -595,19 +448,66 @@ const EventType = {
|
|
|
595
448
|
CUSTOM: '_custom',
|
|
596
449
|
};
|
|
597
450
|
|
|
451
|
+
/**
|
|
452
|
+
* @fileoverview An enum to control who can call certain jsaction APIs.
|
|
453
|
+
*/
|
|
454
|
+
var Restriction;
|
|
455
|
+
(function (Restriction) {
|
|
456
|
+
Restriction[Restriction["I_AM_THE_JSACTION_FRAMEWORK"] = 0] = "I_AM_THE_JSACTION_FRAMEWORK";
|
|
457
|
+
})(Restriction || (Restriction = {}));
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Determines if one node is contained within another. Adapted from
|
|
461
|
+
* {@see goog.dom.contains}.
|
|
462
|
+
* @param node Node that should contain otherNode.
|
|
463
|
+
* @param otherNode Node being contained.
|
|
464
|
+
* @return True if otherNode is contained within node.
|
|
465
|
+
*/
|
|
466
|
+
function contains(node, otherNode) {
|
|
467
|
+
if (otherNode === null) {
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
// We use browser specific methods for this if available since it is faster
|
|
471
|
+
// that way.
|
|
472
|
+
// IE DOM
|
|
473
|
+
if ('contains' in node && otherNode.nodeType === 1) {
|
|
474
|
+
return node.contains(otherNode);
|
|
475
|
+
}
|
|
476
|
+
// W3C DOM Level 3
|
|
477
|
+
if ('compareDocumentPosition' in node) {
|
|
478
|
+
return node === otherNode || Boolean(node.compareDocumentPosition(otherNode) & 16);
|
|
479
|
+
}
|
|
480
|
+
// W3C DOM Level 1
|
|
481
|
+
while (otherNode && node !== otherNode) {
|
|
482
|
+
otherNode = otherNode.parentNode;
|
|
483
|
+
}
|
|
484
|
+
return otherNode === node;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Helper method for broadcastCustomEvent. Returns true if any member of
|
|
488
|
+
* the set is an ancestor of element.
|
|
489
|
+
*/
|
|
490
|
+
function hasAncestorInNodeList(element, nodeList) {
|
|
491
|
+
for (let idx = 0; idx < nodeList.length; ++idx) {
|
|
492
|
+
const member = nodeList[idx];
|
|
493
|
+
if (member !== element && contains(member, element)) {
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* If on a Macintosh with an extended keyboard, the Enter key located in the
|
|
502
|
+
* numeric pad has a different ASCII code.
|
|
503
|
+
*/
|
|
504
|
+
const MAC_ENTER = 3;
|
|
505
|
+
/** The Enter key. */
|
|
506
|
+
const ENTER = 13;
|
|
507
|
+
/** The Space key. */
|
|
508
|
+
const SPACE = 32;
|
|
598
509
|
/** Special keycodes used by jsaction for the generic click action. */
|
|
599
|
-
|
|
600
|
-
(function (KeyCode) {
|
|
601
|
-
/**
|
|
602
|
-
* If on a Macintosh with an extended keyboard, the Enter key located in the
|
|
603
|
-
* numeric pad has a different ASCII code.
|
|
604
|
-
*/
|
|
605
|
-
KeyCode[KeyCode["MAC_ENTER"] = 3] = "MAC_ENTER";
|
|
606
|
-
/** The Enter key. */
|
|
607
|
-
KeyCode[KeyCode["ENTER"] = 13] = "ENTER";
|
|
608
|
-
/** The Space key. */
|
|
609
|
-
KeyCode[KeyCode["SPACE"] = 32] = "SPACE";
|
|
610
|
-
})(KeyCode || (KeyCode = {}));
|
|
510
|
+
const KeyCode = { MAC_ENTER, ENTER, SPACE };
|
|
611
511
|
|
|
612
512
|
/**
|
|
613
513
|
* Gets a browser event type, if it would differ from the JSAction event type.
|
|
@@ -691,7 +591,7 @@ function removeEventListener(element, info) {
|
|
|
691
591
|
* Cancels propagation of an event.
|
|
692
592
|
* @param e The event to cancel propagation for.
|
|
693
593
|
*/
|
|
694
|
-
function stopPropagation
|
|
594
|
+
function stopPropagation(e) {
|
|
695
595
|
e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
|
|
696
596
|
}
|
|
697
597
|
/**
|
|
@@ -1244,32 +1144,20 @@ const testing = {
|
|
|
1244
1144
|
*/
|
|
1245
1145
|
class Dispatcher {
|
|
1246
1146
|
/**
|
|
1247
|
-
*
|
|
1248
|
-
*
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1251
|
-
* @param
|
|
1252
|
-
* given event info.
|
|
1147
|
+
* Options are:
|
|
1148
|
+
* - `eventReplayer`: When the event contract dispatches replay events
|
|
1149
|
+
* to the Dispatcher, the Dispatcher collects them and in the next tick
|
|
1150
|
+
* dispatches them to the `eventReplayer`. Defaults to dispatching to `dispatchDelegate`.
|
|
1151
|
+
* @param dispatchDelegate A function that should handle dispatching an `EventInfoWrapper` to handlers.
|
|
1253
1152
|
*/
|
|
1254
|
-
constructor(
|
|
1255
|
-
this.
|
|
1256
|
-
/**
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
this.actions = {};
|
|
1262
|
-
/** A map of global event handlers, where each key is an event type. */
|
|
1263
|
-
this.globalHandlers = new Map();
|
|
1153
|
+
constructor(dispatchDelegate, { actionResolver, eventReplayer = createEventReplayer(dispatchDelegate), } = {}) {
|
|
1154
|
+
this.dispatchDelegate = dispatchDelegate;
|
|
1155
|
+
/** Whether the event replay is scheduled. */
|
|
1156
|
+
this.eventReplayScheduled = false;
|
|
1157
|
+
/** The queue of events. */
|
|
1158
|
+
this.replayEventInfoWrappers = [];
|
|
1159
|
+
this.actionResolver = actionResolver;
|
|
1264
1160
|
this.eventReplayer = eventReplayer;
|
|
1265
|
-
this.baseDispatcher = new BaseDispatcher((eventInfoWrapper) => {
|
|
1266
|
-
this.dispatchToHandler(eventInfoWrapper);
|
|
1267
|
-
}, {
|
|
1268
|
-
eventReplayer: (eventInfoWrappers) => {
|
|
1269
|
-
this.eventReplayer?.(eventInfoWrappers, this);
|
|
1270
|
-
},
|
|
1271
|
-
});
|
|
1272
|
-
this.stopPropagation = stopPropagation;
|
|
1273
1161
|
}
|
|
1274
1162
|
/**
|
|
1275
1163
|
* Receives an event or the event queue from the EventContract. The event
|
|
@@ -1291,189 +1179,58 @@ class Dispatcher {
|
|
|
1291
1179
|
* @param eventInfo The info for the event that triggered this call or the
|
|
1292
1180
|
* queue of events from EventContract.
|
|
1293
1181
|
*/
|
|
1294
|
-
dispatch(eventInfo
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
/**
|
|
1298
|
-
* Dispatches an `EventInfoWrapper`.
|
|
1299
|
-
*/
|
|
1300
|
-
dispatchToHandler(eventInfoWrapper) {
|
|
1301
|
-
if (this.globalHandlers.size) {
|
|
1302
|
-
const globalEventInfoWrapper = eventInfoWrapper.clone();
|
|
1303
|
-
// In some cases, `populateAction` will rewrite `click` events to
|
|
1304
|
-
// `clickonly`. Revert back to a regular click, otherwise we won't be able
|
|
1305
|
-
// to execute global event handlers registered on click events.
|
|
1306
|
-
if (globalEventInfoWrapper.getEventType() === EventType.CLICKONLY) {
|
|
1307
|
-
globalEventInfoWrapper.setEventType(EventType.CLICK);
|
|
1308
|
-
}
|
|
1309
|
-
// Skip everything related to jsaction handlers, and execute the global
|
|
1310
|
-
// handlers.
|
|
1311
|
-
const event = globalEventInfoWrapper.getEvent();
|
|
1312
|
-
const eventTypeHandlers = this.globalHandlers.get(globalEventInfoWrapper.getEventType());
|
|
1313
|
-
let shouldPreventDefault = false;
|
|
1314
|
-
if (eventTypeHandlers) {
|
|
1315
|
-
for (const handler of eventTypeHandlers) {
|
|
1316
|
-
if (handler(event) === false) {
|
|
1317
|
-
shouldPreventDefault = true;
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
if (shouldPreventDefault) {
|
|
1322
|
-
preventDefault(event);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1182
|
+
dispatch(eventInfo) {
|
|
1183
|
+
const eventInfoWrapper = new EventInfoWrapper(eventInfo);
|
|
1184
|
+
this.actionResolver?.resolve(eventInfo);
|
|
1325
1185
|
const action = eventInfoWrapper.getAction();
|
|
1326
|
-
if (
|
|
1327
|
-
|
|
1328
|
-
}
|
|
1329
|
-
if (this.stopPropagation) {
|
|
1330
|
-
stopPropagation(eventInfoWrapper);
|
|
1331
|
-
}
|
|
1332
|
-
let handler = undefined;
|
|
1333
|
-
if (this.getHandler) {
|
|
1334
|
-
handler = this.getHandler(eventInfoWrapper);
|
|
1186
|
+
if (action && shouldPreventDefaultBeforeDispatching(action.element, eventInfoWrapper)) {
|
|
1187
|
+
preventDefault(eventInfoWrapper.getEvent());
|
|
1335
1188
|
}
|
|
1336
|
-
if (
|
|
1337
|
-
|
|
1338
|
-
}
|
|
1339
|
-
if (handler) {
|
|
1340
|
-
handler(eventInfoWrapper);
|
|
1189
|
+
if (eventInfoWrapper.getIsReplay()) {
|
|
1190
|
+
this.scheduleEventInfoWrapperReplay(eventInfoWrapper);
|
|
1341
1191
|
return;
|
|
1342
1192
|
}
|
|
1343
|
-
|
|
1344
|
-
this.baseDispatcher.queueEventInfoWrapper(eventInfoWrapper);
|
|
1345
|
-
}
|
|
1346
|
-
/**
|
|
1347
|
-
* Registers multiple methods all bound to the same object
|
|
1348
|
-
* instance. This is a common case: an application module binds
|
|
1349
|
-
* multiple of its methods under public names to the event contract of
|
|
1350
|
-
* the application. So we provide a shortcut for it.
|
|
1351
|
-
* Attempts to replay the queued events after registering the handlers.
|
|
1352
|
-
*
|
|
1353
|
-
* @param namespace The namespace of the jsaction name.
|
|
1354
|
-
*
|
|
1355
|
-
* @param instance The object to bind the methods to. If this is null, then
|
|
1356
|
-
* the functions are not bound, but directly added under the public names.
|
|
1357
|
-
*
|
|
1358
|
-
* @param methods A map from public name to functions that will be bound to
|
|
1359
|
-
* instance and registered as action under the public name. I.e. the
|
|
1360
|
-
* property names are the public names. The property values are the
|
|
1361
|
-
* methods of instance.
|
|
1362
|
-
*/
|
|
1363
|
-
registerEventInfoHandlers(namespace, instance, methods) {
|
|
1364
|
-
for (const [name, method] of Object.entries(methods)) {
|
|
1365
|
-
const handler = instance ? method.bind(instance) : method;
|
|
1366
|
-
if (namespace) {
|
|
1367
|
-
// Include a '.' separator between namespace name and action name.
|
|
1368
|
-
// In the case that no namespace name is provided, the jsaction name
|
|
1369
|
-
// consists of the action name only (no period).
|
|
1370
|
-
const fullName = namespace + Char.NAMESPACE_ACTION_SEPARATOR + name;
|
|
1371
|
-
this.actions[fullName] = handler;
|
|
1372
|
-
}
|
|
1373
|
-
else {
|
|
1374
|
-
this.actions[name] = handler;
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
this.baseDispatcher.scheduleEventReplay();
|
|
1193
|
+
this.dispatchDelegate(eventInfoWrapper);
|
|
1378
1194
|
}
|
|
1379
1195
|
/**
|
|
1380
|
-
*
|
|
1381
|
-
*
|
|
1382
|
-
*
|
|
1383
|
-
* @param name The action name to unbind.
|
|
1196
|
+
* Schedules an `EventInfoWrapper` for replay. The replaying will happen in its own
|
|
1197
|
+
* stack once the current flow cedes control. This is done to mimic
|
|
1198
|
+
* browser event handling.
|
|
1384
1199
|
*/
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
/** Registers a global event handler. */
|
|
1390
|
-
registerGlobalHandler(eventType, handler) {
|
|
1391
|
-
if (!this.globalHandlers.has(eventType)) {
|
|
1392
|
-
this.globalHandlers.set(eventType, new Set([handler]));
|
|
1393
|
-
}
|
|
1394
|
-
else {
|
|
1395
|
-
this.globalHandlers.get(eventType).add(handler);
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
/** Unregisters a global event handler. */
|
|
1399
|
-
unregisterGlobalHandler(eventType, handler) {
|
|
1400
|
-
if (this.globalHandlers.has(eventType)) {
|
|
1401
|
-
this.globalHandlers.get(eventType).delete(handler);
|
|
1200
|
+
scheduleEventInfoWrapperReplay(eventInfoWrapper) {
|
|
1201
|
+
this.replayEventInfoWrappers.push(eventInfoWrapper);
|
|
1202
|
+
if (this.eventReplayScheduled) {
|
|
1203
|
+
return;
|
|
1402
1204
|
}
|
|
1205
|
+
this.eventReplayScheduled = true;
|
|
1206
|
+
Promise.resolve().then(() => {
|
|
1207
|
+
this.eventReplayScheduled = false;
|
|
1208
|
+
this.eventReplayer(this.replayEventInfoWrappers);
|
|
1209
|
+
});
|
|
1403
1210
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
hasAction(name) {
|
|
1414
|
-
return this.actions.hasOwnProperty(name);
|
|
1415
|
-
}
|
|
1416
|
-
/**
|
|
1417
|
-
* Whether this dispatcher can dispatch the event. This can be used by
|
|
1418
|
-
* event replayer to check whether the dispatcher can replay an event.
|
|
1419
|
-
*/
|
|
1420
|
-
canDispatch(eventInfoWrapper) {
|
|
1421
|
-
const action = eventInfoWrapper.getAction();
|
|
1422
|
-
if (!action) {
|
|
1423
|
-
return false;
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Creates an `EventReplayer` that calls the `replay` function for every `eventInfoWrapper` in
|
|
1214
|
+
* the queue.
|
|
1215
|
+
*/
|
|
1216
|
+
function createEventReplayer(replay) {
|
|
1217
|
+
return (eventInfoWrappers) => {
|
|
1218
|
+
for (const eventInfoWrapper of eventInfoWrappers) {
|
|
1219
|
+
replay(eventInfoWrapper);
|
|
1424
1220
|
}
|
|
1425
|
-
|
|
1426
|
-
}
|
|
1427
|
-
/**
|
|
1428
|
-
* Sets the event replayer, enabling queued events to be replayed when actions
|
|
1429
|
-
* are bound. To replay events, you must register the dispatcher to the
|
|
1430
|
-
* contract after setting the `EventReplayer`. The event replayer takes as
|
|
1431
|
-
* parameters the queue of events and the dispatcher (used to check whether
|
|
1432
|
-
* actions have handlers registered and can be replayed). The event replayer
|
|
1433
|
-
* is also responsible for dequeuing events.
|
|
1434
|
-
*
|
|
1435
|
-
* Example: An event replayer that replays only the last event.
|
|
1436
|
-
*
|
|
1437
|
-
* const dispatcher = new Dispatcher();
|
|
1438
|
-
* // ...
|
|
1439
|
-
* dispatcher.setEventReplayer((queue, dispatcher) => {
|
|
1440
|
-
* const lastEventInfoWrapper = queue[queue.length -1];
|
|
1441
|
-
* if (dispatcher.canDispatch(lastEventInfoWrapper.getAction())) {
|
|
1442
|
-
* jsaction.replay.replayEvent(
|
|
1443
|
-
* lastEventInfoWrapper.getEvent(),
|
|
1444
|
-
* lastEventInfoWrapper.getTargetElement(),
|
|
1445
|
-
* lastEventInfoWrapper.getEventType(),
|
|
1446
|
-
* );
|
|
1447
|
-
* queue.length = 0;
|
|
1448
|
-
* }
|
|
1449
|
-
* });
|
|
1450
|
-
*
|
|
1451
|
-
* @param eventReplayer It allows elements to be replayed and dequeuing.
|
|
1452
|
-
*/
|
|
1453
|
-
setEventReplayer(eventReplayer) {
|
|
1454
|
-
this.eventReplayer = eventReplayer;
|
|
1455
|
-
}
|
|
1221
|
+
};
|
|
1456
1222
|
}
|
|
1457
|
-
/**
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1470
|
-
const event = eventInfoWrapper.getEvent();
|
|
1471
|
-
// There are some cases where users of the `Dispatcher` will call dispatch
|
|
1472
|
-
// with a fake event that does not support `stopPropagation`.
|
|
1473
|
-
if (!event.stopPropagation) {
|
|
1474
|
-
return;
|
|
1475
|
-
}
|
|
1476
|
-
event.stopPropagation();
|
|
1223
|
+
/**
|
|
1224
|
+
* Returns true if the default action of this event should be prevented before
|
|
1225
|
+
* this event is dispatched.
|
|
1226
|
+
*/
|
|
1227
|
+
function shouldPreventDefaultBeforeDispatching(actionElement, eventInfoWrapper) {
|
|
1228
|
+
// Prevent browser from following <a> node links if a jsaction is present
|
|
1229
|
+
// and we are dispatching the action now. Note that the targetElement may be
|
|
1230
|
+
// a child of an anchor that has a jsaction attached. For that reason, we
|
|
1231
|
+
// need to check the actionElement rather than the targetElement.
|
|
1232
|
+
return ((actionElement.tagName === 'A' && eventInfoWrapper.getEventType() === EventType.CLICK) ||
|
|
1233
|
+
eventInfoWrapper.getEventType() === EventType.CLICKMOD);
|
|
1477
1234
|
}
|
|
1478
1235
|
/**
|
|
1479
1236
|
* Registers deferred functionality for an EventContract and a Jsaction
|
|
@@ -1584,98 +1341,110 @@ function populateClickOnlyAction(actionElement, eventInfo, actionMap) {
|
|
|
1584
1341
|
setAction(eventInfo, actionMap[EventType.CLICKONLY], actionElement);
|
|
1585
1342
|
}
|
|
1586
1343
|
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1344
|
+
/**
|
|
1345
|
+
* The jsaction attribute defines a mapping of a DOM event to a
|
|
1346
|
+
* generic event (aka jsaction), to which the actual event handlers
|
|
1347
|
+
* that implement the behavior of the application are bound. The
|
|
1348
|
+
* value is a semicolon separated list of colon separated pairs of
|
|
1349
|
+
* an optional DOM event name and a jsaction name. If the optional
|
|
1350
|
+
* DOM event name is omitted, 'click' is assumed. The jsaction names
|
|
1351
|
+
* are dot separated pairs of a namespace and a simple jsaction
|
|
1352
|
+
* name.
|
|
1353
|
+
*
|
|
1354
|
+
* See grammar in README.md for expected syntax in the attribute value.
|
|
1355
|
+
*/
|
|
1356
|
+
const JSACTION$1 = 'jsaction';
|
|
1357
|
+
/**
|
|
1358
|
+
* The oi attribute is a log impression tag for impression logging
|
|
1359
|
+
* and action tracking. For an element that carries a jsaction
|
|
1360
|
+
* attribute, the element is identified for the purpose of
|
|
1361
|
+
* impression logging and click tracking by the dot separated path
|
|
1362
|
+
* of all oi attributes in the chain of ancestors of the element.
|
|
1363
|
+
*
|
|
1364
|
+
* Used by ActionFlow.
|
|
1365
|
+
*/
|
|
1366
|
+
const OI$1 = 'oi';
|
|
1367
|
+
/**
|
|
1368
|
+
* The ved attribute is an encoded ClickTrackingCGI proto to track
|
|
1369
|
+
* visual elements.
|
|
1370
|
+
*
|
|
1371
|
+
* Used by ActionFlow.
|
|
1372
|
+
*/
|
|
1373
|
+
const VED = 'ved';
|
|
1374
|
+
/**
|
|
1375
|
+
* The vet attribute is the visual element type used to identify tracked
|
|
1376
|
+
* visual elements.
|
|
1377
|
+
*/
|
|
1378
|
+
const VET = 'vet';
|
|
1379
|
+
/**
|
|
1380
|
+
* Support for iteration on reprocessing.
|
|
1381
|
+
*
|
|
1382
|
+
* Used by ActionFlow.
|
|
1383
|
+
*/
|
|
1384
|
+
const JSINSTANCE = 'jsinstance';
|
|
1385
|
+
/**
|
|
1386
|
+
* All click jsactions that happen on the element that carries this
|
|
1387
|
+
* attribute or its descendants are automatically logged.
|
|
1388
|
+
* Impressions of jsactions on these elements are tracked too, if
|
|
1389
|
+
* requested by the impression() method of ActionFlow.
|
|
1390
|
+
*
|
|
1391
|
+
* Used by ActionFlow.
|
|
1392
|
+
*/
|
|
1393
|
+
const JSTRACK = 'jstrack';
|
|
1394
|
+
const Attribute = { JSACTION: JSACTION$1, OI: OI$1, VED, VET, JSINSTANCE, JSTRACK };
|
|
1395
|
+
|
|
1396
|
+
const Char = {
|
|
1613
1397
|
/**
|
|
1614
|
-
* The
|
|
1615
|
-
*
|
|
1616
|
-
* attribute, the element is identified for the purpose of
|
|
1617
|
-
* impression logging and click tracking by the dot separated path
|
|
1618
|
-
* of all oi attributes in the chain of ancestors of the element.
|
|
1619
|
-
*
|
|
1620
|
-
* Used by ActionFlow.
|
|
1398
|
+
* The separator between the namespace and the action name in the
|
|
1399
|
+
* jsaction attribute value.
|
|
1621
1400
|
*/
|
|
1622
|
-
|
|
1401
|
+
NAMESPACE_ACTION_SEPARATOR: '.',
|
|
1623
1402
|
/**
|
|
1624
|
-
* The
|
|
1625
|
-
*
|
|
1626
|
-
*
|
|
1627
|
-
* Used by ActionFlow.
|
|
1403
|
+
* The separator between the event name and action in the jsaction
|
|
1404
|
+
* attribute value.
|
|
1628
1405
|
*/
|
|
1629
|
-
|
|
1406
|
+
EVENT_ACTION_SEPARATOR: ':',
|
|
1630
1407
|
/**
|
|
1631
|
-
* The
|
|
1632
|
-
*
|
|
1408
|
+
* The separator between the logged oi attribute values in the &oi=
|
|
1409
|
+
* URL parameter value.
|
|
1633
1410
|
*/
|
|
1634
|
-
|
|
1411
|
+
OI_SEPARATOR: '.',
|
|
1635
1412
|
/**
|
|
1636
|
-
*
|
|
1637
|
-
*
|
|
1638
|
-
* Used by ActionFlow.
|
|
1413
|
+
* The separator between the key and the value pairs in the &cad=
|
|
1414
|
+
* URL parameter value.
|
|
1639
1415
|
*/
|
|
1640
|
-
|
|
1416
|
+
CAD_KEY_VALUE_SEPARATOR: ':',
|
|
1641
1417
|
/**
|
|
1642
|
-
*
|
|
1643
|
-
*
|
|
1644
|
-
* Impressions of jsactions on these elements are tracked too, if
|
|
1645
|
-
* requested by the impression() method of ActionFlow.
|
|
1646
|
-
*
|
|
1647
|
-
* Used by ActionFlow.
|
|
1418
|
+
* The separator between the key-value pairs in the &cad= URL
|
|
1419
|
+
* parameter value.
|
|
1648
1420
|
*/
|
|
1649
|
-
|
|
1650
|
-
}
|
|
1421
|
+
CAD_SEPARATOR: ',',
|
|
1422
|
+
};
|
|
1651
1423
|
|
|
1424
|
+
/**
|
|
1425
|
+
* The parsed value of the jsaction attribute is stored in this
|
|
1426
|
+
* property on the DOM node. The parsed value is an Object. The
|
|
1427
|
+
* property names of the object are the events; the values are the
|
|
1428
|
+
* names of the actions. This property is attached even on nodes
|
|
1429
|
+
* that don't have a jsaction attribute as an optimization, because
|
|
1430
|
+
* property lookup is faster than attribute access.
|
|
1431
|
+
*/
|
|
1432
|
+
const JSACTION = '__jsaction';
|
|
1433
|
+
/** The value of the oi attribute as a property, for faster access. */
|
|
1434
|
+
const OI = '__oi';
|
|
1435
|
+
/**
|
|
1436
|
+
* The owner property references an a logical owner for a DOM node. JSAction
|
|
1437
|
+
* will follow this reference instead of parentNode when traversing the DOM
|
|
1438
|
+
* to find jsaction attributes. This allows overlaying a logical structure
|
|
1439
|
+
* over a document where the DOM structure can't reflect that structure.
|
|
1440
|
+
*/
|
|
1441
|
+
const OWNER = '__owner';
|
|
1652
1442
|
/** All properties that are used by jsaction. */
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
* property names of the object are the events; the values are the
|
|
1659
|
-
* names of the actions. This property is attached even on nodes
|
|
1660
|
-
* that don't have a jsaction attribute as an optimization, because
|
|
1661
|
-
* property lookup is faster than attribute access.
|
|
1662
|
-
*/
|
|
1663
|
-
Property["JSACTION"] = "__jsaction";
|
|
1664
|
-
/**
|
|
1665
|
-
* The parsed value of the jsnamespace attribute is stored in this
|
|
1666
|
-
* property on the DOM node.
|
|
1667
|
-
*/
|
|
1668
|
-
Property["JSNAMESPACE"] = "__jsnamespace";
|
|
1669
|
-
/** The value of the oi attribute as a property, for faster access. */
|
|
1670
|
-
Property["OI"] = "__oi";
|
|
1671
|
-
/**
|
|
1672
|
-
* The owner property references an a logical owner for a DOM node. JSAction
|
|
1673
|
-
* will follow this reference instead of parentNode when traversing the DOM
|
|
1674
|
-
* to find jsaction attributes. This allows overlaying a logical structure
|
|
1675
|
-
* over a document where the DOM structure can't reflect that structure.
|
|
1676
|
-
*/
|
|
1677
|
-
Property["OWNER"] = "__owner";
|
|
1678
|
-
})(Property || (Property = {}));
|
|
1443
|
+
const Property = {
|
|
1444
|
+
JSACTION,
|
|
1445
|
+
OI,
|
|
1446
|
+
OWNER,
|
|
1447
|
+
};
|
|
1679
1448
|
|
|
1680
1449
|
/**
|
|
1681
1450
|
* Map from jsaction annotation to a parsed map from event name to action name.
|
|
@@ -1689,7 +1458,7 @@ const parseCache = {};
|
|
|
1689
1458
|
*/
|
|
1690
1459
|
function get(element) {
|
|
1691
1460
|
// @ts-ignore
|
|
1692
|
-
return element[
|
|
1461
|
+
return element[JSACTION];
|
|
1693
1462
|
}
|
|
1694
1463
|
/**
|
|
1695
1464
|
* Writes the jsaction parser cache to the given DOM Element.
|
|
@@ -1700,7 +1469,7 @@ function get(element) {
|
|
|
1700
1469
|
*/
|
|
1701
1470
|
function set(element, actionMap) {
|
|
1702
1471
|
// @ts-ignore
|
|
1703
|
-
element[
|
|
1472
|
+
element[JSACTION] = actionMap;
|
|
1704
1473
|
}
|
|
1705
1474
|
/**
|
|
1706
1475
|
* Looks up the parsed action map from the source jsaction attribute value.
|
|
@@ -1726,41 +1495,8 @@ function setParsed(text, parsed) {
|
|
|
1726
1495
|
* @param element .
|
|
1727
1496
|
*/
|
|
1728
1497
|
function clear(element) {
|
|
1729
|
-
if (
|
|
1730
|
-
delete element[
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
/**
|
|
1734
|
-
* Reads the cached jsaction namespace from the given DOM
|
|
1735
|
-
* Element. Undefined means there is no cached value; null is a cached
|
|
1736
|
-
* jsnamespace attribute that's absent.
|
|
1737
|
-
*
|
|
1738
|
-
* @param element .
|
|
1739
|
-
* @return .
|
|
1740
|
-
*/
|
|
1741
|
-
function getNamespace(element) {
|
|
1742
|
-
// @ts-ignore
|
|
1743
|
-
return element[Property.JSNAMESPACE];
|
|
1744
|
-
}
|
|
1745
|
-
/**
|
|
1746
|
-
* Writes the cached jsaction namespace to the given DOM Element. Null
|
|
1747
|
-
* represents a jsnamespace attribute that's absent.
|
|
1748
|
-
*
|
|
1749
|
-
* @param element .
|
|
1750
|
-
* @param jsnamespace .
|
|
1751
|
-
*/
|
|
1752
|
-
function setNamespace(element, jsnamespace) {
|
|
1753
|
-
// @ts-ignore
|
|
1754
|
-
element[Property.JSNAMESPACE] = jsnamespace;
|
|
1755
|
-
}
|
|
1756
|
-
/**
|
|
1757
|
-
* Clears the cached jsaction namespace from the given DOM Element.
|
|
1758
|
-
*
|
|
1759
|
-
* @param element .
|
|
1760
|
-
*/
|
|
1761
|
-
function clearNamespace(element) {
|
|
1762
|
-
if (Property.JSNAMESPACE in element) {
|
|
1763
|
-
delete element[Property.JSNAMESPACE];
|
|
1498
|
+
if (JSACTION in element) {
|
|
1499
|
+
delete element[JSACTION];
|
|
1764
1500
|
}
|
|
1765
1501
|
}
|
|
1766
1502
|
|
|
@@ -1777,28 +1513,19 @@ const REGEXP_SEMICOLON = /\s*;\s*/;
|
|
|
1777
1513
|
const DEFAULT_EVENT_TYPE = EventType.CLICK;
|
|
1778
1514
|
/** Resolves actions for Events. */
|
|
1779
1515
|
class ActionResolver {
|
|
1780
|
-
constructor({
|
|
1516
|
+
constructor({ syntheticMouseEventSupport = false, } = {}) {
|
|
1781
1517
|
this.a11yClickSupport = false;
|
|
1782
1518
|
this.updateEventInfoForA11yClick = undefined;
|
|
1783
1519
|
this.preventDefaultForA11yClick = undefined;
|
|
1784
1520
|
this.populateClickOnlyAction = undefined;
|
|
1785
|
-
this.customEventSupport = customEventSupport;
|
|
1786
1521
|
this.syntheticMouseEventSupport = syntheticMouseEventSupport;
|
|
1787
1522
|
}
|
|
1788
1523
|
resolve(eventInfo) {
|
|
1789
|
-
if (
|
|
1790
|
-
|
|
1791
|
-
const detail = getEvent(eventInfo).detail;
|
|
1792
|
-
// For custom events, use a secondary dispatch based on the internal
|
|
1793
|
-
// custom type of the event.
|
|
1794
|
-
if (!detail || !detail['_type']) {
|
|
1795
|
-
// This should never happen.
|
|
1796
|
-
return;
|
|
1797
|
-
}
|
|
1798
|
-
setEventType(eventInfo, detail['_type']);
|
|
1799
|
-
}
|
|
1524
|
+
if (getResolved(eventInfo)) {
|
|
1525
|
+
return;
|
|
1800
1526
|
}
|
|
1801
1527
|
this.populateAction(eventInfo);
|
|
1528
|
+
setResolved(eventInfo, true);
|
|
1802
1529
|
}
|
|
1803
1530
|
/**
|
|
1804
1531
|
* Searches for a jsaction that the DOM event maps to and creates an
|
|
@@ -1867,8 +1594,8 @@ class ActionResolver {
|
|
|
1867
1594
|
// ancestor chain of the event target node.
|
|
1868
1595
|
break;
|
|
1869
1596
|
}
|
|
1870
|
-
if (actionElement[
|
|
1871
|
-
actionElement = actionElement[
|
|
1597
|
+
if (actionElement[OWNER]) {
|
|
1598
|
+
actionElement = actionElement[OWNER];
|
|
1872
1599
|
continue;
|
|
1873
1600
|
}
|
|
1874
1601
|
if (actionElement.parentNode?.nodeName !== '#document-fragment') {
|
|
@@ -1994,11 +1721,6 @@ const A11Y_CLICK_SUPPORT = false;
|
|
|
1994
1721
|
* flag can be overridden in a build rule.
|
|
1995
1722
|
*/
|
|
1996
1723
|
const MOUSE_SPECIAL_SUPPORT = false;
|
|
1997
|
-
/**
|
|
1998
|
-
* @define Support for custom events, which are type EventType.CUSTOM. These are
|
|
1999
|
-
* native DOM events with an additional type field and an optional payload.
|
|
2000
|
-
*/
|
|
2001
|
-
const CUSTOM_EVENT_SUPPORT = false;
|
|
2002
1724
|
|
|
2003
1725
|
/**
|
|
2004
1726
|
* @fileoverview Implements the local event handling contract. This
|
|
@@ -2038,14 +1760,10 @@ const CUSTOM_EVENT_SUPPORT = false;
|
|
|
2038
1760
|
* be delay loaded in a generic way.
|
|
2039
1761
|
*/
|
|
2040
1762
|
class EventContract {
|
|
2041
|
-
static { this.CUSTOM_EVENT_SUPPORT = CUSTOM_EVENT_SUPPORT; }
|
|
2042
1763
|
static { this.A11Y_CLICK_SUPPORT = A11Y_CLICK_SUPPORT; }
|
|
2043
1764
|
static { this.MOUSE_SPECIAL_SUPPORT = MOUSE_SPECIAL_SUPPORT; }
|
|
2044
|
-
constructor(containerManager) {
|
|
2045
|
-
this.
|
|
2046
|
-
customEventSupport: EventContract.CUSTOM_EVENT_SUPPORT,
|
|
2047
|
-
syntheticMouseEventSupport: EventContract.MOUSE_SPECIAL_SUPPORT,
|
|
2048
|
-
});
|
|
1765
|
+
constructor(containerManager, useActionResolver = true) {
|
|
1766
|
+
this.useActionResolver = useActionResolver;
|
|
2049
1767
|
/**
|
|
2050
1768
|
* The DOM events which this contract covers. Used to prevent double
|
|
2051
1769
|
* registration of event types. The value of the map is the
|
|
@@ -2071,8 +1789,10 @@ class EventContract {
|
|
|
2071
1789
|
/** Whether to add an a11y click listener. */
|
|
2072
1790
|
this.addA11yClickListener = false;
|
|
2073
1791
|
this.containerManager = containerManager;
|
|
2074
|
-
if (
|
|
2075
|
-
this.
|
|
1792
|
+
if (this.useActionResolver) {
|
|
1793
|
+
this.actionResolver = new ActionResolver({
|
|
1794
|
+
syntheticMouseEventSupport: EventContract.MOUSE_SPECIAL_SUPPORT,
|
|
1795
|
+
});
|
|
2076
1796
|
}
|
|
2077
1797
|
if (EventContract.A11Y_CLICK_SUPPORT) {
|
|
2078
1798
|
// Add a11y click support to the `EventContract`.
|
|
@@ -2098,12 +1818,8 @@ class EventContract {
|
|
|
2098
1818
|
this.queuedEventInfos?.push(eventInfo);
|
|
2099
1819
|
return;
|
|
2100
1820
|
}
|
|
2101
|
-
this.
|
|
2102
|
-
|
|
2103
|
-
if (action) {
|
|
2104
|
-
if (shouldPreventDefaultBeforeDispatching(getActionElement(action), eventInfo)) {
|
|
2105
|
-
preventDefault(getEvent(eventInfo));
|
|
2106
|
-
}
|
|
1821
|
+
if (this.useActionResolver) {
|
|
1822
|
+
this.actionResolver.resolve(eventInfo);
|
|
2107
1823
|
}
|
|
2108
1824
|
this.dispatcher(eventInfo);
|
|
2109
1825
|
}
|
|
@@ -2263,7 +1979,9 @@ class EventContract {
|
|
|
2263
1979
|
*/
|
|
2264
1980
|
addA11yClickSupportImpl(updateEventInfoForA11yClick, preventDefaultForA11yClick, populateClickOnlyAction) {
|
|
2265
1981
|
this.addA11yClickListener = true;
|
|
2266
|
-
this.
|
|
1982
|
+
if (this.useActionResolver) {
|
|
1983
|
+
this.actionResolver.addA11yClickSupport(updateEventInfoForA11yClick, preventDefaultForA11yClick, populateClickOnlyAction);
|
|
1984
|
+
}
|
|
2267
1985
|
}
|
|
2268
1986
|
}
|
|
2269
1987
|
function removeEventListeners(container, eventTypes, earlyEventHandler, capture) {
|
|
@@ -2280,19 +1998,6 @@ function removeEventListeners(container, eventTypes, earlyEventHandler, capture)
|
|
|
2280
1998
|
function addDeferredA11yClickSupport(eventContract) {
|
|
2281
1999
|
eventContract.ecaacs?.(updateEventInfoForA11yClick, preventDefaultForA11yClick, populateClickOnlyAction);
|
|
2282
2000
|
}
|
|
2283
|
-
/**
|
|
2284
|
-
* Returns true if the default action of this event should be prevented before
|
|
2285
|
-
* this event is dispatched.
|
|
2286
|
-
*/
|
|
2287
|
-
function shouldPreventDefaultBeforeDispatching(actionElement, eventInfo) {
|
|
2288
|
-
// Prevent browser from following <a> node links if a jsaction is present
|
|
2289
|
-
// and we are dispatching the action now. Note that the targetElement may be
|
|
2290
|
-
// a child of an anchor that has a jsaction attached. For that reason, we
|
|
2291
|
-
// need to check the actionElement rather than the targetElement.
|
|
2292
|
-
return (actionElement.tagName === 'A' &&
|
|
2293
|
-
(getEventType(eventInfo) === EventType.CLICK ||
|
|
2294
|
-
getEventType(eventInfo) === EventType.CLICKMOD));
|
|
2295
|
-
}
|
|
2296
2001
|
|
|
2297
2002
|
/**
|
|
2298
2003
|
* EarlyEventContract intercepts events in the bubbling phase at the
|
|
@@ -2303,14 +2008,14 @@ class EarlyEventContract {
|
|
|
2303
2008
|
constructor(replaySink = window, container = window.document.documentElement) {
|
|
2304
2009
|
this.replaySink = replaySink;
|
|
2305
2010
|
this.container = container;
|
|
2306
|
-
|
|
2011
|
+
replaySink._ejsa = {
|
|
2307
2012
|
c: container,
|
|
2308
2013
|
q: [],
|
|
2309
2014
|
et: [],
|
|
2310
2015
|
etc: [],
|
|
2311
2016
|
h: (event) => {
|
|
2312
|
-
const eventInfo = createEventInfoFromParameters(event.type, event, event.target,
|
|
2313
|
-
|
|
2017
|
+
const eventInfo = createEventInfoFromParameters(event.type, event, event.target, container, Date.now());
|
|
2018
|
+
replaySink._ejsa.q.push(eventInfo);
|
|
2314
2019
|
},
|
|
2315
2020
|
};
|
|
2316
2021
|
}
|
|
@@ -2328,26 +2033,6 @@ class EarlyEventContract {
|
|
|
2328
2033
|
}
|
|
2329
2034
|
}
|
|
2330
2035
|
|
|
2331
|
-
/**
|
|
2332
|
-
* Provides a factory function for bootstrapping an event contract on a
|
|
2333
|
-
* specified object (by default, exposed on the `window`).
|
|
2334
|
-
* @param field The property on the object that the event contract will be placed on.
|
|
2335
|
-
* @param container The container that listens to events
|
|
2336
|
-
* @param appId A given identifier for an application. If there are multiple apps on the page
|
|
2337
|
-
* then this is how contracts can be initialized for each one.
|
|
2338
|
-
* @param events An array of event names that should be listened to.
|
|
2339
|
-
* @param earlyJsactionTracker The object that should receive the event contract.
|
|
2340
|
-
*/
|
|
2341
|
-
function bootstrapEventContract(field, container, appId, events, earlyJsactionTracker = window) {
|
|
2342
|
-
if (!earlyJsactionTracker[field]) {
|
|
2343
|
-
earlyJsactionTracker[field] = {};
|
|
2344
|
-
}
|
|
2345
|
-
const eventContract = new EventContract(new EventContractContainer(container));
|
|
2346
|
-
earlyJsactionTracker[field][appId] = eventContract;
|
|
2347
|
-
for (const ev of events) {
|
|
2348
|
-
eventContract.addEvent(ev);
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
2036
|
/**
|
|
2352
2037
|
* Provides a factory function for bootstrapping an event contract on a
|
|
2353
2038
|
* specified object (by default, exposed on the `window`).
|
|
@@ -2365,9 +2050,11 @@ function bootstrapEarlyEventContract(field, container, appId, eventTypes, captur
|
|
|
2365
2050
|
}
|
|
2366
2051
|
earlyJsactionTracker[field][appId] = {};
|
|
2367
2052
|
const eventContract = new EarlyEventContract(earlyJsactionTracker[field][appId], container);
|
|
2368
|
-
|
|
2369
|
-
|
|
2053
|
+
if (eventTypes)
|
|
2054
|
+
eventContract.addEvents(eventTypes);
|
|
2055
|
+
if (captureEventTypes)
|
|
2056
|
+
eventContract.addEvents(captureEventTypes, true);
|
|
2370
2057
|
}
|
|
2371
2058
|
|
|
2372
|
-
export { Dispatcher, EventContract, EventContractContainer, EventInfoWrapper, bootstrapEarlyEventContract,
|
|
2059
|
+
export { Dispatcher, EventContract, EventContractContainer, EventInfoWrapper, bootstrapEarlyEventContract, registerDispatcher };
|
|
2373
2060
|
//# sourceMappingURL=event-dispatch.mjs.map
|