@inboxsdk/core 0.2.29-alpha.0 → 0.2.29-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/inboxsdk.js +14 -14
- package/inboxsdk.js.map +1 -1
- package/package.json +1 -1
- package/src/platform-implementation-js/constants/router.js +8 -3
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.d.ts +2 -6
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.d.ts.map +1 -1
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-app-menu-item-view.js +9 -9
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-route-view/gmail-route-processor.js +3 -1
- package/src/platform-implementation-js/dom-driver/gmail/views/gmail-route-view/gmail-route-view.js +35 -0
- package/src/platform-implementation-js/namespaces/app-menu.d.ts +5 -2
- package/src/platform-implementation-js/namespaces/app-menu.d.ts.map +1 -1
- package/src/platform-implementation-js/namespaces/app-menu.js +3 -2
- package/src/platform-implementation-js/views/app-menu-item-view.d.ts +0 -1
- package/src/platform-implementation-js/views/app-menu-item-view.d.ts.map +1 -1
- package/src/platform-implementation-js/views/app-menu-item-view.js +257 -192
- package/src/platform-implementation-js/views/collapsible-panel-view.d.ts +2 -15
- package/src/platform-implementation-js/views/collapsible-panel-view.d.ts.map +1 -1
- package/src/platform-implementation-js/views/collapsible-panel-view.js +6 -61
|
@@ -1,114 +1,226 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import Kefir from 'kefir';
|
|
2
|
+
import kefirStopper from 'kefir-stopper';
|
|
3
|
+
import kefirBus from 'kefir-bus';
|
|
3
4
|
import EventEmitter from '../lib/safe-event-emitter';
|
|
4
5
|
import { GmailAppMenuItemView, NATIVE_CLASS, INBOXSDK_CLASS, } from '../dom-driver/gmail/views/gmail-app-menu-item-view';
|
|
5
|
-
import { CollapsiblePanelView } from './collapsible-panel-view';
|
|
6
|
+
import { NATIVE_CLASS as PANEL_NATIVE_CLASS, CollapsiblePanelView, } from './collapsible-panel-view';
|
|
6
7
|
import { addCollapsiblePanel } from '../dom-driver/gmail/gmail-driver/add-collapsible-panel';
|
|
7
8
|
import GmailElementGetter from '../dom-driver/gmail/gmail-element-getter';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
var NativeAppMenuClassName;
|
|
10
|
+
(function (NativeAppMenuClassName) {
|
|
11
|
+
NativeAppMenuClassName["MAIL"] = "XJ";
|
|
12
|
+
NativeAppMenuClassName["CHAT"] = "ao4";
|
|
13
|
+
NativeAppMenuClassName["SPACES"] = "aIt";
|
|
14
|
+
NativeAppMenuClassName["MEET"] = "adZ";
|
|
15
|
+
})(NativeAppMenuClassName || (NativeAppMenuClassName = {}));
|
|
16
|
+
// Native Gmail menu button => the panel class names mapping
|
|
17
|
+
const nativeButtonToPanelMap = new Map([
|
|
18
|
+
[NativeAppMenuClassName.MAIL, 'aIH'],
|
|
19
|
+
[NativeAppMenuClassName.CHAT, 'arL'],
|
|
20
|
+
[NativeAppMenuClassName.SPACES, 'arM'],
|
|
21
|
+
[NativeAppMenuClassName.MEET, undefined], // Meet
|
|
22
|
+
]);
|
|
23
|
+
/**
|
|
24
|
+
* Mail routes list is not exhaustive
|
|
25
|
+
*/
|
|
26
|
+
const MAIL_ROUTES = ['inbox/:page'];
|
|
27
|
+
const CHAT_ROUTES = ['chat/welcome', 'chat/dm/:chatID'];
|
|
28
|
+
const SPACES_ROUTES = ['rooms/welcome', 'chat/space/:spaceID'];
|
|
29
|
+
const MEET_ROUTES = ['calls'];
|
|
30
|
+
const routeIDtoMenuItemClass = Object.fromEntries([
|
|
31
|
+
...MAIL_ROUTES.map((route) => [route, NativeAppMenuClassName.MAIL]),
|
|
32
|
+
...CHAT_ROUTES.map((route) => [route, NativeAppMenuClassName.CHAT]),
|
|
33
|
+
...SPACES_ROUTES.map((route) => [route, NativeAppMenuClassName.SPACES]),
|
|
34
|
+
...MEET_ROUTES.map((route) => [route, NativeAppMenuClassName.MEET]),
|
|
35
|
+
]);
|
|
36
|
+
const initialRoutingStateStopper = kefirStopper();
|
|
19
37
|
/**
|
|
20
38
|
* Contains both a native Gmail app menu item and a collapsible panel.
|
|
21
39
|
*/
|
|
22
40
|
export class AppMenuItemView extends EventEmitter {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
static #
|
|
27
|
-
static #
|
|
28
|
-
const stream = kefir.stream((emitter) => {
|
|
29
|
-
const observer = new MutationObserver((mutations) => {
|
|
30
|
-
for (const mutation of mutations) {
|
|
31
|
-
const { target } = mutation;
|
|
32
|
-
if (mutation.type === 'attributes' &&
|
|
33
|
-
target instanceof HTMLElement &&
|
|
34
|
-
target.classList.contains(NATIVE_CLASS) &&
|
|
35
|
-
!target.classList.contains(INBOXSDK_CLASS)) {
|
|
36
|
-
if (target.classList.contains(GmailAppMenuItemView.elementCss.ACTIVE)) {
|
|
37
|
-
emitter.emit(['activated', target]);
|
|
38
|
-
}
|
|
39
|
-
else if (target.classList.contains(GmailAppMenuItemView.elementCss.HOVER)) {
|
|
40
|
-
emitter.emit(['hovered', target]);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
const f = async () => {
|
|
46
|
-
const gmailAppMenu = await GmailElementGetter.getAppMenuAsync();
|
|
47
|
-
if (!gmailAppMenu) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
const { ACTIVE } = GmailAppMenuItemView.elementCss;
|
|
51
|
-
const nativeMenuItemSelector = `.${NATIVE_CLASS}.${ACTIVE}:not(.${INBOXSDK_CLASS})`;
|
|
52
|
-
const nativeActivePanel = AppMenuItemView.#getNativeActivePanel();
|
|
53
|
-
setPrevNative({
|
|
54
|
-
menuItem: gmailAppMenu.querySelector(nativeMenuItemSelector),
|
|
55
|
-
panel: nativeActivePanel,
|
|
56
|
-
});
|
|
57
|
-
AppMenuItemView.#activePanel = nativeActivePanel;
|
|
58
|
-
document.addEventListener('mousedown', (e) => {
|
|
59
|
-
const { target } = e;
|
|
60
|
-
if (!(target instanceof Element)) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (!gmailAppMenu.contains(target)) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const closest = target.closest(`.${NATIVE_CLASS}:not(.${INBOXSDK_CLASS})`);
|
|
67
|
-
if (closest) {
|
|
68
|
-
emitter.emit(['mousedown-on-native-el', closest, e]);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
observer.observe(gmailAppMenu, {
|
|
72
|
-
attributes: true,
|
|
73
|
-
childList: true,
|
|
74
|
-
subtree: true,
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
f();
|
|
78
|
-
});
|
|
79
|
-
return stream;
|
|
80
|
-
})();
|
|
81
|
-
static #getNativeActivePanel() {
|
|
41
|
+
static #menuItemChangeStream = Kefir.pool();
|
|
42
|
+
static #routeViewDriverStream;
|
|
43
|
+
static #menuItemToPanelMap = new Map();
|
|
44
|
+
static #appMenuItemViews = new Set();
|
|
45
|
+
static #getActivePanel() {
|
|
82
46
|
const appMenuElement = GmailElementGetter.getAppMenuContainer();
|
|
83
|
-
const { ACTIVE
|
|
84
|
-
const nativePanel = appMenuElement?.querySelector(
|
|
47
|
+
const { ACTIVE } = CollapsiblePanelView.elementCss;
|
|
48
|
+
const nativePanel = appMenuElement?.querySelector(`.${PANEL_NATIVE_CLASS}.${ACTIVE}`);
|
|
85
49
|
return nativePanel;
|
|
86
50
|
}
|
|
87
|
-
static #
|
|
51
|
+
static #getActiveMenuItem() {
|
|
52
|
+
const appMenuElement = GmailElementGetter.getAppMenuContainer();
|
|
53
|
+
const { ACTIVE } = GmailAppMenuItemView.elementCss;
|
|
54
|
+
const button = appMenuElement?.querySelector(`.${NATIVE_CLASS}.${ACTIVE}`);
|
|
55
|
+
return button;
|
|
56
|
+
}
|
|
57
|
+
static #setUpRouteViewDriverStream(driver) {
|
|
58
|
+
if (AppMenuItemView.#routeViewDriverStream)
|
|
59
|
+
return;
|
|
60
|
+
AppMenuItemView.#routeViewDriverStream = driver.getRouteViewDriverStream();
|
|
61
|
+
const bus = kefirBus();
|
|
62
|
+
AppMenuItemView.#menuItemChangeStream.plug(bus);
|
|
63
|
+
AppMenuItemView.#routeViewDriverStream
|
|
64
|
+
.takeUntilBy(initialRoutingStateStopper)
|
|
65
|
+
.onValue(async (routeView) => {
|
|
66
|
+
const routeViewID = routeView.getRouteID();
|
|
67
|
+
const routeType = routeView.getRouteType();
|
|
68
|
+
const routeViewParams = routeView.getParams();
|
|
69
|
+
console.debug({
|
|
70
|
+
routeViewID,
|
|
71
|
+
routeType,
|
|
72
|
+
routeViewParams,
|
|
73
|
+
});
|
|
74
|
+
/* Handling custom app menu items */
|
|
75
|
+
const descriptors = Array.from(AppMenuItemView.#appMenuItemViews, async (appMenuItemView) => {
|
|
76
|
+
const gmailView = await appMenuItemView.#gmailViewPromise;
|
|
77
|
+
return [gmailView.menuItemDescriptor, gmailView];
|
|
78
|
+
});
|
|
79
|
+
const results = await Promise.all(descriptors);
|
|
80
|
+
const [, gmailView] = results.find(([descriptor]) => {
|
|
81
|
+
return descriptor?.isRouteActive(routeView);
|
|
82
|
+
}) ?? [];
|
|
83
|
+
if (gmailView?.element) {
|
|
84
|
+
bus.emit(['click', gmailView.element]);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
/* Handling native app menu items */
|
|
88
|
+
const selector = `.${routeViewID
|
|
89
|
+
? routeIDtoMenuItemClass[routeViewID] ?? NativeAppMenuClassName.MAIL
|
|
90
|
+
: NativeAppMenuClassName.MAIL}`;
|
|
91
|
+
const element = document.querySelector(selector);
|
|
92
|
+
if (element) {
|
|
93
|
+
bus.emit(['click', element]);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
88
98
|
static {
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
await Promise.all(Array.from(AppMenuItemView.#customMenuItems).map(async (customMenuItem) => {
|
|
94
|
-
await customMenuItem.#deactivate();
|
|
95
|
-
}));
|
|
99
|
+
(async () => {
|
|
100
|
+
const gmailAppMenu = await GmailElementGetter.getAppMenuAsync();
|
|
101
|
+
if (!gmailAppMenu) {
|
|
102
|
+
return;
|
|
96
103
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
// Set up menu item panel -> menu collapsible panel element mappings
|
|
105
|
+
for (const [menuItemClass, panelClass] of nativeButtonToPanelMap) {
|
|
106
|
+
const menuItemElement = document.querySelector(`.${NATIVE_CLASS}.${menuItemClass}`);
|
|
107
|
+
const panelElement = panelClass
|
|
108
|
+
? document.querySelector(`.${PANEL_NATIVE_CLASS}.${panelClass}`)
|
|
109
|
+
: null;
|
|
110
|
+
if (menuItemElement) {
|
|
111
|
+
AppMenuItemView.#menuItemToPanelMap.set(menuItemElement, panelElement ?? undefined);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Set up event listeners we use to control menu UI
|
|
115
|
+
const stream = Kefir.stream((emitter) => {
|
|
116
|
+
// We intercept some events emitted on Gmail (native) menu items to gain full control of the menu (menu items and panels).
|
|
117
|
+
// Thus, some native event handlers won't be invoked so we replicate the Gmail's behavior by ourselves.
|
|
118
|
+
const appMenuElement = GmailElementGetter.getAppMenuContainer();
|
|
119
|
+
for (const nativeMenuItem of appMenuElement?.querySelectorAll(`.${NATIVE_CLASS}:not(.${INBOXSDK_CLASS})`) ?? []) {
|
|
120
|
+
// Gmail uses this listener for panel hover state activation. It's prevented from propagation and we handle UI updates
|
|
121
|
+
nativeMenuItem.addEventListener('mouseenter', (e) => {
|
|
122
|
+
e.stopImmediatePropagation();
|
|
123
|
+
emitter.emit(['mouseenter', nativeMenuItem, e]);
|
|
124
|
+
}, true);
|
|
125
|
+
// Gmail uses this listener for panel hover state deactivation. It's prevented from propagation and we handle UI updates
|
|
126
|
+
nativeMenuItem.addEventListener('mouseleave', (e) => {
|
|
127
|
+
e.stopImmediatePropagation();
|
|
128
|
+
emitter.emit(['mouseleave', nativeMenuItem, e]);
|
|
129
|
+
}, true);
|
|
130
|
+
// Click event isn't prevented from propagation to let Gmail handle routing. The styling is handled by us
|
|
131
|
+
nativeMenuItem.addEventListener('click', () => {
|
|
132
|
+
emitter.emit(['click', nativeMenuItem]);
|
|
133
|
+
});
|
|
134
|
+
// Handle moving cursor out of panel. We use it to enhance the styling since it won't be handled by Gmail
|
|
135
|
+
const panel = AppMenuItemView.#menuItemToPanelMap.get(nativeMenuItem);
|
|
136
|
+
panel?.addEventListener('mouseleave', (e) => {
|
|
137
|
+
emitter.emit(['mouseleave', nativeMenuItem, e]);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
AppMenuItemView.#menuItemChangeStream.plug(stream);
|
|
142
|
+
})();
|
|
143
|
+
}
|
|
144
|
+
static {
|
|
145
|
+
AppMenuItemView.#menuItemChangeStream.onValue(async (v) => {
|
|
146
|
+
const [type, menuItem, mouseEvent] = v;
|
|
147
|
+
const { ACTIVE, HOVER } = GmailAppMenuItemView.elementCss;
|
|
148
|
+
if (type === 'mouseenter') {
|
|
149
|
+
const panel = AppMenuItemView.#menuItemToPanelMap.get(menuItem);
|
|
150
|
+
if (mouseEvent.relatedTarget instanceof Node &&
|
|
151
|
+
(menuItem.contains(mouseEvent.relatedTarget) ||
|
|
152
|
+
panel?.contains(mouseEvent.relatedTarget)))
|
|
100
153
|
return;
|
|
154
|
+
const activeMenuItem = AppMenuItemView.#getActiveMenuItem();
|
|
155
|
+
const activePanel = AppMenuItemView.#getActivePanel();
|
|
156
|
+
if (activeMenuItem === menuItem && activePanel === panel)
|
|
157
|
+
return;
|
|
158
|
+
// deactivate active panel
|
|
159
|
+
if (activePanel) {
|
|
160
|
+
activePanel.style.removeProperty('height');
|
|
161
|
+
activePanel.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
|
|
162
|
+
activePanel.classList.remove(CollapsiblePanelView.elementCss.HOVER);
|
|
163
|
+
}
|
|
164
|
+
// activate new panel
|
|
165
|
+
if (panel) {
|
|
166
|
+
const height = window.innerHeight - panel.getBoundingClientRect().top;
|
|
167
|
+
panel.style.cssText = `height: ${height}px;`;
|
|
168
|
+
panel.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
169
|
+
panel.classList.add(CollapsiblePanelView.elementCss.HOVER);
|
|
170
|
+
// hover menu item
|
|
171
|
+
menuItem.classList.add(HOVER);
|
|
101
172
|
}
|
|
102
173
|
else {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
document.location.hash = route;
|
|
107
|
-
}
|
|
108
|
-
menuItem?.classList.add(GmailAppMenuItemView.elementCss.ACTIVE);
|
|
109
|
-
menuItem.classList.remove(GmailAppMenuItemView.elementCss.HOVER);
|
|
174
|
+
// panel doesn't exist (i.e. Meet) so activate active menu item's panel instead (as Gmail currently does -- FEB 2023)
|
|
175
|
+
const panel = activeMenuItem &&
|
|
176
|
+
AppMenuItemView.#menuItemToPanelMap.get(activeMenuItem);
|
|
110
177
|
panel?.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
111
|
-
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (type === 'mouseleave') {
|
|
181
|
+
const activeMenuItem = AppMenuItemView.#getActiveMenuItem();
|
|
182
|
+
const activePanel = AppMenuItemView.#getActivePanel();
|
|
183
|
+
const activeMenuItemPanel = activeMenuItem &&
|
|
184
|
+
AppMenuItemView.#menuItemToPanelMap.get(activeMenuItem);
|
|
185
|
+
if (mouseEvent.relatedTarget instanceof Node &&
|
|
186
|
+
(menuItem.contains(mouseEvent.relatedTarget) ||
|
|
187
|
+
activePanel?.contains(mouseEvent.relatedTarget)))
|
|
188
|
+
return;
|
|
189
|
+
if (activePanel === activeMenuItemPanel)
|
|
190
|
+
return;
|
|
191
|
+
// unhover menu item
|
|
192
|
+
menuItem.classList.remove(HOVER);
|
|
193
|
+
// deactivate active panel
|
|
194
|
+
if (activePanel) {
|
|
195
|
+
activePanel.style.removeProperty('height');
|
|
196
|
+
activePanel.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
|
|
197
|
+
activePanel.classList.remove(CollapsiblePanelView.elementCss.HOVER);
|
|
198
|
+
}
|
|
199
|
+
// activate active menu item panel
|
|
200
|
+
if (activeMenuItemPanel) {
|
|
201
|
+
activeMenuItemPanel.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (type === 'click') {
|
|
205
|
+
const appMenuElement = GmailElementGetter.getAppMenuContainer();
|
|
206
|
+
// deactivate active panel
|
|
207
|
+
const activePanel = AppMenuItemView.#getActivePanel();
|
|
208
|
+
if (activePanel) {
|
|
209
|
+
activePanel.style.removeProperty('height');
|
|
210
|
+
activePanel.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
|
|
211
|
+
activePanel.classList.remove(CollapsiblePanelView.elementCss.HOVER);
|
|
212
|
+
}
|
|
213
|
+
// deactivate menu items
|
|
214
|
+
for (const menuItem_ of appMenuElement?.querySelectorAll(`.${NATIVE_CLASS}`) ?? []) {
|
|
215
|
+
menuItem_.classList.remove(ACTIVE);
|
|
216
|
+
menuItem_.classList.remove(HOVER);
|
|
217
|
+
}
|
|
218
|
+
// activate menu item
|
|
219
|
+
menuItem.classList.add(ACTIVE);
|
|
220
|
+
// activate panel
|
|
221
|
+
const panel = AppMenuItemView.#menuItemToPanelMap.get(menuItem);
|
|
222
|
+
if (panel) {
|
|
223
|
+
panel.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
112
224
|
}
|
|
113
225
|
}
|
|
114
226
|
});
|
|
@@ -117,60 +229,61 @@ export class AppMenuItemView extends EventEmitter {
|
|
|
117
229
|
#destroyed = false;
|
|
118
230
|
#gmailViewPromise;
|
|
119
231
|
#collapsiblePanel;
|
|
120
|
-
|
|
121
|
-
#
|
|
122
|
-
menuItemDescriptor;
|
|
232
|
+
#appMenuItemStream;
|
|
233
|
+
#collapsiblePanelStream;
|
|
123
234
|
constructor(driver, menuItemDescriptor) {
|
|
124
235
|
super();
|
|
125
236
|
this.#driver = driver;
|
|
126
|
-
this.menuItemDescriptor = menuItemDescriptor;
|
|
127
237
|
const gmailAppMenuItemView = this.#driver.addAppMenuItem(menuItemDescriptor);
|
|
128
238
|
this.#gmailViewPromise = gmailAppMenuItemView;
|
|
129
239
|
gmailAppMenuItemView.then((gmailView) => {
|
|
130
240
|
if (this.#destroyed || !gmailView) {
|
|
131
241
|
return; //we have been removed already
|
|
132
242
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (activeRouteParams) {
|
|
155
|
-
isActive = isEqual(activeRouteParams, routeViewParams);
|
|
156
|
-
}
|
|
157
|
-
else if (routeParams) {
|
|
158
|
-
isActive = isEqual(routeParams, routeViewParams);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
// deactivation is handled by the native menu item change stream
|
|
162
|
-
if (isActive) {
|
|
163
|
-
this.#activate();
|
|
164
|
-
}
|
|
243
|
+
const gmailElement = gmailView.element;
|
|
244
|
+
if (gmailElement) {
|
|
245
|
+
AppMenuItemView.#menuItemToPanelMap.set(gmailElement, undefined);
|
|
246
|
+
}
|
|
247
|
+
this.#appMenuItemStream = Kefir.stream((emitter) => {
|
|
248
|
+
gmailView.on('destroy', () => {
|
|
249
|
+
emitter.end();
|
|
250
|
+
this.remove();
|
|
251
|
+
});
|
|
252
|
+
gmailView.on('click', () => {
|
|
253
|
+
emitter.emit(['click', gmailElement]);
|
|
254
|
+
this.emit('click');
|
|
255
|
+
});
|
|
256
|
+
gmailView.on('hover', (e) => {
|
|
257
|
+
emitter.emit(['mouseenter', gmailElement, e]);
|
|
258
|
+
this.emit('hover');
|
|
259
|
+
});
|
|
260
|
+
gmailView.on('blur', (e) => {
|
|
261
|
+
emitter.emit(['mouseleave', gmailElement, e]);
|
|
262
|
+
this.emit('blur');
|
|
263
|
+
});
|
|
165
264
|
});
|
|
265
|
+
AppMenuItemView.#menuItemChangeStream.plug(this.#appMenuItemStream);
|
|
266
|
+
AppMenuItemView.#setUpRouteViewDriverStream(driver);
|
|
267
|
+
AppMenuItemView.#appMenuItemViews.add(this);
|
|
166
268
|
});
|
|
167
|
-
AppMenuItemView.#customMenuItems.add(this);
|
|
168
269
|
}
|
|
169
270
|
async addCollapsiblePanel(panelDescriptor) {
|
|
170
271
|
const collapsiblePanel = await addCollapsiblePanel(this.#driver, panelDescriptor);
|
|
171
272
|
if (collapsiblePanel) {
|
|
172
|
-
|
|
173
|
-
|
|
273
|
+
this.#gmailViewPromise.then((gmailView) => {
|
|
274
|
+
const gmailElement = gmailView.element;
|
|
275
|
+
if (gmailElement) {
|
|
276
|
+
this.#collapsiblePanelStream = Kefir.stream((emitter) => {
|
|
277
|
+
collapsiblePanel.on('blur', (e) => {
|
|
278
|
+
emitter.value(['mouseleave', gmailElement, e]);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
AppMenuItemView.#menuItemChangeStream.plug(this.#collapsiblePanelStream);
|
|
282
|
+
}
|
|
283
|
+
if (gmailElement && collapsiblePanel) {
|
|
284
|
+
AppMenuItemView.#menuItemToPanelMap.set(gmailElement, collapsiblePanel.element);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
174
287
|
}
|
|
175
288
|
this.#collapsiblePanel = collapsiblePanel;
|
|
176
289
|
return collapsiblePanel;
|
|
@@ -183,18 +296,21 @@ export class AppMenuItemView extends EventEmitter {
|
|
|
183
296
|
if (this.#destroyed)
|
|
184
297
|
return;
|
|
185
298
|
this.#destroyed = true;
|
|
186
|
-
AppMenuItemView.#customMenuItems.delete(this);
|
|
187
299
|
this.emit('destroy');
|
|
188
300
|
this.#collapsiblePanel?.remove();
|
|
189
|
-
this.#gmailViewPromise.then((gmailView) =>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
this.#
|
|
301
|
+
this.#gmailViewPromise.then((gmailView) => {
|
|
302
|
+
gmailView.element &&
|
|
303
|
+
AppMenuItemView.#menuItemToPanelMap.delete(gmailView.element);
|
|
304
|
+
gmailView.remove();
|
|
305
|
+
});
|
|
306
|
+
this.#appMenuItemStream &&
|
|
307
|
+
AppMenuItemView.#menuItemChangeStream.unplug(this.#appMenuItemStream);
|
|
308
|
+
this.#collapsiblePanelStream &&
|
|
309
|
+
AppMenuItemView.#menuItemChangeStream.unplug(this.#collapsiblePanelStream);
|
|
310
|
+
AppMenuItemView.#appMenuItemViews.delete(this);
|
|
311
|
+
initialRoutingStateStopper.destroy();
|
|
195
312
|
}
|
|
196
313
|
async #activate() {
|
|
197
|
-
AppMenuItemView.#activePanel = this.#collapsiblePanel;
|
|
198
314
|
const gmailView = await this.#gmailViewPromise;
|
|
199
315
|
const appMenuElement = GmailElementGetter.getAppMenuContainer();
|
|
200
316
|
const { ACTIVE } = GmailAppMenuItemView.elementCss;
|
|
@@ -205,55 +321,4 @@ export class AppMenuItemView extends EventEmitter {
|
|
|
205
321
|
gmailView.activate();
|
|
206
322
|
this.#collapsiblePanel?.activate();
|
|
207
323
|
}
|
|
208
|
-
#onBlur = async (e) => {
|
|
209
|
-
const gmailView = await this.#gmailViewPromise;
|
|
210
|
-
const { relatedTarget } = e;
|
|
211
|
-
const blurringMenuItem = relatedTarget instanceof Node &&
|
|
212
|
-
gmailView.element?.contains(relatedTarget);
|
|
213
|
-
const blurringPanel = relatedTarget instanceof Node &&
|
|
214
|
-
this.#collapsiblePanel?.element?.contains(relatedTarget);
|
|
215
|
-
if (blurringMenuItem || blurringPanel) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
this.#hovered = false;
|
|
219
|
-
gmailView.blur();
|
|
220
|
-
const hasActivePanel = this.#hasActivePanel();
|
|
221
|
-
this.#collapsiblePanel?.blur(hasActivePanel);
|
|
222
|
-
if (!hasActivePanel) {
|
|
223
|
-
if (AppMenuItemView.#activePanel instanceof CollapsiblePanelView) {
|
|
224
|
-
AppMenuItemView.#activePanel?.activate();
|
|
225
|
-
}
|
|
226
|
-
else if (AppMenuItemView.#activePanel instanceof HTMLElement) {
|
|
227
|
-
AppMenuItemView.#activePanel.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
this.emit('blur');
|
|
231
|
-
};
|
|
232
|
-
#hasActivePanel() {
|
|
233
|
-
return (this.#collapsiblePanel != null &&
|
|
234
|
-
AppMenuItemView.#activePanel === this.#collapsiblePanel);
|
|
235
|
-
}
|
|
236
|
-
#onHover = async (_e) => {
|
|
237
|
-
if (this.#hovered) {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
this.#hovered = true;
|
|
241
|
-
const gmailView = await this.#gmailViewPromise;
|
|
242
|
-
gmailView.hover();
|
|
243
|
-
const hasActivePanel = this.#hasActivePanel();
|
|
244
|
-
if (!hasActivePanel) {
|
|
245
|
-
if (AppMenuItemView.#activePanel instanceof CollapsiblePanelView) {
|
|
246
|
-
AppMenuItemView.#activePanel?.deactivate();
|
|
247
|
-
}
|
|
248
|
-
else if (AppMenuItemView.#activePanel instanceof HTMLElement) {
|
|
249
|
-
AppMenuItemView.#activePanel.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
this.#collapsiblePanel?.hover(hasActivePanel);
|
|
253
|
-
this.emit('hover');
|
|
254
|
-
};
|
|
255
|
-
#onClick = () => {
|
|
256
|
-
this.#activate();
|
|
257
|
-
this.emit('click');
|
|
258
|
-
};
|
|
259
324
|
}
|
|
@@ -4,11 +4,11 @@ import { AppMenuItemPanelDescriptor } from '../namespaces/app-menu';
|
|
|
4
4
|
import GmailDriver from '../dom-driver/gmail/gmail-driver';
|
|
5
5
|
import { NavItemDescriptor } from '../dom-driver/gmail/views/gmail-nav-item-view';
|
|
6
6
|
import NavItemView from './nav-item-view';
|
|
7
|
+
export declare const NATIVE_CLASS: "aqn";
|
|
8
|
+
export declare const INBOXSDK_CLASS: "inboxsdk__collapsiblePanel";
|
|
7
9
|
type MessageEvents = {
|
|
8
|
-
toggle: (collapsed: boolean) => void;
|
|
9
10
|
destroy: () => void;
|
|
10
11
|
blur: (e: MouseEvent) => void;
|
|
11
|
-
hover: (e: MouseEvent) => void;
|
|
12
12
|
};
|
|
13
13
|
declare const CollapsiblePanelView_base: new () => TypedEmitter<MessageEvents>;
|
|
14
14
|
export declare class CollapsiblePanelView extends CollapsiblePanelView_base {
|
|
@@ -26,23 +26,10 @@ export declare class CollapsiblePanelView extends CollapsiblePanelView_base {
|
|
|
26
26
|
get element(): HTMLElement | undefined;
|
|
27
27
|
set panelDescriptor(panelDescriptor: AppMenuItemPanelDescriptor);
|
|
28
28
|
constructor(driver: GmailDriver);
|
|
29
|
-
toggleCollapse(collapsed: boolean): void;
|
|
30
|
-
/**
|
|
31
|
-
* @internal
|
|
32
|
-
*/
|
|
33
|
-
blur(isActivePanel: boolean): void;
|
|
34
|
-
/**
|
|
35
|
-
* @internal
|
|
36
|
-
*/
|
|
37
|
-
hover(isActivePanel: boolean): void;
|
|
38
29
|
/**
|
|
39
30
|
* @internal
|
|
40
31
|
*/
|
|
41
32
|
activate(): void;
|
|
42
|
-
/**
|
|
43
|
-
* @internal
|
|
44
|
-
*/
|
|
45
|
-
deactivate(): void;
|
|
46
33
|
remove(): void;
|
|
47
34
|
addNavItem(navItemDescriptor: NavItemDescriptor | Kefir.Observable<NavItemDescriptor, any>): NavItemView | undefined;
|
|
48
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collapsible-panel-view.d.ts","sourceRoot":"","sources":["../../../../../src/platform-implementation-js/views/collapsible-panel-view.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAC;AAEzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAIpE,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,WAAW,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"collapsible-panel-view.d.ts","sourceRoot":"","sources":["../../../../../src/platform-implementation-js/views/collapsible-panel-view.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAC;AAEzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAIpE,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAE1C,eAAO,MAAM,YAAY,OAAiB,CAAC;AAC3C,eAAO,MAAM,cAAc,8BAAwC,CAAC;AAQpE,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;CAC/B,CAAC;mDAEmE,aAAa,aAAa,CAAC;AAAhG,qBAAa,oBAAqB,SAAQ,yBAAuD;;IAC/F,MAAM,CAAC,gBAAgB;;;MAGZ;IACX,MAAM,CAAC,UAAU;;;QAGf,kDAAkD;;MAEzC;IAQX,IAAI,OAAO,4BAEV;IAED,IAAI,eAAe,CAAC,eAAe,EAAE,0BAA0B,EAG9D;gBAEW,MAAM,EAAE,WAAW;IAS/B;;OAEG;IACH,QAAQ;IAQR,MAAM;IAON,UAAU,CACR,iBAAiB,EACb,iBAAiB,GACjB,KAAK,CAAC,UAAU,CAAC,iBAAiB,EAAE,GAAG,CAAC;CA+J/C"}
|
|
@@ -6,10 +6,9 @@ import autoHtml from 'auto-html';
|
|
|
6
6
|
import querySelector from '../lib/dom/querySelectorOrFail';
|
|
7
7
|
import GmailElementGetter from '../dom-driver/gmail/gmail-element-getter';
|
|
8
8
|
import NavItemView from './nav-item-view';
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// `aqn oy8Mbf ${COLLAPSED_CLASS_NAME_TOKEN}` as const;
|
|
9
|
+
export const NATIVE_CLASS = 'aqn';
|
|
10
|
+
export const INBOXSDK_CLASS = 'inboxsdk__collapsiblePanel';
|
|
11
|
+
const ELEMENT_CLASS = `${NATIVE_CLASS} ${INBOXSDK_CLASS} oy8Mbf`;
|
|
13
12
|
const PRIMARY_BUTTON_ELEMENT_CLASS = 'T-I T-I-KE L3';
|
|
14
13
|
const PRIMARY_BUTTON_ELEMENT_SELECTOR = '.T-I.T-I-KE.L3';
|
|
15
14
|
const NAV_MENU_CONTAINER_ELEMENT_SELECTOR = '.at9 .n3 .TK';
|
|
@@ -41,48 +40,9 @@ export class CollapsiblePanelView extends EventEmitter {
|
|
|
41
40
|
super();
|
|
42
41
|
this.#driver = driver;
|
|
43
42
|
this.#element = this.#setupElement();
|
|
44
|
-
this.#element.addEventListener('
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
toggleCollapse(collapsed) {
|
|
48
|
-
const element = this.element;
|
|
49
|
-
if (!element)
|
|
50
|
-
return;
|
|
51
|
-
const { COLLAPSED } = CollapsiblePanelView.elementCss;
|
|
52
|
-
if (collapsed) {
|
|
53
|
-
element.classList.add(COLLAPSED);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
element.classList.remove(COLLAPSED);
|
|
57
|
-
}
|
|
58
|
-
this.emit('toggle', collapsed);
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* @internal
|
|
62
|
-
*/
|
|
63
|
-
blur(isActivePanel) {
|
|
64
|
-
const { element } = this;
|
|
65
|
-
if (!element)
|
|
66
|
-
return;
|
|
67
|
-
element.classList.remove(CollapsiblePanelView.elementCss.HOVER);
|
|
68
|
-
if (!isActivePanel) {
|
|
69
|
-
element.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
|
|
70
|
-
}
|
|
71
|
-
element.style.removeProperty('height');
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* @internal
|
|
75
|
-
*/
|
|
76
|
-
hover(isActivePanel) {
|
|
77
|
-
const { element } = this;
|
|
78
|
-
const { ACTIVE, HOVER } = CollapsiblePanelView.elementCss;
|
|
79
|
-
if (!element || element.classList.contains(ACTIVE))
|
|
80
|
-
return;
|
|
81
|
-
element.classList.add(HOVER);
|
|
82
|
-
if (!isActivePanel) {
|
|
83
|
-
element.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
84
|
-
}
|
|
85
|
-
element.style.cssText = 'height: 785px;';
|
|
43
|
+
this.#element.addEventListener('mouseleave', (e) => {
|
|
44
|
+
this.emit('blur', e);
|
|
45
|
+
});
|
|
86
46
|
}
|
|
87
47
|
/**
|
|
88
48
|
* @internal
|
|
@@ -94,15 +54,6 @@ export class CollapsiblePanelView extends EventEmitter {
|
|
|
94
54
|
element?.classList.remove(CollapsiblePanelView.elementCss.HOVER);
|
|
95
55
|
element.classList.add(CollapsiblePanelView.elementCss.ACTIVE);
|
|
96
56
|
}
|
|
97
|
-
/**
|
|
98
|
-
* @internal
|
|
99
|
-
*/
|
|
100
|
-
deactivate() {
|
|
101
|
-
const element = this.element;
|
|
102
|
-
if (!element)
|
|
103
|
-
return;
|
|
104
|
-
element.classList.remove(CollapsiblePanelView.elementCss.ACTIVE);
|
|
105
|
-
}
|
|
106
57
|
remove() {
|
|
107
58
|
if (this.#destroyed)
|
|
108
59
|
return;
|
|
@@ -213,10 +164,4 @@ export class CollapsiblePanelView extends EventEmitter {
|
|
|
213
164
|
}
|
|
214
165
|
buttonTextEl.textContent = this.#panelDescriptor?.primaryButton?.name ?? '';
|
|
215
166
|
}
|
|
216
|
-
#onBlur = (e) => {
|
|
217
|
-
this.emit('blur', e);
|
|
218
|
-
};
|
|
219
|
-
#onHover = (e) => {
|
|
220
|
-
this.emit('hover', e);
|
|
221
|
-
};
|
|
222
167
|
}
|