UNPKG

6.28 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var tslib_1 = require("tslib");
4var react_1 = tslib_1.__importDefault(require("react"));
5var prefetch_1 = require("./context/prefetch");
6var EventListener_1 = require("./EventListener");
7exports.INTENTION_DELAY_MS = 150;
8var ConnectedPrefetcher = /** @class */ (function (_super) {
9 tslib_1.__extends(ConnectedPrefetcher, _super);
10 function ConnectedPrefetcher() {
11 var _this = _super !== null && _super.apply(this, arguments) || this;
12 _this.state = {};
13 _this.prefetchAgressively = shouldPrefetchAggressively();
14 _this.handlePressStart = function (_a) {
15 var target = _a.target;
16 _this.clearTimeout();
17 if (target == null) {
18 return;
19 }
20 var url = closestUrlFromNode(target);
21 if (url != null) {
22 _this.setState({ url: url });
23 }
24 };
25 _this.handlePointerLeave = function (_a) {
26 var target = _a.target, relatedTarget = _a.relatedTarget;
27 var url = _this.state.url;
28 var _b = _this, timeout = _b.timeout, timeoutUrl = _b.timeoutUrl;
29 if (target == null) {
30 if (timeout) {
31 _this.clearTimeout();
32 }
33 return;
34 }
35 if (url == null && timeout == null) {
36 return;
37 }
38 var closestUrl = closestUrlFromNode(target);
39 var relatedUrl = relatedTarget && closestUrlFromNode(relatedTarget);
40 if (timeout != null &&
41 urlsEqual(closestUrl, timeoutUrl) &&
42 !urlsEqual(relatedUrl, timeoutUrl)) {
43 _this.clearTimeout();
44 }
45 if (urlsEqual(closestUrl, url) && !urlsEqual(relatedUrl, url)) {
46 _this.setState({ url: undefined });
47 }
48 };
49 _this.handlePointerEnter = function (_a) {
50 var target = _a.target;
51 if (target == null) {
52 return;
53 }
54 var _b = _this, timeoutUrl = _b.timeoutUrl, timeout = _b.timeout;
55 var url = closestUrlFromNode(target);
56 if (url == null) {
57 return;
58 }
59 if (timeout) {
60 if (urlsEqual(url, timeoutUrl)) {
61 return;
62 }
63 else {
64 _this.clearTimeout();
65 }
66 }
67 _this.timeoutUrl = url;
68 _this.timeout = setTimeout(function () {
69 _this.clearTimeout();
70 _this.setState({ url: url });
71 }, exports.INTENTION_DELAY_MS);
72 };
73 return _this;
74 }
75 ConnectedPrefetcher.prototype.render = function () {
76 var url = this.state.url;
77 var manager = this.props.manager;
78 var preloadMarkup = url ? (react_1.default.createElement("div", { style: { visibility: 'hidden' } }, findMatches(manager.registered, url).map(function (_a, index) {
79 var render = _a.render, path = _a.path;
80 // eslint-disable-next-line react/no-array-index-key
81 return react_1.default.createElement("div", { key: "" + path + index }, render(url));
82 }))) : null;
83 var expensiveListeners = this.prefetchAgressively ? (react_1.default.createElement(react_1.default.Fragment, null,
84 react_1.default.createElement(EventListener_1.EventListener, { passive: true, event: "mouseover", handler: this.handlePointerEnter }),
85 react_1.default.createElement(EventListener_1.EventListener, { passive: true, event: "focusin", handler: this.handlePointerEnter }),
86 react_1.default.createElement(EventListener_1.EventListener, { passive: true, event: "mouseout", handler: this.handlePointerLeave }),
87 react_1.default.createElement(EventListener_1.EventListener, { passive: true, event: "focusout", handler: this.handlePointerLeave }))) : null;
88 return (react_1.default.createElement(react_1.default.Fragment, null,
89 react_1.default.createElement(EventListener_1.EventListener, { passive: true, event: "mousedown", handler: this.handlePressStart }),
90 react_1.default.createElement(EventListener_1.EventListener, { passive: true, event: "touchstart", handler: this.handlePressStart }),
91 expensiveListeners,
92 preloadMarkup));
93 };
94 ConnectedPrefetcher.prototype.clearTimeout = function () {
95 if (this.timeout != null) {
96 clearTimeout(this.timeout);
97 this.timeout = undefined;
98 this.timeoutUrl = undefined;
99 }
100 };
101 return ConnectedPrefetcher;
102}(react_1.default.PureComponent));
103function Prefetcher(props) {
104 return (react_1.default.createElement(prefetch_1.PrefetchContext.Consumer, null, function (manager) { return react_1.default.createElement(ConnectedPrefetcher, tslib_1.__assign({}, props, { manager: manager })); }));
105}
106exports.Prefetcher = Prefetcher;
107function shouldPrefetchAggressively() {
108 return (typeof navigator === 'undefined' ||
109 !('connection' in navigator) ||
110 !navigator.connection.saveData);
111}
112function urlsEqual(first, second) {
113 return ((first == null && first === second) ||
114 (first != null && second != null && first.href === second.href));
115}
116function findMatches(records, url) {
117 return tslib_1.__spread(records).filter(function (_a) {
118 var match = _a.path;
119 return matches(url, match);
120 });
121}
122function matches(url, matcher) {
123 return typeof matcher === 'string'
124 ? matcher === url.pathname
125 : matcher.test(url.pathname);
126}
127function closestUrlFromNode(element) {
128 if (!(element instanceof HTMLElement)) {
129 return undefined;
130 }
131 // data-href is a hack for resource list doing the <a> as a sibling
132 var closestUrl = element.closest('[href], [data-href]');
133 if (closestUrl == null || !(closestUrl instanceof HTMLElement)) {
134 return undefined;
135 }
136 var url = closestUrl.getAttribute('href') || closestUrl.getAttribute('data-href');
137 try {
138 return url ? new URL(url, window.location.href) : undefined;
139 }
140 catch (error) {
141 return undefined;
142 }
143}