@inboxsdk/core 1.1.0 → 1.1.2
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/inboxsdk.js +7 -34
- package/inboxsdk.js.map +1 -1
- package/package.json +1 -1
- package/pageWorld.js +1 -1
- package/pageWorld.js.map +1 -1
- package/src/common/version.d.ts.map +1 -1
- package/src/common/version.js +3 -1
- package/src/injected-js/main.js +0 -9
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-sidebar-view/index.test.js +6 -2
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-sidebar-view/primary/index.js +4 -2
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-thread-sidebar-view.js +4 -2
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-thread-sidebar-view.test.js +6 -2
- package/src/platform-implementation-js/driver-common/sidebar/ContentPanelViewDriver.js +2 -2
- package/src/platform-implementation-js/driver-common/sidebar/constants.d.ts +9 -0
- package/src/platform-implementation-js/driver-common/sidebar/constants.d.ts.map +1 -0
- package/src/platform-implementation-js/driver-common/sidebar/constants.js +26 -0
- package/src/platform-implementation-js/lib/idMap.d.ts +7 -0
- package/src/platform-implementation-js/lib/idMap.d.ts.map +1 -1
- package/src/platform-implementation-js/lib/idMap.js +35 -0
- package/src/platform-implementation-js/platform-implementation.d.ts +0 -3
- package/src/platform-implementation-js/platform-implementation.js +1 -9
- package/src/injected-js/inbox/setupAjaxInterceptor.js +0 -211
- package/src/injected-js/inbox/setupClickAndGetNewIframeSrc.js +0 -67
- package/src/injected-js/inbox/setupComposeViewDraftIDFinder.js +0 -35
- package/src/injected-js/inbox/setupInboxFakeWindowResizeListener.js +0 -29
- package/src/platform-implementation-js/dom-driver/inbox/__mocks__/getSidebarClassnames.js +0 -13
- package/src/platform-implementation-js/dom-driver/inbox/addNavItem.js +0 -38
- package/src/platform-implementation-js/dom-driver/inbox/addRecipientRow.js +0 -55
- package/src/platform-implementation-js/dom-driver/inbox/createLink.js +0 -19
- package/src/platform-implementation-js/dom-driver/inbox/createLink.test.js +0 -27
- package/src/platform-implementation-js/dom-driver/inbox/detection/appToolbarLocation/parser.js +0 -43
- package/src/platform-implementation-js/dom-driver/inbox/detection/attachmentCard/parser.js +0 -34
- package/src/platform-implementation-js/dom-driver/inbox/detection/attachmentOverlay/parser.js +0 -53
- package/src/platform-implementation-js/dom-driver/inbox/detection/chatSidebar/parser.js +0 -31
- package/src/platform-implementation-js/dom-driver/inbox/detection/compose/parser.js +0 -103
- package/src/platform-implementation-js/dom-driver/inbox/detection/message/parser.js +0 -69
- package/src/platform-implementation-js/dom-driver/inbox/detection/nativeDrawer/parser.js +0 -32
- package/src/platform-implementation-js/dom-driver/inbox/detection/searchBar/parser.js +0 -28
- package/src/platform-implementation-js/dom-driver/inbox/detection/thread/parser.js +0 -49
- package/src/platform-implementation-js/dom-driver/inbox/detection/thread-row/parser.js +0 -100
- package/src/platform-implementation-js/dom-driver/inbox/getComposeViewDriverLiveSet.js +0 -99
- package/src/platform-implementation-js/dom-driver/inbox/getInboxMessageIdForInboxThreadId.js +0 -36
- package/src/platform-implementation-js/dom-driver/inbox/getSidebarClassnames.js +0 -114
- package/src/platform-implementation-js/dom-driver/inbox/getSidebarClassnames.test.js +0 -73
- package/src/platform-implementation-js/dom-driver/inbox/gotoView.js +0 -39
- package/src/platform-implementation-js/dom-driver/inbox/gotoView.test.js +0 -28
- package/src/platform-implementation-js/dom-driver/inbox/inbox-butter-bar-driver.js +0 -148
- package/src/platform-implementation-js/dom-driver/inbox/inbox-driver.js +0 -863
- package/src/platform-implementation-js/dom-driver/inbox/inbox-page-communicator.js +0 -62
- package/src/platform-implementation-js/dom-driver/inbox/inboxResponseProcessor.js +0 -12
- package/src/platform-implementation-js/dom-driver/inbox/inboxResponseProcessor.test.js +0 -18
- package/src/platform-implementation-js/dom-driver/inbox/makePageParserTree.js +0 -33
- package/src/platform-implementation-js/dom-driver/inbox/pageParserOptions.js +0 -265
- package/src/platform-implementation-js/dom-driver/inbox/registerSearchSuggestionsProvider.js +0 -301
- package/src/platform-implementation-js/dom-driver/inbox/setupCustomAutocompleteSelectionHandling.js +0 -183
- package/src/platform-implementation-js/dom-driver/inbox/setupRouteViewDriverStream.js +0 -64
- package/src/platform-implementation-js/dom-driver/inbox/setupRouteViewDriverStream.test.js +0 -72
- package/src/platform-implementation-js/dom-driver/inbox/views/InboxLabelView.js +0 -78
- package/src/platform-implementation-js/dom-driver/inbox/views/InboxMoleViewDriver.js +0 -296
- package/src/platform-implementation-js/dom-driver/inbox/views/InboxToolbarButtonView.js +0 -91
- package/src/platform-implementation-js/dom-driver/inbox/views/InboxToolbarView.js +0 -53
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-app-sidebar-view.js +0 -271
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-app-toolbar-button-view.js +0 -160
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-app-toolbar-tooltip-view.js +0 -57
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-attachment-card-view.js +0 -197
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-attachment-overlay-view.js +0 -83
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-chat-sidebar-view.js +0 -45
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-compose-button-view.js +0 -116
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-compose-view.js +0 -842
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-custom-route-view.js +0 -75
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-dropdown-view.js +0 -25
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-dummy-route-view.js +0 -63
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-message-view.js +0 -274
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-modal-view.js +0 -112
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-route-view.js +0 -96
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-thread-row-view.js +0 -315
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-thread-view.js +0 -218
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-thread-view.test.js +0 -171
- package/src/platform-implementation-js/dom-driver/inbox/views/inbox-tooltip-view.js +0 -127
- package/src/platform-implementation-js/dom-driver/inbox/views/inboxNavItemView.js +0 -311
- package/src/platform-implementation-js/dom-driver/inbox/waitForAnimationClickBlockerGone.js +0 -26
package/src/platform-implementation-js/dom-driver/inbox/registerSearchSuggestionsProvider.js
DELETED
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.default = registerSearchSuggestionsProvider;
|
|
8
|
-
var _kefir = _interopRequireDefault(require("kefir"));
|
|
9
|
-
var _kefirBus = _interopRequireDefault(require("kefir-bus"));
|
|
10
|
-
var _kefirStopper = _interopRequireDefault(require("kefir-stopper"));
|
|
11
|
-
var _toItemWithLifetimeStream = _interopRequireDefault(require("../../lib/toItemWithLifetimeStream"));
|
|
12
|
-
var _makeMutationObserverChunkedStream = _interopRequireDefault(require("../../lib/dom/make-mutation-observer-chunked-stream"));
|
|
13
|
-
var _fromEventTargetCapture = _interopRequireDefault(require("../../lib/from-event-target-capture"));
|
|
14
|
-
var _insertElementInOrder = _interopRequireDefault(require("../../lib/dom/insert-element-in-order"));
|
|
15
|
-
var _parser = _interopRequireDefault(require("./detection/searchBar/parser"));
|
|
16
|
-
var _copyAndValidateAutocompleteResults = _interopRequireDefault(require("../../lib/copyAndValidateAutocompleteResults"));
|
|
17
|
-
var _setupCustomAutocompleteSelectionHandling = _interopRequireDefault(require("./setupCustomAutocompleteSelectionHandling"));
|
|
18
|
-
var _autoHtml = _interopRequireDefault(require("auto-html"));
|
|
19
|
-
const ORDERING_ATTR = 'data-inboxsdk-search-provider-count';
|
|
20
|
-
const DEFAULT_RESULT_ICON = '//www.gstatic.com/images/icons/material/system/2x/search_black_24dp.png';
|
|
21
|
-
const getProviderOrder = () => {
|
|
22
|
-
const {
|
|
23
|
-
documentElement
|
|
24
|
-
} = document;
|
|
25
|
-
if (!documentElement) {
|
|
26
|
-
throw new Error();
|
|
27
|
-
}
|
|
28
|
-
const orderAttr = documentElement.getAttribute(ORDERING_ATTR);
|
|
29
|
-
const providerOrder = (orderAttr ? parseInt(orderAttr) + 1 : 0).toString();
|
|
30
|
-
documentElement.setAttribute(ORDERING_ATTR, providerOrder);
|
|
31
|
-
return providerOrder;
|
|
32
|
-
};
|
|
33
|
-
const handleResultChosen = _ref => {
|
|
34
|
-
let {
|
|
35
|
-
driver,
|
|
36
|
-
searchInput,
|
|
37
|
-
result,
|
|
38
|
-
event
|
|
39
|
-
} = _ref;
|
|
40
|
-
if (typeof result.onClick === 'function') {
|
|
41
|
-
result.onClick();
|
|
42
|
-
}
|
|
43
|
-
if (typeof result.externalURL === 'string') {
|
|
44
|
-
window.open(result.externalURL);
|
|
45
|
-
}
|
|
46
|
-
if (result.routeName && result.routeParams) {
|
|
47
|
-
driver.goto(result.routeName, result.routeParams);
|
|
48
|
-
}
|
|
49
|
-
if (typeof result.searchTerm === 'string') {
|
|
50
|
-
searchInput.value = result.searchTerm;
|
|
51
|
-
searchInput.dispatchEvent(new Event('input'));
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
const renderResultsList = _ref2 => {
|
|
55
|
-
let {
|
|
56
|
-
driver,
|
|
57
|
-
searchInput,
|
|
58
|
-
removalStream,
|
|
59
|
-
results,
|
|
60
|
-
providerOrder
|
|
61
|
-
} = _ref2;
|
|
62
|
-
const container = document.createElement('div');
|
|
63
|
-
container.setAttribute('data-order-hint', providerOrder);
|
|
64
|
-
container.classList.add('inboxsdk__search_suggestion_group');
|
|
65
|
-
results.forEach(result => {
|
|
66
|
-
const listItem = document.createElement('li');
|
|
67
|
-
const description = result.description || result.descriptionHTML ? (0, _autoHtml.default)`
|
|
68
|
-
<span class="inboxsdk__search_suggestion_desc">
|
|
69
|
-
${result.description || {
|
|
70
|
-
__html: result.descriptionHTML
|
|
71
|
-
}}
|
|
72
|
-
</span>
|
|
73
|
-
` : '';
|
|
74
|
-
listItem.classList.add('inboxsdk__search_suggestion');
|
|
75
|
-
listItem.innerHTML = (0, _autoHtml.default)`
|
|
76
|
-
<img src="${result.iconUrl || DEFAULT_RESULT_ICON}">
|
|
77
|
-
<span>
|
|
78
|
-
<span class="inboxsdk__search_suggestion_name" role="option">
|
|
79
|
-
${result.name || {
|
|
80
|
-
__html: result.nameHTML
|
|
81
|
-
}}
|
|
82
|
-
</span>
|
|
83
|
-
${{
|
|
84
|
-
__html: description
|
|
85
|
-
}}
|
|
86
|
-
</span>
|
|
87
|
-
`;
|
|
88
|
-
_kefir.default.fromEvents(listItem, 'click').takeUntilBy(removalStream).onValue(event => handleResultChosen({
|
|
89
|
-
driver,
|
|
90
|
-
searchInput,
|
|
91
|
-
result,
|
|
92
|
-
event
|
|
93
|
-
}));
|
|
94
|
-
container.appendChild(listItem);
|
|
95
|
-
});
|
|
96
|
-
return container;
|
|
97
|
-
};
|
|
98
|
-
function registerSearchSuggestionsProvider(driver, handler) {
|
|
99
|
-
const stopper = (0, _kefirStopper.default)();
|
|
100
|
-
const providerOrder = getProviderOrder();
|
|
101
|
-
(0, _toItemWithLifetimeStream.default)(driver.getTagTree().getAllByTag('searchBar')).flatMap(_ref3 => {
|
|
102
|
-
let {
|
|
103
|
-
el,
|
|
104
|
-
removalStream
|
|
105
|
-
} = _ref3;
|
|
106
|
-
const {
|
|
107
|
-
searchInput
|
|
108
|
-
} = (0, _parser.default)(el.getValue()).elements;
|
|
109
|
-
if (searchInput instanceof HTMLInputElement) {
|
|
110
|
-
return _kefir.default.constant({
|
|
111
|
-
searchInput,
|
|
112
|
-
searchInputRemovalStream: removalStream
|
|
113
|
-
});
|
|
114
|
-
} else {
|
|
115
|
-
return _kefir.default.never();
|
|
116
|
-
}
|
|
117
|
-
}).flatMap(_ref4 => {
|
|
118
|
-
let {
|
|
119
|
-
searchInput,
|
|
120
|
-
searchInputRemovalStream
|
|
121
|
-
} = _ref4;
|
|
122
|
-
return (0, _toItemWithLifetimeStream.default)(driver.getTagTree().getAllByTag('searchAutocompleteResults')).takeUntilBy(searchInputRemovalStream).map(_ref5 => {
|
|
123
|
-
let {
|
|
124
|
-
el,
|
|
125
|
-
removalStream
|
|
126
|
-
} = _ref5;
|
|
127
|
-
return {
|
|
128
|
-
searchInput,
|
|
129
|
-
searchInputRemovalStream,
|
|
130
|
-
resultsEl: el.getValue(),
|
|
131
|
-
resultsElRemovalStream: removalStream
|
|
132
|
-
};
|
|
133
|
-
});
|
|
134
|
-
}).flatMap(_ref6 => {
|
|
135
|
-
let {
|
|
136
|
-
searchInput,
|
|
137
|
-
searchInputRemovalStream,
|
|
138
|
-
resultsEl,
|
|
139
|
-
resultsElRemovalStream
|
|
140
|
-
} = _ref6;
|
|
141
|
-
const inputs = _kefir.default.fromEvents(searchInput, 'input').takeUntilBy(searchInputRemovalStream).takeUntilBy(resultsElRemovalStream);
|
|
142
|
-
const enterAndTabPresses = _kefir.default.fromEvents(searchInput, 'keydown').filter(_ref7 => {
|
|
143
|
-
let {
|
|
144
|
-
keyCode
|
|
145
|
-
} = _ref7;
|
|
146
|
-
return keyCode === 13 || keyCode === 9;
|
|
147
|
-
}).takeUntilBy(searchInputRemovalStream).takeUntilBy(resultsElRemovalStream);
|
|
148
|
-
return inputs.map(event => ({
|
|
149
|
-
event,
|
|
150
|
-
searchInput,
|
|
151
|
-
resultsEl,
|
|
152
|
-
inputStream: inputs,
|
|
153
|
-
enterAndTabPresses,
|
|
154
|
-
resultsElRemovalStream
|
|
155
|
-
}));
|
|
156
|
-
}).flatMapLatest(item => {
|
|
157
|
-
const suggestionsResponse = driver.getPageCommunicator().ajaxInterceptStream.filter(_ref8 => {
|
|
158
|
-
let {
|
|
159
|
-
type
|
|
160
|
-
} = _ref8;
|
|
161
|
-
return type === 'searchSuggestionsReceieved';
|
|
162
|
-
});
|
|
163
|
-
const removalStream = _kefir.default.merge([
|
|
164
|
-
// Handle cleanup when a new search query is entered. We want to wait
|
|
165
|
-
// to remove our old results until *after* Inbox's results from the new
|
|
166
|
-
// query have come back, since that will allow our modifications to
|
|
167
|
-
// switch from old -> new in sync with Inbox's native suggestions.
|
|
168
|
-
// If we didn't wait on `suggestionsResponse` to trigger cleanup,
|
|
169
|
-
// Our modifications would disappear the moment the user started typing,
|
|
170
|
-
// which ends up looking jarring and inconsistent with Inbox's results
|
|
171
|
-
// which stick around until the new results are ready.
|
|
172
|
-
item.inputStream.take(1).flatMap(() => suggestionsResponse),
|
|
173
|
-
// Handle cleanup when the user deletes their entire search query.
|
|
174
|
-
item.inputStream.filter(_ref9 => {
|
|
175
|
-
let {
|
|
176
|
-
target: {
|
|
177
|
-
value
|
|
178
|
-
}
|
|
179
|
-
} = _ref9;
|
|
180
|
-
return value === '';
|
|
181
|
-
}), item.resultsElRemovalStream]).take(1);
|
|
182
|
-
return _kefir.default.combine([_kefir.default.fromPromise(Promise.resolve(handler(item.event.target.value))),
|
|
183
|
-
// Wait to send results to the UI until Inbox's results have come back
|
|
184
|
-
// to avoid rendering too soon.
|
|
185
|
-
suggestionsResponse.take(1)]).takeUntilBy(removalStream).map(_ref10 => {
|
|
186
|
-
let [results, _ignored] = _ref10;
|
|
187
|
-
return {
|
|
188
|
-
...item,
|
|
189
|
-
removalStream,
|
|
190
|
-
results
|
|
191
|
-
};
|
|
192
|
-
});
|
|
193
|
-
}).takeUntilBy(stopper).flatMap(_ref11 => {
|
|
194
|
-
let {
|
|
195
|
-
resultsEl,
|
|
196
|
-
searchInput,
|
|
197
|
-
resultsElRemovalStream,
|
|
198
|
-
removalStream,
|
|
199
|
-
enterAndTabPresses,
|
|
200
|
-
results
|
|
201
|
-
} = _ref11;
|
|
202
|
-
try {
|
|
203
|
-
const validatedResults = (0, _copyAndValidateAutocompleteResults.default)(driver, results);
|
|
204
|
-
return _kefir.default.constant({
|
|
205
|
-
resultsEl,
|
|
206
|
-
searchInput,
|
|
207
|
-
resultsElRemovalStream,
|
|
208
|
-
removalStream,
|
|
209
|
-
enterAndTabPresses,
|
|
210
|
-
results: validatedResults
|
|
211
|
-
});
|
|
212
|
-
} catch (error) {
|
|
213
|
-
return _kefir.default.constantError(error);
|
|
214
|
-
}
|
|
215
|
-
}).filter(_ref12 => {
|
|
216
|
-
let {
|
|
217
|
-
results
|
|
218
|
-
} = _ref12;
|
|
219
|
-
return results.length > 0;
|
|
220
|
-
}).onError(error => driver.getLogger().error(error)).onValue(_ref13 => {
|
|
221
|
-
let {
|
|
222
|
-
resultsEl,
|
|
223
|
-
searchInput,
|
|
224
|
-
resultsElRemovalStream,
|
|
225
|
-
removalStream,
|
|
226
|
-
enterAndTabPresses,
|
|
227
|
-
results
|
|
228
|
-
} = _ref13;
|
|
229
|
-
(0, _setupCustomAutocompleteSelectionHandling.default)({
|
|
230
|
-
resultsEl,
|
|
231
|
-
resultsElRemovalStream,
|
|
232
|
-
searchInput
|
|
233
|
-
});
|
|
234
|
-
const suggestionsElement = renderResultsList({
|
|
235
|
-
driver,
|
|
236
|
-
searchInput,
|
|
237
|
-
removalStream,
|
|
238
|
-
results,
|
|
239
|
-
providerOrder
|
|
240
|
-
});
|
|
241
|
-
(0, _insertElementInOrder.default)(resultsEl, suggestionsElement);
|
|
242
|
-
|
|
243
|
-
// NOTE: Because we're manually overriding the 'display' property, we've
|
|
244
|
-
// basically taken responsibility for showing/hiding `resultsEl`
|
|
245
|
-
// since Inbox no longer knows when the element is truly visible.
|
|
246
|
-
// When we want to show results for a search term but Inbox doesn't have
|
|
247
|
-
// any results, we need to force the results element to be displayed.
|
|
248
|
-
// When Inbox hides the element it also removes a class that applies
|
|
249
|
-
// some padding adjustments, so we have to force that as well.
|
|
250
|
-
resultsEl.style.display = 'block';
|
|
251
|
-
resultsEl.style.padding = '6px 0';
|
|
252
|
-
removalStream.onValue(() => {
|
|
253
|
-
suggestionsElement.remove();
|
|
254
|
-
|
|
255
|
-
// Because we've mostly overridden Inbox's native show/hide logic we're
|
|
256
|
-
// responsible for hiding `resultsEl` in a couple removal cases:
|
|
257
|
-
// 1) when we go directly from only custom results to having
|
|
258
|
-
// no text in the search box.
|
|
259
|
-
// 2) when there are only custom results and the user subsequently
|
|
260
|
-
// enters a search that returns no results of any type.
|
|
261
|
-
if (searchInput.value === '' || resultsEl.matches(':empty')) {
|
|
262
|
-
resultsEl.style.display = 'none';
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
// We have to take over responsibility for hiding `resultsEl` when
|
|
267
|
-
// the user presses enter or tab because our other overrides prevent Inbox
|
|
268
|
-
// from handling this sensibly.
|
|
269
|
-
enterAndTabPresses.takeUntilBy(removalStream).take(1).onValue(() => {
|
|
270
|
-
resultsEl.style.display = 'none';
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
// When Inbox gets the *first* set of suggestions after opening search,
|
|
274
|
-
// it clears away the current children of the `resultsEl` element.
|
|
275
|
-
// When this happens, our modifications will get cleared away if
|
|
276
|
-
// we've already added them — this can happen if Inbox skips a turn of
|
|
277
|
-
// the event loop between getting the AJAX response back and rendering to
|
|
278
|
-
// the DOM. To handle this case, we watch `resultsEl` for mutations
|
|
279
|
-
// and re-add our modifications if they've been cleared.
|
|
280
|
-
// We also force `resultsEl` to show because the first time
|
|
281
|
-
// we display modifications that aren't accompanied by native results
|
|
282
|
-
// Inbox hides `resultsEl` after we force it to show. Because Inbox
|
|
283
|
-
// removes the previous search's results in the same event loop tick as
|
|
284
|
-
// hiding `resultsEl`, we can hook into the child element removal and
|
|
285
|
-
// re-show it before the hidden state gets painted to the screen.
|
|
286
|
-
// We need to stop this entire process when tab or enter is pressed,
|
|
287
|
-
// because if a custom result was selected when the key was pressed
|
|
288
|
-
// then Inbox will remove the native results that no longer match the
|
|
289
|
-
// search term — causing this observer to fire and subsequently
|
|
290
|
-
// re-show `resultsEl` just as we're trying to manually hide it.
|
|
291
|
-
(0, _makeMutationObserverChunkedStream.default)(resultsEl, {
|
|
292
|
-
childList: true
|
|
293
|
-
}).takeUntilBy(enterAndTabPresses).takeUntilBy(removalStream).onValue(() => {
|
|
294
|
-
resultsEl.style.display = 'block';
|
|
295
|
-
if (suggestionsElement.parentElement !== resultsEl) {
|
|
296
|
-
(0, _insertElementInOrder.default)(resultsEl, suggestionsElement);
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
});
|
|
300
|
-
return () => stopper.destroy();
|
|
301
|
-
}
|
package/src/platform-implementation-js/dom-driver/inbox/setupCustomAutocompleteSelectionHandling.js
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.default = setupCustomAutocompleteSelectionHandling;
|
|
8
|
-
var _kefir = _interopRequireDefault(require("kefir"));
|
|
9
|
-
var _fromEventTargetCapture = _interopRequireDefault(require("../../lib/from-event-target-capture"));
|
|
10
|
-
var _closestNg = _interopRequireDefault(require("closest-ng"));
|
|
11
|
-
const SELECTION_MASTER_ATTR = 'data-inboxsdk-selection-master-claimed';
|
|
12
|
-
const hasNativeResults = resultsEl => resultsEl.querySelectorAll('li:not(.inboxsdk__search_suggestion)').length > 0;
|
|
13
|
-
const hasCustomResults = resultsEl => resultsEl.querySelectorAll('.inboxsdk__search_suggestion').length > 0;
|
|
14
|
-
const getSelectedNativeResult = resultsEl => {
|
|
15
|
-
const nativeResults = resultsEl.querySelectorAll('li:not(.inboxsdk__search_suggestion)');
|
|
16
|
-
|
|
17
|
-
// Unfortunately there are no distinguishable features of a selected
|
|
18
|
-
// native result besides its background color... (ಥ﹏ಥ)
|
|
19
|
-
return Array.from(nativeResults).find(result => {
|
|
20
|
-
const {
|
|
21
|
-
backgroundColor
|
|
22
|
-
} = getComputedStyle(result);
|
|
23
|
-
const colorValues = backgroundColor.match(/([\d.]+)/g);
|
|
24
|
-
return colorValues && parseFloat(colorValues[3]) > 0;
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
const selectFirstCustomResult = resultsEl => {
|
|
28
|
-
const firstCustomResult = resultsEl.querySelector('.inboxsdk__search_suggestion_group:first-of-type > ' + '.inboxsdk__search_suggestion:first-child');
|
|
29
|
-
firstCustomResult && firstCustomResult.classList.add('inboxsdk__selected');
|
|
30
|
-
};
|
|
31
|
-
const setupCustomResultHoverListeners = (resultsEl, resultsElRemovalStream) => {
|
|
32
|
-
_kefir.default.fromEvents(resultsEl, 'mouseover').takeUntilBy(resultsElRemovalStream).map(_ref => {
|
|
33
|
-
let {
|
|
34
|
-
target
|
|
35
|
-
} = _ref;
|
|
36
|
-
return (0, _closestNg.default)(target, '.inboxsdk__search_suggestion:not(.inboxsdk__selected)');
|
|
37
|
-
}).filter(Boolean).onValue(el => {
|
|
38
|
-
const customResults = resultsEl.querySelectorAll('.inboxsdk__search_suggestion.inboxsdk__selected');
|
|
39
|
-
|
|
40
|
-
// Needed to ensure custom results selected via keyboard events
|
|
41
|
-
// have their selected state removed (since no mouseout event fires).
|
|
42
|
-
Array.from(customResults).forEach(result => result.classList.remove('inboxsdk__selected'));
|
|
43
|
-
el.classList.add('inboxsdk__selected');
|
|
44
|
-
});
|
|
45
|
-
_kefir.default.fromEvents(resultsEl, 'mouseout').takeUntilBy(resultsElRemovalStream).map(_ref2 => {
|
|
46
|
-
let {
|
|
47
|
-
target
|
|
48
|
-
} = _ref2;
|
|
49
|
-
return (0, _closestNg.default)(target, '.inboxsdk__search_suggestion.inboxsdk__selected');
|
|
50
|
-
}).filter(Boolean).onValue(el => el.classList.remove('inboxsdk__selected'));
|
|
51
|
-
};
|
|
52
|
-
function setupCustomAutocompleteSelectionHandling(_ref3) {
|
|
53
|
-
let {
|
|
54
|
-
resultsEl,
|
|
55
|
-
resultsElRemovalStream,
|
|
56
|
-
searchInput
|
|
57
|
-
} = _ref3;
|
|
58
|
-
if (resultsEl.hasAttribute(SELECTION_MASTER_ATTR)) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
resultsEl.setAttribute(SELECTION_MASTER_ATTR, 'true');
|
|
62
|
-
|
|
63
|
-
// We need to be able to cancel up/down arrow events before Inbox gets them,
|
|
64
|
-
// but we only want to listen for events that happen while the search box
|
|
65
|
-
// is in focus (since that's when up/down arrows manipulate selection).
|
|
66
|
-
// As a result, we need to grab the search box's parent element so we can
|
|
67
|
-
// capture and cancel events prior to Inbox's listeners (and our own).
|
|
68
|
-
const searchInputParent = searchInput.parentElement;
|
|
69
|
-
if (!searchInputParent) {
|
|
70
|
-
throw new Error();
|
|
71
|
-
}
|
|
72
|
-
const keyboardEvents = (0, _fromEventTargetCapture.default)(searchInputParent, 'keydown').takeUntilBy(resultsElRemovalStream);
|
|
73
|
-
const upArrowPresses = keyboardEvents.filter(_ref4 => {
|
|
74
|
-
let {
|
|
75
|
-
keyCode
|
|
76
|
-
} = _ref4;
|
|
77
|
-
return keyCode === 38;
|
|
78
|
-
});
|
|
79
|
-
const downArrowPresses = keyboardEvents.filter(_ref5 => {
|
|
80
|
-
let {
|
|
81
|
-
keyCode
|
|
82
|
-
} = _ref5;
|
|
83
|
-
return keyCode === 40;
|
|
84
|
-
});
|
|
85
|
-
const enterPresses = keyboardEvents.filter(_ref6 => {
|
|
86
|
-
let {
|
|
87
|
-
keyCode
|
|
88
|
-
} = _ref6;
|
|
89
|
-
return keyCode === 13;
|
|
90
|
-
});
|
|
91
|
-
upArrowPresses.onValue(event => {
|
|
92
|
-
const selectedNativeResult = getSelectedNativeResult(resultsEl);
|
|
93
|
-
const selectedCustomResult = resultsEl.querySelector('.inboxsdk__search_suggestion.inboxsdk__selected');
|
|
94
|
-
const customResultGroup = selectedCustomResult && (0, _closestNg.default)(selectedCustomResult, '.inboxsdk__search_suggestion_group');
|
|
95
|
-
if (selectedNativeResult) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
if (selectedCustomResult && customResultGroup && selectedCustomResult.matches(':first-child') && customResultGroup.matches(':first-of-type')) {
|
|
99
|
-
// If there are native results, Inbox will automatically select
|
|
100
|
-
// the last one when it sees this up arrow press, so all we need to do
|
|
101
|
-
// is remove the highlighting from our result. If there *aren't* any
|
|
102
|
-
// native results, then nothing will be selected, which is consistent
|
|
103
|
-
// with native behavior (hitting the up arrow with the first item selected
|
|
104
|
-
// leaves *nothing* selected).
|
|
105
|
-
selectedCustomResult.classList.remove('inboxsdk__selected');
|
|
106
|
-
} else if (hasCustomResults(resultsEl) && !selectedCustomResult) {
|
|
107
|
-
event.stopPropagation();
|
|
108
|
-
const lastCustomResult = resultsEl.querySelector('.inboxsdk__search_suggestion_group:last-of-type > ' + '.inboxsdk__search_suggestion:last-child');
|
|
109
|
-
lastCustomResult && lastCustomResult.classList.add('inboxsdk__selected');
|
|
110
|
-
} else if (selectedCustomResult && customResultGroup) {
|
|
111
|
-
event.stopPropagation();
|
|
112
|
-
selectedCustomResult.classList.remove('inboxsdk__selected');
|
|
113
|
-
|
|
114
|
-
// The case where this is the first result in the first group
|
|
115
|
-
// has already been handled above, so if this check is true then
|
|
116
|
-
// the selected result is the first item in a non-first group.
|
|
117
|
-
if (selectedCustomResult.matches(':first-child')) {
|
|
118
|
-
const previousResultGroup = customResultGroup.previousElementSibling;
|
|
119
|
-
const customResultToSelect = previousResultGroup && previousResultGroup.querySelector('.inboxsdk__search_suggestion:last-child');
|
|
120
|
-
customResultToSelect && customResultToSelect.classList.add('inboxsdk__selected');
|
|
121
|
-
} else {
|
|
122
|
-
const previousCustomResult = selectedCustomResult.previousElementSibling;
|
|
123
|
-
previousCustomResult && previousCustomResult.classList.add('inboxsdk__selected');
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
downArrowPresses.onValue(event => {
|
|
128
|
-
const selectedNativeResult = getSelectedNativeResult(resultsEl);
|
|
129
|
-
const selectedCustomResult = resultsEl.querySelector('.inboxsdk__search_suggestion.inboxsdk__selected');
|
|
130
|
-
const customResultGroup = selectedCustomResult && (0, _closestNg.default)(selectedCustomResult, '.inboxsdk__search_suggestion_group');
|
|
131
|
-
if (selectedNativeResult && !selectedNativeResult.matches(':last-of-type')) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
if (selectedNativeResult) {
|
|
135
|
-
selectFirstCustomResult(resultsEl);
|
|
136
|
-
} else if (selectedCustomResult && customResultGroup && selectedCustomResult.matches(':last-child') && customResultGroup.matches(':last-of-type')) {
|
|
137
|
-
// Inbox's native behavior is to leave nothing selected when you hit
|
|
138
|
-
// the down arrow while the last item is selected, so we don't
|
|
139
|
-
// try to select any other results if the last custom result is currently
|
|
140
|
-
// selected.
|
|
141
|
-
event.stopPropagation();
|
|
142
|
-
selectedCustomResult.classList.remove('inboxsdk__selected');
|
|
143
|
-
} else if (!selectedCustomResult) {
|
|
144
|
-
// Inbox will automatically select the first native result if
|
|
145
|
-
// one exists.
|
|
146
|
-
if (hasNativeResults(resultsEl)) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Theoretically we could stop propegation here, but inbox doesn't do
|
|
151
|
-
// anything with the event anyway given that there's no results to select.
|
|
152
|
-
selectFirstCustomResult(resultsEl);
|
|
153
|
-
} else if (selectedCustomResult && customResultGroup) {
|
|
154
|
-
event.stopPropagation();
|
|
155
|
-
selectedCustomResult.classList.remove('inboxsdk__selected');
|
|
156
|
-
|
|
157
|
-
// The case where this is the last result in the last group
|
|
158
|
-
// has already been handled above, so if this check is true then
|
|
159
|
-
// the selected result is the last item in a non-last group.
|
|
160
|
-
if (selectedCustomResult.matches(':last-child')) {
|
|
161
|
-
const nextResultGroup = customResultGroup.nextElementSibling;
|
|
162
|
-
const customResultToSelect = nextResultGroup && nextResultGroup.querySelector('.inboxsdk__search_suggestion:first-child');
|
|
163
|
-
customResultToSelect && customResultToSelect.classList.add('inboxsdk__selected');
|
|
164
|
-
} else {
|
|
165
|
-
const nextCustomResult = selectedCustomResult.nextElementSibling;
|
|
166
|
-
nextCustomResult && nextCustomResult.classList.add('inboxsdk__selected');
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
enterPresses.onValue(event => {
|
|
171
|
-
const selectedCustomResult = resultsEl.querySelector('.inboxsdk__search_suggestion.inboxsdk__selected');
|
|
172
|
-
|
|
173
|
-
// If the user hits enter and has a custom result selected, we want to
|
|
174
|
-
// trigger the custom result's action *but* avoid letting the native
|
|
175
|
-
// behavior (hiding `resultsEl`) happen.
|
|
176
|
-
if (selectedCustomResult) {
|
|
177
|
-
event.stopPropagation();
|
|
178
|
-
selectedCustomResult.dispatchEvent(new MouseEvent('click'));
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
keyboardEvents.onEnd(() => resultsEl.removeAttribute(SELECTION_MASTER_ATTR));
|
|
182
|
-
setupCustomResultHoverListeners(resultsEl, resultsElRemovalStream);
|
|
183
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.default = setupRouteViewDriverStream;
|
|
8
|
-
var _kefir = _interopRequireDefault(require("kefir"));
|
|
9
|
-
var _inboxDriver = _interopRequireDefault(require("./inbox-driver"));
|
|
10
|
-
var _inboxRouteView = _interopRequireDefault(require("./views/inbox-route-view"));
|
|
11
|
-
var _inboxCustomRouteView = _interopRequireDefault(require("./views/inbox-custom-route-view"));
|
|
12
|
-
var _inboxDummyRouteView = _interopRequireDefault(require("./views/inbox-dummy-route-view"));
|
|
13
|
-
var _routeIDmatchesHash = _interopRequireDefault(require("../../lib/routeIDmatchesHash"));
|
|
14
|
-
function setupRouteViewDriverStream(driver) {
|
|
15
|
-
const customRouteIDs = driver.getCustomRouteIDs();
|
|
16
|
-
let lastRouteView = null;
|
|
17
|
-
driver.getStopper().onValue(() => {
|
|
18
|
-
if (lastRouteView) {
|
|
19
|
-
lastRouteView.destroy();
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
return _kefir.default.merge([_kefir.default.merge([_kefir.default.fromEvents(document, 'inboxSDKpushState'), _kefir.default.fromEvents(window, 'popstate')]).map(e => process.env.NODE_ENV === 'test' && e.detail && e.detail.__test_url || document.location.href), _kefir.default.fromEvents(window, 'hashchange').map(e => e.newURL)
|
|
23
|
-
// When the user hits back and leaves a hash URL, a hashchange *and*
|
|
24
|
-
// popstate events are emitted. Let's just process the popstate event
|
|
25
|
-
// alone.
|
|
26
|
-
.filter(href => /#/.test(href))]).toProperty(() => document.location.href).map(href => {
|
|
27
|
-
const m = /#([^?]*)/.exec(href);
|
|
28
|
-
if (!m) return {
|
|
29
|
-
type: 'NATIVE'
|
|
30
|
-
};
|
|
31
|
-
const hash = m[1];
|
|
32
|
-
for (let routeIDs of customRouteIDs) {
|
|
33
|
-
let routeID = (0, _routeIDmatchesHash.default)(routeIDs, hash);
|
|
34
|
-
if (routeID) {
|
|
35
|
-
return {
|
|
36
|
-
hash,
|
|
37
|
-
type: 'CUSTOM',
|
|
38
|
-
routeID
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
type: 'OTHER_APP_CUSTOM'
|
|
44
|
-
};
|
|
45
|
-
}).map(detail => {
|
|
46
|
-
if (detail.type === 'CUSTOM') {
|
|
47
|
-
return new _inboxCustomRouteView.default(detail.routeID, detail.hash);
|
|
48
|
-
} else if (detail.type === 'NATIVE') {
|
|
49
|
-
driver.showNativeRouteView();
|
|
50
|
-
return new _inboxDummyRouteView.default('NATIVE');
|
|
51
|
-
} else if (detail.type === 'OTHER_APP_CUSTOM') {
|
|
52
|
-
return new _inboxDummyRouteView.default('OTHER_APP_CUSTOM');
|
|
53
|
-
} else {
|
|
54
|
-
driver.getLogger().error(new Error('should not happen'));
|
|
55
|
-
return new _inboxDummyRouteView.default('UNKNOWN');
|
|
56
|
-
}
|
|
57
|
-
}).map(routeView => {
|
|
58
|
-
if (lastRouteView) {
|
|
59
|
-
lastRouteView.destroy();
|
|
60
|
-
}
|
|
61
|
-
lastRouteView = routeView;
|
|
62
|
-
return routeView;
|
|
63
|
-
});
|
|
64
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
var _lodash = _interopRequireDefault(require("lodash"));
|
|
5
|
-
var _pdelay = _interopRequireDefault(require("pdelay"));
|
|
6
|
-
var _kefir = _interopRequireDefault(require("kefir"));
|
|
7
|
-
var _kefirBus = _interopRequireDefault(require("kefir-bus"));
|
|
8
|
-
var _inboxRouteView = _interopRequireDefault(require("./views/inbox-route-view"));
|
|
9
|
-
var _inboxCustomRouteView = _interopRequireDefault(require("./views/inbox-custom-route-view"));
|
|
10
|
-
var _inboxDummyRouteView = _interopRequireDefault(require("./views/inbox-dummy-route-view"));
|
|
11
|
-
var _setupRouteViewDriverStream = _interopRequireDefault(require("./setupRouteViewDriverStream"));
|
|
12
|
-
jest.mock('./getSidebarClassnames');
|
|
13
|
-
const stopper = (0, _kefirBus.default)();
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
stopper.emit(null);
|
|
16
|
-
});
|
|
17
|
-
function makeMockDriver() {
|
|
18
|
-
return {
|
|
19
|
-
getStopper: _lodash.default.constant(stopper),
|
|
20
|
-
getCustomRouteIDs: _lodash.default.constant(new Set()),
|
|
21
|
-
showNativeRouteView: jest.fn()
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
test('test', async () => {
|
|
25
|
-
const items = [];
|
|
26
|
-
const driver = makeMockDriver();
|
|
27
|
-
driver.getCustomRouteIDs().add('foo/:id');
|
|
28
|
-
driver.getCustomRouteIDs().add('bar/:id/blah');
|
|
29
|
-
(0, _setupRouteViewDriverStream.default)(driver).takeUntilBy(stopper).onValue(item => {
|
|
30
|
-
items.push(item);
|
|
31
|
-
});
|
|
32
|
-
expect(items.length).toBe(1);
|
|
33
|
-
expect(items[0]).toBeInstanceOf(_inboxDummyRouteView.default);
|
|
34
|
-
const firstStopper = jest.fn();
|
|
35
|
-
items[0].getStopper().onValue(firstStopper);
|
|
36
|
-
expect(firstStopper).toHaveBeenCalledTimes(0);
|
|
37
|
-
document.dispatchEvent(new CustomEvent('inboxSDKpushState', {
|
|
38
|
-
bubbles: false,
|
|
39
|
-
cancelable: false,
|
|
40
|
-
detail: {
|
|
41
|
-
__test_url: 'https://inbox.google.com/u/0/snoozed',
|
|
42
|
-
args: ['%5B1%2C%5B%5B11%2C0%2Cfalse%2Cnull%2Cnull%2C0%5D%5D%5D', '', '/u/0/snoozed']
|
|
43
|
-
}
|
|
44
|
-
}));
|
|
45
|
-
expect(items.length).toBe(2);
|
|
46
|
-
expect(items[1]).toBeInstanceOf(_inboxDummyRouteView.default);
|
|
47
|
-
expect(firstStopper).toHaveBeenCalledTimes(1);
|
|
48
|
-
expect(driver.showNativeRouteView).toHaveBeenCalledTimes(2);
|
|
49
|
-
|
|
50
|
-
// TODO test breaks here because jest+jsdom now emits popstate event along with HashChangeEvent.
|
|
51
|
-
// Might be real bug here.
|
|
52
|
-
if (true) return; // eslint-disable-line
|
|
53
|
-
document.location.hash = '#bar/123/blah';
|
|
54
|
-
await (0, _pdelay.default)(1);
|
|
55
|
-
expect(items.length).toBe(3);
|
|
56
|
-
expect(items[2]).toBeInstanceOf(_inboxCustomRouteView.default);
|
|
57
|
-
expect(items[2].getRouteID()).toBe('bar/:id/blah');
|
|
58
|
-
expect(items[2].getParams()).toEqual({
|
|
59
|
-
id: '123'
|
|
60
|
-
});
|
|
61
|
-
expect(driver.showNativeRouteView).toHaveBeenCalledTimes(2);
|
|
62
|
-
document.dispatchEvent(new CustomEvent('inboxSDKpushState', {
|
|
63
|
-
bubbles: false,
|
|
64
|
-
cancelable: false,
|
|
65
|
-
detail: {
|
|
66
|
-
__test_url: 'https://inbox.google.com/u/0/done',
|
|
67
|
-
args: ['%5B1%2C%5B%5B2%2C0%2Cfalse%2Cnull%2Cnull%2C0%5D%5D%5D', '', '/u/0/done']
|
|
68
|
-
}
|
|
69
|
-
}));
|
|
70
|
-
expect(items.length).toBe(4);
|
|
71
|
-
expect(items[3]).toBeInstanceOf(_inboxDummyRouteView.default);
|
|
72
|
-
});
|