@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.
Files changed (138) hide show
  1. package/inboxsdk.js +1 -1
  2. package/inboxsdk.js.map +1 -1
  3. package/package.json +1 -1
  4. package/src/build/exec.js +26 -0
  5. package/src/build/spawn.js +17 -0
  6. package/src/common/ajax.js +90 -0
  7. package/src/common/cachebust-url.js +10 -0
  8. package/src/common/censorHTMLstring.js +37 -0
  9. package/src/common/censorHTMLtree.js +28 -0
  10. package/src/common/censorJSONTree.js +15 -0
  11. package/src/common/connectivity-test.js +21 -0
  12. package/src/common/defer.js +11 -0
  13. package/src/common/find-parent.js +10 -0
  14. package/src/common/get-extension-id.js +7 -0
  15. package/src/common/get-or-fail.js +8 -0
  16. package/src/common/get-session-id.js +14 -0
  17. package/src/common/get-stack-trace.js +6 -0
  18. package/src/common/html-to-text.js +7 -0
  19. package/src/common/isElementVisible.js +6 -0
  20. package/src/common/load-script.js +127 -0
  21. package/src/common/log-error.js +191 -0
  22. package/src/common/quoted-split.js +18 -0
  23. package/src/common/rate-limit-queuer.js +57 -0
  24. package/src/common/rate-limit.js +14 -0
  25. package/src/common/version.js +6 -0
  26. package/src/inboxsdk-js/loading/platform-implementation-loader.js +27 -0
  27. package/src/inboxsdk.d.ts +2 -0
  28. package/src/injected-js/gmail/constants.js +2 -0
  29. package/src/injected-js/gmail/modify-suggestions.js +106 -0
  30. package/src/injected-js/gmail/setup-gmonkey-handler.js +49 -0
  31. package/src/injected-js/gmail/sync-compose-processor-20220909.js +298 -0
  32. package/src/injected-js/gmail/sync-compose-processor.js +55 -0
  33. package/src/injected-js/gmail/sync-compose-request-processor.js +110 -0
  34. package/src/injected-js/injected-logger.js +50 -0
  35. package/src/injected-js/setupCustomViewEventAssassin.js +90 -0
  36. package/src/platform-implementation-js/constants/nav-item-types.js +19 -0
  37. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-app-menu-item.js +21 -0
  38. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-collapsible-panel.js +28 -0
  39. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-nav-item.js +98 -0
  40. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/add-support-item.js +4 -0
  41. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/encodeDraftUrlId.js +8 -0
  42. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/get-rfc-message-id-for-gmail-message-id.js +12 -0
  43. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/get-rfc-message-id-for-gmail-thread-id.js +33 -0
  44. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/isIntegratedViewGmail.js +4 -0
  45. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/open-draft-by-message-id.js +44 -0
  46. package/src/platform-implementation-js/dom-driver/gmail/gmail-driver/track-gmail-styles.js +95 -0
  47. package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter/get-main-content-element-changed-stream.js +38 -0
  48. package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter/wait-for-gmail-mode-to-settle.js +12 -0
  49. package/src/platform-implementation-js/dom-driver/gmail/gmail-element-getter.js +253 -0
  50. package/src/platform-implementation-js/dom-driver/gmail/gmail-page-communicator.js +200 -0
  51. package/src/platform-implementation-js/dom-driver/gmail/gmail-response-processor.js +533 -0
  52. package/src/platform-implementation-js/dom-driver/gmail/gmail-sync-response-processor.js +289 -0
  53. package/src/platform-implementation-js/dom-driver/gmail/is-compose-titlebar-light-color.js +21 -0
  54. package/src/platform-implementation-js/dom-driver/gmail/makePageParserTree.js +28 -0
  55. package/src/platform-implementation-js/dom-driver/gmail/pageParserOptions.js +19 -0
  56. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.js +126 -0
  57. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/add-status-bar.js +101 -0
  58. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/detectClassicRecipientsArea.js +38 -0
  59. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/get-address-information-extractor.js +28 -0
  60. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/get-recipients.js +22 -0
  61. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/gmail-compose-button-view.js +233 -0
  62. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/page-parser.js +223 -0
  63. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/set-recipients.js +157 -0
  64. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-compose-view/setupLinkPopovers.js +109 -0
  65. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-message-view/attachment-icon.js +5 -0
  66. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-nav-item-view.js +759 -0
  67. package/src/platform-implementation-js/dom-driver/gmail/views/gmail-support-item-view.js +84 -0
  68. package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/button-color-classes.js +33 -0
  69. package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/button-view.js +325 -0
  70. package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/create-accessory-button-view.js +58 -0
  71. package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/create-parent-accessory-button-view.js +55 -0
  72. package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/modal-button-view.js +96 -0
  73. package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/more-dropdown-button-view.js +30 -0
  74. package/src/platform-implementation-js/dom-driver/gmail/widgets/buttons/more-parent-accessory-button-view.js +10 -0
  75. package/src/platform-implementation-js/dom-driver/gmail/widgets/gmail-dropdown-view.js +22 -0
  76. package/src/platform-implementation-js/driver-common/getAccountUrlPart.js +17 -0
  77. package/src/platform-implementation-js/driver-common/getOriginalMessagePage.js +33 -0
  78. package/src/platform-implementation-js/driver-common/getSyncThreadsForSearch.js +49 -0
  79. package/src/platform-implementation-js/driver-common/gmailAjax.js +65 -0
  80. package/src/platform-implementation-js/driver-common/render-custom-icon.js +16 -0
  81. package/src/platform-implementation-js/driver-common/update-icon.js +90 -0
  82. package/src/platform-implementation-js/lib/ErrorCollector.js +47 -0
  83. package/src/platform-implementation-js/lib/Membrane.js +22 -0
  84. package/src/platform-implementation-js/lib/ScrollableContainByScreen.js +30 -0
  85. package/src/platform-implementation-js/lib/attemptWithRetries.js +16 -0
  86. package/src/platform-implementation-js/lib/common-page-communicator.js +137 -0
  87. package/src/platform-implementation-js/lib/delay-asap.js +12 -0
  88. package/src/platform-implementation-js/lib/delay-idle.js +16 -0
  89. package/src/platform-implementation-js/lib/dom/block-and-reemit-keyboard-events.js +36 -0
  90. package/src/platform-implementation-js/lib/dom/generic-button-view.js +39 -0
  91. package/src/platform-implementation-js/lib/dom/get-insert-before-element.js +39 -0
  92. package/src/platform-implementation-js/lib/dom/insert-element-in-order.js +38 -0
  93. package/src/platform-implementation-js/lib/dom/keyboard-shortcut-stream.js +12 -0
  94. package/src/platform-implementation-js/lib/dom/make-element-child-stream.js +79 -0
  95. package/src/platform-implementation-js/lib/dom/make-element-stream-merger.js +28 -0
  96. package/src/platform-implementation-js/lib/dom/make-element-view-stream.js +15 -0
  97. package/src/platform-implementation-js/lib/dom/make-mutation-observer-chunked-stream.js +15 -0
  98. package/src/platform-implementation-js/lib/dom/make-mutation-observer-stream.js +5 -0
  99. package/src/platform-implementation-js/lib/dom/outsideClicksAndEscape.js +39 -0
  100. package/src/platform-implementation-js/lib/dom/parentNodes.js +8 -0
  101. package/src/platform-implementation-js/lib/dom/querySelectorOrFail.js +6 -0
  102. package/src/platform-implementation-js/lib/dom/reemitClickEventForReact.js +22 -0
  103. package/src/platform-implementation-js/lib/dom/simulate-key.js +46 -0
  104. package/src/platform-implementation-js/lib/dom/simulate-mouse-event.js +16 -0
  105. package/src/platform-implementation-js/lib/dom/trigger-relay-event.js +7 -0
  106. package/src/platform-implementation-js/lib/extract-contact-from-email-contact-string.js +25 -0
  107. package/src/platform-implementation-js/lib/fake-window-resize.js +5 -0
  108. package/src/platform-implementation-js/lib/from-event-target-capture.js +12 -0
  109. package/src/platform-implementation-js/lib/fromEventsWithOptions.js +10 -0
  110. package/src/platform-implementation-js/lib/handler-registry.js +67 -0
  111. package/src/platform-implementation-js/lib/idMap.js +45 -0
  112. package/src/platform-implementation-js/lib/imageRequest.js +8 -0
  113. package/src/platform-implementation-js/lib/incrementName.js +7 -0
  114. package/src/platform-implementation-js/lib/inject-script-EMBEDDED.js +14 -0
  115. package/src/platform-implementation-js/lib/inject-script.js +33 -0
  116. package/src/platform-implementation-js/lib/is-valid-app-id.js +27 -0
  117. package/src/platform-implementation-js/lib/is-valid-email.js +14 -0
  118. package/src/platform-implementation-js/lib/isNotNil.js +5 -0
  119. package/src/platform-implementation-js/lib/isStreakAppId.js +11 -0
  120. package/src/platform-implementation-js/lib/logger.js +441 -0
  121. package/src/platform-implementation-js/lib/persistent-queue.js +107 -0
  122. package/src/platform-implementation-js/lib/safe-event-emitter.js +17 -0
  123. package/src/platform-implementation-js/lib/stopper-pool.js +41 -0
  124. package/src/platform-implementation-js/lib/stream-wait-for.js +30 -0
  125. package/src/platform-implementation-js/lib/wait-for.js +28 -0
  126. package/src/platform-implementation-js/lib/waitForAsync.js +19 -0
  127. package/src/platform-implementation-js/namespaces/app-menu.d.ts.map +1 -1
  128. package/src/platform-implementation-js/namespaces/app-menu.js +31 -0
  129. package/src/platform-implementation-js/namespaces/butter-bar.js +163 -0
  130. package/src/platform-implementation-js/views/SimpleElementView.js +16 -0
  131. package/src/platform-implementation-js/views/app-menu-item-view.js +257 -0
  132. package/src/platform-implementation-js/views/collapsible-panel-view.js +222 -0
  133. package/src/platform-implementation-js/views/compose-button-view.js +45 -0
  134. package/src/platform-implementation-js/views/compose-view.js +312 -0
  135. package/src/platform-implementation-js/views/keyboard-shortcut-handle.js +14 -0
  136. package/src/platform-implementation-js/widgets/buttons/basic-button-view-controller.js +39 -0
  137. package/src/platform-implementation-js/widgets/buttons/dropdown-button-view-controller.js +98 -0
  138. package/src/platform-implementation-js/widgets/buttons/dropdown-view.js +122 -0
