@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,289 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import isNotNil from '../../lib/isNotNil';
3
+ export function extractThreadsFromSearchResponse(response) {
4
+ const parsedResponse = JSON.parse(response);
5
+ if (Array.isArray(parsedResponse)) {
6
+ try {
7
+ return extractThreadsFromSearchResponse_20220909(parsedResponse);
8
+ }
9
+ catch (err) {
10
+ return [];
11
+ }
12
+ }
13
+ const threadDescriptors = parsedResponse && parsedResponse[3];
14
+ if (!threadDescriptors)
15
+ return [];
16
+ return threadDescriptors
17
+ .map((descriptorWrapper, index) => {
18
+ const descriptor = descriptorWrapper[1];
19
+ if (!descriptor)
20
+ return null;
21
+ return {
22
+ subject: descriptor[1],
23
+ snippet: descriptor[2],
24
+ syncThreadID: descriptor[4],
25
+ // It seems Gmail is A/B testing including gmailThreadID in descriptor[20] and not including
26
+ // the encoded version of it in descriptor[18], so pull it from [20] if [18] is not set.
27
+ oldGmailThreadID: descriptor[18] != null
28
+ ? new BigNumber(descriptor[18]).toString(16)
29
+ : descriptor[20],
30
+ rawResponse: descriptorWrapper,
31
+ extraMetaData: {
32
+ snippet: (parsedResponse[15] &&
33
+ parsedResponse[15][1] &&
34
+ parsedResponse[15][1][index]) ||
35
+ '',
36
+ syncMessageData: descriptor[5].map((md) => ({
37
+ syncMessageID: md[1],
38
+ oldMessageID: md[56],
39
+ date: +md[7],
40
+ })),
41
+ },
42
+ };
43
+ })
44
+ .filter(isNotNil);
45
+ }
46
+ export function extractThreadsFromSearchResponse_20220909(parsedResponse) {
47
+ const threadDescriptors = parsedResponse && parsedResponse[2];
48
+ if (!threadDescriptors)
49
+ return [];
50
+ return threadDescriptors
51
+ .map((descriptorWrapper, index) => {
52
+ const descriptor = descriptorWrapper[0];
53
+ if (!descriptor)
54
+ return null;
55
+ return {
56
+ subject: descriptor[0],
57
+ snippet: descriptor[1],
58
+ syncThreadID: descriptor[3],
59
+ // It seems Gmail is A/B testing including gmailThreadID in descriptor[20] and not including
60
+ // the encoded version of it in descriptor[18], so pull it from [20] if [18] is not set.
61
+ oldGmailThreadID: descriptor[17] != null
62
+ ? new BigNumber(descriptor[17]).toString(16)
63
+ : descriptor[19],
64
+ rawResponse: descriptorWrapper,
65
+ extraMetaData: {
66
+ snippet: (parsedResponse[14] &&
67
+ parsedResponse[14][0] &&
68
+ parsedResponse[14][0][index]) ||
69
+ '',
70
+ syncMessageData: descriptor[4].map((md) => ({
71
+ syncMessageID: md[0],
72
+ oldMessageID: md[55],
73
+ date: +md[6],
74
+ })),
75
+ },
76
+ };
77
+ })
78
+ .filter(isNotNil);
79
+ }
80
+ export function extractThreadsFromThreadResponse(response) {
81
+ const parsedResponse = JSON.parse(response);
82
+ if (Array.isArray(parsedResponse)) {
83
+ return extractThreadsFromThreadResponse_20220909(parsedResponse);
84
+ }
85
+ const threadDescriptors = parsedResponse && parsedResponse[2];
86
+ if (!threadDescriptors)
87
+ throw new Error('Failed to process thread response');
88
+ return threadDescriptors
89
+ .map((descriptorWrapper) => {
90
+ if (typeof descriptorWrapper[1] === 'string' &&
91
+ Array.isArray(descriptorWrapper[3]) &&
92
+ !(descriptorWrapper[2] &&
93
+ descriptorWrapper[2][1] &&
94
+ descriptorWrapper[2][1][14] &&
95
+ Array.isArray(descriptorWrapper[2][2]))) {
96
+ return {
97
+ syncThreadID: descriptorWrapper[1],
98
+ oldGmailThreadID: (descriptorWrapper[2] &&
99
+ descriptorWrapper[2][1] &&
100
+ descriptorWrapper[2][1][16]) ||
101
+ undefined,
102
+ extraMetaData: {
103
+ snippet: (descriptorWrapper[2] &&
104
+ descriptorWrapper[2][1] &&
105
+ descriptorWrapper[2][1][3]) ||
106
+ undefined,
107
+ syncMessageData: (descriptorWrapper[3] || [])
108
+ .filter((md) => Boolean(md[2]))
109
+ .map((md) => ({
110
+ syncMessageID: md[1],
111
+ date: +md[2][17],
112
+ recipients: getRecipientsFromMessageDescriptor(md),
113
+ })),
114
+ },
115
+ };
116
+ }
117
+ else {
118
+ const threadDescriptor = descriptorWrapper[2] && descriptorWrapper[2][1];
119
+ if (!threadDescriptor)
120
+ return null;
121
+ let syncMessageData;
122
+ const fullMessageDescriptors = Array.isArray(descriptorWrapper[3]) && descriptorWrapper[3];
123
+ if (fullMessageDescriptors) {
124
+ syncMessageData = fullMessageDescriptors.map((md) => ({
125
+ syncMessageID: md[1],
126
+ date: +md[2][17],
127
+ recipients: getRecipientsFromMessageDescriptor(md),
128
+ }));
129
+ }
130
+ else {
131
+ const messageDescriptors = descriptorWrapper[2] && descriptorWrapper[2][2];
132
+ syncMessageData = messageDescriptors.map((md) => ({
133
+ syncMessageId: md[1],
134
+ date: +md[16],
135
+ }));
136
+ }
137
+ return {
138
+ subject: threadDescriptor[2],
139
+ snippet: threadDescriptor[3],
140
+ syncThreadID: threadDescriptor[1],
141
+ oldGmailThreadID: new BigNumber(threadDescriptor[14]).toString(16),
142
+ rawResponse: descriptorWrapper,
143
+ extraMetaData: {
144
+ syncMessageData,
145
+ snippet: '',
146
+ },
147
+ };
148
+ }
149
+ })
150
+ .filter(isNotNil);
151
+ }
152
+ function extractThreadsFromThreadResponse_20220909(parsedResponse) {
153
+ const threadDescriptors = parsedResponse && parsedResponse[1];
154
+ if (!threadDescriptors)
155
+ throw new Error('Failed to process thread response');
156
+ return threadDescriptors
157
+ .map((descriptorWrapper) => {
158
+ if (typeof descriptorWrapper[0] === 'string' &&
159
+ Array.isArray(descriptorWrapper[2]) &&
160
+ !(descriptorWrapper[1] &&
161
+ descriptorWrapper[1][0] &&
162
+ descriptorWrapper[1][0][13] &&
163
+ Array.isArray(descriptorWrapper[1][1]))) {
164
+ return {
165
+ syncThreadID: descriptorWrapper[0],
166
+ oldGmailThreadID: (descriptorWrapper[1] &&
167
+ descriptorWrapper[1][0] &&
168
+ descriptorWrapper[1][0][15]) ||
169
+ undefined,
170
+ extraMetaData: {
171
+ snippet: (descriptorWrapper[1] &&
172
+ descriptorWrapper[1][0] &&
173
+ descriptorWrapper[1][0][2]) ||
174
+ undefined,
175
+ syncMessageData: (descriptorWrapper[2] || [])
176
+ .filter((md) => Boolean(md[1]))
177
+ .map((md) => ({
178
+ syncMessageID: md[0],
179
+ date: +md[1][16],
180
+ recipients: getRecipientsFromMessageDescriptor_20220909(md),
181
+ })),
182
+ },
183
+ };
184
+ }
185
+ else {
186
+ const threadDescriptor = descriptorWrapper[1] && descriptorWrapper[1][0];
187
+ if (!threadDescriptor)
188
+ return null;
189
+ let syncMessageData;
190
+ const fullMessageDescriptors = Array.isArray(descriptorWrapper[2]) && descriptorWrapper[2];
191
+ if (fullMessageDescriptors) {
192
+ syncMessageData = fullMessageDescriptors.map((md) => ({
193
+ syncMessageID: md[0],
194
+ date: +md[1][16],
195
+ recipients: getRecipientsFromMessageDescriptor_20220909(md),
196
+ }));
197
+ }
198
+ else {
199
+ const messageDescriptors = descriptorWrapper[1] && descriptorWrapper[1][1];
200
+ syncMessageData = messageDescriptors.map((md) => ({
201
+ syncMessageId: md[0],
202
+ date: +md[15],
203
+ }));
204
+ }
205
+ return {
206
+ subject: threadDescriptor[1],
207
+ snippet: threadDescriptor[2],
208
+ syncThreadID: threadDescriptor[0],
209
+ oldGmailThreadID: new BigNumber(threadDescriptor[13]).toString(16),
210
+ rawResponse: descriptorWrapper,
211
+ extraMetaData: {
212
+ syncMessageData,
213
+ snippet: '',
214
+ },
215
+ };
216
+ }
217
+ })
218
+ .filter(isNotNil);
219
+ }
220
+ function getRecipientsFromMessageDescriptor(messageDescriptor) {
221
+ if (!messageDescriptor[2])
222
+ return;
223
+ const to = messageDescriptor[2][1] || [];
224
+ const cc = messageDescriptor[2][2] || [];
225
+ const bcc = messageDescriptor[2][3] || [];
226
+ return to
227
+ .concat(cc)
228
+ .concat(bcc)
229
+ .map((recipientDescriptor) => ({
230
+ emailAddress: recipientDescriptor[2],
231
+ name: recipientDescriptor[3],
232
+ }));
233
+ }
234
+ function getRecipientsFromMessageDescriptor_20220909(messageDescriptor) {
235
+ if (!messageDescriptor[1])
236
+ return;
237
+ const to = messageDescriptor[1][0] || [];
238
+ const cc = messageDescriptor[1][1] || [];
239
+ const bcc = messageDescriptor[1][2] || [];
240
+ return to
241
+ .concat(cc)
242
+ .concat(bcc)
243
+ .map((recipientDescriptor) => ({
244
+ emailAddress: recipientDescriptor[1],
245
+ name: recipientDescriptor[2],
246
+ }));
247
+ }
248
+ export function replaceThreadsInSearchResponse(response, replacementThreads, _unused // TODO why is this unused?
249
+ ) {
250
+ const parsedResponse = JSON.parse(response);
251
+ if (Array.isArray(parsedResponse)) {
252
+ try {
253
+ return replaceThreadsInSearchResponse_20220909(parsedResponse, replacementThreads, _unused);
254
+ }
255
+ catch (err) {
256
+ return response;
257
+ }
258
+ }
259
+ if (parsedResponse[3] || replacementThreads.length) {
260
+ parsedResponse[3] = replacementThreads.map(({ rawResponse }, index) => ({
261
+ ...rawResponse,
262
+ '2': index,
263
+ }));
264
+ }
265
+ if (parsedResponse[15] || replacementThreads.length) {
266
+ parsedResponse[15] = {
267
+ ...parsedResponse[15],
268
+ '1': replacementThreads.map(({ extraMetaData }) => extraMetaData.snippet),
269
+ '2': replacementThreads.map(({ extraMetaData }) => extraMetaData.syncMessageData.map(({ syncMessageID }) => syncMessageID)),
270
+ };
271
+ }
272
+ return JSON.stringify(parsedResponse);
273
+ }
274
+ export function replaceThreadsInSearchResponse_20220909(parsedResponse, replacementThreads, _unused // TODO why is this unused?
275
+ ) {
276
+ if (parsedResponse[2] || replacementThreads.length) {
277
+ parsedResponse[2] = replacementThreads.map(({ rawResponse }, index) => {
278
+ const res = [...rawResponse];
279
+ res[1] = index;
280
+ return res;
281
+ });
282
+ }
283
+ if (parsedResponse[14] || replacementThreads.length) {
284
+ parsedResponse[14] = [...parsedResponse[14]];
285
+ parsedResponse[14][0] = replacementThreads.map(({ extraMetaData }) => extraMetaData.snippet);
286
+ parsedResponse[14][1] = replacementThreads.map(({ extraMetaData }) => extraMetaData.syncMessageData.map(({ syncMessageID }) => syncMessageID));
287
+ }
288
+ return JSON.stringify(parsedResponse);
289
+ }
@@ -0,0 +1,21 @@
1
+ import once from 'lodash/once';
2
+ function isGmailRuleForTitlebarWideIcons() {
3
+ return !![...document.styleSheets].find((s) => {
4
+ try {
5
+ if (s.cssRules) {
6
+ return [...s.cssRules].find((rule) => rule instanceof CSSStyleRule &&
7
+ rule.selectorText === '.Hl' &&
8
+ rule.style.width === '24px');
9
+ }
10
+ }
11
+ catch (e) {
12
+ // Some stylesheets are crossorigin and throw if we try to access
13
+ // their rules. Don't worry about them.
14
+ }
15
+ return false;
16
+ });
17
+ }
18
+ const isComposeTitleBarLightColor = once(() => {
19
+ return !isGmailRuleForTitlebarWideIcons();
20
+ });
21
+ export default isComposeTitleBarLightColor;
@@ -0,0 +1,28 @@
1
+ import PageParserTree from 'page-parser-tree';
2
+ import udKefir from 'ud-kefir';
3
+ import pageParserOptions from './pageParserOptions';
4
+ import censorHTMLtree from '../../../common/censorHTMLtree';
5
+ const pageParserOptionsStream = udKefir(module, pageParserOptions);
6
+ export default function makePageParserTree(driver, root) {
7
+ const _driver = driver;
8
+ function transformOptions(pageParserOptions) {
9
+ return !_driver
10
+ ? pageParserOptions
11
+ : {
12
+ ...pageParserOptions,
13
+ logError(err, el) {
14
+ const details = {
15
+ el,
16
+ html: el ? censorHTMLtree(el) : null,
17
+ };
18
+ _driver.getLogger().errorSite(err, details);
19
+ },
20
+ };
21
+ }
22
+ const page = new PageParserTree(root, transformOptions(pageParserOptions));
23
+ pageParserOptionsStream.changes().onValue((pageParserOptions) => {
24
+ console.log('replacing PageParserTree options'); //eslint-disable-line no-console
25
+ page.replaceOptions(transformOptions(pageParserOptions));
26
+ });
27
+ return page;
28
+ }
@@ -0,0 +1,19 @@
1
+ const pageParserOptions = {
2
+ tags: {},
3
+ watchers: [
4
+ {
5
+ sources: [null],
6
+ tag: 'composeLinkPopOverContainer',
7
+ selectors: ['body', '.Lf.a5s'],
8
+ },
9
+ ],
10
+ finders: {
11
+ supportMenu: {
12
+ fn: (root) => root.querySelectorAll('header[role=banner] div:not([aria-label]):not([data-ogsr-up]) > div:not(.inboxsdk__appButton) > div[data-tooltip] + div[role=menu]'),
13
+ },
14
+ composeLinkPopOverContainer: {
15
+ fn: (root) => root.querySelectorAll('body > .Lf.a5s'),
16
+ },
17
+ },
18
+ };
19
+ export default pageParserOptions;
@@ -0,0 +1,126 @@
1
+ import querySelector from '../../../lib/dom/querySelectorOrFail';
2
+ import { EventEmitter } from 'events';
3
+ import cx from 'classnames';
4
+ import GmailElementGetter from '../gmail-element-getter';
5
+ export const NATIVE_CLASS = 'Xa';
6
+ export const INBOXSDK_CLASS = 'inboxsdk__appMenuItem';
7
+ export const ELEMENT_CLASS = `${NATIVE_CLASS} ${INBOXSDK_CLASS}`;
8
+ const ICON_ELEMENT_CLASS = 'V6 CL';
9
+ const HEADING_ELEMENT_CLASS = 'apW';
10
+ const ICON_ELEMENT_SELECTOR = '.V6.CL';
11
+ const HEADING_ELEMENT_SELECTOR = '.apW';
12
+ export class GmailAppMenuItemView extends EventEmitter {
13
+ static elementCss = {
14
+ HOVER: 'aIk',
15
+ ACTIVE: 'apV',
16
+ };
17
+ #menuItemDescriptor;
18
+ #element;
19
+ #destroyed = false;
20
+ #driver;
21
+ get element() {
22
+ return this.#element;
23
+ }
24
+ setMenuItemDescriptor(newMenuItemDescriptor) {
25
+ this.#menuItemDescriptor = newMenuItemDescriptor;
26
+ this.#update();
27
+ }
28
+ get menuItemDescriptor() {
29
+ return this.#menuItemDescriptor;
30
+ }
31
+ constructor(driver) {
32
+ super();
33
+ this.#element = this.#setupElement();
34
+ this.#driver = driver;
35
+ driver.getStopper().onValue(() => this.remove());
36
+ this.#element.addEventListener('click', (e) => this.#onClick(e));
37
+ this.#element.addEventListener('mouseover', this.#onHover);
38
+ this.#element.addEventListener('mouseout', this.#onBlur);
39
+ }
40
+ remove() {
41
+ if (this.#destroyed)
42
+ return;
43
+ this.#destroyed = true;
44
+ this.element?.remove();
45
+ this.emit('destroy');
46
+ }
47
+ /**
48
+ * @internal
49
+ */
50
+ blur() {
51
+ this.element?.classList.remove(GmailAppMenuItemView.elementCss.HOVER);
52
+ }
53
+ /**
54
+ * @internal
55
+ */
56
+ hover() {
57
+ if (this.element?.classList.contains(GmailAppMenuItemView.elementCss.ACTIVE)) {
58
+ return;
59
+ }
60
+ this.element?.classList.add(GmailAppMenuItemView.elementCss.HOVER);
61
+ }
62
+ /**
63
+ * @internal
64
+ */
65
+ activate() {
66
+ this.element?.classList.remove(GmailAppMenuItemView.elementCss.HOVER);
67
+ this.element?.classList.add(GmailAppMenuItemView.elementCss.ACTIVE);
68
+ }
69
+ /**
70
+ * @internal
71
+ */
72
+ deactivate() {
73
+ this.element?.classList.remove(GmailAppMenuItemView.elementCss.ACTIVE);
74
+ }
75
+ #setupElement() {
76
+ const element = document.createElement('div');
77
+ element.className = ELEMENT_CLASS;
78
+ element.innerHTML = `
79
+ <div class="${ICON_ELEMENT_CLASS}" aria-label="" role="link" tabindex="-1"></div>
80
+ <div class="${HEADING_ELEMENT_CLASS}" role="heading" aria-level="2"></div>
81
+ `.trim();
82
+ return element;
83
+ }
84
+ #update() {
85
+ const element = this.element;
86
+ if (!element)
87
+ return;
88
+ element.className = cx(ELEMENT_CLASS, this.#menuItemDescriptor?.className);
89
+ this.#updateName(element);
90
+ this.#updateIcon(element);
91
+ this.#updateARIA(element);
92
+ }
93
+ #updateName(element) {
94
+ const headingElement = querySelector(element, HEADING_ELEMENT_SELECTOR);
95
+ headingElement.textContent = this.#menuItemDescriptor?.name ?? '';
96
+ }
97
+ #updateIcon(element) {
98
+ const iconContainerEl = querySelector(element, ICON_ELEMENT_SELECTOR);
99
+ const { iconUrl, iconClassName } = this.#menuItemDescriptor ?? {};
100
+ if (iconUrl) {
101
+ const theme = GmailElementGetter.isDarkTheme()
102
+ ? iconUrl.darkTheme
103
+ : iconUrl.lightTheme;
104
+ iconContainerEl.style.setProperty('--background-image', `url(${theme})`);
105
+ }
106
+ iconContainerEl.className = cx(ICON_ELEMENT_CLASS, iconClassName);
107
+ }
108
+ #updateARIA(element) {
109
+ const iconContainerEl = querySelector(element, ICON_ELEMENT_SELECTOR);
110
+ iconContainerEl.setAttribute('aria-label', this.#menuItemDescriptor?.name ?? '');
111
+ }
112
+ #onClick(e) {
113
+ this.emit('click');
114
+ this.#menuItemDescriptor?.onClick?.(e);
115
+ if (this.#menuItemDescriptor?.routeID) {
116
+ this.#driver.goto(this.#menuItemDescriptor.routeID, this.#menuItemDescriptor?.routeParams);
117
+ }
118
+ }
119
+ #onBlur = (e) => {
120
+ this.emit('blur', e);
121
+ };
122
+ #onHover = (e) => {
123
+ this.emit('hover', e);
124
+ this.#menuItemDescriptor?.onHover?.(e);
125
+ };
126
+ }
@@ -0,0 +1,101 @@
1
+ import { defn } from 'ud';
2
+ import Kefir from 'kefir';
3
+ import kefirStopper from 'kefir-stopper';
4
+ import cx from 'classnames';
5
+ import insertElementInOrder from '../../../../lib/dom/insert-element-in-order';
6
+ import Logger from '../../../../lib/logger';
7
+ import querySelector from '../../../../lib/dom/querySelectorOrFail';
8
+ import SimpleElementView from '../../../../views/SimpleElementView';
9
+ export default defn(module, addStatusBar);
10
+ function addStatusBar(gmailComposeView, options) {
11
+ const { height, orderHint, addAboveNativeStatusBar } = {
12
+ height: 40,
13
+ orderHint: 0,
14
+ addAboveNativeStatusBar: false,
15
+ ...options,
16
+ };
17
+ const statusbar = new StatusBar(gmailComposeView, height, orderHint, addAboveNativeStatusBar);
18
+ gmailComposeView
19
+ .getStopper()
20
+ .takeUntilBy(Kefir.fromEvents(statusbar, 'destroy'))
21
+ .onValue(() => statusbar.destroy());
22
+ return statusbar;
23
+ }
24
+ function createElement(orderHint, addAboveNativeStatusBar) {
25
+ const el = document.createElement('div');
26
+ el.className = cx('aDh', 'inboxsdk__compose_statusbar', {
27
+ inboxsdk__addAboveNative: addAboveNativeStatusBar,
28
+ });
29
+ el.style.fontFamily = 'Roboto,RobotoDraft,Helvetica,Arial,sans-serif';
30
+ el.style.fontSize = '15.6px';
31
+ el.setAttribute('data-order-hint', String(orderHint));
32
+ return el;
33
+ }
34
+ class StatusBar extends SimpleElementView {
35
+ _addAboveNativeStatusBar;
36
+ _gmailComposeView;
37
+ _nativeStatusContainer;
38
+ _prependContainer = null;
39
+ _stopper = kefirStopper();
40
+ constructor(gmailComposeView, height, orderHint, addAboveNativeStatusBar) {
41
+ super(createElement(orderHint, addAboveNativeStatusBar));
42
+ this._addAboveNativeStatusBar = addAboveNativeStatusBar;
43
+ this._gmailComposeView = gmailComposeView;
44
+ this._nativeStatusContainer = querySelector(gmailComposeView.getElement(), '.iN > tbody .aDj');
45
+ this._setStatusBar();
46
+ this.setHeight(height);
47
+ }
48
+ destroy() {
49
+ if (this.destroyed) {
50
+ return;
51
+ }
52
+ super.destroy();
53
+ this._stopper.destroy();
54
+ if (this._prependContainer &&
55
+ this._prependContainer.children.length === 0) {
56
+ this._prependContainer.remove();
57
+ }
58
+ this._updateTotalHeight();
59
+ }
60
+ setHeight(newHeight) {
61
+ this.el.style.height = newHeight + 'px';
62
+ this._updateTotalHeight();
63
+ }
64
+ _updateTotalHeight() {
65
+ const totalAddedStatusBarHeight = Array.from(this._gmailComposeView
66
+ .getElement()
67
+ .querySelectorAll('.inboxsdk__compose_statusbar'))
68
+ .map((el) => el.getBoundingClientRect().height)
69
+ .reduce((a, b) => a + b, 0);
70
+ this._gmailComposeView
71
+ .getElement()
72
+ .style.setProperty('--inboxsdk-total-added-statusbar-height', totalAddedStatusBarHeight + 'px');
73
+ }
74
+ _setStatusBar() {
75
+ try {
76
+ const statusArea = this._gmailComposeView.getStatusArea();
77
+ this._gmailComposeView
78
+ .getElement()
79
+ .classList.add('inboxsdk__compose_statusbarActive');
80
+ if (this._addAboveNativeStatusBar) {
81
+ const prependContainer = (this._prependContainer =
82
+ statusArea.querySelector('.inboxsdk__compose_statusBarPrependContainer') || document.createElement('div'));
83
+ prependContainer.classList.add('inboxsdk__compose_statusBarPrependContainer');
84
+ statusArea.insertAdjacentElement('afterbegin', prependContainer);
85
+ insertElementInOrder(prependContainer, this.el);
86
+ }
87
+ else {
88
+ if (this._gmailComposeView.isInlineReplyForm()) {
89
+ const nativeStatusBar = querySelector(this._gmailComposeView.getElement(), '.iN > tbody .aDj .aDh .IZ');
90
+ insertElementInOrder(nativeStatusBar, this.el);
91
+ }
92
+ else {
93
+ insertElementInOrder(statusArea, this.el);
94
+ }
95
+ }
96
+ }
97
+ catch (err) {
98
+ Logger.error(err);
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,38 @@
1
+ import once from 'lodash/once';
2
+ export default once(function detectClassicRecipientsArea() {
3
+ const styleSheetWithComposeRules = [...document.styleSheets].find((s) => {
4
+ try {
5
+ if (s.cssRules) {
6
+ // Both classic and new recipients Gmail should have this rule
7
+ return [...s.cssRules].find((rule) => rule instanceof CSSStyleRule &&
8
+ rule.selectorText === '.aoI' &&
9
+ rule.style.fontSize &&
10
+ rule.style.color);
11
+ }
12
+ }
13
+ catch (e) {
14
+ // Some stylesheets are crossorigin and throw if we try to access
15
+ // their rules. Don't worry about them.
16
+ }
17
+ return false;
18
+ });
19
+ if (styleSheetWithComposeRules) {
20
+ // Check if we don't have any of these specific rules.
21
+ // If so, we're on classic recipients Gmail.
22
+ const hasOverflowYVisibleRule = [
23
+ ...styleSheetWithComposeRules.cssRules,
24
+ ].some((rule) => rule instanceof CSSStyleRule &&
25
+ rule.selectorText === '.aoI' &&
26
+ rule.style.overflowY === 'visible');
27
+ if (hasOverflowYVisibleRule) {
28
+ return;
29
+ }
30
+ const hasOverflowYAutoRule = [...styleSheetWithComposeRules.cssRules].some((rule) => rule instanceof CSSStyleRule &&
31
+ rule.selectorText === '.aaZ > .M9 > .aoI' &&
32
+ rule.style.overflowY === 'auto');
33
+ if (hasOverflowYAutoRule) {
34
+ return;
35
+ }
36
+ document.body.classList.add('inboxsdk__classic_gmail_recipients_area');
37
+ }
38
+ });
@@ -0,0 +1,28 @@
1
+ import Logger from '../../../../lib/logger';
2
+ import extractContactFromEmailContactString from '../../../../lib/extract-contact-from-email-contact-string';
3
+ import censorHTMLstring from '../../../../../common/censorHTMLstring';
4
+ export default function getAddressInformationExtractor(addressType, composeView) {
5
+ return function (node) {
6
+ const contactNode = node instanceof HTMLInputElement &&
7
+ node.getAttribute('name') === addressType
8
+ ? node
9
+ : node.querySelector(`input[name='${addressType}']`);
10
+ if (contactNode) {
11
+ var contactInfoString = contactNode.value;
12
+ try {
13
+ return extractContactFromEmailContactString(contactInfoString);
14
+ }
15
+ catch (err) {
16
+ // The user might have typed in a partial address. We can just ignore that.
17
+ return null;
18
+ }
19
+ }
20
+ else {
21
+ Logger.error(new Error(`contactNode can't be found`), {
22
+ addressType,
23
+ composeViewHtml: censorHTMLstring(composeView.getElement().outerHTML),
24
+ });
25
+ return null;
26
+ }
27
+ };
28
+ }
@@ -0,0 +1,22 @@
1
+ import { getRecipientChips } from './page-parser';
2
+ import getAddressInformationExtractor from './get-address-information-extractor';
3
+ import isNotNil from '../../../../lib/isNotNil';
4
+ export default function getRecipients(gmailComposeView, addressType) {
5
+ const contactNodes = getRecipientChips(gmailComposeView.getElement(), addressType);
6
+ return Array.from(contactNodes)
7
+ .map((contactNode) => {
8
+ if (contactNode.getAttribute('role') === 'option') {
9
+ // new recipient
10
+ // https://workspaceupdates.googleblog.com/2021/10/visual-updates-for-composing-email-in-gmail.html
11
+ return {
12
+ name: contactNode.getAttribute('data-name'),
13
+ emailAddress: contactNode.getAttribute('data-hovercard-id'),
14
+ };
15
+ }
16
+ else {
17
+ // old
18
+ return getAddressInformationExtractor(addressType, gmailComposeView)(contactNode);
19
+ }
20
+ })
21
+ .filter(isNotNil);
22
+ }