@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,759 @@
1
+ import autoHtml from 'auto-html';
2
+ import * as Kefir from 'kefir';
3
+ import kefirBus from 'kefir-bus';
4
+ import GmailElementGetter from '../gmail-element-getter';
5
+ import getInsertBeforeElement from '../../../lib/dom/get-insert-before-element';
6
+ import querySelector from '../../../lib/dom/querySelectorOrFail';
7
+ import makeMutationObserverChunkedStream from '../../../lib/dom/make-mutation-observer-chunked-stream';
8
+ import ButtonView from '../widgets/buttons/button-view';
9
+ import MoreDropdownButtonView from '../widgets/buttons/more-dropdown-button-view';
10
+ import MoreParentDropdownButtonView from '../widgets/buttons/more-parent-accessory-button-view';
11
+ import CreateAccessoryButtonView from '../widgets/buttons/create-accessory-button-view';
12
+ import CreateParentAccessoryButtonView from '../widgets/buttons/create-parent-accessory-button-view';
13
+ import GmailDropdownView from '../widgets/gmail-dropdown-view';
14
+ import DropdownButtonViewController from '../../../widgets/buttons/dropdown-button-view-controller';
15
+ import BasicButtonViewController from '../../../widgets/buttons/basic-button-view-controller';
16
+ import updateIcon from '../../../driver-common/update-icon';
17
+ import renderCustomIcon from '../../../driver-common/render-custom-icon';
18
+ import NAV_ITEM_TYPES from '../../../constants/nav-item-types';
19
+ let NUMBER_OF_GMAIL_NAV_ITEM_VIEWS_CREATED = 0;
20
+ const GMAIL_V2_LEFT_INDENTATION_PADDING = 12;
21
+ // TODO could we recreate this with React? There's so much statefulness that it's
22
+ export default class GmailNavItemView {
23
+ _accessory = null;
24
+ _accessoryViewController = null;
25
+ _driver;
26
+ _element;
27
+ _eventStream;
28
+ _expandoElement = null;
29
+ _iconSettings = {};
30
+ _isActive = false;
31
+ _isCollapsed = false;
32
+ _itemContainerElement = null;
33
+ _level;
34
+ _name = '';
35
+ _navItemDescriptor;
36
+ _navItemNumber;
37
+ _orderGroup;
38
+ _orderHint;
39
+ _type = null;
40
+ _collapseKey = null;
41
+ // delete after new left nav is fully launched, use this._level === 1 instead
42
+ _isNewLeftNavParent;
43
+ constructor(driver, orderGroup, level) {
44
+ this._driver = driver;
45
+ this._eventStream = kefirBus();
46
+ this._level = level || 0;
47
+ this._navItemNumber = ++NUMBER_OF_GMAIL_NAV_ITEM_VIEWS_CREATED;
48
+ this._orderGroup = orderGroup;
49
+ this._isNewLeftNavParent =
50
+ !GmailElementGetter.shouldAddNavItemsInline() && this._level === 1;
51
+ if (this._isNewLeftNavParent) {
52
+ this._element = this._setupParentElement();
53
+ }
54
+ else {
55
+ this._element = this._setupChildElement();
56
+ }
57
+ }
58
+ addNavItem(orderGroup, navItemDescriptor) {
59
+ const nestedNavItemLevel = this._type === NAV_ITEM_TYPES.GROUPER ? this._level : this._level + 1;
60
+ const gmailNavItemView = new GmailNavItemView(this._driver, orderGroup, nestedNavItemLevel);
61
+ gmailNavItemView
62
+ .getEventStream()
63
+ .filter((event) => event.eventName === 'orderChanged')
64
+ .onValue(() => this._addNavItemElement(gmailNavItemView));
65
+ gmailNavItemView.setNavItemDescriptor(navItemDescriptor);
66
+ if (this._isNewLeftNavParent) {
67
+ this._createExpandoParent();
68
+ }
69
+ return gmailNavItemView;
70
+ }
71
+ destroy() {
72
+ this._element.remove();
73
+ if (this._accessoryViewController)
74
+ this._accessoryViewController.destroy();
75
+ if (this._eventStream)
76
+ this._eventStream.end();
77
+ if (this._expandoElement)
78
+ this._expandoElement.remove();
79
+ if (this._itemContainerElement)
80
+ this._itemContainerElement.remove();
81
+ }
82
+ getElement() {
83
+ return this._element;
84
+ }
85
+ getEventStream() {
86
+ return this._eventStream;
87
+ }
88
+ getNavItemDescriptor() {
89
+ return this._navItemDescriptor;
90
+ }
91
+ getOrderGroup() {
92
+ return this._orderGroup;
93
+ }
94
+ getOrderHint() {
95
+ return this._orderHint;
96
+ }
97
+ getName() {
98
+ return this._name;
99
+ }
100
+ isCollapsed() {
101
+ return this._isCollapsed;
102
+ }
103
+ remove() {
104
+ this.destroy();
105
+ }
106
+ setActive(value) {
107
+ if (!this._element ||
108
+ this._type === NAV_ITEM_TYPES.LINK ||
109
+ this._type === NAV_ITEM_TYPES.MANAGE ||
110
+ this._isActive === value ||
111
+ this._isNewLeftNavParent) {
112
+ return;
113
+ }
114
+ const toElement = querySelector(this._element, '.TO');
115
+ if (value) {
116
+ this._element.classList.add('ain');
117
+ toElement.classList.add('nZ');
118
+ toElement.classList.add('aiq');
119
+ }
120
+ else {
121
+ this._element.classList.remove('ain');
122
+ toElement.classList.remove('nZ');
123
+ toElement.classList.remove('aiq');
124
+ }
125
+ this._setHeights();
126
+ this._isActive = value;
127
+ }
128
+ setCollapsed(value) {
129
+ this._isCollapsed = value;
130
+ if (this._isCollapsible()) {
131
+ if (value) {
132
+ this._collapse();
133
+ }
134
+ else {
135
+ this._expand();
136
+ }
137
+ }
138
+ try {
139
+ const storageKey = 'inboxsdk__navitem_collapsed__' + this._collapseKey;
140
+ if (this._isCollapsed) {
141
+ localStorage.setItem(storageKey, 'true');
142
+ }
143
+ else {
144
+ localStorage.removeItem(storageKey);
145
+ }
146
+ }
147
+ catch (e) {
148
+ // eslint-disable-next-line no-console
149
+ console.error('Caught error', e);
150
+ }
151
+ }
152
+ setNavItemDescriptor(navItemDescriptorPropertyStream) {
153
+ navItemDescriptorPropertyStream
154
+ .takeUntilBy(this._eventStream.filter(() => false).beforeEnd(() => null))
155
+ .onValue((x) => this._updateValues(x));
156
+ }
157
+ toggleCollapse() {
158
+ this.setCollapsed(!this._isCollapsed);
159
+ }
160
+ // TODO this method is only called on orderChanged? is that right?
161
+ _addNavItemElement(gmailNavItemView) {
162
+ const itemContainerElement = this._getItemContainerElement();
163
+ const insertBeforeElement = getInsertBeforeElement(gmailNavItemView.getElement(), itemContainerElement.children, ['data-group-order-hint', 'data-order-hint', 'data-insertion-order-hint']);
164
+ itemContainerElement.insertBefore(gmailNavItemView.getElement(), insertBeforeElement);
165
+ // If the current nav-item is of type GROUPER and we are in Gmailv2, then any nested nav-items
166
+ // should be at the same indentation as the current nav-item. Somewhat confusingly, this._level
167
+ // is normally the indentationFactor for the nested children of the current nav-item, so we
168
+ // actually use this._level - 1 as the indentationFactor if we don't want to further indent the
169
+ // nested items (i.e. the current item is of type GROUPER and we're in Gmailv2).
170
+ const indentationFactor = this._type === NAV_ITEM_TYPES.GROUPER || this._isNewLeftNavParent
171
+ ? this._level - 1
172
+ : this._level;
173
+ const element = gmailNavItemView.getElement();
174
+ if (!GmailElementGetter.shouldAddNavItemsInline()) {
175
+ querySelector(element, '.TN').style.marginLeft =
176
+ 6 * indentationFactor + 'px';
177
+ }
178
+ else {
179
+ querySelector(element, '.TN').style.marginLeft =
180
+ getLeftIndentationPaddingValue() * indentationFactor + 'px';
181
+ }
182
+ this._setHeights();
183
+ }
184
+ _collapse() {
185
+ this._isCollapsed = true;
186
+ if (this._isNewLeftNavParent) {
187
+ this._element.classList.remove('Xr');
188
+ }
189
+ else {
190
+ const expandoElement = this._expandoElement;
191
+ if (expandoElement) {
192
+ expandoElement.classList.remove('aih');
193
+ expandoElement.classList.add('aii');
194
+ }
195
+ else if (this._type === NAV_ITEM_TYPES.GROUPER) {
196
+ const navItemElement = this._element.firstElementChild;
197
+ if (navItemElement)
198
+ navItemElement.classList.remove('air');
199
+ }
200
+ if (this._itemContainerElement)
201
+ this._itemContainerElement.style.display = 'none';
202
+ this._setHeights();
203
+ }
204
+ this._eventStream.emit({
205
+ eventName: 'collapsed',
206
+ });
207
+ }
208
+ _createAccessory(accessoryDescriptor) {
209
+ switch (accessoryDescriptor.type) {
210
+ case 'CREATE':
211
+ this._createCreateAccessory(accessoryDescriptor);
212
+ break;
213
+ case 'ICON_BUTTON':
214
+ this._createIconButtonAccessory(accessoryDescriptor);
215
+ break;
216
+ case 'DROPDOWN_BUTTON':
217
+ this._createDropdownButtonAccessory(accessoryDescriptor);
218
+ break;
219
+ case 'SETTINGS_BUTTON':
220
+ this._driver
221
+ .getLogger()
222
+ .deprecationWarning('SettingsButtonAccessoryDescriptor', 'DropdownButtonAccessoryDescriptor');
223
+ this._createDropdownButtonAccessory({
224
+ ...accessoryDescriptor,
225
+ type: 'DROPDOWN_BUTTON',
226
+ });
227
+ break;
228
+ }
229
+ }
230
+ _createCreateAccessory(accessoryDescriptor) {
231
+ this._createPlusButtonAccessory(accessoryDescriptor);
232
+ }
233
+ _createDropdownButtonAccessory(accessoryDescriptor) {
234
+ if (this._isNewLeftNavParent) {
235
+ const buttonOptions = { ...accessoryDescriptor };
236
+ buttonOptions.buttonView = new MoreParentDropdownButtonView();
237
+ buttonOptions.dropdownViewDriverClass = GmailDropdownView;
238
+ buttonOptions.dropdownPositionOptions = {
239
+ position: 'right',
240
+ hAlign: 'left',
241
+ vAlign: 'top',
242
+ };
243
+ buttonOptions.dropdownShowFunction = ({ dropdown }) => {
244
+ dropdown.el.style.marginLeft = '24px';
245
+ buttonOptions.onClick({ dropdown });
246
+ };
247
+ const accessoryViewController = new DropdownButtonViewController(buttonOptions);
248
+ this._accessoryViewController = accessoryViewController;
249
+ const accessoryEl = querySelector(this._element, '.Yh');
250
+ const parentNode = accessoryEl.parentNode;
251
+ if (parentNode) {
252
+ buttonOptions.buttonView
253
+ .getElement()
254
+ .classList.add(...accessoryEl.classList);
255
+ parentNode.replaceChild(buttonOptions.buttonView.getElement(), accessoryEl);
256
+ this._iconSettings.iconElement = null;
257
+ }
258
+ return;
259
+ }
260
+ // child dropdown button accessory
261
+ const buttonOptions = { ...accessoryDescriptor };
262
+ buttonOptions.buttonView = new MoreDropdownButtonView();
263
+ buttonOptions.dropdownViewDriverClass = GmailDropdownView;
264
+ buttonOptions.dropdownPositionOptions = {
265
+ position: 'bottom',
266
+ hAlign: 'left',
267
+ vAlign: 'top',
268
+ };
269
+ const container = GmailElementGetter.getLeftNavContainerElement();
270
+ if (!container)
271
+ throw new Error('leftNavContainer not found');
272
+ buttonOptions.dropdownShowFunction = (event) => {
273
+ // bhZ is the class to indicate the left nav is collapsible mode
274
+ // bym is class to show expanded when the left nav is collapsible
275
+ if (container.classList.contains('bhZ')) {
276
+ const stopper = Kefir.fromEvents(event.dropdown, 'destroy');
277
+ // monitor class on the container and keep re-adding bym until dropdown closes
278
+ makeMutationObserverChunkedStream(container, {
279
+ attributes: true,
280
+ attributeFilter: ['class'],
281
+ })
282
+ .takeUntilBy(stopper)
283
+ .toProperty(() => null)
284
+ .onValue(() => {
285
+ if (!container.classList.contains('bym'))
286
+ container.classList.add('bym');
287
+ });
288
+ stopper.onValue(() => {
289
+ container.classList.remove('bym');
290
+ });
291
+ }
292
+ buttonOptions.onClick(event);
293
+ event.dropdown.on('destroy', () => {
294
+ buttonOptions.buttonView.deactivate();
295
+ });
296
+ };
297
+ const accessoryViewController = new DropdownButtonViewController(buttonOptions);
298
+ this._accessoryViewController = accessoryViewController;
299
+ const innerElement = querySelector(this._element, '.TO');
300
+ innerElement.addEventListener('mouseenter', () => innerElement.classList.add('inboxsdk__navItem_hover'));
301
+ innerElement.addEventListener('mouseleave', () => innerElement.classList.remove('inboxsdk__navItem_hover'));
302
+ const insertionPoint = querySelector(this._element, '.TN');
303
+ insertionPoint.appendChild(buttonOptions.buttonView.getElement());
304
+ this._setupContextClickHandler(accessoryViewController);
305
+ }
306
+ _createExpando() {
307
+ if (this._type === NAV_ITEM_TYPES.GROUPER) {
308
+ return;
309
+ }
310
+ const expandoElement = (this._expandoElement =
311
+ document.createElement('div'));
312
+ expandoElement.setAttribute('class', 'TH aih J-J5-Ji inboxsdk__expando');
313
+ expandoElement.setAttribute('role', 'link');
314
+ expandoElement.title = `Expand ${this._name || ''}`;
315
+ expandoElement.addEventListener('click', (e) => {
316
+ this.toggleCollapse();
317
+ e.stopPropagation();
318
+ });
319
+ const insertionPoint = this._element.querySelector('.TN.aik');
320
+ if (insertionPoint)
321
+ insertionPoint.insertAdjacentElement('afterbegin', expandoElement);
322
+ if (this._isCollapsed) {
323
+ this._collapse();
324
+ }
325
+ else {
326
+ this._expand();
327
+ }
328
+ }
329
+ _createExpandoParent() {
330
+ const parentExpandoElement = querySelector(this._element, '.XR');
331
+ parentExpandoElement.style.visibility = 'visible';
332
+ this._expandoElement = parentExpandoElement;
333
+ if (this._isCollapsed) {
334
+ this._collapse();
335
+ }
336
+ else {
337
+ this._expand();
338
+ }
339
+ }
340
+ _createIconButtonAccessory(accessoryDescriptor) {
341
+ this._driver
342
+ .getLogger()
343
+ .deprecationWarning('IconButtonAccessoryDescriptor accessory for a parent level NavItemView', 'CreateAccessoryDescriptor or DropdownButtonAccessoryDescriptor');
344
+ if (this._isNewLeftNavParent) {
345
+ return;
346
+ }
347
+ const buttonOptions = {
348
+ ...accessoryDescriptor,
349
+ buttonColor: 'pureIcon',
350
+ };
351
+ buttonOptions.buttonView = new ButtonView(buttonOptions);
352
+ this._accessoryViewController = new BasicButtonViewController(buttonOptions);
353
+ const insertionPoint = querySelector(this._element, '.TN');
354
+ insertionPoint.appendChild(buttonOptions.buttonView.getElement());
355
+ }
356
+ _createItemContainerElement() {
357
+ const itemContainerElement = (this._itemContainerElement =
358
+ document.createElement('div'));
359
+ itemContainerElement.classList.add('inboxsdk__navItem_container');
360
+ this._element.appendChild(itemContainerElement);
361
+ // If this is a collapsible nav-item, run collapse or expand to set the container styling
362
+ if (this._isCollapsible()) {
363
+ if (this._isCollapsed)
364
+ this._collapse();
365
+ else
366
+ this._expand();
367
+ }
368
+ return itemContainerElement;
369
+ }
370
+ _createLinkButtonAccessory(accessoryDescriptor) {
371
+ const linkDiv = document.createElement('div');
372
+ const linkDivClassName = 'inboxsdk__navItem_link';
373
+ linkDiv.setAttribute('class', linkDivClassName);
374
+ const anchor = document.createElement('a');
375
+ anchor.classList.add('CK');
376
+ anchor.textContent = accessoryDescriptor.name;
377
+ linkDiv.appendChild(anchor);
378
+ anchor.href = '#';
379
+ anchor.addEventListener('click', (e) => {
380
+ e.stopPropagation();
381
+ e.preventDefault();
382
+ accessoryDescriptor.onClick();
383
+ });
384
+ querySelector(this._element, '.aio').appendChild(linkDiv);
385
+ }
386
+ _createPlusButtonAccessory(accessoryDescriptor) {
387
+ if (this._isNewLeftNavParent) {
388
+ const buttonOptions = { ...accessoryDescriptor };
389
+ buttonOptions.buttonView = new CreateParentAccessoryButtonView();
390
+ // TODO: new Gmail left nav parent accessory opens a dropdown which would be a breaking
391
+ // change if we were to also create a dropdown view bc existing users would have to manually
392
+ // close the dropdown if they only wanted a click callback. We could have a "hasDropdown"
393
+ // prop to conditionally render the dropdown, but when is enough enough?
394
+ // buttonOptions.dropdownViewDriverClass = GmailDropdownView;
395
+ // buttonOptions.dropdownPositionOptions = {
396
+ // position: 'right',
397
+ // hAlign: 'left',
398
+ // vAlign: 'top'
399
+ // };
400
+ // buttonOptions.dropdownShowFunction = ({ dropdown }) => {
401
+ // dropdown.el.style.marginLeft = '24px';
402
+ // buttonOptions.onClick({ dropdown });
403
+ // };
404
+ this._accessoryViewController = new BasicButtonViewController(buttonOptions);
405
+ const accessoryEl = querySelector(this._element, '.Yh');
406
+ const parentNode = accessoryEl.parentNode;
407
+ if (parentNode) {
408
+ buttonOptions.buttonView
409
+ .getElement()
410
+ .classList.add(...accessoryEl.classList);
411
+ parentNode.replaceChild(buttonOptions.buttonView.getElement(), accessoryEl);
412
+ this._iconSettings.iconElement = null;
413
+ }
414
+ return;
415
+ }
416
+ // child create button accessory
417
+ const buttonOptions = { ...accessoryDescriptor };
418
+ buttonOptions.buttonView = new CreateAccessoryButtonView();
419
+ this._accessoryViewController = new BasicButtonViewController(buttonOptions);
420
+ const insertionPoint = querySelector(this._element, '.TN');
421
+ insertionPoint.appendChild(buttonOptions.buttonView.getElement());
422
+ }
423
+ _expand() {
424
+ if (this._isNewLeftNavParent) {
425
+ this._element.classList.add('Xr');
426
+ }
427
+ else {
428
+ const expandoElement = this._expandoElement;
429
+ if (expandoElement) {
430
+ expandoElement.classList.add('aih');
431
+ expandoElement.classList.remove('aii');
432
+ }
433
+ else if (this._type === NAV_ITEM_TYPES.GROUPER) {
434
+ const navItemElement = this._element.firstElementChild;
435
+ if (navItemElement) {
436
+ navItemElement.classList.add('air');
437
+ }
438
+ }
439
+ if (this._itemContainerElement) {
440
+ this._itemContainerElement.style.display = '';
441
+ }
442
+ this._setHeights();
443
+ }
444
+ this._isCollapsed = false;
445
+ this._eventStream.emit({
446
+ eventName: 'expanded',
447
+ });
448
+ }
449
+ _getItemContainerElement() {
450
+ if (this._isNewLeftNavParent) {
451
+ return querySelector(this._element, '.TK');
452
+ }
453
+ else {
454
+ let itemContainerElement = this._itemContainerElement;
455
+ if (!itemContainerElement) {
456
+ itemContainerElement = this._createItemContainerElement();
457
+ this._createExpando();
458
+ }
459
+ return itemContainerElement;
460
+ }
461
+ }
462
+ _isCollapsible() {
463
+ return (Boolean(this._expandoElement) || this._type === NAV_ITEM_TYPES.GROUPER);
464
+ }
465
+ _makeEventMapper(eventName) {
466
+ return function (domEvent) {
467
+ domEvent.stopPropagation();
468
+ domEvent.preventDefault();
469
+ return {
470
+ eventName,
471
+ domEvent,
472
+ };
473
+ };
474
+ }
475
+ _setHeights() {
476
+ if (this._level == 1) {
477
+ return;
478
+ }
479
+ const toElement = querySelector(this._element, '.TO');
480
+ if (this._element.classList.contains('ain') && this._itemContainerElement) {
481
+ this._element.style.height = '';
482
+ const totalHeight = this._element.clientHeight;
483
+ const itemHeight = toElement.clientHeight;
484
+ this._element.style.height = itemHeight + 'px';
485
+ this._element.style.overflow = 'visible';
486
+ this._element.style.marginBottom = totalHeight - itemHeight + 'px';
487
+ }
488
+ else {
489
+ this._element.style.height = '';
490
+ this._element.style.overflow = '';
491
+ this._element.style.marginBottom = '';
492
+ }
493
+ }
494
+ _setHighlight(value) {
495
+ if (!this._element ||
496
+ this._type === NAV_ITEM_TYPES.LINK ||
497
+ this._type === NAV_ITEM_TYPES.MANAGE) {
498
+ return;
499
+ }
500
+ if (value) {
501
+ querySelector(this._element, '.TO').classList.add('NQ');
502
+ }
503
+ else {
504
+ querySelector(this._element, '.TO').classList.remove('NQ');
505
+ }
506
+ }
507
+ _setupContextClickHandler(accessoryViewController) {
508
+ Kefir.fromEvents(this._element, 'contextmenu')
509
+ .takeWhile(() => this._accessoryViewController === accessoryViewController)
510
+ .onValue((domEvent) => {
511
+ domEvent.stopPropagation();
512
+ domEvent.preventDefault();
513
+ accessoryViewController.showDropdown();
514
+ });
515
+ }
516
+ _setupChildElement() {
517
+ const element = document.createElement('div');
518
+ element.setAttribute('class', 'aim inboxsdk__navItem');
519
+ element.innerHTML = [
520
+ '<div class="TO">',
521
+ '<div class="TN aik">',
522
+ // This element needs a style attribute defined on it as there is a Gmail css rule of
523
+ // selecting for "gj[style]" the sets the opacity to 1 rather than 0.6.
524
+ '<div class="qj" style="">',
525
+ '</div>',
526
+ '<div class="aio aip">',
527
+ '<span class="nU" role="link">',
528
+ '</span>',
529
+ // This bsU element is the container "subtitle" text.
530
+ '<span class="bsU">',
531
+ '</span>',
532
+ '</div>',
533
+ '</div>',
534
+ '</div>',
535
+ ].join('');
536
+ const innerElement = querySelector(element, '.TO');
537
+ Kefir.merge([
538
+ Kefir.fromEvents(innerElement, 'mouseenter').map(this._makeEventMapper('mouseenter')),
539
+ Kefir.fromEvents(innerElement, 'mouseleave').map(this._makeEventMapper('mouseleave')),
540
+ ]).onValue((event) => {
541
+ this._updateHighlight(event);
542
+ });
543
+ this._eventStream.plug(Kefir.fromEvents(innerElement, 'click').map(this._makeEventMapper('click')));
544
+ return element;
545
+ }
546
+ _setupParentElement() {
547
+ const element = document.createElement('div');
548
+ element.className = 'Xa wT W8 XJ inboxsdk__navItem';
549
+ element.innerHTML = [
550
+ '<div class="V6 CL Y2">',
551
+ '<div class="XR" role="button" tabindex="0" type="button" style="visibility: hidden">',
552
+ '</div>',
553
+ '<span class="XS">',
554
+ '<span class="WW inboxsdk__navItem_name" role="heading" aria-level="2">',
555
+ '</span>',
556
+ '<span class="XU" aria-hidden="true" style="display: none">',
557
+ '</span>',
558
+ '</span>',
559
+ '<div class="Yh">',
560
+ '</div>',
561
+ '</div>',
562
+ '<div class="V3 ada">',
563
+ '<div class="wT">',
564
+ '<div class="TK">',
565
+ '</div>',
566
+ '</div>',
567
+ '</div>',
568
+ ].join('');
569
+ // adds shadow rule to nav item container
570
+ const scrollContainer = querySelector(element, '.V3');
571
+ Kefir.fromEvents(scrollContainer, 'scroll')
572
+ .debounce(10)
573
+ .onValue(() => {
574
+ if (scrollContainer.scrollTop > 0) {
575
+ scrollContainer.classList.add('adh');
576
+ }
577
+ else {
578
+ scrollContainer.classList.remove('adh');
579
+ }
580
+ });
581
+ const expandoElement = querySelector(element, '.XR');
582
+ Kefir.fromEvents(expandoElement, 'click')
583
+ .map(this._makeEventMapper('click'))
584
+ .onValue(() => {
585
+ this.toggleCollapse();
586
+ });
587
+ const innerElement = querySelector(element, '.V6.CL');
588
+ this._eventStream.plug(Kefir.fromEvents(innerElement, 'click').map(this._makeEventMapper('click')));
589
+ return element;
590
+ }
591
+ _setupGrouper() {
592
+ const navItemElement = this._element
593
+ .firstElementChild;
594
+ if (navItemElement) {
595
+ navItemElement.classList.add('n4');
596
+ navItemElement.addEventListener('click', (e) => {
597
+ e.stopPropagation();
598
+ this.toggleCollapse();
599
+ });
600
+ if (this._isCollapsed) {
601
+ this._collapse();
602
+ }
603
+ else {
604
+ this._expand();
605
+ }
606
+ }
607
+ const iconContainerElement = querySelector(this._element, '.qj');
608
+ iconContainerElement.innerHTML =
609
+ '<div class="G-asx T-I-J3 J-J5-Ji">&nbsp;</div>';
610
+ }
611
+ _updateAccessory(accessory) {
612
+ if (this._accessory === accessory) {
613
+ return;
614
+ }
615
+ if (this._accessoryViewController) {
616
+ this._accessoryViewController.destroy();
617
+ this._accessoryViewController = null;
618
+ }
619
+ if (accessory) {
620
+ this._createAccessory(accessory);
621
+ }
622
+ this._accessory = accessory;
623
+ }
624
+ _updateClickability(navItemDescriptor) {
625
+ if (navItemDescriptor.type === NAV_ITEM_TYPES.LINK ||
626
+ navItemDescriptor.type === NAV_ITEM_TYPES.MANAGE) {
627
+ this._element.classList.add('inboxsdk__navItem_nonClickable');
628
+ }
629
+ else {
630
+ this._element.classList.remove('inboxsdk__navItem_nonClickable');
631
+ }
632
+ }
633
+ _updateHighlight({ eventName }) {
634
+ switch (eventName) {
635
+ case 'mouseenter':
636
+ this._setHighlight(true);
637
+ break;
638
+ case 'mouseleave':
639
+ this._setHighlight(false);
640
+ break;
641
+ }
642
+ }
643
+ _updateIcon(navItemDescriptor) {
644
+ const iconContainerElement = this._isNewLeftNavParent
645
+ ? querySelector(this._element, '.Yh')
646
+ : querySelector(this._element, '.qj');
647
+ // render custom icon
648
+ if (navItemDescriptor.iconElement) {
649
+ renderCustomIcon(iconContainerElement, navItemDescriptor.iconElement, navItemDescriptor.iconPosition !== 'BEFORE_NAME');
650
+ return;
651
+ }
652
+ updateIcon(this._iconSettings, iconContainerElement, navItemDescriptor.iconPosition !== 'BEFORE_NAME', navItemDescriptor.iconClass, navItemDescriptor.iconUrl);
653
+ // Setting the border-color of the icon container element while in Gmailv2 will trigger an SDK
654
+ // css rule that will render a circle of border-color if the icon container element has no
655
+ // children i.e. if no iconUrl or iconClass is defined on navItemDescriptor.
656
+ if (navItemDescriptor.backgroundColor) {
657
+ const circleColor = navItemDescriptor.backgroundColor;
658
+ iconContainerElement.style.borderColor = circleColor;
659
+ }
660
+ }
661
+ _updateName(name) {
662
+ if (this._name === name) {
663
+ return;
664
+ }
665
+ const navItemNameElement = querySelector(this._element, '.inboxsdk__navItem_name');
666
+ navItemNameElement.textContent = name;
667
+ navItemNameElement.setAttribute('title', name);
668
+ if (this._expandoElement) {
669
+ this._expandoElement.title = `Expand ${name}`;
670
+ }
671
+ this._name = name;
672
+ }
673
+ _updateOrder(navItemDescriptor) {
674
+ this._element.setAttribute('data-group-order-hint', '' + this._orderGroup);
675
+ this._element.setAttribute('data-insertion-order-hint', '' + this._navItemNumber);
676
+ navItemDescriptor.orderHint =
677
+ navItemDescriptor.orderHint || navItemDescriptor.orderHint === 0
678
+ ? navItemDescriptor.orderHint
679
+ : Number.MAX_SAFE_INTEGER;
680
+ if (navItemDescriptor.orderHint !== this._orderHint) {
681
+ this._element.setAttribute('data-order-hint', '' + navItemDescriptor.orderHint);
682
+ this._eventStream.emit({
683
+ eventName: 'orderChanged',
684
+ });
685
+ }
686
+ this._orderHint = navItemDescriptor.orderHint;
687
+ }
688
+ _updateRole(routeID) {
689
+ const roleElement = querySelector(this._element, '.V6.CL');
690
+ if (routeID) {
691
+ roleElement.setAttribute('role', 'link');
692
+ }
693
+ else {
694
+ roleElement.setAttribute('role', 'group');
695
+ roleElement.classList.add('X9');
696
+ }
697
+ }
698
+ _updateSubtitle(navItemDescriptor) {
699
+ if (this._isNewLeftNavParent) {
700
+ return;
701
+ }
702
+ if (navItemDescriptor.accessory &&
703
+ !['SETTINGS_BUTTON', 'DROPDOWN_BUTTON'].includes(navItemDescriptor.accessory.type) &&
704
+ navItemDescriptor.type !== NAV_ITEM_TYPES.GROUPER) {
705
+ return;
706
+ }
707
+ querySelector(this._element, '.bsU').innerHTML += autoHtml `${navItemDescriptor.subtitle || ''}`;
708
+ }
709
+ _updateType(type = NAV_ITEM_TYPES.NAVIGATION) {
710
+ if (!this._element) {
711
+ return;
712
+ }
713
+ type = type || NAV_ITEM_TYPES.NAVIGATION;
714
+ if (this._type === type) {
715
+ return;
716
+ }
717
+ const nameElement = this._element.querySelector('.inboxsdk__navItem_name');
718
+ switch (type) {
719
+ case NAV_ITEM_TYPES.GROUPER:
720
+ case NAV_ITEM_TYPES.NAVIGATION:
721
+ if (!nameElement || nameElement.tagName !== 'SPAN') {
722
+ querySelector(this._element, '.nU').innerHTML += autoHtml `<span class="inboxsdk__navItem_name">${this._name}</span>`;
723
+ }
724
+ break;
725
+ case NAV_ITEM_TYPES.LINK:
726
+ case NAV_ITEM_TYPES.MANAGE:
727
+ if (!nameElement || nameElement.tagName !== 'A') {
728
+ querySelector(this._element, '.nU').innerHTML += autoHtml `<a href="#" class="CK inboxsdk__navItem_name">${this._name}</a>`;
729
+ }
730
+ break;
731
+ }
732
+ this._type = type;
733
+ }
734
+ _updateValues(navItemDescriptor) {
735
+ this._navItemDescriptor = navItemDescriptor;
736
+ if (this._collapseKey == null) {
737
+ this._collapseKey = navItemDescriptor.key || `${navItemDescriptor.name}`;
738
+ this._isCollapsed =
739
+ localStorage.getItem('inboxsdk__navitem_collapsed__' + this._collapseKey) === 'true';
740
+ }
741
+ this._updateType(navItemDescriptor.type);
742
+ this._updateName(navItemDescriptor.name);
743
+ this._updateSubtitle(navItemDescriptor);
744
+ this._updateOrder(navItemDescriptor);
745
+ if (this._isNewLeftNavParent) {
746
+ this._updateRole(navItemDescriptor.routeID);
747
+ }
748
+ if (this._type === NAV_ITEM_TYPES.GROUPER) {
749
+ this._setupGrouper();
750
+ return;
751
+ }
752
+ this._updateAccessory(navItemDescriptor.accessory);
753
+ this._updateIcon(navItemDescriptor);
754
+ this._updateClickability(navItemDescriptor);
755
+ }
756
+ }
757
+ export function getLeftIndentationPaddingValue() {
758
+ return GMAIL_V2_LEFT_INDENTATION_PADDING;
759
+ }