@@ -0,0 +1,22 @@
1
+ import blockAndReemiteKeyboardEvents from '../../../lib/dom/block-and-reemit-keyboard-events';
2
+ export default class GmailDropdownView {
3
+ _containerElement;
4
+ _contentElement;
5
+ constructor() {
6
+ this._containerElement = document.createElement('div');
7
+ this._containerElement.setAttribute('class', 'inboxsdk__menu');
8
+ this._contentElement = document.createElement('div');
9
+ this._contentElement.setAttribute('class', 'inboxsdk__menuContent');
10
+ this._containerElement.appendChild(this._contentElement);
11
+ blockAndReemiteKeyboardEvents(this._containerElement);
12
+ }
13
+ destroy() {
14
+ this._containerElement.remove();
15
+ }
16
+ getContainerElement() {
17
+ return this._containerElement;
18
+ }
19
+ getContentElement() {
20
+ return this._contentElement;
21
+ }
22
+ }
@@ -0,0 +1,17 @@
1
+ /*
2
+ returns "/u/NUMBER" or "/u/NUMBER/d/DELEGATE_ID" for delegated accounts
3
+ */
4
+ export default function getAccountUrlPart() {
5
+ const delegatedAccountMatch = document.location.pathname.match(/\/b\/(.+?)\/u\/(\d+)/);
6
+ if (delegatedAccountMatch) {
7
+ const delegatedAccountId = delegatedAccountMatch[1];
8
+ const delegatedAccountNumber = delegatedAccountMatch[2];
9
+ return `/u/${delegatedAccountNumber}/d/${delegatedAccountId}`;
10
+ }
11
+ else {
12
+ const accountParamMatch = document.location.pathname.match(/(\/u\/\d+)\//i);
13
+ //no match happens in inbox when user only has one account
14
+ const accountParam = accountParamMatch ? accountParamMatch[1] : '/u/0';
15
+ return accountParam;
16
+ }
17
+ }
@@ -0,0 +1,33 @@
1
+ import { defn } from 'ud';
2
+ import gmailAjax from './gmailAjax';
3
+ async function getOriginalMessagePage(driver, options) {
4
+ const data = {
5
+ ik: driver.getPageCommunicator().getIkValue(),
6
+ view: 'om',
7
+ };
8
+ if (options.oldGmailMessageID) {
9
+ data.th = options.oldGmailMessageID;
10
+ }
11
+ else if (options.syncMessageID) {
12
+ data.permmsgid = options.syncMessageID;
13
+ }
14
+ let url;
15
+ const delegatedAccountMatch = document.location.pathname.match(/\/b\/(.+?)\/u\/(\d+)/);
16
+ if (delegatedAccountMatch) {
17
+ url = document.location.origin + document.location.pathname;
18
+ }
19
+ else {
20
+ const accountParamMatch = document.location.pathname.match(/(\/u\/\d+)\//i);
21
+ //no match happens in inbox when user only has one account
22
+ const accountParam = accountParamMatch ? accountParamMatch[1] : '/u/0';
23
+ url = `https://mail.google.com/mail${accountParam}`;
24
+ }
25
+ const { text } = await gmailAjax({
26
+ url,
27
+ method: 'GET',
28
+ canRetry: true,
29
+ data,
30
+ });
31
+ return text;
32
+ }
33
+ export default defn(module, getOriginalMessagePage);
@@ -0,0 +1,49 @@
1
+ import { defn } from 'ud';
2
+ import { extractThreadsFromSearchResponse } from '../dom-driver/gmail/gmail-sync-response-processor';
3
+ import gmailAjax from './gmailAjax';
4
+ import getAccountUrlPart from './getAccountUrlPart';
5
+ async function getSyncThreadsForSearch(driver, searchTerm) {
6
+ let responseText = null;
7
+ try {
8
+ const { text } = await gmailAjax({
9
+ method: 'POST',
10
+ url: `https://mail.google.com/sync${getAccountUrlPart()}/i/bv`,
11
+ headers: {
12
+ 'Content-Type': 'application/json',
13
+ 'X-Framework-Xsrf-Token': await driver
14
+ .getPageCommunicator()
15
+ .getXsrfToken(),
16
+ 'X-Gmail-BTAI': await driver.getPageCommunicator().getBtaiHeader(),
17
+ 'X-Google-BTD': '1',
18
+ },
19
+ data: JSON.stringify({
20
+ '1': {
21
+ '2': 1,
22
+ '4': searchTerm,
23
+ },
24
+ }),
25
+ });
26
+ responseText = text;
27
+ }
28
+ catch (err) {
29
+ const { text } = await gmailAjax({
30
+ method: 'POST',
31
+ url: `https://mail.google.com/sync${getAccountUrlPart()}/i/bv?rt=r&pt=ji`,
32
+ headers: {
33
+ 'Content-Type': 'application/json',
34
+ 'X-Framework-Xsrf-Token': await driver
35
+ .getPageCommunicator()
36
+ .getXsrfToken(),
37
+ 'X-Gmail-BTAI': await driver.getPageCommunicator().getBtaiHeader(),
38
+ 'X-Google-BTD': '1',
39
+ },
40
+ data: JSON.stringify([[null, 51, null, searchTerm]]),
41
+ });
42
+ responseText = text;
43
+ }
44
+ return {
45
+ threads: extractThreadsFromSearchResponse(responseText),
46
+ _text: responseText,
47
+ };
48
+ }
49
+ export default defn(module, getSyncThreadsForSearch);
@@ -0,0 +1,65 @@
1
+ import { defn } from 'ud';
2
+ import Kefir from 'kefir';
3
+ import imageRequest from '../lib/imageRequest';
4
+ import rateLimitQueuer from '../../common/rate-limit-queuer';
5
+ import ajax from '../../common/ajax';
6
+ const IMAGE_REQUEST_TIMEOUT = 1000 * 60; // one minute
7
+ const limitedAjax = rateLimitQueuer(rateLimitQueuer(ajax, 1000, 7), 10 * 1000, 50);
8
+ // Tool for making ajax requests to Gmail endpoints. When used in Inbox, this
9
+ // function is able to handle the issue that happens when the user has no Gmail
10
+ // cookies.
11
+ async function gmailAjax(opts) {
12
+ if (!/^https:\/\/mail\.google\.com(?:$|\/)/.test(opts.url)) {
13
+ throw new Error('Should not happen: gmailAjax called with non-gmail url');
14
+ }
15
+ if (document.location.origin === 'https://mail.google.com') {
16
+ return await limitedAjax(opts);
17
+ }
18
+ try {
19
+ return await limitedAjax({ ...opts, canRetry: false });
20
+ }
21
+ catch (e) {
22
+ if (e && e.status === 0) {
23
+ // The connection failed for an unspecified reason. One possible reason
24
+ // is that we have no Gmail cookies, and the connection tried to redirect
25
+ // to an accounts.google.com URL so the Gmail cookies could be set, but
26
+ // then this connection failed because we don't have ajax permission to
27
+ // accounts.google.com. We can work around this by trying an image
28
+ // request (which doesn't have cross-domain restrictions) so the Gmail
29
+ // cookies get set, and then retrying the original ajax request.
30
+ try {
31
+ await Kefir.fromPromise(imageRequest('https://mail.google.com/mail/u/0/'))
32
+ .merge(Kefir.later(IMAGE_REQUEST_TIMEOUT, undefined))
33
+ .take(1)
34
+ .takeErrors(1)
35
+ .toPromise();
36
+ }
37
+ catch (e) {
38
+ // ignore. If we got an error here, there are several possible causes:
39
+ // 1. The user has Gmail cookies, but the first connection attempt
40
+ // failed for another reason. In this case, we don't care about how
41
+ // this image request turned out.
42
+ // 2. The user did not have Gmail cookies, and the image's original
43
+ // request and its first few redirects succeeded, setting the
44
+ // cookies, but the final request, after the cookies were set,
45
+ // failed. We don't care about the image's final request.
46
+ // 3. The user did not have Gmail cookies, and the image request didn't
47
+ // work at all.
48
+ // In the final case, ideally we would retry the image request, but we
49
+ // can't distinguish that case from the other cases and doing retries
50
+ // of the image request would slow down the other cases. The first case
51
+ // is expected to be significantly more common -- the second two cases
52
+ // where the user has no Gmail cookies is expected to happen maybe once
53
+ // in total to an individual user.
54
+ }
55
+ return await limitedAjax(opts);
56
+ }
57
+ else if (e && typeof e.status === 'number' && e.status >= 500) {
58
+ return await limitedAjax(opts);
59
+ }
60
+ else {
61
+ throw e;
62
+ }
63
+ }
64
+ }
65
+ export default defn(module, gmailAjax);
@@ -0,0 +1,16 @@
1
+ export default function renderCustomIcon(containerElement, customIconElement, append, insertBeforeEl) {
2
+ // Check if icon wrapper exist or not
3
+ // when renderCustomIcon gets called for updating navItemDescriptor
4
+ let iconElementWrapper = containerElement.querySelector('.inboxsdk__button_icon');
5
+ if (!iconElementWrapper) {
6
+ iconElementWrapper = document.createElement('div');
7
+ iconElementWrapper.classList.add('inboxsdk__button_icon');
8
+ iconElementWrapper.appendChild(customIconElement);
9
+ }
10
+ if (append) {
11
+ containerElement.appendChild(iconElementWrapper);
12
+ }
13
+ else {
14
+ containerElement.insertBefore(containerElement, insertBeforeEl || containerElement.firstElementChild);
15
+ }
16
+ }
@@ -0,0 +1,90 @@
1
+ function createIconElement(containerElement, append, insertBeforeEl) {
2
+ const iconElement = document.createElement('div');
3
+ iconElement.classList.add('inboxsdk__button_icon');
4
+ iconElement.innerHTML = ' ';
5
+ if (append) {
6
+ containerElement.appendChild(iconElement);
7
+ }
8
+ else {
9
+ containerElement.insertBefore(iconElement, insertBeforeEl || containerElement.firstElementChild);
10
+ }
11
+ return iconElement;
12
+ }
13
+ function createIconImgElement(iconUrl, containerElement, append, insertBeforeEl) {
14
+ const iconElement = createIconElement(containerElement, append, insertBeforeEl);
15
+ iconElement.innerHTML = '';
16
+ const iconImgElement = document.createElement('img');
17
+ iconImgElement.classList.add('inboxsdk__button_iconImg');
18
+ iconImgElement.src = iconUrl;
19
+ iconElement.appendChild(iconImgElement);
20
+ return iconElement;
21
+ }
22
+ // TODO make this return a class instead of taking the iconSettings state object
23
+ export default function updateIcon(iconSettings, containerElement, append, newIconClass, newIconUrl, insertBeforeEl, // Should not be used with append: true — the append flag will override
24
+ newIconHtml) {
25
+ if (append && insertBeforeEl)
26
+ throw new Error('append and insertBeforeEl should not be used together');
27
+ // if iconHtml exists, class or url presents just throw error
28
+ if (newIconHtml && (newIconClass || newIconUrl)) {
29
+ throw new Error('iconHtml can not be used together with iconClass or iconUrl');
30
+ }
31
+ if (newIconHtml) {
32
+ if (!iconSettings.iconHtmlElement) {
33
+ iconSettings.iconHtmlElement = createIconElement(containerElement, append, insertBeforeEl);
34
+ }
35
+ iconSettings.iconHtmlElement.innerHTML = newIconHtml;
36
+ if (iconSettings.iconImgElement) {
37
+ iconSettings.iconImgElement.remove();
38
+ iconSettings.iconImgElement = null;
39
+ }
40
+ if (iconSettings.iconElement) {
41
+ iconSettings.iconElement.remove();
42
+ iconSettings.iconElement = null;
43
+ }
44
+ }
45
+ else if (newIconUrl) {
46
+ if (!iconSettings.iconImgElement) {
47
+ iconSettings.iconImgElement = createIconImgElement(newIconUrl, containerElement, append, insertBeforeEl);
48
+ }
49
+ else {
50
+ iconSettings.iconImgElement.firstElementChild.src = newIconUrl;
51
+ }
52
+ iconSettings.iconImgElement.setAttribute('class', `inboxsdk__button_icon ${newIconClass || ''}`);
53
+ if (iconSettings.iconHtmlElement) {
54
+ iconSettings.iconHtmlElement.remove();
55
+ iconSettings.iconHtmlElement = null;
56
+ }
57
+ if (iconSettings.iconElement) {
58
+ iconSettings.iconElement.remove();
59
+ iconSettings.iconElement = null;
60
+ }
61
+ }
62
+ else if (newIconClass) {
63
+ if (!iconSettings.iconElement) {
64
+ iconSettings.iconElement = createIconElement(containerElement, append, insertBeforeEl);
65
+ }
66
+ iconSettings.iconElement.setAttribute('class', 'inboxsdk__button_icon ' + newIconClass);
67
+ if (iconSettings.iconHtmlElement) {
68
+ iconSettings.iconHtmlElement.remove();
69
+ iconSettings.iconHtmlElement = null;
70
+ }
71
+ if (iconSettings.iconImgElement) {
72
+ iconSettings.iconImgElement.remove();
73
+ iconSettings.iconImgElement = null;
74
+ }
75
+ }
76
+ else {
77
+ if (iconSettings.iconElement) {
78
+ iconSettings.iconElement.remove();
79
+ iconSettings.iconElement = null;
80
+ }
81
+ if (iconSettings.iconHtmlElement) {
82
+ iconSettings.iconHtmlElement.remove();
83
+ iconSettings.iconHtmlElement = null;
84
+ }
85
+ if (iconSettings.iconImgElement) {
86
+ iconSettings.iconImgElement.remove();
87
+ iconSettings.iconImgElement = null;
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,47 @@
1
+ import Logger from './logger';
2
+ export default class ErrorCollector {
3
+ _name;
4
+ _runCount = 0;
5
+ _errorLogs = [];
6
+ _hasReported = false;
7
+ constructor(name) {
8
+ this._name = name;
9
+ }
10
+ run(name, cb) {
11
+ if (this._hasReported) {
12
+ throw new Error('Has already reported');
13
+ }
14
+ this._runCount++;
15
+ try {
16
+ return cb();
17
+ }
18
+ catch (e) {
19
+ this._errorLogs.push({
20
+ name,
21
+ message: e.message,
22
+ });
23
+ return null;
24
+ }
25
+ }
26
+ report(errorDataCb) {
27
+ if (this._hasReported) {
28
+ throw new Error('Has already reported');
29
+ }
30
+ this._hasReported = true;
31
+ if (this._errorLogs.length) {
32
+ Logger.error(new Error(`Error Collector: ${this._name}`), {
33
+ errorLogs: this._errorLogs,
34
+ extra: errorDataCb(),
35
+ });
36
+ }
37
+ }
38
+ getErrorLogs() {
39
+ return this._errorLogs;
40
+ }
41
+ runCount() {
42
+ return this._runCount;
43
+ }
44
+ errorCount() {
45
+ return this._errorLogs.length;
46
+ }
47
+ }
@@ -0,0 +1,22 @@
1
+ // Used to make the *View objects out of our *ViewDriver objects, and to make
2
+ // sure we return the same *View object back if we've already made one for
3
+ // given *ViewDriver.
4
+ export default class Membrane {
5
+ _mappers;
6
+ _map = new WeakMap();
7
+ constructor(mappers) {
8
+ this._mappers = new Map(mappers);
9
+ }
10
+ get(wet) {
11
+ let dry = this._map.get(wet);
12
+ if (!dry) {
13
+ const mapperFn = this._mappers.get(wet.constructor);
14
+ if (!mapperFn) {
15
+ throw new Error(`Unknown class ${wet.constructor.name}`);
16
+ }
17
+ dry = mapperFn(wet);
18
+ this._map.set(wet, dry);
19
+ }
20
+ return dry;
21
+ }
22
+ }
@@ -0,0 +1,30 @@
1
+ import containByScreen from 'contain-by-screen';
2
+ import Kefir from 'kefir';
3
+ import kefirBus from 'kefir-bus';
4
+ import kefirStopper from 'kefir-stopper';
5
+ import fromEventsWithOptions from './fromEventsWithOptions';
6
+ export default class ScrollableContainByScreen {
7
+ _manualRepositions = kefirBus();
8
+ _stopper = kefirStopper();
9
+ constructor(element, anchorPoint, options) {
10
+ Kefir.merge([
11
+ this._manualRepositions,
12
+ Kefir.fromEvents(window, 'resize'),
13
+ fromEventsWithOptions(window, 'scroll', {
14
+ capture: true,
15
+ passive: true,
16
+ }).filter((event) => event.target.contains(anchorPoint)),
17
+ ])
18
+ .toProperty(() => null)
19
+ .takeUntilBy(this._stopper)
20
+ .onValue(() => {
21
+ containByScreen(element, anchorPoint, options);
22
+ });
23
+ }
24
+ reposition() {
25
+ this._manualRepositions.emit(null);
26
+ }
27
+ destroy() {
28
+ this._stopper.destroy();
29
+ }
30
+ }
@@ -0,0 +1,16 @@
1
+ export default async function attemptWithRetries(fn, attemptCount, errorsToRetry = () => true) {
2
+ if (attemptCount < 1) {
3
+ throw new Error('Attempt count must be positive');
4
+ }
5
+ try {
6
+ return await fn();
7
+ }
8
+ catch (err) {
9
+ if (attemptCount > 1 && errorsToRetry(err)) {
10
+ return attemptWithRetries(fn, attemptCount - 1, errorsToRetry);
11
+ }
12
+ else {
13
+ throw err;
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,137 @@
1
+ import asap from 'asap';
2
+ import once from 'lodash/once';
3
+ import * as Kefir from 'kefir';
4
+ import Logger from './logger';
5
+ export default class CommonPageCommunicator {
6
+ ajaxInterceptStream;
7
+ constructor() {
8
+ this.ajaxInterceptStream = Kefir.fromEvents(document, 'inboxSDKajaxIntercept').map((x) => x.detail);
9
+ }
10
+ getUserEmailAddress() {
11
+ const s = document.head.getAttribute('data-inboxsdk-user-email-address');
12
+ if (typeof s !== 'string')
13
+ throw new Error('should not happen');
14
+ return s;
15
+ }
16
+ getUserLanguage() {
17
+ const s = document.head.getAttribute('data-inboxsdk-user-language');
18
+ if (typeof s !== 'string')
19
+ throw new Error('should not happen');
20
+ return s;
21
+ }
22
+ getIkValue() {
23
+ const ownIk = document.head.getAttribute('data-inboxsdk-ik-value');
24
+ if (ownIk) {
25
+ return ownIk;
26
+ }
27
+ // For standalone windows.
28
+ if (window.opener) {
29
+ const openerIk = window.opener.document.head.getAttribute('data-inboxsdk-ik-value');
30
+ if (openerIk) {
31
+ return openerIk;
32
+ }
33
+ else {
34
+ throw new Error("Failed to look up parent window 'ik' value");
35
+ }
36
+ }
37
+ throw new Error("Failed to look up 'ik' value");
38
+ }
39
+ isUsingSyncAPI() {
40
+ return false;
41
+ }
42
+ async getXsrfToken() {
43
+ const existingHeader = document.head.getAttribute('data-inboxsdk-xsrf-token');
44
+ if (existingHeader) {
45
+ return existingHeader;
46
+ }
47
+ else {
48
+ await this.ajaxInterceptStream
49
+ .filter(({ type }) => type === 'xsrfTokenHeaderReceived')
50
+ .take(1)
51
+ .toPromise();
52
+ const newHeader = document.head.getAttribute('data-inboxsdk-xsrf-token');
53
+ if (!newHeader)
54
+ throw new Error('Failed to look up XSRF token');
55
+ return newHeader;
56
+ }
57
+ }
58
+ async getBtaiHeader() {
59
+ const existingHeader = document.head.getAttribute('data-inboxsdk-btai-header');
60
+ if (existingHeader) {
61
+ return existingHeader;
62
+ }
63
+ else {
64
+ await this.ajaxInterceptStream
65
+ .filter(({ type }) => type === 'btaiHeaderReceived')
66
+ .take(1)
67
+ .toPromise();
68
+ const newHeader = document.head.getAttribute('data-inboxsdk-btai-header');
69
+ if (!newHeader)
70
+ throw new Error('Failed to look up BTAI header');
71
+ return newHeader;
72
+ }
73
+ }
74
+ resolveUrlRedirects(url) {
75
+ return this.pageAjax({ url, method: 'HEAD' }).then((result) => result.responseURL);
76
+ }
77
+ pageAjax(opts) {
78
+ const id = `${Date.now()}-${Math.random()}`;
79
+ const promise = Kefir.fromEvents(document, 'inboxSDKpageAjaxDone')
80
+ .filter((event) => event.detail && event.detail.id === id)
81
+ .take(1)
82
+ .flatMap((event) => {
83
+ if (event.detail.error) {
84
+ const err = Object.assign(new Error(event.detail.message || 'Connection error'), { status: event.detail.status });
85
+ if (event.detail.stack) {
86
+ err.stack = event.detail.stack;
87
+ }
88
+ return Kefir.constantError(err);
89
+ }
90
+ else {
91
+ return Kefir.constant({
92
+ text: event.detail.text,
93
+ responseURL: event.detail.responseURL,
94
+ });
95
+ }
96
+ })
97
+ .toPromise();
98
+ document.dispatchEvent(new CustomEvent('inboxSDKpageAjax', {
99
+ bubbles: false,
100
+ cancelable: false,
101
+ detail: Object.assign({}, opts, { id }),
102
+ }));
103
+ return promise;
104
+ }
105
+ silenceGmailErrorsForAMoment() {
106
+ document.dispatchEvent(new CustomEvent('inboxSDKsilencePageErrors', {
107
+ bubbles: false,
108
+ cancelable: false,
109
+ detail: null,
110
+ }));
111
+ // create error here for stacktrace
112
+ const error = new Error('Forgot to unsilence page errors');
113
+ let unsilenced = false;
114
+ const unsilence = once(() => {
115
+ unsilenced = true;
116
+ document.dispatchEvent(new CustomEvent('inboxSDKunsilencePageErrors', {
117
+ bubbles: false,
118
+ cancelable: false,
119
+ detail: null,
120
+ }));
121
+ });
122
+ asap(() => {
123
+ if (!unsilenced) {
124
+ Logger.error(error);
125
+ unsilence();
126
+ }
127
+ });
128
+ return unsilence;
129
+ }
130
+ registerAllowedHashLinkStartTerm(term) {
131
+ document.dispatchEvent(new CustomEvent('inboxSDKregisterAllowedHashLinkStartTerm', {
132
+ bubbles: false,
133
+ cancelable: false,
134
+ detail: { term },
135
+ }));
136
+ }
137
+ }
@@ -0,0 +1,12 @@
1
+ import asap from 'asap';
2
+ import * as Kefir from 'kefir';
3
+ // Returns a stream that emits a value in the next event loop run. Works well
4
+ // with flatmap.
5
+ export default function delayAsap(value) {
6
+ return Kefir.stream((emitter) => {
7
+ asap(() => {
8
+ emitter.emit(value);
9
+ emitter.end();
10
+ });
11
+ });
12
+ }
@@ -0,0 +1,16 @@
1
+ import * as Kefir from 'kefir';
2
+ const requestIdleCallback = global.requestIdleCallback || ((cb) => setTimeout(cb, 0));
3
+ const cancelIdleCallback = global.cancelIdleCallback || clearTimeout;
4
+ // Returns a stream that emits a value using requestIdleCallback. Works well
5
+ // with flatmap.
6
+ export default function delayIdle(timeout, value) {
7
+ return Kefir.stream((emitter) => {
8
+ const t = requestIdleCallback(() => {
9
+ emitter.emit(value);
10
+ emitter.end();
11
+ }, timeout == null ? null : { timeout });
12
+ return () => {
13
+ cancelIdleCallback(t);
14
+ };
15
+ });
16
+ }
@@ -0,0 +1,36 @@
1
+ import Kefir from 'kefir';
2
+ export default function blockAndReemiteKeyboardEvents(element) {
3
+ // Gmail stops propagation of keyboard events from escaping
4
+ // a specific compose window, which prevents any React components rendered
5
+ // in the compose window's subtree from getting them (since React adds
6
+ // a single event listener on the document). By stopping propagation of
7
+ // the original event and reemiting it on the document, we preserve
8
+ // exisitng behavior while giving React a chance to hear it.
9
+ Kefir.merge([
10
+ Kefir.fromEvents(element, 'keypress'),
11
+ Kefir.fromEvents(element, 'keydown'),
12
+ Kefir.fromEvents(element, 'keyup'),
13
+ ]).onValue((event) => {
14
+ event.stopPropagation();
15
+ const fakeEvent = new KeyboardEvent(event.type, { bubbles: true });
16
+ Object.defineProperties(fakeEvent, {
17
+ cancelable: { value: event.cancelable },
18
+ bubbles: { value: event.bubbles },
19
+ target: { value: event.target },
20
+ detail: { value: event.detail },
21
+ key: { value: event.key },
22
+ code: { value: event.code },
23
+ location: { value: event.location },
24
+ ctrlKey: { value: event.ctrlKey },
25
+ shiftKey: { value: event.shiftKey },
26
+ altKey: { value: event.altKey },
27
+ metaKey: { value: event.metaKey },
28
+ repeat: { value: event.repeat },
29
+ isComposing: { value: event.isComposing },
30
+ charCode: { value: event.charCode },
31
+ keyCode: { value: event.keyCode },
32
+ which: { value: event.which },
33
+ });
34
+ document.dispatchEvent(fakeEvent);
35
+ });
36
+ }
@@ -0,0 +1,39 @@
1
+ import * as Kefir from 'kefir';
2
+ import kefirBus from 'kefir-bus';
3
+ export default class GenericButtonView {
4
+ _eventStream = kefirBus();
5
+ _element;
6
+ constructor(element) {
7
+ this._element = element;
8
+ this._setupEventStream();
9
+ }
10
+ destroy() {
11
+ this._element.remove();
12
+ this._eventStream.end();
13
+ }
14
+ getElement() {
15
+ return this._element;
16
+ }
17
+ getEventStream() {
18
+ return this._eventStream;
19
+ }
20
+ activate() {
21
+ /* do nothing */
22
+ }
23
+ deactivate() {
24
+ /* do nothing */
25
+ }
26
+ _setupEventStream() {
27
+ const clickEventStream = Kefir.fromEvents(this._element, 'click');
28
+ clickEventStream.onValue((event) => {
29
+ event.stopPropagation();
30
+ event.preventDefault();
31
+ });
32
+ this._eventStream.plug(clickEventStream.map((event) => {
33
+ return {
34
+ eventName: 'click',
35
+ domEvent: event,
36
+ };
37
+ }));
38
+ }
39
+ }