@angular/core 18.0.0-rc.0 → 18.0.0-rc.1
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/index.mjs +2 -2
- package/esm2022/primitives/event-dispatch/src/action_resolver.mjs +234 -0
- package/esm2022/primitives/event-dispatch/src/base_dispatcher.mjs +6 -8
- package/esm2022/primitives/event-dispatch/src/custom_events.mjs +40 -1
- package/esm2022/primitives/event-dispatch/src/dispatcher.mjs +22 -15
- package/esm2022/primitives/event-dispatch/src/earlyeventcontract.mjs +14 -8
- package/esm2022/primitives/event-dispatch/src/event_contract_defines.mjs +1 -14
- package/esm2022/primitives/event-dispatch/src/eventcontract.mjs +23 -344
- package/esm2022/primitives/event-dispatch/src/register_events.mjs +29 -10
- package/esm2022/src/application/application_ref.mjs +6 -3
- package/esm2022/src/application/create_application.mjs +3 -3
- package/esm2022/src/change_detection/scheduling/exhaustive_check_no_changes.mjs +150 -0
- package/esm2022/src/change_detection/scheduling/ng_zone_scheduling.mjs +17 -3
- package/esm2022/src/change_detection/scheduling/zoneless_scheduling_impl.mjs +5 -5
- package/esm2022/src/core.mjs +2 -1
- package/esm2022/src/core_private_export.mjs +2 -1
- package/esm2022/src/defer/instructions.mjs +20 -12
- package/esm2022/src/defer/interfaces.mjs +1 -3
- package/esm2022/src/errors.mjs +1 -1
- package/esm2022/src/hydration/event_replay.mjs +23 -3
- package/esm2022/src/platform/platform_ref.mjs +8 -1
- package/esm2022/src/render3/after_render_hooks.mjs +4 -2
- package/esm2022/src/render3/component_ref.mjs +1 -1
- package/esm2022/src/render3/instructions/change_detection.mjs +13 -10
- package/esm2022/src/render3/instructions/listener.mjs +12 -1
- package/esm2022/src/render3/state.mjs +14 -4
- package/esm2022/src/render3/view_ref.mjs +3 -2
- package/esm2022/src/util/callback_scheduler.mjs +12 -26
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/src/zone/ng_zone.mjs +9 -23
- package/esm2022/testing/src/component_fixture.mjs +1 -3
- package/esm2022/testing/src/defer.mjs +1 -2
- package/esm2022/testing/src/logger.mjs +3 -3
- package/esm2022/testing/src/test_bed_compiler.mjs +3 -4
- package/event-dispatch-contract.min.js +1 -1
- package/fesm2022/core.mjs +752 -574
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/event-dispatch.mjs +315 -369
- 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 +3 -7
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +34 -4
- package/package.json +1 -1
- package/primitives/event-dispatch/index.d.ts +41 -44
- package/primitives/signals/index.d.ts +1 -1
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/migrations/http-providers/bundle.js +66 -44
- package/schematics/migrations/http-providers/bundle.js.map +2 -2
- package/schematics/migrations/invalid-two-way-bindings/bundle.js +39 -9
- package/schematics/migrations/invalid-two-way-bindings/bundle.js.map +2 -2
- package/schematics/ng-generate/control-flow-migration/bundle.js +39 -9
- package/schematics/ng-generate/control-flow-migration/bundle.js.map +2 -2
- package/schematics/ng-generate/standalone-migration/bundle.js +48 -18
- package/schematics/ng-generate/standalone-migration/bundle.js.map +2 -2
- package/testing/index.d.ts +1 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v18.0.0-rc.
|
|
2
|
+
* @license Angular v18.0.0-rc.1
|
|
3
3
|
* (c) 2010-2024 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -244,20 +244,18 @@ class BaseDispatcher {
|
|
|
244
244
|
*
|
|
245
245
|
* @param eventInfo The info for the event that triggered this call or the
|
|
246
246
|
* queue of events from EventContract.
|
|
247
|
-
* @param isGlobalDispatch If true, dispatches a global event instead of a
|
|
248
|
-
* regular jsaction handler.
|
|
249
247
|
*/
|
|
250
|
-
dispatch(eventInfo
|
|
248
|
+
dispatch(eventInfo) {
|
|
251
249
|
const eventInfoWrapper = new EventInfoWrapper(eventInfo);
|
|
252
250
|
if (eventInfoWrapper.getIsReplay()) {
|
|
253
|
-
if (
|
|
251
|
+
if (!this.eventReplayer) {
|
|
254
252
|
return;
|
|
255
253
|
}
|
|
256
254
|
this.queueEventInfoWrapper(eventInfoWrapper);
|
|
257
255
|
this.scheduleEventReplay();
|
|
258
256
|
return;
|
|
259
257
|
}
|
|
260
|
-
this.dispatchDelegate(eventInfoWrapper
|
|
258
|
+
this.dispatchDelegate(eventInfoWrapper);
|
|
261
259
|
}
|
|
262
260
|
/** Queue an `EventInfoWrapper` for replay. */
|
|
263
261
|
queueEventInfoWrapper(eventInfoWrapper) {
|
|
@@ -286,8 +284,8 @@ class BaseDispatcher {
|
|
|
286
284
|
* Dispatcher.
|
|
287
285
|
*/
|
|
288
286
|
function registerDispatcher$1(eventContract, dispatcher) {
|
|
289
|
-
eventContract.ecrd((eventInfo
|
|
290
|
-
dispatcher.dispatch(eventInfo
|
|
287
|
+
eventContract.ecrd((eventInfo) => {
|
|
288
|
+
dispatcher.dispatch(eventInfo);
|
|
291
289
|
}, Restriction.I_AM_THE_JSACTION_FRAMEWORK);
|
|
292
290
|
}
|
|
293
291
|
|
|
@@ -1264,8 +1262,8 @@ class Dispatcher {
|
|
|
1264
1262
|
/** A map of global event handlers, where each key is an event type. */
|
|
1265
1263
|
this.globalHandlers = new Map();
|
|
1266
1264
|
this.eventReplayer = eventReplayer;
|
|
1267
|
-
this.baseDispatcher = new BaseDispatcher((eventInfoWrapper
|
|
1268
|
-
this.dispatchToHandler(eventInfoWrapper
|
|
1265
|
+
this.baseDispatcher = new BaseDispatcher((eventInfoWrapper) => {
|
|
1266
|
+
this.dispatchToHandler(eventInfoWrapper);
|
|
1269
1267
|
}, {
|
|
1270
1268
|
eventReplayer: (eventInfoWrappers) => {
|
|
1271
1269
|
this.eventReplayer?.(eventInfoWrappers, this);
|
|
@@ -1292,38 +1290,45 @@ class Dispatcher {
|
|
|
1292
1290
|
*
|
|
1293
1291
|
* @param eventInfo The info for the event that triggered this call or the
|
|
1294
1292
|
* queue of events from EventContract.
|
|
1295
|
-
* @param isGlobalDispatch If true, dispatches a global event instead of a
|
|
1296
|
-
* regular jsaction handler.
|
|
1297
1293
|
*/
|
|
1298
1294
|
dispatch(eventInfo, isGlobalDispatch) {
|
|
1299
|
-
this.baseDispatcher.dispatch(eventInfo
|
|
1295
|
+
this.baseDispatcher.dispatch(eventInfo);
|
|
1300
1296
|
}
|
|
1301
1297
|
/**
|
|
1302
1298
|
* Dispatches an `EventInfoWrapper`.
|
|
1303
1299
|
*/
|
|
1304
|
-
dispatchToHandler(eventInfoWrapper
|
|
1305
|
-
if (
|
|
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
|
+
}
|
|
1306
1309
|
// Skip everything related to jsaction handlers, and execute the global
|
|
1307
1310
|
// handlers.
|
|
1308
|
-
const
|
|
1309
|
-
const eventTypeHandlers = this.globalHandlers.get(
|
|
1311
|
+
const event = globalEventInfoWrapper.getEvent();
|
|
1312
|
+
const eventTypeHandlers = this.globalHandlers.get(globalEventInfoWrapper.getEventType());
|
|
1310
1313
|
let shouldPreventDefault = false;
|
|
1311
1314
|
if (eventTypeHandlers) {
|
|
1312
1315
|
for (const handler of eventTypeHandlers) {
|
|
1313
|
-
if (handler(
|
|
1316
|
+
if (handler(event) === false) {
|
|
1314
1317
|
shouldPreventDefault = true;
|
|
1315
1318
|
}
|
|
1316
1319
|
}
|
|
1317
1320
|
}
|
|
1318
1321
|
if (shouldPreventDefault) {
|
|
1319
|
-
preventDefault(
|
|
1322
|
+
preventDefault(event);
|
|
1320
1323
|
}
|
|
1324
|
+
}
|
|
1325
|
+
const action = eventInfoWrapper.getAction();
|
|
1326
|
+
if (!action) {
|
|
1321
1327
|
return;
|
|
1322
1328
|
}
|
|
1323
1329
|
if (this.stopPropagation) {
|
|
1324
1330
|
stopPropagation(eventInfoWrapper);
|
|
1325
1331
|
}
|
|
1326
|
-
const action = eventInfoWrapper.getAction();
|
|
1327
1332
|
let handler = undefined;
|
|
1328
1333
|
if (this.getHandler) {
|
|
1329
1334
|
handler = this.getHandler(eventInfoWrapper);
|
|
@@ -1475,8 +1480,8 @@ function stopPropagation(eventInfoWrapper) {
|
|
|
1475
1480
|
* Dispatcher.
|
|
1476
1481
|
*/
|
|
1477
1482
|
function registerDispatcher(eventContract, dispatcher) {
|
|
1478
|
-
eventContract.ecrd((eventInfo
|
|
1479
|
-
dispatcher.dispatch(eventInfo
|
|
1483
|
+
eventContract.ecrd((eventInfo) => {
|
|
1484
|
+
dispatcher.dispatch(eventInfo);
|
|
1480
1485
|
}, Restriction.I_AM_THE_JSACTION_FRAMEWORK);
|
|
1481
1486
|
}
|
|
1482
1487
|
|
|
@@ -1759,59 +1764,6 @@ function clearNamespace(element) {
|
|
|
1759
1764
|
}
|
|
1760
1765
|
}
|
|
1761
1766
|
|
|
1762
|
-
/**
|
|
1763
|
-
* @define Support for jsnamespace attribute. This flag can be overridden in a
|
|
1764
|
-
* build rule to trim down the EventContract's binary size.
|
|
1765
|
-
*/
|
|
1766
|
-
const JSNAMESPACE_SUPPORT = true;
|
|
1767
|
-
/**
|
|
1768
|
-
* @define Support for accessible click actions. This flag can be overridden in
|
|
1769
|
-
* a build rule.
|
|
1770
|
-
*/
|
|
1771
|
-
const A11Y_CLICK_SUPPORT = false;
|
|
1772
|
-
/**
|
|
1773
|
-
* @define Support for the non-bubbling mouseenter and mouseleave events. This
|
|
1774
|
-
* flag can be overridden in a build rule.
|
|
1775
|
-
*/
|
|
1776
|
-
const MOUSE_SPECIAL_SUPPORT = false;
|
|
1777
|
-
/**
|
|
1778
|
-
* @define Call stopPropagation on handled events. When integrating with
|
|
1779
|
-
* non-jsaction event handler based code, you will likely want to turn this flag
|
|
1780
|
-
* off. While most event handlers will continue to work, jsaction binds focus
|
|
1781
|
-
* and blur events in the capture phase and thus with stopPropagation, none of
|
|
1782
|
-
* your non-jsaction-handlers will ever see it.
|
|
1783
|
-
*/
|
|
1784
|
-
const STOP_PROPAGATION = true;
|
|
1785
|
-
/**
|
|
1786
|
-
* @define Support for custom events, which are type EventType.CUSTOM. These are
|
|
1787
|
-
* native DOM events with an additional type field and an optional payload.
|
|
1788
|
-
*/
|
|
1789
|
-
const CUSTOM_EVENT_SUPPORT = false;
|
|
1790
|
-
|
|
1791
|
-
/**
|
|
1792
|
-
* @fileoverview Implements the local event handling contract. This
|
|
1793
|
-
* allows DOM objects in a container that enters into this contract to
|
|
1794
|
-
* define event handlers which are executed in a local context.
|
|
1795
|
-
*
|
|
1796
|
-
* One EventContract instance can manage the contract for multiple
|
|
1797
|
-
* containers, which are added using the addContainer() method.
|
|
1798
|
-
*
|
|
1799
|
-
* Events can be registered using the addEvent() method.
|
|
1800
|
-
*
|
|
1801
|
-
* A Dispatcher is added using the registerDispatcher() method. Until there is
|
|
1802
|
-
* a dispatcher, events are queued. The idea is that the EventContract
|
|
1803
|
-
* class is inlined in the HTML of the top level page and instantiated
|
|
1804
|
-
* right after the start of <body>. The Dispatcher class is contained
|
|
1805
|
-
* in the external deferred js, and instantiated and registered with
|
|
1806
|
-
* EventContract when the external javascript in the page loads. The
|
|
1807
|
-
* external javascript will also register the jsaction handlers, which
|
|
1808
|
-
* then pick up the queued events at the time of registration.
|
|
1809
|
-
*
|
|
1810
|
-
* Since this class is meant to be inlined in the main page HTML, the
|
|
1811
|
-
* size of the binary compiled from this file MUST be kept as small as
|
|
1812
|
-
* possible and thus its dependencies to a minimum.
|
|
1813
|
-
*/
|
|
1814
|
-
const DEFAULT_EVENT_TYPE = EventType.CLICK;
|
|
1815
1767
|
/**
|
|
1816
1768
|
* Since maps from event to action are immutable we can use a single map
|
|
1817
1769
|
* to represent the empty map.
|
|
@@ -1821,114 +1773,32 @@ const EMPTY_ACTION_MAP = {};
|
|
|
1821
1773
|
* This regular expression matches a semicolon.
|
|
1822
1774
|
*/
|
|
1823
1775
|
const REGEXP_SEMICOLON = /\s*;\s*/;
|
|
1824
|
-
/**
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
*
|
|
1831
|
-
* This has several benefits: (1) No DOM event handlers need to be
|
|
1832
|
-
* registered on the specific elements in the UI. (2) The set of
|
|
1833
|
-
* events that the application has to handle can be specified in terms
|
|
1834
|
-
* of the semantics of the application, rather than in terms of DOM
|
|
1835
|
-
* events. (3) Invocation of handlers can be delayed and handlers can
|
|
1836
|
-
* be delay loaded in a generic way.
|
|
1837
|
-
*/
|
|
1838
|
-
class EventContract {
|
|
1839
|
-
static { this.CUSTOM_EVENT_SUPPORT = CUSTOM_EVENT_SUPPORT; }
|
|
1840
|
-
static { this.STOP_PROPAGATION = STOP_PROPAGATION; }
|
|
1841
|
-
static { this.A11Y_CLICK_SUPPORT = A11Y_CLICK_SUPPORT; }
|
|
1842
|
-
static { this.MOUSE_SPECIAL_SUPPORT = MOUSE_SPECIAL_SUPPORT; }
|
|
1843
|
-
static { this.JSNAMESPACE_SUPPORT = JSNAMESPACE_SUPPORT; }
|
|
1844
|
-
constructor(containerManager) {
|
|
1845
|
-
/**
|
|
1846
|
-
* The DOM events which this contract covers. Used to prevent double
|
|
1847
|
-
* registration of event types. The value of the map is the
|
|
1848
|
-
* internally created DOM event handler function that handles the
|
|
1849
|
-
* DOM events. See addEvent().
|
|
1850
|
-
*
|
|
1851
|
-
*/
|
|
1852
|
-
this.eventHandlers = {};
|
|
1853
|
-
this.browserEventTypeToExtraEventTypes = {};
|
|
1854
|
-
/**
|
|
1855
|
-
* The dispatcher function. Events are passed to this function for
|
|
1856
|
-
* handling once it was set using the registerDispatcher() method. This is
|
|
1857
|
-
* done because the function is passed from another jsbinary, so passing the
|
|
1858
|
-
* instance and invoking the method here would require to leave the method
|
|
1859
|
-
* unobfuscated.
|
|
1860
|
-
*/
|
|
1861
|
-
this.dispatcher = null;
|
|
1862
|
-
/**
|
|
1863
|
-
* The list of suspended `EventInfo` that will be dispatched
|
|
1864
|
-
* as soon as the `Dispatcher` is registered.
|
|
1865
|
-
*/
|
|
1866
|
-
this.queuedEventInfos = [];
|
|
1867
|
-
/** Whether a11y click support has been loaded or not. */
|
|
1868
|
-
this.hasA11yClickSupport = false;
|
|
1869
|
-
/** Whether to add an a11y click listener. */
|
|
1870
|
-
this.addA11yClickListener = false;
|
|
1776
|
+
/** If no event type is defined, defaults to `click`. */
|
|
1777
|
+
const DEFAULT_EVENT_TYPE = EventType.CLICK;
|
|
1778
|
+
/** Resolves actions for Events. */
|
|
1779
|
+
class ActionResolver {
|
|
1780
|
+
constructor({ customEventSupport = false, syntheticMouseEventSupport = false, } = {}) {
|
|
1781
|
+
this.a11yClickSupport = false;
|
|
1871
1782
|
this.updateEventInfoForA11yClick = undefined;
|
|
1872
1783
|
this.preventDefaultForA11yClick = undefined;
|
|
1873
1784
|
this.populateClickOnlyAction = undefined;
|
|
1874
|
-
this.
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
if (
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
/* container= */ container,
|
|
1889
|
-
/* timestamp= */ Date.now());
|
|
1890
|
-
this.handleEventInfo(eventInfo);
|
|
1891
|
-
}
|
|
1892
|
-
/**
|
|
1893
|
-
* Handle an `EventInfo`.
|
|
1894
|
-
*/
|
|
1895
|
-
handleEventInfo(eventInfo) {
|
|
1896
|
-
if (!this.dispatcher) {
|
|
1897
|
-
// All events are queued when the dispatcher isn't yet loaded.
|
|
1898
|
-
setIsReplay(eventInfo, true);
|
|
1899
|
-
this.queuedEventInfos?.push(eventInfo);
|
|
1900
|
-
}
|
|
1901
|
-
if (EventContract.CUSTOM_EVENT_SUPPORT &&
|
|
1902
|
-
getEventType(eventInfo) === EventType.CUSTOM) {
|
|
1903
|
-
const detail = getEvent(eventInfo).detail;
|
|
1904
|
-
// For custom events, use a secondary dispatch based on the internal
|
|
1905
|
-
// custom type of the event.
|
|
1906
|
-
if (!detail || !detail['_type']) {
|
|
1907
|
-
// This should never happen.
|
|
1908
|
-
return;
|
|
1785
|
+
this.customEventSupport = customEventSupport;
|
|
1786
|
+
this.syntheticMouseEventSupport = syntheticMouseEventSupport;
|
|
1787
|
+
}
|
|
1788
|
+
resolve(eventInfo) {
|
|
1789
|
+
if (this.customEventSupport) {
|
|
1790
|
+
if (getEventType(eventInfo) === EventType.CUSTOM) {
|
|
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']);
|
|
1909
1799
|
}
|
|
1910
|
-
setEventType(eventInfo, detail['_type']);
|
|
1911
1800
|
}
|
|
1912
1801
|
this.populateAction(eventInfo);
|
|
1913
|
-
if (!this.dispatcher) {
|
|
1914
|
-
return;
|
|
1915
|
-
}
|
|
1916
|
-
const globalEventInfo = cloneEventInfo(eventInfo);
|
|
1917
|
-
// In some cases, `populateAction` will rewrite `click` events to
|
|
1918
|
-
// `clickonly`. Revert back to a regular click, otherwise we won't be able
|
|
1919
|
-
// to execute global event handlers registered on click events.
|
|
1920
|
-
if (getEventType(globalEventInfo) === EventType.CLICKONLY) {
|
|
1921
|
-
setEventType(globalEventInfo, EventType.CLICK);
|
|
1922
|
-
}
|
|
1923
|
-
this.dispatcher(globalEventInfo, /* dispatch global event */ true);
|
|
1924
|
-
const action = getAction(eventInfo);
|
|
1925
|
-
if (!action) {
|
|
1926
|
-
return;
|
|
1927
|
-
}
|
|
1928
|
-
if (shouldPreventDefaultBeforeDispatching(getActionElement(action), eventInfo)) {
|
|
1929
|
-
preventDefault(getEvent(eventInfo));
|
|
1930
|
-
}
|
|
1931
|
-
this.dispatcher(eventInfo);
|
|
1932
1802
|
}
|
|
1933
1803
|
/**
|
|
1934
1804
|
* Searches for a jsaction that the DOM event maps to and creates an
|
|
@@ -1980,7 +1850,7 @@ class EventContract {
|
|
|
1980
1850
|
isModifiedClickEvent(getEvent(eventInfo))) {
|
|
1981
1851
|
setEventType(eventInfo, EventType.CLICKMOD);
|
|
1982
1852
|
}
|
|
1983
|
-
else if (this.
|
|
1853
|
+
else if (this.a11yClickSupport) {
|
|
1984
1854
|
this.updateEventInfoForA11yClick(eventInfo);
|
|
1985
1855
|
}
|
|
1986
1856
|
// Walk to the parent node, unless the node has a different owner in
|
|
@@ -1988,7 +1858,9 @@ class EventContract {
|
|
|
1988
1858
|
// shadow root if needed.
|
|
1989
1859
|
let actionElement = getTargetElement(eventInfo);
|
|
1990
1860
|
while (actionElement && actionElement !== getContainer(eventInfo)) {
|
|
1991
|
-
|
|
1861
|
+
if (actionElement.nodeType === Node.ELEMENT_NODE) {
|
|
1862
|
+
this.populateActionOnElement(actionElement, eventInfo);
|
|
1863
|
+
}
|
|
1992
1864
|
if (getAction(eventInfo)) {
|
|
1993
1865
|
// An event is handled by at most one jsaction. Thus we stop at the
|
|
1994
1866
|
// first matching jsaction specified in a jsaction attribute up the
|
|
@@ -2011,35 +1883,36 @@ class EventContract {
|
|
|
2011
1883
|
// No action found.
|
|
2012
1884
|
return;
|
|
2013
1885
|
}
|
|
2014
|
-
if (this.
|
|
1886
|
+
if (this.a11yClickSupport) {
|
|
2015
1887
|
this.preventDefaultForA11yClick(eventInfo);
|
|
2016
1888
|
}
|
|
2017
1889
|
// We attempt to handle the mouseenter/mouseleave events here by
|
|
2018
1890
|
// detecting whether the mouseover/mouseout events correspond to
|
|
2019
1891
|
// entering/leaving an element.
|
|
2020
|
-
if (
|
|
2021
|
-
(getEventType(eventInfo) === EventType.MOUSEENTER ||
|
|
1892
|
+
if (this.syntheticMouseEventSupport) {
|
|
1893
|
+
if (getEventType(eventInfo) === EventType.MOUSEENTER ||
|
|
2022
1894
|
getEventType(eventInfo) === EventType.MOUSELEAVE ||
|
|
2023
1895
|
getEventType(eventInfo) === EventType.POINTERENTER ||
|
|
2024
|
-
getEventType(eventInfo) === EventType.POINTERLEAVE)
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
1896
|
+
getEventType(eventInfo) === EventType.POINTERLEAVE) {
|
|
1897
|
+
// We attempt to handle the mouseenter/mouseleave events here by
|
|
1898
|
+
// detecting whether the mouseover/mouseout events correspond to
|
|
1899
|
+
// entering/leaving an element.
|
|
1900
|
+
if (isMouseSpecialEvent(getEvent(eventInfo), getEventType(eventInfo), getActionElement(action))) {
|
|
1901
|
+
// If both mouseover/mouseout and mouseenter/mouseleave events are
|
|
1902
|
+
// enabled, two separate handlers for mouseover/mouseout are
|
|
1903
|
+
// registered. Both handlers will see the same event instance
|
|
1904
|
+
// so we create a copy to avoid interfering with the dispatching of
|
|
1905
|
+
// the mouseover/mouseout event.
|
|
1906
|
+
const copiedEvent = createMouseSpecialEvent(getEvent(eventInfo), getActionElement(action));
|
|
1907
|
+
setEvent(eventInfo, copiedEvent);
|
|
1908
|
+
// Since the mouseenter/mouseleave events do not bubble, the target
|
|
1909
|
+
// of the event is technically the `actionElement` (the node with the
|
|
1910
|
+
// `jsaction` attribute)
|
|
1911
|
+
setTargetElement(eventInfo, getActionElement(action));
|
|
1912
|
+
}
|
|
1913
|
+
else {
|
|
1914
|
+
unsetAction(eventInfo);
|
|
1915
|
+
}
|
|
2043
1916
|
}
|
|
2044
1917
|
}
|
|
2045
1918
|
}
|
|
@@ -2048,25 +1921,192 @@ class EventContract {
|
|
|
2048
1921
|
* action the given event is mapped to, if any. It parses the
|
|
2049
1922
|
* attribute value and stores it in a property on the node for
|
|
2050
1923
|
* subsequent retrieval without re-parsing and re-accessing the
|
|
2051
|
-
* attribute.
|
|
2052
|
-
* namespace, the DOM is searched starting at the current node and
|
|
2053
|
-
* going through ancestor nodes until a jsnamespace attribute is
|
|
2054
|
-
* found.
|
|
1924
|
+
* attribute.
|
|
2055
1925
|
*
|
|
2056
1926
|
* @param actionElement The DOM node to retrieve the jsaction map from.
|
|
2057
1927
|
* @param eventInfo `EventInfo` to set `action` and `actionElement` if an
|
|
2058
1928
|
* action is found on the `actionElement`.
|
|
2059
1929
|
*/
|
|
2060
1930
|
populateActionOnElement(actionElement, eventInfo) {
|
|
2061
|
-
const actionMap = parseActions(actionElement
|
|
1931
|
+
const actionMap = this.parseActions(actionElement);
|
|
2062
1932
|
const actionName = actionMap[getEventType(eventInfo)];
|
|
2063
1933
|
if (actionName !== undefined) {
|
|
2064
1934
|
setAction(eventInfo, actionName, actionElement);
|
|
2065
1935
|
}
|
|
2066
|
-
if (this.
|
|
1936
|
+
if (this.a11yClickSupport) {
|
|
2067
1937
|
this.populateClickOnlyAction(actionElement, eventInfo, actionMap);
|
|
2068
1938
|
}
|
|
2069
1939
|
}
|
|
1940
|
+
/**
|
|
1941
|
+
* Parses and caches an element's jsaction element into a map.
|
|
1942
|
+
*
|
|
1943
|
+
* This is primarily for internal use.
|
|
1944
|
+
*
|
|
1945
|
+
* @param actionElement The DOM node to retrieve the jsaction map from.
|
|
1946
|
+
* @return Map from event to qualified name of the jsaction bound to it.
|
|
1947
|
+
*/
|
|
1948
|
+
parseActions(actionElement) {
|
|
1949
|
+
let actionMap = get(actionElement);
|
|
1950
|
+
if (!actionMap) {
|
|
1951
|
+
const jsactionAttribute = actionElement.getAttribute(Attribute.JSACTION);
|
|
1952
|
+
if (!jsactionAttribute) {
|
|
1953
|
+
actionMap = EMPTY_ACTION_MAP;
|
|
1954
|
+
set(actionElement, actionMap);
|
|
1955
|
+
}
|
|
1956
|
+
else {
|
|
1957
|
+
actionMap = getParsed(jsactionAttribute);
|
|
1958
|
+
if (!actionMap) {
|
|
1959
|
+
actionMap = {};
|
|
1960
|
+
const values = jsactionAttribute.split(REGEXP_SEMICOLON);
|
|
1961
|
+
for (let idx = 0; idx < values.length; idx++) {
|
|
1962
|
+
const value = values[idx];
|
|
1963
|
+
if (!value) {
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
const colon = value.indexOf(Char.EVENT_ACTION_SEPARATOR);
|
|
1967
|
+
const hasColon = colon !== -1;
|
|
1968
|
+
const type = hasColon ? value.substr(0, colon).trim() : DEFAULT_EVENT_TYPE;
|
|
1969
|
+
const action = hasColon ? value.substr(colon + 1).trim() : value;
|
|
1970
|
+
actionMap[type] = action;
|
|
1971
|
+
}
|
|
1972
|
+
setParsed(jsactionAttribute, actionMap);
|
|
1973
|
+
}
|
|
1974
|
+
set(actionElement, actionMap);
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
return actionMap;
|
|
1978
|
+
}
|
|
1979
|
+
addA11yClickSupport(updateEventInfoForA11yClick, preventDefaultForA11yClick, populateClickOnlyAction) {
|
|
1980
|
+
this.a11yClickSupport = true;
|
|
1981
|
+
this.updateEventInfoForA11yClick = updateEventInfoForA11yClick;
|
|
1982
|
+
this.preventDefaultForA11yClick = preventDefaultForA11yClick;
|
|
1983
|
+
this.populateClickOnlyAction = populateClickOnlyAction;
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
/**
|
|
1988
|
+
* @define Support for accessible click actions. This flag can be overridden in
|
|
1989
|
+
* a build rule.
|
|
1990
|
+
*/
|
|
1991
|
+
const A11Y_CLICK_SUPPORT = false;
|
|
1992
|
+
/**
|
|
1993
|
+
* @define Support for the non-bubbling mouseenter and mouseleave events. This
|
|
1994
|
+
* flag can be overridden in a build rule.
|
|
1995
|
+
*/
|
|
1996
|
+
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
|
+
|
|
2003
|
+
/**
|
|
2004
|
+
* @fileoverview Implements the local event handling contract. This
|
|
2005
|
+
* allows DOM objects in a container that enters into this contract to
|
|
2006
|
+
* define event handlers which are executed in a local context.
|
|
2007
|
+
*
|
|
2008
|
+
* One EventContract instance can manage the contract for multiple
|
|
2009
|
+
* containers, which are added using the addContainer() method.
|
|
2010
|
+
*
|
|
2011
|
+
* Events can be registered using the addEvent() method.
|
|
2012
|
+
*
|
|
2013
|
+
* A Dispatcher is added using the registerDispatcher() method. Until there is
|
|
2014
|
+
* a dispatcher, events are queued. The idea is that the EventContract
|
|
2015
|
+
* class is inlined in the HTML of the top level page and instantiated
|
|
2016
|
+
* right after the start of <body>. The Dispatcher class is contained
|
|
2017
|
+
* in the external deferred js, and instantiated and registered with
|
|
2018
|
+
* EventContract when the external javascript in the page loads. The
|
|
2019
|
+
* external javascript will also register the jsaction handlers, which
|
|
2020
|
+
* then pick up the queued events at the time of registration.
|
|
2021
|
+
*
|
|
2022
|
+
* Since this class is meant to be inlined in the main page HTML, the
|
|
2023
|
+
* size of the binary compiled from this file MUST be kept as small as
|
|
2024
|
+
* possible and thus its dependencies to a minimum.
|
|
2025
|
+
*/
|
|
2026
|
+
/**
|
|
2027
|
+
* EventContract intercepts events in the bubbling phase at the
|
|
2028
|
+
* boundary of a container element, and maps them to generic actions
|
|
2029
|
+
* which are specified using the custom jsaction attribute in
|
|
2030
|
+
* HTML. Behavior of the application is then specified in terms of
|
|
2031
|
+
* handler for such actions, cf. jsaction.Dispatcher in dispatcher.js.
|
|
2032
|
+
*
|
|
2033
|
+
* This has several benefits: (1) No DOM event handlers need to be
|
|
2034
|
+
* registered on the specific elements in the UI. (2) The set of
|
|
2035
|
+
* events that the application has to handle can be specified in terms
|
|
2036
|
+
* of the semantics of the application, rather than in terms of DOM
|
|
2037
|
+
* events. (3) Invocation of handlers can be delayed and handlers can
|
|
2038
|
+
* be delay loaded in a generic way.
|
|
2039
|
+
*/
|
|
2040
|
+
class EventContract {
|
|
2041
|
+
static { this.CUSTOM_EVENT_SUPPORT = CUSTOM_EVENT_SUPPORT; }
|
|
2042
|
+
static { this.A11Y_CLICK_SUPPORT = A11Y_CLICK_SUPPORT; }
|
|
2043
|
+
static { this.MOUSE_SPECIAL_SUPPORT = MOUSE_SPECIAL_SUPPORT; }
|
|
2044
|
+
constructor(containerManager) {
|
|
2045
|
+
this.actionResolver = new ActionResolver({
|
|
2046
|
+
customEventSupport: EventContract.CUSTOM_EVENT_SUPPORT,
|
|
2047
|
+
syntheticMouseEventSupport: EventContract.MOUSE_SPECIAL_SUPPORT,
|
|
2048
|
+
});
|
|
2049
|
+
/**
|
|
2050
|
+
* The DOM events which this contract covers. Used to prevent double
|
|
2051
|
+
* registration of event types. The value of the map is the
|
|
2052
|
+
* internally created DOM event handler function that handles the
|
|
2053
|
+
* DOM events. See addEvent().
|
|
2054
|
+
*
|
|
2055
|
+
*/
|
|
2056
|
+
this.eventHandlers = {};
|
|
2057
|
+
this.browserEventTypeToExtraEventTypes = {};
|
|
2058
|
+
/**
|
|
2059
|
+
* The dispatcher function. Events are passed to this function for
|
|
2060
|
+
* handling once it was set using the registerDispatcher() method. This is
|
|
2061
|
+
* done because the function is passed from another jsbinary, so passing the
|
|
2062
|
+
* instance and invoking the method here would require to leave the method
|
|
2063
|
+
* unobfuscated.
|
|
2064
|
+
*/
|
|
2065
|
+
this.dispatcher = null;
|
|
2066
|
+
/**
|
|
2067
|
+
* The list of suspended `EventInfo` that will be dispatched
|
|
2068
|
+
* as soon as the `Dispatcher` is registered.
|
|
2069
|
+
*/
|
|
2070
|
+
this.queuedEventInfos = [];
|
|
2071
|
+
/** Whether to add an a11y click listener. */
|
|
2072
|
+
this.addA11yClickListener = false;
|
|
2073
|
+
this.containerManager = containerManager;
|
|
2074
|
+
if (EventContract.CUSTOM_EVENT_SUPPORT) {
|
|
2075
|
+
this.addEvent(EventType.CUSTOM);
|
|
2076
|
+
}
|
|
2077
|
+
if (EventContract.A11Y_CLICK_SUPPORT) {
|
|
2078
|
+
// Add a11y click support to the `EventContract`.
|
|
2079
|
+
this.addA11yClickSupport();
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
handleEvent(eventType, event, container) {
|
|
2083
|
+
const eventInfo = createEventInfoFromParameters(
|
|
2084
|
+
/* eventType= */ eventType,
|
|
2085
|
+
/* event= */ event,
|
|
2086
|
+
/* targetElement= */ event.target,
|
|
2087
|
+
/* container= */ container,
|
|
2088
|
+
/* timestamp= */ Date.now());
|
|
2089
|
+
this.handleEventInfo(eventInfo);
|
|
2090
|
+
}
|
|
2091
|
+
/**
|
|
2092
|
+
* Handle an `EventInfo`.
|
|
2093
|
+
*/
|
|
2094
|
+
handleEventInfo(eventInfo) {
|
|
2095
|
+
if (!this.dispatcher) {
|
|
2096
|
+
// All events are queued when the dispatcher isn't yet loaded.
|
|
2097
|
+
setIsReplay(eventInfo, true);
|
|
2098
|
+
this.queuedEventInfos?.push(eventInfo);
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
this.actionResolver.resolve(eventInfo);
|
|
2102
|
+
const action = getAction(eventInfo);
|
|
2103
|
+
if (action) {
|
|
2104
|
+
if (shouldPreventDefaultBeforeDispatching(getActionElement(action), eventInfo)) {
|
|
2105
|
+
preventDefault(getEvent(eventInfo));
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
this.dispatcher(eventInfo);
|
|
2109
|
+
}
|
|
2070
2110
|
/**
|
|
2071
2111
|
* Enables jsaction handlers to be called for the event type given by
|
|
2072
2112
|
* name.
|
|
@@ -2118,10 +2158,10 @@ class EventContract {
|
|
|
2118
2158
|
* in the provided event contract. Once all the events are replayed, it cleans
|
|
2119
2159
|
* up the early contract.
|
|
2120
2160
|
*/
|
|
2121
|
-
replayEarlyEvents() {
|
|
2161
|
+
replayEarlyEvents(earlyJsactionContainer = window) {
|
|
2122
2162
|
// Check if the early contract is present and prevent calling this function
|
|
2123
2163
|
// more than once.
|
|
2124
|
-
const earlyJsactionData =
|
|
2164
|
+
const earlyJsactionData = earlyJsactionContainer._ejsa;
|
|
2125
2165
|
if (!earlyJsactionData) {
|
|
2126
2166
|
return;
|
|
2127
2167
|
}
|
|
@@ -2139,13 +2179,10 @@ class EventContract {
|
|
|
2139
2179
|
}
|
|
2140
2180
|
}
|
|
2141
2181
|
// Clean up the early contract.
|
|
2142
|
-
const earlyEventTypes = earlyJsactionData.et;
|
|
2143
2182
|
const earlyEventHandler = earlyJsactionData.h;
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
}
|
|
2148
|
-
delete window._ejsa;
|
|
2183
|
+
removeEventListeners(earlyJsactionData.c, earlyJsactionData.et, earlyEventHandler);
|
|
2184
|
+
removeEventListeners(earlyJsactionData.c, earlyJsactionData.etc, earlyEventHandler, true);
|
|
2185
|
+
delete earlyJsactionContainer._ejsa;
|
|
2149
2186
|
}
|
|
2150
2187
|
/**
|
|
2151
2188
|
* Returns all JSAction event types that have been registered for a given
|
|
@@ -2226,10 +2263,12 @@ class EventContract {
|
|
|
2226
2263
|
*/
|
|
2227
2264
|
addA11yClickSupportImpl(updateEventInfoForA11yClick, preventDefaultForA11yClick, populateClickOnlyAction) {
|
|
2228
2265
|
this.addA11yClickListener = true;
|
|
2229
|
-
this.
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2266
|
+
this.actionResolver.addA11yClickSupport(updateEventInfoForA11yClick, preventDefaultForA11yClick, populateClickOnlyAction);
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
function removeEventListeners(container, eventTypes, earlyEventHandler, capture) {
|
|
2270
|
+
for (let idx = 0; idx < eventTypes.length; idx++) {
|
|
2271
|
+
container.removeEventListener(eventTypes[idx], earlyEventHandler, /* useCapture */ capture);
|
|
2233
2272
|
}
|
|
2234
2273
|
}
|
|
2235
2274
|
/**
|
|
@@ -2254,174 +2293,81 @@ function shouldPreventDefaultBeforeDispatching(actionElement, eventInfo) {
|
|
|
2254
2293
|
(getEventType(eventInfo) === EventType.CLICK ||
|
|
2255
2294
|
getEventType(eventInfo) === EventType.CLICKMOD));
|
|
2256
2295
|
}
|
|
2296
|
+
|
|
2257
2297
|
/**
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
2260
|
-
*
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
actionMap = getParsed(jsactionAttribute);
|
|
2277
|
-
if (!actionMap) {
|
|
2278
|
-
actionMap = {};
|
|
2279
|
-
const values = jsactionAttribute.split(REGEXP_SEMICOLON);
|
|
2280
|
-
for (let idx = 0; idx < values.length; idx++) {
|
|
2281
|
-
const value = values[idx];
|
|
2282
|
-
if (!value) {
|
|
2283
|
-
continue;
|
|
2284
|
-
}
|
|
2285
|
-
const colon = value.indexOf(Char.EVENT_ACTION_SEPARATOR);
|
|
2286
|
-
const hasColon = colon !== -1;
|
|
2287
|
-
const type = hasColon ? stringTrim(value.substr(0, colon)) : DEFAULT_EVENT_TYPE;
|
|
2288
|
-
const action = hasColon ? stringTrim(value.substr(colon + 1)) : value;
|
|
2289
|
-
actionMap[type] = action;
|
|
2290
|
-
}
|
|
2291
|
-
setParsed(jsactionAttribute, actionMap);
|
|
2292
|
-
}
|
|
2293
|
-
// If namespace support is active we need to augment the (potentially
|
|
2294
|
-
// cached) jsaction mapping with the namespace.
|
|
2295
|
-
if (EventContract.JSNAMESPACE_SUPPORT) {
|
|
2296
|
-
const noNs = actionMap;
|
|
2297
|
-
actionMap = {};
|
|
2298
|
-
for (const type in noNs) {
|
|
2299
|
-
actionMap[type] = getFullyQualifiedAction(noNs[type], actionElement, container);
|
|
2300
|
-
}
|
|
2301
|
-
}
|
|
2302
|
-
set(actionElement, actionMap);
|
|
2303
|
-
}
|
|
2298
|
+
* EarlyEventContract intercepts events in the bubbling phase at the
|
|
2299
|
+
* boundary of the document body. This mapping will be passed to the
|
|
2300
|
+
* late-loaded EventContract.
|
|
2301
|
+
*/
|
|
2302
|
+
class EarlyEventContract {
|
|
2303
|
+
constructor(replaySink = window, container = window.document.documentElement) {
|
|
2304
|
+
this.replaySink = replaySink;
|
|
2305
|
+
this.container = container;
|
|
2306
|
+
this.replaySink._ejsa = {
|
|
2307
|
+
c: container,
|
|
2308
|
+
q: [],
|
|
2309
|
+
et: [],
|
|
2310
|
+
etc: [],
|
|
2311
|
+
h: (event) => {
|
|
2312
|
+
const eventInfo = createEventInfoFromParameters(event.type, event, event.target, window.document.documentElement, Date.now());
|
|
2313
|
+
this.replaySink._ejsa.q.push(eventInfo);
|
|
2314
|
+
},
|
|
2315
|
+
};
|
|
2304
2316
|
}
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
* attribute.
|
|
2316
|
-
* @param container The node which limits the search for a jsnamespace
|
|
2317
|
-
* attribute. This node will be searched.
|
|
2318
|
-
* @return The fully qualified name of the jsaction. If no namespace is found,
|
|
2319
|
-
* returns the unqualified name in case it exists in the global namespace.
|
|
2320
|
-
*/
|
|
2321
|
-
function getFullyQualifiedAction(action, start, container) {
|
|
2322
|
-
if (EventContract.JSNAMESPACE_SUPPORT) {
|
|
2323
|
-
if (isNamespacedAction(action)) {
|
|
2324
|
-
return action;
|
|
2325
|
-
}
|
|
2326
|
-
let node = start;
|
|
2327
|
-
while (node) {
|
|
2328
|
-
const namespace = getNamespaceFromElement(node);
|
|
2329
|
-
if (namespace) {
|
|
2330
|
-
return namespace + Char.NAMESPACE_ACTION_SEPARATOR + action;
|
|
2331
|
-
}
|
|
2332
|
-
// If this node is the container, stop.
|
|
2333
|
-
if (node === container) {
|
|
2334
|
-
break;
|
|
2335
|
-
}
|
|
2336
|
-
node = node.parentNode;
|
|
2317
|
+
/**
|
|
2318
|
+
* Installs a list of event types for container .
|
|
2319
|
+
*/
|
|
2320
|
+
addEvents(types, capture) {
|
|
2321
|
+
const replaySink = this.replaySink._ejsa;
|
|
2322
|
+
for (let idx = 0; idx < types.length; idx++) {
|
|
2323
|
+
const eventType = types[idx];
|
|
2324
|
+
const eventTypes = capture ? replaySink.etc : replaySink.et;
|
|
2325
|
+
eventTypes.push(eventType);
|
|
2326
|
+
this.container.addEventListener(eventType, replaySink.h, capture);
|
|
2337
2327
|
}
|
|
2338
2328
|
}
|
|
2339
|
-
return action;
|
|
2340
|
-
}
|
|
2341
|
-
/**
|
|
2342
|
-
* Checks if a jsaction action contains a namespace part.
|
|
2343
|
-
*/
|
|
2344
|
-
function isNamespacedAction(action) {
|
|
2345
|
-
return action.indexOf(Char.NAMESPACE_ACTION_SEPARATOR) >= 0;
|
|
2346
|
-
}
|
|
2347
|
-
/**
|
|
2348
|
-
* Returns the value of the jsnamespace attribute of the given node.
|
|
2349
|
-
* Also caches the value for subsequent lookups.
|
|
2350
|
-
* @param element The node whose jsnamespace attribute is being asked for.
|
|
2351
|
-
* @return The value of the jsnamespace attribute, or null if not found.
|
|
2352
|
-
*/
|
|
2353
|
-
function getNamespaceFromElement(element) {
|
|
2354
|
-
let namespace = getNamespace(element);
|
|
2355
|
-
// Only query for the attribute if it has not been queried for
|
|
2356
|
-
// before. getAttr() returns null if an attribute is not present. Thus,
|
|
2357
|
-
// namespace is string|null if the query took place in the past, or
|
|
2358
|
-
// undefined if the query did not take place.
|
|
2359
|
-
if (namespace === undefined) {
|
|
2360
|
-
namespace = getAttr(element, Attribute.JSNAMESPACE);
|
|
2361
|
-
setNamespace(element, namespace);
|
|
2362
|
-
}
|
|
2363
|
-
return namespace;
|
|
2364
|
-
}
|
|
2365
|
-
/**
|
|
2366
|
-
* Accesses the event handler attribute value of a DOM node. It guards
|
|
2367
|
-
* against weird situations (described in the body) that occur in
|
|
2368
|
-
* connection with nodes that are removed from their document.
|
|
2369
|
-
* @param element The DOM element.
|
|
2370
|
-
* @param attribute The name of the attribute to access.
|
|
2371
|
-
* @return The attribute value if it was found, null otherwise.
|
|
2372
|
-
*/
|
|
2373
|
-
function getAttr(element, attribute) {
|
|
2374
|
-
let value = null;
|
|
2375
|
-
// NOTE: Nodes in IE do not always have a getAttribute
|
|
2376
|
-
// method defined. This is the case where sourceElement has in
|
|
2377
|
-
// fact been removed from the DOM before eventContract begins
|
|
2378
|
-
// handling - where a parentNode does not have getAttribute
|
|
2379
|
-
// defined.
|
|
2380
|
-
// NOTE: We must use the 'in' operator instead of the regular dot
|
|
2381
|
-
// notation, since the latter fails in IE8 if the getAttribute method is not
|
|
2382
|
-
// defined. See b/7139109.
|
|
2383
|
-
if ('getAttribute' in element) {
|
|
2384
|
-
value = element.getAttribute(attribute);
|
|
2385
|
-
}
|
|
2386
|
-
return value;
|
|
2387
|
-
}
|
|
2388
|
-
/**
|
|
2389
|
-
* Helper function to trim whitespace from the beginning and the end
|
|
2390
|
-
* of the string. This deliberately doesn't use the closure equivalent
|
|
2391
|
-
* to keep dependencies small.
|
|
2392
|
-
* @param str Input string.
|
|
2393
|
-
* @return Trimmed string.
|
|
2394
|
-
*/
|
|
2395
|
-
function stringTrim(str) {
|
|
2396
|
-
if (typeof String.prototype.trim === 'function') {
|
|
2397
|
-
return str.trim();
|
|
2398
|
-
}
|
|
2399
|
-
const trimmedLeft = str.replace(/^\s+/, '');
|
|
2400
|
-
return trimmedLeft.replace(/\s+$/, '');
|
|
2401
2329
|
}
|
|
2402
2330
|
|
|
2403
2331
|
/**
|
|
2404
2332
|
* Provides a factory function for bootstrapping an event contract on a
|
|
2405
|
-
*
|
|
2406
|
-
* @param field The property on the
|
|
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.
|
|
2407
2335
|
* @param container The container that listens to events
|
|
2408
2336
|
* @param appId A given identifier for an application. If there are multiple apps on the page
|
|
2409
2337
|
* then this is how contracts can be initialized for each one.
|
|
2410
2338
|
* @param events An array of event names that should be listened to.
|
|
2411
|
-
* @param
|
|
2412
|
-
* @returns The `event` contract. This is both assigned to `anyWindow` and returned for testing.
|
|
2339
|
+
* @param earlyJsactionTracker The object that should receive the event contract.
|
|
2413
2340
|
*/
|
|
2414
|
-
function bootstrapEventContract(field, container, appId, events,
|
|
2415
|
-
if (!
|
|
2416
|
-
|
|
2341
|
+
function bootstrapEventContract(field, container, appId, events, earlyJsactionTracker = window) {
|
|
2342
|
+
if (!earlyJsactionTracker[field]) {
|
|
2343
|
+
earlyJsactionTracker[field] = {};
|
|
2417
2344
|
}
|
|
2418
2345
|
const eventContract = new EventContract(new EventContractContainer(container));
|
|
2419
|
-
|
|
2346
|
+
earlyJsactionTracker[field][appId] = eventContract;
|
|
2420
2347
|
for (const ev of events) {
|
|
2421
2348
|
eventContract.addEvent(ev);
|
|
2422
2349
|
}
|
|
2423
|
-
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* Provides a factory function for bootstrapping an event contract on a
|
|
2353
|
+
* specified object (by default, exposed on the `window`).
|
|
2354
|
+
* @param field The property on the object that the event contract will be placed on.
|
|
2355
|
+
* @param container The container that listens to events
|
|
2356
|
+
* @param appId A given identifier for an application. If there are multiple apps on the page
|
|
2357
|
+
* then this is how contracts can be initialized for each one.
|
|
2358
|
+
* @param eventTypes An array of event names that should be listened to.
|
|
2359
|
+
* @param captureEventTypes An array of event names that should be listened to with capture.
|
|
2360
|
+
* @param earlyJsactionTracker The object that should receive the event contract.
|
|
2361
|
+
*/
|
|
2362
|
+
function bootstrapEarlyEventContract(field, container, appId, eventTypes, captureEventTypes, earlyJsactionTracker = window) {
|
|
2363
|
+
if (!earlyJsactionTracker[field]) {
|
|
2364
|
+
earlyJsactionTracker[field] = {};
|
|
2365
|
+
}
|
|
2366
|
+
earlyJsactionTracker[field][appId] = {};
|
|
2367
|
+
const eventContract = new EarlyEventContract(earlyJsactionTracker[field][appId], container);
|
|
2368
|
+
eventContract.addEvents(eventTypes);
|
|
2369
|
+
eventContract.addEvents(captureEventTypes, true);
|
|
2424
2370
|
}
|
|
2425
2371
|
|
|
2426
|
-
export { Dispatcher, EventContract, EventContractContainer, EventInfoWrapper, bootstrapEventContract, registerDispatcher };
|
|
2372
|
+
export { Dispatcher, EventContract, EventContractContainer, EventInfoWrapper, bootstrapEarlyEventContract, bootstrapEventContract, registerDispatcher };
|
|
2427
2373
|
//# sourceMappingURL=event-dispatch.mjs.map
|