@inboxsdk/core 0.2.28-alpha.2 → 0.2.28-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/inboxsdk.js +1 -1
- package/inboxsdk.js.map +1 -1
- package/package.json +1 -1
- package/src/build/exec.js +26 -0
- package/src/build/spawn.js +17 -0
- package/src/common/ajax.js +90 -0
- package/src/common/cachebust-url.js +10 -0
- package/src/common/censorHTMLstring.js +37 -0
- package/src/common/censorHTMLtree.js +28 -0
- package/src/common/censorJSONTree.js +15 -0
- package/src/common/connectivity-test.js +21 -0
- package/src/common/defer.js +11 -0
- package/src/common/find-parent.js +10 -0
- package/src/common/get-extension-id.js +7 -0
- package/src/common/get-or-fail.js +8 -0
- package/src/common/get-session-id.js +14 -0
- package/src/common/get-stack-trace.js +6 -0
- package/src/common/html-to-text.js +7 -0
- package/src/common/isElementVisible.js +6 -0
- package/src/common/load-script.js +127 -0
- package/src/common/log-error.js +191 -0
- package/src/common/quoted-split.js +18 -0
- package/src/common/rate-limit-queuer.js +57 -0
- package/src/common/rate-limit.js +14 -0
- package/src/common/version.js +6 -0
- package/src/inboxsdk-js/loading/platform-implementation-loader.js +27 -0
- package/src/inboxsdk.d.ts +2 -0
- package/src/injected-js/gmail/constants.js +2 -0
- package/src/injected-js/gmail/modify-suggestions.js +106 -0
- package/src/injected-js/gmail/setup-gmonkey-handler.js +49 -0
- package/src/injected-js/gmail/sync-compose-processor-20220909.js +298 -0
- package/src/injected-js/gmail/sync-compose-processor.js +55 -0
- package/src/injected-js/gmail/sync-compose-request-processor.js +110 -0
- package/src/injected-js/injected-logger.js +50 -0
- package/src/injected-js/setupCustomViewEventAssassin.js +90 -0
- package/src/platform-implementation-js/constants/nav-item-types.js +19 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-app-menu-item.js +21 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-collapsible-panel.js +28 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-nav-item.js +98 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-support-item.js +4 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/encodeDraftUrlId.js +8 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/get-rfc-message-id-for-gmail-message-id.js +12 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/get-rfc-message-id-for-gmail-thread-id.js +33 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/isIntegratedViewGmail.js +4 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/open-draft-by-message-id.js +44 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.js +95 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter/get-main-content-element-changed-stream.js +38 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter/wait-for-gmail-mode-to-settle.js +12 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.js +253 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-page-communicator.js +200 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-response-processor.js +533 -0
- package/src/platform-implementation-js/dom-driver/gmail/gmail-sync-response-processor.js +289 -0
- package/src/platform-implementation-js/dom-driver/gmail/is-compose-titlebar-light-color.js +21 -0
- package/src/platform-implementation-js/dom-driver/gmail/makePageParserTree.js +28 -0
- package/src/platform-implementation-js/dom-driver/gmail/pageParserOptions.js +19 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.js +126 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/add-status-bar.js +101 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/detectClassicRecipientsArea.js +38 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/get-address-information-extractor.js +28 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/get-recipients.js +22 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/gmail-compose-button-view.js +233 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/page-parser.js +223 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/set-recipients.js +157 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/setupLinkPopovers.js +109 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-message-view/attachment-icon.js +5 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-nav-item-view.js +759 -0
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-support-item-view.js +84 -0
- package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/button-color-classes.js +33 -0
- package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/button-view.js +325 -0
- package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/create-accessory-button-view.js +58 -0
- package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/create-parent-accessory-button-view.js +55 -0
- package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/modal-button-view.js +96 -0
- package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/more-dropdown-button-view.js +30 -0
- package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/more-parent-accessory-button-view.js +10 -0
- package/src/platform-implementation-js/dom-driver/gmail/widgets/gmail-dropdown-view.js +22 -0
- package/src/platform-implementation-js/driver-common/getAccountUrlPart.js +17 -0
- package/src/platform-implementation-js/driver-common/getOriginalMessagePage.js +33 -0
- package/src/platform-implementation-js/driver-common/getSyncThreadsForSearch.js +49 -0
- package/src/platform-implementation-js/driver-common/gmailAjax.js +65 -0
- package/src/platform-implementation-js/driver-common/render-custom-icon.js +16 -0
- package/src/platform-implementation-js/driver-common/update-icon.js +90 -0
- package/src/platform-implementation-js/lib/ErrorCollector.js +47 -0
- package/src/platform-implementation-js/lib/Membrane.js +22 -0
- package/src/platform-implementation-js/lib/ScrollableContainByScreen.js +30 -0
- package/src/platform-implementation-js/lib/attemptWithRetries.js +16 -0
- package/src/platform-implementation-js/lib/common-page-communicator.js +137 -0
- package/src/platform-implementation-js/lib/delay-asap.js +12 -0
- package/src/platform-implementation-js/lib/delay-idle.js +16 -0
- package/src/platform-implementation-js/lib/dom/block-and-reemit-keyboard-events.js +36 -0
- package/src/platform-implementation-js/lib/dom/generic-button-view.js +39 -0
- package/src/platform-implementation-js/lib/dom/get-insert-before-element.js +39 -0
- package/src/platform-implementation-js/lib/dom/insert-element-in-order.js +38 -0
- package/src/platform-implementation-js/lib/dom/keyboard-shortcut-stream.js +12 -0
- package/src/platform-implementation-js/lib/dom/make-element-child-stream.js +79 -0
- package/src/platform-implementation-js/lib/dom/make-element-stream-merger.js +28 -0
- package/src/platform-implementation-js/lib/dom/make-element-view-stream.js +15 -0
- package/src/platform-implementation-js/lib/dom/make-mutation-observer-chunked-stream.js +15 -0
- package/src/platform-implementation-js/lib/dom/make-mutation-observer-stream.js +5 -0
- package/src/platform-implementation-js/lib/dom/outsideClicksAndEscape.js +39 -0
- package/src/platform-implementation-js/lib/dom/parentNodes.js +8 -0
- package/src/platform-implementation-js/lib/dom/querySelectorOrFail.js +6 -0
- package/src/platform-implementation-js/lib/dom/reemitClickEventForReact.js +22 -0
- package/src/platform-implementation-js/lib/dom/simulate-key.js +46 -0
- package/src/platform-implementation-js/lib/dom/simulate-mouse-event.js +16 -0
- package/src/platform-implementation-js/lib/dom/trigger-relay-event.js +7 -0
- package/src/platform-implementation-js/lib/extract-contact-from-email-contact-string.js +25 -0
- package/src/platform-implementation-js/lib/fake-window-resize.js +5 -0
- package/src/platform-implementation-js/lib/from-event-target-capture.js +12 -0
- package/src/platform-implementation-js/lib/fromEventsWithOptions.js +10 -0
- package/src/platform-implementation-js/lib/handler-registry.js +67 -0
- package/src/platform-implementation-js/lib/idMap.js +45 -0
- package/src/platform-implementation-js/lib/imageRequest.js +8 -0
- package/src/platform-implementation-js/lib/incrementName.js +7 -0
- package/src/platform-implementation-js/lib/inject-script-EMBEDDED.js +14 -0
- package/src/platform-implementation-js/lib/inject-script.js +33 -0
- package/src/platform-implementation-js/lib/is-valid-app-id.js +27 -0
- package/src/platform-implementation-js/lib/is-valid-email.js +14 -0
- package/src/platform-implementation-js/lib/isNotNil.js +5 -0
- package/src/platform-implementation-js/lib/isStreakAppId.js +11 -0
- package/src/platform-implementation-js/lib/logger.js +441 -0
- package/src/platform-implementation-js/lib/persistent-queue.js +107 -0
- package/src/platform-implementation-js/lib/safe-event-emitter.js +17 -0
- package/src/platform-implementation-js/lib/stopper-pool.js +41 -0
- package/src/platform-implementation-js/lib/stream-wait-for.js +30 -0
- package/src/platform-implementation-js/lib/wait-for.js +28 -0
- package/src/platform-implementation-js/lib/waitForAsync.js +19 -0
- package/src/platform-implementation-js/namespaces/app-menu.d.ts.map +1 -1
- package/src/platform-implementation-js/namespaces/app-menu.js +31 -0
- package/src/platform-implementation-js/namespaces/butter-bar.js +163 -0
- package/src/platform-implementation-js/views/SimpleElementView.js +16 -0
- package/src/platform-implementation-js/views/app-menu-item-view.js +257 -0
- package/src/platform-implementation-js/views/collapsible-panel-view.js +222 -0
- package/src/platform-implementation-js/views/compose-button-view.js +45 -0
- package/src/platform-implementation-js/views/compose-view.js +312 -0
- package/src/platform-implementation-js/views/keyboard-shortcut-handle.js +14 -0
- package/src/platform-implementation-js/widgets/buttons/basic-button-view-controller.js +39 -0
- package/src/platform-implementation-js/widgets/buttons/dropdown-button-view-controller.js +98 -0
- package/src/platform-implementation-js/widgets/buttons/dropdown-view.js +122 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export default function waitFor(condition, timeout = 120 * 1000, steptime = 250) {
|
|
2
|
+
// make this error here so we have a sensible stack.
|
|
3
|
+
const timeoutError = new Error('waitFor timeout');
|
|
4
|
+
return new Promise(function (resolve, reject) {
|
|
5
|
+
let waited = 0;
|
|
6
|
+
function step() {
|
|
7
|
+
try {
|
|
8
|
+
const result = condition();
|
|
9
|
+
if (result) {
|
|
10
|
+
resolve(result);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
if (waited >= timeout) {
|
|
14
|
+
reject(timeoutError);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
waited += steptime;
|
|
18
|
+
setTimeout(step, steptime);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
reject(e);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
setTimeout(step, 1);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import delay from 'pdelay';
|
|
2
|
+
export default async function waitForAsync(condition, timeout = 120 * 1000, steptime = 250) {
|
|
3
|
+
// make this error here so we have a sensible stack.
|
|
4
|
+
const timeoutError = new Error('waitForAsync timeout');
|
|
5
|
+
const timeoutTime = Date.now() + timeout;
|
|
6
|
+
// eslint-disable-next-line no-constant-condition
|
|
7
|
+
while (true) {
|
|
8
|
+
const result = await condition();
|
|
9
|
+
if (result) {
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
await delay(steptime);
|
|
13
|
+
if (Date.now() > timeoutTime) {
|
|
14
|
+
throw timeoutError;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// eslint-disable-next-line no-unreachable
|
|
18
|
+
throw new Error();
|
|
19
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-menu.d.ts","sourceRoot":"","sources":["../../../../../src/platform-implementation-js/namespaces/app-menu.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,EAAE,CAAC;CACxB,CAAC;
|
|
1
|
+
{"version":3,"file":"app-menu.d.ts","sourceRoot":"","sources":["../../../../../src/platform-implementation-js/namespaces/app-menu.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;QACjC,OAAO,CAAC,EAAE;YACR,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;QACF,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CAIH,CAAC;AAaF,MAAM,CAAC,OAAO,OAAO,OAAO;;gBAGd,MAAM,EAAE,WAAW;IAI/B,WAAW,CAAC,kBAAkB,EAAE,qBAAqB,GAAG,eAAe;IASjE,OAAO;IAKb,uBAAuB,CAAC,qBAAqB,EAAE,MAAM;CAGtD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import GmailElementGetter from '../dom-driver/gmail/gmail-element-getter';
|
|
2
|
+
import { AppMenuItemView } from '../views/app-menu-item-view';
|
|
3
|
+
// export type CollapsiblePanelView = {
|
|
4
|
+
// update: (panelDescriptor: AppMenuItemPanelDescriptor) => void;
|
|
5
|
+
// destroy: () => void;
|
|
6
|
+
// collapse: (state: boolean) => boolean;
|
|
7
|
+
// isCollapsed: () => boolean;
|
|
8
|
+
// // TBD
|
|
9
|
+
// // Aleem: add ability to add primary/secondary button to all panels (mainly ours but Google's too)
|
|
10
|
+
// // typed-emitter
|
|
11
|
+
// on: (event: 'toggle') => void;
|
|
12
|
+
// };
|
|
13
|
+
export default class AppMenu {
|
|
14
|
+
#driver;
|
|
15
|
+
constructor(driver) {
|
|
16
|
+
this.#driver = driver;
|
|
17
|
+
}
|
|
18
|
+
addMenuItem(menuItemDescriptor) {
|
|
19
|
+
// TODO: should we support the Observable being passed in
|
|
20
|
+
const navItemView = new AppMenuItemView(this.#driver, menuItemDescriptor);
|
|
21
|
+
// this.#menuItemViews.push(navItemView);
|
|
22
|
+
return navItemView;
|
|
23
|
+
}
|
|
24
|
+
async isShown() {
|
|
25
|
+
const result = await GmailElementGetter.getAppMenuAsync();
|
|
26
|
+
return !!result;
|
|
27
|
+
}
|
|
28
|
+
isCollapsiblePanelShown(_panelIndexOrIDorType) {
|
|
29
|
+
// shim
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import defaults from 'lodash/defaults';
|
|
2
|
+
import sortBy from 'lodash/sortBy';
|
|
3
|
+
import find from 'lodash/find';
|
|
4
|
+
import Kefir from 'kefir';
|
|
5
|
+
import kefirBus from 'kefir-bus';
|
|
6
|
+
import defer from '../../common/defer';
|
|
7
|
+
import get from '../../common/get-or-fail';
|
|
8
|
+
const ancientComplainTime = 2 * 60 * 1000;
|
|
9
|
+
const dummyPacket = Object.freeze({
|
|
10
|
+
destroy: Object.freeze(function () {
|
|
11
|
+
// do nothing
|
|
12
|
+
}),
|
|
13
|
+
});
|
|
14
|
+
const memberMap = new WeakMap();
|
|
15
|
+
// documented in src/docs/
|
|
16
|
+
export default class ButterBar {
|
|
17
|
+
constructor(appId, driver) {
|
|
18
|
+
const members = {
|
|
19
|
+
driver,
|
|
20
|
+
messagesByKey: new Map(),
|
|
21
|
+
queuedPackets: [],
|
|
22
|
+
};
|
|
23
|
+
memberMap.set(this, members);
|
|
24
|
+
}
|
|
25
|
+
showMessage(options) {
|
|
26
|
+
defaults(options, {
|
|
27
|
+
priority: 0,
|
|
28
|
+
time: 15 * 1000,
|
|
29
|
+
hideOnViewChanged: true,
|
|
30
|
+
persistent: false,
|
|
31
|
+
});
|
|
32
|
+
this.hideMessage(options.messageKey);
|
|
33
|
+
const members = get(memberMap, this);
|
|
34
|
+
const butterBarDriver = members.driver.getButterBarDriver();
|
|
35
|
+
const messageId = Date.now() + '-' + Math.random();
|
|
36
|
+
{
|
|
37
|
+
let queue = butterBarDriver.getSharedMessageQueue();
|
|
38
|
+
queue.unshift({
|
|
39
|
+
messageId,
|
|
40
|
+
priority: options.priority,
|
|
41
|
+
persistent: options.persistent,
|
|
42
|
+
});
|
|
43
|
+
queue = sortBy(queue, (item) => -item.priority);
|
|
44
|
+
queue = queue.filter((item, i) => i === 0 || item.persistent);
|
|
45
|
+
butterBarDriver.setSharedMessageQueue(queue);
|
|
46
|
+
if (!find(queue, (item) => item.messageId === messageId)) {
|
|
47
|
+
return dummyPacket;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const stopper = kefirBus();
|
|
51
|
+
if (options.hideOnViewChanged) {
|
|
52
|
+
// Set hideOnViewChanged to true only after this run of the event
|
|
53
|
+
// loop completes. This fixes the issue where a butterbar message
|
|
54
|
+
// with hideOnViewChanged spawned in a gmail viewChanged handler
|
|
55
|
+
// would die immediately as the rest of the event's handlers are
|
|
56
|
+
// called.
|
|
57
|
+
stopper.plug(Kefir.later(0, null)
|
|
58
|
+
.flatMap(() => members.driver.getRouteViewDriverStream().changes())
|
|
59
|
+
.map(() => null));
|
|
60
|
+
}
|
|
61
|
+
if (isFinite(options.time)) {
|
|
62
|
+
stopper.plug(Kefir.later(options.time, null));
|
|
63
|
+
}
|
|
64
|
+
// Error made here for sensible stack
|
|
65
|
+
const timeoutErr = new Error('Butter bar message timed out');
|
|
66
|
+
stopper.plug(Kefir.later(ancientComplainTime, null).map((x) => {
|
|
67
|
+
members.driver.getLogger().errorApp(timeoutErr);
|
|
68
|
+
return x;
|
|
69
|
+
}));
|
|
70
|
+
stopper.take(1).onValue(() => {
|
|
71
|
+
if (options.messageKey) {
|
|
72
|
+
members.messagesByKey.delete(options.messageKey);
|
|
73
|
+
}
|
|
74
|
+
const queue = butterBarDriver.getSharedMessageQueue();
|
|
75
|
+
butterBarDriver.setSharedMessageQueue(queue.filter((item) => item.messageId !== messageId));
|
|
76
|
+
});
|
|
77
|
+
butterBarDriver
|
|
78
|
+
.getNoticeAvailableStream()
|
|
79
|
+
.toProperty(() => null)
|
|
80
|
+
.takeUntilBy(stopper)
|
|
81
|
+
.filter(() => {
|
|
82
|
+
const queue = butterBarDriver.getSharedMessageQueue();
|
|
83
|
+
if (!queue[0])
|
|
84
|
+
stopper.value(undefined);
|
|
85
|
+
return queue[0] && queue[0].messageId === messageId;
|
|
86
|
+
})
|
|
87
|
+
.onValue(() => {
|
|
88
|
+
const rawHandle = butterBarDriver.showMessage(options);
|
|
89
|
+
stopper.take(1).onValue(() => {
|
|
90
|
+
rawHandle.destroy();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
const message = {
|
|
94
|
+
destroy() {
|
|
95
|
+
stopper.value(undefined);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
if (options.messageKey) {
|
|
99
|
+
members.messagesByKey.set(options.messageKey, message);
|
|
100
|
+
}
|
|
101
|
+
return message;
|
|
102
|
+
}
|
|
103
|
+
showLoading(options = {}) {
|
|
104
|
+
defaults(options, {
|
|
105
|
+
text: 'Loading...',
|
|
106
|
+
priority: -3,
|
|
107
|
+
time: Infinity,
|
|
108
|
+
persistent: true,
|
|
109
|
+
hideOnViewChanged: true,
|
|
110
|
+
});
|
|
111
|
+
options.time = Infinity; // Loading messages should exist until destroyed.
|
|
112
|
+
return this.showMessage(options);
|
|
113
|
+
}
|
|
114
|
+
showError(options) {
|
|
115
|
+
defaults(options, {
|
|
116
|
+
priority: 100,
|
|
117
|
+
className: 'inboxsdk__butterbar_error',
|
|
118
|
+
});
|
|
119
|
+
return this.showMessage(options);
|
|
120
|
+
}
|
|
121
|
+
showSaving(options = {}) {
|
|
122
|
+
defaults(options, {
|
|
123
|
+
text: 'Saving...',
|
|
124
|
+
confirmationText: 'Saved',
|
|
125
|
+
confirmationTime: 1 * 1000,
|
|
126
|
+
priority: -2,
|
|
127
|
+
time: Infinity,
|
|
128
|
+
persistent: true,
|
|
129
|
+
hideOnViewChanged: false,
|
|
130
|
+
showConfirmation: true,
|
|
131
|
+
});
|
|
132
|
+
const savingMessage = this.showMessage(options);
|
|
133
|
+
const deferred = defer();
|
|
134
|
+
deferred.promise.then(() => {
|
|
135
|
+
savingMessage.destroy();
|
|
136
|
+
if (options.showConfirmation) {
|
|
137
|
+
this.showMessage({
|
|
138
|
+
text: options.confirmationText,
|
|
139
|
+
messageKey: options.messageKey,
|
|
140
|
+
time: options.confirmationTime,
|
|
141
|
+
priority: 200,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}, () => {
|
|
145
|
+
savingMessage.destroy();
|
|
146
|
+
});
|
|
147
|
+
return deferred;
|
|
148
|
+
}
|
|
149
|
+
hideMessage(messageKey) {
|
|
150
|
+
if (messageKey) {
|
|
151
|
+
const members = get(memberMap, this);
|
|
152
|
+
const message = members.messagesByKey.get(messageKey);
|
|
153
|
+
if (message) {
|
|
154
|
+
message.destroy();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
hideGmailMessage() {
|
|
159
|
+
const members = get(memberMap, this);
|
|
160
|
+
const butterBarDriver = members.driver.getButterBarDriver();
|
|
161
|
+
butterBarDriver.hideGmailMessage();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import SafeEventEmitter from '../lib/safe-event-emitter';
|
|
2
|
+
export default class SimpleElementView extends SafeEventEmitter {
|
|
3
|
+
el;
|
|
4
|
+
destroyed = false;
|
|
5
|
+
constructor(el) {
|
|
6
|
+
super();
|
|
7
|
+
this.el = el;
|
|
8
|
+
}
|
|
9
|
+
destroy() {
|
|
10
|
+
if (this.destroyed)
|
|
11
|
+
return;
|
|
12
|
+
this.destroyed = true;
|
|
13
|
+
this.emit('destroy');
|
|
14
|
+
this.el.remove();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import isEqual from 'lodash/isEqual';
|
|
2
|
+
import kefir from 'kefir';
|
|
3
|
+
import EventEmitter from '../lib/safe-event-emitter';
|
|
4
|
+
import { GmailAppMenuItemView, NATIVE_CLASS, INBOXSDK_CLASS, } from '../dom-driver/gmail/views/gmail-app-menu-item-view';
|
|
5
|
+
import { CollapsiblePanelView } from './collapsible-panel-view';
|
|
6
|
+
import { addCollapsiblePanel } from '../dom-driver/gmail/gmail-driver/add-collapsible-panel';
|
|
7
|
+
import GmailElementGetter from '../dom-driver/gmail/gmail-element-getter';
|
|
8
|
+
let prevNative = {
|
|
9
|
+
menuItem: null,
|
|
10
|
+
panel: null,
|
|
11
|
+
route: null,
|
|
12
|
+
};
|
|
13
|
+
const setPrevNative = (next) => {
|
|
14
|
+
prevNative = {
|
|
15
|
+
...prevNative,
|
|
16
|
+
...next,
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Contains both a native Gmail app menu item and a collapsible panel.
|
|
21
|
+
*/
|
|
22
|
+
export class AppMenuItemView extends EventEmitter {
|
|
23
|
+
/**
|
|
24
|
+
* Native panels are HTMLElements, custom panels are CollapsiblePanelViews.
|
|
25
|
+
*/
|
|
26
|
+
static #activePanel;
|
|
27
|
+
static #nativeMenuItemChangeStream = (() => {
|
|
28
|
+
const stream = kefir.stream((emitter) => {
|
|
29
|
+
const observer = new MutationObserver((mutations) => {
|
|
30
|
+
for (const mutation of mutations) {
|
|
31
|
+
const { target } = mutation;
|
|
32
|
+
if (mutation.type === 'attributes' &&
|
|
33
|
+
target instanceof HTMLElement &&
|
|
34
|
+
target.classList.contains(NATIVE_CLASS) &&
|
|
35
|
+
!target.classList.contains(INBOXSDK_CLASS)) {
|
|
36
|
+
if (target.classList.contains(GmailAppMenuItemView.elementCss.ACTIVE)) {
|
|
37
|
+
emitter.emit(['activated', target]);
|
|
38
|
+
}
|
|
39
|
+
else if (target.classList.contains(GmailAppMenuItemView.elementCss.HOVER)) {
|
|
40
|
+
emitter.emit(['hovered', target]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const f = async () => {
|
|
46
|
+
const gmailAppMenu = await GmailElementGetter.getAppMenuAsync();
|
|
47
|
+
if (!gmailAppMenu) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const { ACTIVE } = GmailAppMenuItemView.elementCss;
|
|
51
|
+
const nativeMenuItemSelector = `.${NATIVE_CLASS}.${ACTIVE}:not(.${INBOXSDK_CLASS})`;
|
|
52
|
+
const nativeActivePanel = AppMenuItemView.#getNativeActivePanel();
|
|
53
|
+
setPrevNative({
|
|
54
|
+
menuItem: gmailAppMenu.querySelector(nativeMenuItemSelector),
|
|
55
|
+
panel: nativeActivePanel,
|
|
56
|
+
});
|
|
57
|
+
AppMenuItemView.#activePanel = nativeActivePanel;
|
|
58
|
+
document.addEventListener('mousedown', (e) => {
|
|
59
|
+
const { target } = e;
|
|
60
|
+
if (!(target instanceof Element)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!gmailAppMenu.contains(target)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const closest = target.closest(`.${NATIVE_CLASS}:not(.${INBOXSDK_CLASS})`);
|
|
67
|
+
if (closest) {
|
|
68
|
+
emitter.emit(['mousedown-on-native-el', closest, e]);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
observer.observe(gmailAppMenu, {
|
|
72
|
+
attributes: true,
|
|
73
|
+
childList: true,
|
|
74
|
+
subtree: true,
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
f();
|
|
78
|
+
});
|
|
79
|
+
return stream;
|
|
80
|
+
})();
|
|
81
|
+
static #getNativeActivePanel() {
|
|
82
|
+
const appMenuElement = GmailElementGetter.getAppMenuContainer();
|
|
83
|
+
const { ACTIVE, HOVER } = CollapsiblePanelView.elementCss;
|
|
84
|
+
const nativePanel = appMenuElement?.querySelector(`${CollapsiblePanelView.elementSelectors.NATIVE}.${ACTIVE}:not(.${HOVER}):not(${CollapsiblePanelView.elementSelectors.CUSTOM})`);
|
|
85
|
+
return nativePanel;
|
|
86
|
+
}
|
|
87
|
+
static #customMenuItems = new Set();
|
|
88
|
+
static {
|
|
89
|
+
AppMenuItemView.#nativeMenuItemChangeStream.onValue(async (e) => {
|
|
90
|
+
const [type, el /*, mouseEvent */] = e;
|
|
91
|
+
if (type === 'activated') {
|
|
92
|
+
AppMenuItemView.#activePanel = AppMenuItemView.#getNativeActivePanel();
|
|
93
|
+
await Promise.all(Array.from(AppMenuItemView.#customMenuItems).map(async (customMenuItem) => {
|
|
94
|
+
await customMenuItem.#deactivate();
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
if (type === 'mousedown-on-native-el') {
|
|
98
|
+
if (prevNative.menuItem !== el) {
|
|
99
|
+
prevNative.menuItem = el;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const { menuItem, panel, route } = prevNative;
|
|
104
|
+
prevNative.menuItem = el;
|
|
105
|
+
if (route) {
|
|
106
|
+
document.location.hash = route;
|
|
107
|
+
}
|
|
108
|
+
menuItem?.classList.add(GmailAppMenuItemView.elementCss.ACTIVE);
|
|
109
|
+
menuItem.classList.remove(GmailAppMenuItemView.elementCss.HOVER);
|
|
110
|
+
panel?.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
111
|
+
panel?.classList.remove(CollapsiblePanelView.elementCss.HOVER);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
#driver;
|
|
117
|
+
#destroyed = false;
|
|
118
|
+
#gmailViewPromise;
|
|
119
|
+
#collapsiblePanel;
|
|
120
|
+
/** Denotes if either the collapsable panel or app menu item are hovered. */
|
|
121
|
+
#hovered = false;
|
|
122
|
+
constructor(driver, menuItemDescriptor) {
|
|
123
|
+
super();
|
|
124
|
+
this.#driver = driver;
|
|
125
|
+
const gmailAppMenuItemView = this.#driver.addAppMenuItem(menuItemDescriptor);
|
|
126
|
+
this.#gmailViewPromise = gmailAppMenuItemView;
|
|
127
|
+
gmailAppMenuItemView.then((gmailView) => {
|
|
128
|
+
if (this.#destroyed || !gmailView) {
|
|
129
|
+
return; //we have been removed already
|
|
130
|
+
}
|
|
131
|
+
// add callbacks and listeners here
|
|
132
|
+
gmailView.on('click', this.#onClick);
|
|
133
|
+
gmailView.on('destroy', () => this.remove());
|
|
134
|
+
gmailView.on('blur', this.#onBlur);
|
|
135
|
+
gmailView.on('hover', this.#onHover);
|
|
136
|
+
// handle routing
|
|
137
|
+
driver.getRouteViewDriverStream().onValue((routeView) => {
|
|
138
|
+
const routeViewID = routeView.getRouteID();
|
|
139
|
+
const routeViewParams = routeView.getParams();
|
|
140
|
+
const routeViewType = routeView.getRouteType();
|
|
141
|
+
// Ignore custom routes that don't have a route id
|
|
142
|
+
// TODO fix chat/spaces routes to have NATIVE routeViewTypes so we can gate on that instead.
|
|
143
|
+
if (!(routeViewType === 'UNKNOWN' && routeViewID === null)) {
|
|
144
|
+
console.log({ routeViewID, routeViewType });
|
|
145
|
+
if (routeViewType !== 'CUSTOM') {
|
|
146
|
+
prevNative.route === document.location.hash;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const { activeRouteID, routeID, routeParams, activeRouteParams } = gmailView.menuItemDescriptor ?? {};
|
|
150
|
+
let isActive = isEqual(activeRouteID || routeID, routeViewID);
|
|
151
|
+
if (isActive) {
|
|
152
|
+
if (activeRouteParams) {
|
|
153
|
+
isActive = isEqual(activeRouteParams, routeViewParams);
|
|
154
|
+
}
|
|
155
|
+
else if (routeParams) {
|
|
156
|
+
isActive = isEqual(routeParams, routeViewParams);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// deactivation is handled by the native menu item change stream
|
|
160
|
+
if (isActive) {
|
|
161
|
+
this.#activate();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
AppMenuItemView.#customMenuItems.add(this);
|
|
166
|
+
}
|
|
167
|
+
async addCollapsiblePanel(panelDescriptor) {
|
|
168
|
+
const collapsiblePanel = await addCollapsiblePanel(this.#driver, panelDescriptor);
|
|
169
|
+
if (collapsiblePanel) {
|
|
170
|
+
collapsiblePanel.on('blur', this.#onBlur);
|
|
171
|
+
collapsiblePanel.on('hover', this.#onHover);
|
|
172
|
+
}
|
|
173
|
+
this.#collapsiblePanel = collapsiblePanel;
|
|
174
|
+
return collapsiblePanel;
|
|
175
|
+
}
|
|
176
|
+
async update(menuItemDescriptor) {
|
|
177
|
+
const gmailView = await this.#gmailViewPromise;
|
|
178
|
+
gmailView.setMenuItemDescriptor(menuItemDescriptor);
|
|
179
|
+
}
|
|
180
|
+
remove() {
|
|
181
|
+
if (this.#destroyed)
|
|
182
|
+
return;
|
|
183
|
+
this.#destroyed = true;
|
|
184
|
+
AppMenuItemView.#customMenuItems.delete(this);
|
|
185
|
+
this.emit('destroy');
|
|
186
|
+
this.#collapsiblePanel?.remove();
|
|
187
|
+
this.#gmailViewPromise.then((gmailView) => gmailView.remove());
|
|
188
|
+
}
|
|
189
|
+
async #deactivate() {
|
|
190
|
+
const gmailView = await this.#gmailViewPromise;
|
|
191
|
+
gmailView.deactivate();
|
|
192
|
+
this.#collapsiblePanel?.deactivate();
|
|
193
|
+
}
|
|
194
|
+
async #activate() {
|
|
195
|
+
AppMenuItemView.#activePanel = this.#collapsiblePanel;
|
|
196
|
+
const gmailView = await this.#gmailViewPromise;
|
|
197
|
+
const appMenuElement = GmailElementGetter.getAppMenuContainer();
|
|
198
|
+
const { ACTIVE } = GmailAppMenuItemView.elementCss;
|
|
199
|
+
// Note this affects both the active app menu item and the collapsible panel.
|
|
200
|
+
for (const el of appMenuElement?.querySelectorAll(`.${ACTIVE}`) ?? []) {
|
|
201
|
+
el.classList.remove(ACTIVE);
|
|
202
|
+
}
|
|
203
|
+
gmailView.activate();
|
|
204
|
+
this.#collapsiblePanel?.activate();
|
|
205
|
+
}
|
|
206
|
+
#onBlur = async (e) => {
|
|
207
|
+
const gmailView = await this.#gmailViewPromise;
|
|
208
|
+
const { relatedTarget } = e;
|
|
209
|
+
const blurringMenuItem = relatedTarget instanceof Node &&
|
|
210
|
+
gmailView.element?.contains(relatedTarget);
|
|
211
|
+
const blurringPanel = relatedTarget instanceof Node &&
|
|
212
|
+
this.#collapsiblePanel?.element?.contains(relatedTarget);
|
|
213
|
+
if (blurringMenuItem || blurringPanel) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this.#hovered = false;
|
|
217
|
+
gmailView.blur();
|
|
218
|
+
const hasActivePanel = this.#hasActivePanel();
|
|
219
|
+
this.#collapsiblePanel?.blur(hasActivePanel);
|
|
220
|
+
if (!hasActivePanel) {
|
|
221
|
+
if (AppMenuItemView.#activePanel instanceof CollapsiblePanelView) {
|
|
222
|
+
AppMenuItemView.#activePanel?.activate();
|
|
223
|
+
}
|
|
224
|
+
else if (AppMenuItemView.#activePanel instanceof HTMLElement) {
|
|
225
|
+
AppMenuItemView.#activePanel.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
this.emit('blur');
|
|
229
|
+
};
|
|
230
|
+
#hasActivePanel() {
|
|
231
|
+
return (this.#collapsiblePanel != null &&
|
|
232
|
+
AppMenuItemView.#activePanel === this.#collapsiblePanel);
|
|
233
|
+
}
|
|
234
|
+
#onHover = async (_e) => {
|
|
235
|
+
if (this.#hovered) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
this.#hovered = true;
|
|
239
|
+
const gmailView = await this.#gmailViewPromise;
|
|
240
|
+
gmailView.hover();
|
|
241
|
+
const hasActivePanel = this.#hasActivePanel();
|
|
242
|
+
if (!hasActivePanel) {
|
|
243
|
+
if (AppMenuItemView.#activePanel instanceof CollapsiblePanelView) {
|
|
244
|
+
AppMenuItemView.#activePanel?.deactivate();
|
|
245
|
+
}
|
|
246
|
+
else if (AppMenuItemView.#activePanel instanceof HTMLElement) {
|
|
247
|
+
AppMenuItemView.#activePanel.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
this.#collapsiblePanel?.hover(hasActivePanel);
|
|
251
|
+
this.emit('hover');
|
|
252
|
+
};
|
|
253
|
+
#onClick = () => {
|
|
254
|
+
this.#activate();
|
|
255
|
+
this.emit('click');
|
|
256
|
+
};
|
|
257
|
+
}
|