@lvce-editor/title-bar-worker 1.4.0 → 1.6.0
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/dist/titleBarWorkerMain.js +328 -227
- package/package.json +1 -1
|
@@ -1354,10 +1354,15 @@ const getMenuVirtualDom = menuItems => {
|
|
|
1354
1354
|
};
|
|
1355
1355
|
|
|
1356
1356
|
const HandleClick = 'handleClick';
|
|
1357
|
+
const HandleClickMinimize = 'handleClickMinimize';
|
|
1358
|
+
const HandleClickToggleClose = 'handleClickToggleClose';
|
|
1359
|
+
const HandleClickToggleMaximize = 'handleClickToggleMaximize';
|
|
1357
1360
|
const HandleFocusIn = 'handleFocusIn';
|
|
1358
1361
|
const HandleFocusOut = 'handleFocusOut';
|
|
1359
1362
|
const HandlePointerOut = 'handlePointerOut';
|
|
1360
1363
|
const HandlePointerOver = 'handlePointerOver';
|
|
1364
|
+
const HandleMenuClick = 'handleMenuClick';
|
|
1365
|
+
const HandleMenuMouseOver = 'handleMenuMouseOver';
|
|
1361
1366
|
|
|
1362
1367
|
const getItemVirtualDom = item => {
|
|
1363
1368
|
// @ts-ignore
|
|
@@ -1459,9 +1464,11 @@ const File$1 = 'File';
|
|
|
1459
1464
|
const Go$1 = 'Go';
|
|
1460
1465
|
const Help$1 = 'Help';
|
|
1461
1466
|
const MoreDot = 'More ...';
|
|
1467
|
+
const OpenProcessExplorer = 'Open Process Explorer';
|
|
1462
1468
|
const Run$1 = 'Run';
|
|
1463
1469
|
const Selection$1 = 'Selection';
|
|
1464
1470
|
const Terminal$1 = 'Terminal';
|
|
1471
|
+
const ToggleDeveloperTools = 'Toggle Developer Tools';
|
|
1465
1472
|
const View$1 = 'View';
|
|
1466
1473
|
|
|
1467
1474
|
const moreDot = () => {
|
|
@@ -1598,7 +1605,8 @@ const doRender = async uid => {
|
|
|
1598
1605
|
return commands;
|
|
1599
1606
|
};
|
|
1600
1607
|
|
|
1601
|
-
const commandsIds = ['closeMenu', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusPrevious', 'handleKeyArrowDown', 'handleKeyArrowLeft', 'handleKeyArrowRight', 'handleKeyArrowUp', 'handleKeyEnd', 'handleKeyEnter', 'handleKeyEscape', 'handleKeyHome', 'handleKeySpace', 'handleMenuClick', 'handleMenuMouseOver', '
|
|
1608
|
+
const commandsIds = ['closeMenu', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusPrevious', 'handleClick', 'handleFocus', 'handleKeyArrowDown', 'handleKeyArrowLeft', 'handleKeyArrowRight', 'handleKeyArrowUp', 'handleKeyEnd', 'handleKeyEnter', 'handleKeyEscape', 'handleKeyHome', 'handleKeySpace', 'handleMenuClick', 'handleMenuMouseOver', 'handleMouseOut', 'handleMouseOver', 'handlePointerOver', 'handlePointerOut', 'toggleIndex', 'toggleMenu'];
|
|
1609
|
+
|
|
1602
1610
|
const getCommandIds = () => {
|
|
1603
1611
|
return commandsIds;
|
|
1604
1612
|
};
|
|
@@ -1767,6 +1775,7 @@ const UiStrings$1 = {
|
|
|
1767
1775
|
OpenFile: 'Open File',
|
|
1768
1776
|
OpenFolder: 'Open Folder',
|
|
1769
1777
|
OpenRecent: 'Open Recent',
|
|
1778
|
+
Exit: 'Exit',
|
|
1770
1779
|
Save: 'Save',
|
|
1771
1780
|
SaveAll: 'Save All'
|
|
1772
1781
|
};
|
|
@@ -1791,13 +1800,15 @@ const save = () => {
|
|
|
1791
1800
|
const saveAll = () => {
|
|
1792
1801
|
return i18nString(UiStrings$1.SaveAll);
|
|
1793
1802
|
};
|
|
1794
|
-
|
|
1795
|
-
|
|
1803
|
+
const exit = () => {
|
|
1804
|
+
return i18nString(UiStrings$1.Exit);
|
|
1805
|
+
};
|
|
1796
1806
|
|
|
1797
1807
|
const Web = 1;
|
|
1808
|
+
const Electron = 2;
|
|
1798
1809
|
|
|
1799
1810
|
const id$8 = File;
|
|
1800
|
-
const getMenuEntries$c =
|
|
1811
|
+
const getMenuEntries$c = platform => {
|
|
1801
1812
|
const entries = [{
|
|
1802
1813
|
id: 'newFile',
|
|
1803
1814
|
label: newFile(),
|
|
@@ -1834,6 +1845,14 @@ const getMenuEntries$c = () => {
|
|
|
1834
1845
|
flags: None,
|
|
1835
1846
|
command: 'Main.saveAll'
|
|
1836
1847
|
}];
|
|
1848
|
+
if (platform === Electron) {
|
|
1849
|
+
entries.push(menuEntrySeparator, {
|
|
1850
|
+
id: 'exit',
|
|
1851
|
+
label: exit(),
|
|
1852
|
+
flags: Ignore,
|
|
1853
|
+
command: 'Chrome.exit'
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1837
1856
|
return entries;
|
|
1838
1857
|
};
|
|
1839
1858
|
|
|
@@ -1854,6 +1873,12 @@ const MenuEntriesGo = {
|
|
|
1854
1873
|
id: id$7
|
|
1855
1874
|
};
|
|
1856
1875
|
|
|
1876
|
+
const toggleDeveloperTools = () => {
|
|
1877
|
+
return i18nString(ToggleDeveloperTools);
|
|
1878
|
+
};
|
|
1879
|
+
const openProcessExplorer = () => {
|
|
1880
|
+
return i18nString(OpenProcessExplorer);
|
|
1881
|
+
};
|
|
1857
1882
|
const checkForUpdates = () => {
|
|
1858
1883
|
return i18nString(CheckForUpdates);
|
|
1859
1884
|
};
|
|
@@ -1861,16 +1886,30 @@ const about = () => {
|
|
|
1861
1886
|
return i18nString(About);
|
|
1862
1887
|
};
|
|
1863
1888
|
|
|
1864
|
-
const isAutoUpdateSupported =
|
|
1865
|
-
{
|
|
1889
|
+
const isAutoUpdateSupported = platform => {
|
|
1890
|
+
if (platform !== Electron) {
|
|
1866
1891
|
return false;
|
|
1867
1892
|
}
|
|
1893
|
+
return false;
|
|
1868
1894
|
};
|
|
1869
1895
|
|
|
1870
1896
|
const id$6 = Help;
|
|
1871
|
-
const getMenuEntries$a = async
|
|
1872
|
-
const autoUpdateSupported = isAutoUpdateSupported();
|
|
1897
|
+
const getMenuEntries$a = async platform => {
|
|
1898
|
+
const autoUpdateSupported = isAutoUpdateSupported(platform);
|
|
1873
1899
|
const entries = [];
|
|
1900
|
+
if (platform !== Web) {
|
|
1901
|
+
entries.push({
|
|
1902
|
+
id: 'toggleDeveloperTools',
|
|
1903
|
+
label: toggleDeveloperTools(),
|
|
1904
|
+
flags: None,
|
|
1905
|
+
command: 'Developer.toggleDeveloperTools'
|
|
1906
|
+
}, {
|
|
1907
|
+
id: 'openProcessExplorer',
|
|
1908
|
+
label: openProcessExplorer(),
|
|
1909
|
+
flags: RestoreFocus,
|
|
1910
|
+
command: 'Developer.openProcessExplorer'
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1874
1913
|
if (autoUpdateSupported) {
|
|
1875
1914
|
entries.push(menuEntrySeparator, {
|
|
1876
1915
|
id: 'checkForUpdates',
|
|
@@ -2126,7 +2165,7 @@ const getMenuEntries$4 = () => {
|
|
|
2126
2165
|
}];
|
|
2127
2166
|
};
|
|
2128
2167
|
|
|
2129
|
-
const getFn =
|
|
2168
|
+
const getFn = platform => {
|
|
2130
2169
|
switch (platform) {
|
|
2131
2170
|
case Web:
|
|
2132
2171
|
return getMenuEntries$4;
|
|
@@ -2135,8 +2174,8 @@ const getFn = () => {
|
|
|
2135
2174
|
}
|
|
2136
2175
|
};
|
|
2137
2176
|
const id$1 = TitleBar;
|
|
2138
|
-
const getMenuEntries$3 = async
|
|
2139
|
-
const fn = getFn();
|
|
2177
|
+
const getMenuEntries$3 = async platform => {
|
|
2178
|
+
const fn = getFn(platform);
|
|
2140
2179
|
return fn();
|
|
2141
2180
|
};
|
|
2142
2181
|
|
|
@@ -2158,15 +2197,16 @@ const MenuEntriesView = {
|
|
|
2158
2197
|
};
|
|
2159
2198
|
|
|
2160
2199
|
const menus$1 = [MenuEntriesEdit, MenuEntriesFile, MenuEntriesGo, MenuEntriesHelp, MenuEntriesRun, MenuEntriesSelection, MenuEntriesTerminal, MenuEntriesTitleBar, MenuEntriesView, MenuEntriesOpenRecent];
|
|
2200
|
+
|
|
2161
2201
|
const getMenuIds = () => {
|
|
2162
2202
|
return menus$1.map(menu => menu.id);
|
|
2163
2203
|
};
|
|
2164
|
-
const getMenuEntries$1 = id => {
|
|
2204
|
+
const getMenuEntries$1 = (id, platform) => {
|
|
2165
2205
|
const menu = menus$1.find(item => item.id === id);
|
|
2166
2206
|
if (!menu) {
|
|
2167
2207
|
return [];
|
|
2168
2208
|
}
|
|
2169
|
-
return menu.getMenuEntries();
|
|
2209
|
+
return menu.getMenuEntries(platform);
|
|
2170
2210
|
};
|
|
2171
2211
|
|
|
2172
2212
|
const getIconVirtualDom = (icon, type = Div) => {
|
|
@@ -2250,6 +2290,252 @@ const handleClick$1 = (state, className) => {
|
|
|
2250
2290
|
return state;
|
|
2251
2291
|
};
|
|
2252
2292
|
|
|
2293
|
+
const handleContextMenu = state => {
|
|
2294
|
+
return state;
|
|
2295
|
+
};
|
|
2296
|
+
|
|
2297
|
+
const getTitleBarIndexFromPosition = (titleBarEntries, x, y) => {
|
|
2298
|
+
let currentX = 0;
|
|
2299
|
+
for (let i = 0; i < titleBarEntries.length; i++) {
|
|
2300
|
+
const entry = titleBarEntries[i];
|
|
2301
|
+
const entryWidth = entry.width;
|
|
2302
|
+
if (x >= currentX && x < currentX + entryWidth) {
|
|
2303
|
+
return i;
|
|
2304
|
+
}
|
|
2305
|
+
currentX += entryWidth;
|
|
2306
|
+
}
|
|
2307
|
+
return -1;
|
|
2308
|
+
};
|
|
2309
|
+
|
|
2310
|
+
const getTotalWidth = entries => {
|
|
2311
|
+
let total = 0;
|
|
2312
|
+
for (const entry of entries) {
|
|
2313
|
+
total += entry.width;
|
|
2314
|
+
}
|
|
2315
|
+
return total;
|
|
2316
|
+
};
|
|
2317
|
+
|
|
2318
|
+
// TODO lazyload menuEntries and use Command.execute (maybe)
|
|
2319
|
+
const CONTEXT_MENU_ITEM_HEIGHT = 26;
|
|
2320
|
+
const CONTEXT_MENU_SEPARATOR_HEIGHT = 11;
|
|
2321
|
+
const CONTEXT_MENU_PADDING = 8;
|
|
2322
|
+
const getMenuHeight = items => {
|
|
2323
|
+
let height = CONTEXT_MENU_PADDING;
|
|
2324
|
+
for (const item of items) {
|
|
2325
|
+
switch (item.flags) {
|
|
2326
|
+
case Separator:
|
|
2327
|
+
height += CONTEXT_MENU_SEPARATOR_HEIGHT;
|
|
2328
|
+
break;
|
|
2329
|
+
default:
|
|
2330
|
+
height += CONTEXT_MENU_ITEM_HEIGHT;
|
|
2331
|
+
break;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
return height;
|
|
2335
|
+
};
|
|
2336
|
+
|
|
2337
|
+
// TODO lazyload menuEntries and use Command.execute (maybe)
|
|
2338
|
+
const MENU_WIDTH = 150;
|
|
2339
|
+
const CONTEXT_MENU_WIDTH = 250;
|
|
2340
|
+
const getMenuWidth = () => {
|
|
2341
|
+
return CONTEXT_MENU_WIDTH;
|
|
2342
|
+
};
|
|
2343
|
+
|
|
2344
|
+
// TODO difference between focusing with mouse or keyboard
|
|
2345
|
+
// with mouse -> open submenu
|
|
2346
|
+
// with keyboard -> don't open submenu, only focus
|
|
2347
|
+
|
|
2348
|
+
const getIndexToFocusNextStartingAt = (items, startIndex) => {
|
|
2349
|
+
for (let i = startIndex; i < startIndex + items.length; i++) {
|
|
2350
|
+
const index = i % items.length;
|
|
2351
|
+
const item = items[index];
|
|
2352
|
+
if (canBeFocused(item)) {
|
|
2353
|
+
return index;
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
return -1;
|
|
2357
|
+
};
|
|
2358
|
+
const getIndexToFocusFirst = items => {
|
|
2359
|
+
return getIndexToFocusNextStartingAt(items, 0);
|
|
2360
|
+
};
|
|
2361
|
+
const getIndexToFocusLast = items => {
|
|
2362
|
+
return getIndexToFocusPreviousStartingAt(items, items.length - 1);
|
|
2363
|
+
};
|
|
2364
|
+
|
|
2365
|
+
// TODO this code seems a bit too complicated, maybe it can be simplified
|
|
2366
|
+
const getIndexToFocusPreviousStartingAt = (items, startIndex) => {
|
|
2367
|
+
for (let i = startIndex; i > startIndex - items.length; i--) {
|
|
2368
|
+
const index = (i + items.length) % items.length;
|
|
2369
|
+
const item = items[index];
|
|
2370
|
+
if (canBeFocused(item)) {
|
|
2371
|
+
return index;
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
return -1;
|
|
2375
|
+
};
|
|
2376
|
+
const getIndexToFocusPrevious = menu => {
|
|
2377
|
+
const startIndex = menu.focusedIndex === -1 ? menu.items.length - 1 : menu.focusedIndex - 1;
|
|
2378
|
+
return getIndexToFocusPreviousStartingAt(menu.items, startIndex);
|
|
2379
|
+
};
|
|
2380
|
+
const canBeFocused = item => {
|
|
2381
|
+
switch (item.flags) {
|
|
2382
|
+
case Separator:
|
|
2383
|
+
case Disabled:
|
|
2384
|
+
return false;
|
|
2385
|
+
default:
|
|
2386
|
+
return true;
|
|
2387
|
+
}
|
|
2388
|
+
};
|
|
2389
|
+
const getIndexToFocusNext = menu => {
|
|
2390
|
+
const startIndex = menu.focusedIndex + 1;
|
|
2391
|
+
return getIndexToFocusNextStartingAt(menu.items, startIndex);
|
|
2392
|
+
};
|
|
2393
|
+
|
|
2394
|
+
// TODO handle printable letter and focus item that starts with that letter
|
|
2395
|
+
|
|
2396
|
+
// TODO pageup / pagedown keys
|
|
2397
|
+
|
|
2398
|
+
// TODO more tests
|
|
2399
|
+
|
|
2400
|
+
const menus = [MenuEntriesEdit, MenuEntriesFile, MenuEntriesGo, MenuEntriesHelp, MenuEntriesRun, MenuEntriesSelection, MenuEntriesTerminal, MenuEntriesTitleBar, MenuEntriesView, MenuEntriesOpenRecent];
|
|
2401
|
+
const getMenus = () => {
|
|
2402
|
+
return menus;
|
|
2403
|
+
};
|
|
2404
|
+
const getModule = id => {
|
|
2405
|
+
for (const module of menus) {
|
|
2406
|
+
if (module.id === id) {
|
|
2407
|
+
return module;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
return undefined;
|
|
2411
|
+
};
|
|
2412
|
+
const getMenuEntries = async (id, ...args) => {
|
|
2413
|
+
try {
|
|
2414
|
+
const module = getModule(id);
|
|
2415
|
+
// @ts-ignore
|
|
2416
|
+
const inject = module.inject || [];
|
|
2417
|
+
// @ts-ignore
|
|
2418
|
+
return module.getMenuEntries(...args);
|
|
2419
|
+
} catch (error) {
|
|
2420
|
+
throw new VError(error, `Failed to load menu entries for id ${id}`);
|
|
2421
|
+
}
|
|
2422
|
+
};
|
|
2423
|
+
|
|
2424
|
+
const openMenuAtIndex = async (state, index, shouldBeFocused) => {
|
|
2425
|
+
const {
|
|
2426
|
+
titleBarEntries,
|
|
2427
|
+
titleBarHeight,
|
|
2428
|
+
x
|
|
2429
|
+
} = state;
|
|
2430
|
+
// TODO race conditions
|
|
2431
|
+
// TODO send renderer process
|
|
2432
|
+
// 1. open menu, items to show
|
|
2433
|
+
// 2. focus menu
|
|
2434
|
+
const titleBarEntry = titleBarEntries[index];
|
|
2435
|
+
const {
|
|
2436
|
+
id
|
|
2437
|
+
} = titleBarEntry;
|
|
2438
|
+
const items = await getMenuEntries(id);
|
|
2439
|
+
const relevantEntries = titleBarEntries.slice(0, index);
|
|
2440
|
+
const totalWidths = getTotalWidth(relevantEntries);
|
|
2441
|
+
const offset = totalWidths;
|
|
2442
|
+
// TODO race condition: another menu might already be open at this point
|
|
2443
|
+
|
|
2444
|
+
const menuX = x + offset;
|
|
2445
|
+
const menuY = titleBarHeight;
|
|
2446
|
+
const width = getMenuWidth();
|
|
2447
|
+
const height = getMenuHeight(items);
|
|
2448
|
+
const menuFocusedIndex = shouldBeFocused ? getIndexToFocusNextStartingAt(items, 0) : -1;
|
|
2449
|
+
const menu = {
|
|
2450
|
+
id,
|
|
2451
|
+
items,
|
|
2452
|
+
focusedIndex: menuFocusedIndex,
|
|
2453
|
+
level: 0,
|
|
2454
|
+
x: menuX,
|
|
2455
|
+
y: menuY,
|
|
2456
|
+
width,
|
|
2457
|
+
height
|
|
2458
|
+
};
|
|
2459
|
+
const menus = [menu];
|
|
2460
|
+
return {
|
|
2461
|
+
...state,
|
|
2462
|
+
isMenuOpen: true,
|
|
2463
|
+
focusedIndex: index,
|
|
2464
|
+
menus
|
|
2465
|
+
};
|
|
2466
|
+
};
|
|
2467
|
+
|
|
2468
|
+
const focusIndex = async (state, index) => {
|
|
2469
|
+
object(state);
|
|
2470
|
+
number(index);
|
|
2471
|
+
const {
|
|
2472
|
+
isMenuOpen,
|
|
2473
|
+
focusedIndex
|
|
2474
|
+
} = state;
|
|
2475
|
+
if (index === focusedIndex) {
|
|
2476
|
+
return state;
|
|
2477
|
+
}
|
|
2478
|
+
if (isMenuOpen) {
|
|
2479
|
+
return openMenuAtIndex(state, index, /* focus */false);
|
|
2480
|
+
}
|
|
2481
|
+
return {
|
|
2482
|
+
...state,
|
|
2483
|
+
focusedIndex: index
|
|
2484
|
+
};
|
|
2485
|
+
};
|
|
2486
|
+
|
|
2487
|
+
const handleMouseOutMenuClosed = state => {
|
|
2488
|
+
return focusIndex(state, -1);
|
|
2489
|
+
};
|
|
2490
|
+
|
|
2491
|
+
const handleMouseOutMenuOpen = state => {
|
|
2492
|
+
return state;
|
|
2493
|
+
};
|
|
2494
|
+
|
|
2495
|
+
const ifElse = (menuOpenFunction, menuClosedFunction) => {
|
|
2496
|
+
const ifElseFunction = (state, ...args) => {
|
|
2497
|
+
const {
|
|
2498
|
+
isMenuOpen
|
|
2499
|
+
} = state;
|
|
2500
|
+
if (isMenuOpen) {
|
|
2501
|
+
return menuOpenFunction(state, ...args);
|
|
2502
|
+
}
|
|
2503
|
+
return menuClosedFunction(state, ...args);
|
|
2504
|
+
};
|
|
2505
|
+
return ifElseFunction;
|
|
2506
|
+
};
|
|
2507
|
+
|
|
2508
|
+
const handleMouseOut = ifElse(handleMouseOutMenuOpen, handleMouseOutMenuClosed);
|
|
2509
|
+
|
|
2510
|
+
const handlePointerOut = (state, clientX, clientY) => {
|
|
2511
|
+
const index = getTitleBarIndexFromPosition(state.titleBarEntries, clientX - state.x);
|
|
2512
|
+
if (index === -1) {
|
|
2513
|
+
return state;
|
|
2514
|
+
}
|
|
2515
|
+
return handleMouseOut(state, index);
|
|
2516
|
+
};
|
|
2517
|
+
|
|
2518
|
+
const handleMouseOverMenuClosed = (state, index) => {
|
|
2519
|
+
return focusIndex(state, index);
|
|
2520
|
+
};
|
|
2521
|
+
|
|
2522
|
+
const handleMouseOverMenuOpen = async (state, index) => {
|
|
2523
|
+
if (index === -1) {
|
|
2524
|
+
return state;
|
|
2525
|
+
}
|
|
2526
|
+
return focusIndex(state, index);
|
|
2527
|
+
};
|
|
2528
|
+
|
|
2529
|
+
const handleMouseOver = ifElse(handleMouseOverMenuOpen, handleMouseOverMenuClosed);
|
|
2530
|
+
|
|
2531
|
+
const handlePointerOver = (state, clientX, clientY) => {
|
|
2532
|
+
const index = getTitleBarIndexFromPosition(state.titleBarEntries, clientX - state.x);
|
|
2533
|
+
if (index === -1) {
|
|
2534
|
+
return state;
|
|
2535
|
+
}
|
|
2536
|
+
return handleMouseOver(state, index);
|
|
2537
|
+
};
|
|
2538
|
+
|
|
2253
2539
|
const getFontString = (fontWeight, fontSize, fontFamily) => {
|
|
2254
2540
|
return `${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
2255
2541
|
};
|
|
@@ -2342,40 +2628,37 @@ const loadContent = async (state, titleBarEntries) => {
|
|
|
2342
2628
|
};
|
|
2343
2629
|
};
|
|
2344
2630
|
|
|
2345
|
-
const menus = [MenuEntriesEdit, MenuEntriesFile, MenuEntriesGo, MenuEntriesHelp, MenuEntriesRun, MenuEntriesSelection, MenuEntriesTerminal, MenuEntriesTitleBar, MenuEntriesView, MenuEntriesOpenRecent];
|
|
2346
|
-
const getMenus = () => {
|
|
2347
|
-
return menus;
|
|
2348
|
-
};
|
|
2349
|
-
const getModule = id => {
|
|
2350
|
-
for (const module of menus) {
|
|
2351
|
-
if (module.id === id) {
|
|
2352
|
-
return module;
|
|
2353
|
-
}
|
|
2354
|
-
}
|
|
2355
|
-
return undefined;
|
|
2356
|
-
};
|
|
2357
|
-
const getMenuEntries = async (id, ...args) => {
|
|
2358
|
-
try {
|
|
2359
|
-
const module = getModule(id);
|
|
2360
|
-
// @ts-ignore
|
|
2361
|
-
const inject = module.inject || [];
|
|
2362
|
-
// @ts-ignore
|
|
2363
|
-
return module.getMenuEntries(...args);
|
|
2364
|
-
} catch (error) {
|
|
2365
|
-
throw new VError(error, `Failed to load menu entries for id ${id}`);
|
|
2366
|
-
}
|
|
2367
|
-
};
|
|
2368
|
-
|
|
2369
2631
|
const renderEventListeners = () => {
|
|
2370
2632
|
return [{
|
|
2371
|
-
name:
|
|
2633
|
+
name: HandleClickMinimize,
|
|
2372
2634
|
params: ['handleClickMinimize']
|
|
2373
2635
|
}, {
|
|
2374
|
-
name:
|
|
2636
|
+
name: HandleClickToggleClose,
|
|
2375
2637
|
params: ['handleClickClose']
|
|
2376
2638
|
}, {
|
|
2377
|
-
name:
|
|
2639
|
+
name: HandleClickToggleMaximize,
|
|
2378
2640
|
params: ['handleClickToggleMaximize']
|
|
2641
|
+
}, {
|
|
2642
|
+
name: HandleFocusIn,
|
|
2643
|
+
params: ['handlefocus']
|
|
2644
|
+
}, {
|
|
2645
|
+
name: HandleMenuClick,
|
|
2646
|
+
params: ['handleMenuClick', 'event.clientX', 'event.clientY']
|
|
2647
|
+
}, {
|
|
2648
|
+
name: HandleMenuMouseOver,
|
|
2649
|
+
params: ['handleMenuMouseOver', 'event.clientX', 'event.clientY']
|
|
2650
|
+
}, {
|
|
2651
|
+
name: HandleClick,
|
|
2652
|
+
params: ['handleClick', 'event.button', 'event.clientX', 'event.clientY']
|
|
2653
|
+
}, {
|
|
2654
|
+
name: HandlePointerOut,
|
|
2655
|
+
params: ['handlePointerOut', 'event.clientX', 'event.clientY']
|
|
2656
|
+
}, {
|
|
2657
|
+
name: HandlePointerOver,
|
|
2658
|
+
params: ['handlePointerOver', 'event.clientX', 'event.clientY']
|
|
2659
|
+
}, {
|
|
2660
|
+
name: HandleFocusOut,
|
|
2661
|
+
params: ['handleFocusOut', 'event.clientX', 'event.clientY'] // TODO maybe check relatedTarget
|
|
2379
2662
|
}];
|
|
2380
2663
|
};
|
|
2381
2664
|
|
|
@@ -2438,155 +2721,6 @@ const previous = (items, index) => {
|
|
|
2438
2721
|
return index === 0 ? items.length - 1 : index - 1;
|
|
2439
2722
|
};
|
|
2440
2723
|
|
|
2441
|
-
const getTotalWidth = entries => {
|
|
2442
|
-
let total = 0;
|
|
2443
|
-
for (const entry of entries) {
|
|
2444
|
-
total += entry.width;
|
|
2445
|
-
}
|
|
2446
|
-
return total;
|
|
2447
|
-
};
|
|
2448
|
-
|
|
2449
|
-
// TODO lazyload menuEntries and use Command.execute (maybe)
|
|
2450
|
-
const CONTEXT_MENU_ITEM_HEIGHT = 26;
|
|
2451
|
-
const CONTEXT_MENU_SEPARATOR_HEIGHT = 11;
|
|
2452
|
-
const CONTEXT_MENU_PADDING = 8;
|
|
2453
|
-
const getMenuHeight = items => {
|
|
2454
|
-
let height = CONTEXT_MENU_PADDING;
|
|
2455
|
-
for (const item of items) {
|
|
2456
|
-
switch (item.flags) {
|
|
2457
|
-
case Separator:
|
|
2458
|
-
height += CONTEXT_MENU_SEPARATOR_HEIGHT;
|
|
2459
|
-
break;
|
|
2460
|
-
default:
|
|
2461
|
-
height += CONTEXT_MENU_ITEM_HEIGHT;
|
|
2462
|
-
break;
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2465
|
-
return height;
|
|
2466
|
-
};
|
|
2467
|
-
|
|
2468
|
-
// TODO lazyload menuEntries and use Command.execute (maybe)
|
|
2469
|
-
const MENU_WIDTH = 150;
|
|
2470
|
-
const CONTEXT_MENU_WIDTH = 250;
|
|
2471
|
-
const getMenuWidth = () => {
|
|
2472
|
-
return CONTEXT_MENU_WIDTH;
|
|
2473
|
-
};
|
|
2474
|
-
|
|
2475
|
-
// TODO difference between focusing with mouse or keyboard
|
|
2476
|
-
// with mouse -> open submenu
|
|
2477
|
-
// with keyboard -> don't open submenu, only focus
|
|
2478
|
-
|
|
2479
|
-
const getIndexToFocusNextStartingAt = (items, startIndex) => {
|
|
2480
|
-
for (let i = startIndex; i < startIndex + items.length; i++) {
|
|
2481
|
-
const index = i % items.length;
|
|
2482
|
-
const item = items[index];
|
|
2483
|
-
if (canBeFocused(item)) {
|
|
2484
|
-
return index;
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
return -1;
|
|
2488
|
-
};
|
|
2489
|
-
const getIndexToFocusFirst = items => {
|
|
2490
|
-
return getIndexToFocusNextStartingAt(items, 0);
|
|
2491
|
-
};
|
|
2492
|
-
const getIndexToFocusLast = items => {
|
|
2493
|
-
return getIndexToFocusPreviousStartingAt(items, items.length - 1);
|
|
2494
|
-
};
|
|
2495
|
-
|
|
2496
|
-
// TODO this code seems a bit too complicated, maybe it can be simplified
|
|
2497
|
-
const getIndexToFocusPreviousStartingAt = (items, startIndex) => {
|
|
2498
|
-
for (let i = startIndex; i > startIndex - items.length; i--) {
|
|
2499
|
-
const index = (i + items.length) % items.length;
|
|
2500
|
-
const item = items[index];
|
|
2501
|
-
if (canBeFocused(item)) {
|
|
2502
|
-
return index;
|
|
2503
|
-
}
|
|
2504
|
-
}
|
|
2505
|
-
return -1;
|
|
2506
|
-
};
|
|
2507
|
-
const getIndexToFocusPrevious = menu => {
|
|
2508
|
-
const startIndex = menu.focusedIndex === -1 ? menu.items.length - 1 : menu.focusedIndex - 1;
|
|
2509
|
-
return getIndexToFocusPreviousStartingAt(menu.items, startIndex);
|
|
2510
|
-
};
|
|
2511
|
-
const canBeFocused = item => {
|
|
2512
|
-
switch (item.flags) {
|
|
2513
|
-
case Separator:
|
|
2514
|
-
case Disabled:
|
|
2515
|
-
return false;
|
|
2516
|
-
default:
|
|
2517
|
-
return true;
|
|
2518
|
-
}
|
|
2519
|
-
};
|
|
2520
|
-
const getIndexToFocusNext = menu => {
|
|
2521
|
-
const startIndex = menu.focusedIndex + 1;
|
|
2522
|
-
return getIndexToFocusNextStartingAt(menu.items, startIndex);
|
|
2523
|
-
};
|
|
2524
|
-
|
|
2525
|
-
// TODO handle printable letter and focus item that starts with that letter
|
|
2526
|
-
|
|
2527
|
-
// TODO pageup / pagedown keys
|
|
2528
|
-
|
|
2529
|
-
// TODO more tests
|
|
2530
|
-
|
|
2531
|
-
const openMenuAtIndex = async (state, index, shouldBeFocused) => {
|
|
2532
|
-
const {
|
|
2533
|
-
titleBarEntries,
|
|
2534
|
-
titleBarHeight,
|
|
2535
|
-
x
|
|
2536
|
-
} = state;
|
|
2537
|
-
// TODO race conditions
|
|
2538
|
-
// TODO send renderer process
|
|
2539
|
-
// 1. open menu, items to show
|
|
2540
|
-
// 2. focus menu
|
|
2541
|
-
const titleBarEntry = titleBarEntries[index];
|
|
2542
|
-
const {
|
|
2543
|
-
id
|
|
2544
|
-
} = titleBarEntry;
|
|
2545
|
-
const items = await getMenuEntries(id);
|
|
2546
|
-
const relevantEntries = titleBarEntries.slice(0, index);
|
|
2547
|
-
const totalWidths = getTotalWidth(relevantEntries);
|
|
2548
|
-
const offset = totalWidths;
|
|
2549
|
-
// TODO race condition: another menu might already be open at this point
|
|
2550
|
-
|
|
2551
|
-
const menuX = x + offset;
|
|
2552
|
-
const menuY = titleBarHeight;
|
|
2553
|
-
const width = getMenuWidth();
|
|
2554
|
-
const height = getMenuHeight(items);
|
|
2555
|
-
const menuFocusedIndex = shouldBeFocused ? getIndexToFocusNextStartingAt(items, 0) : -1;
|
|
2556
|
-
const menu = {
|
|
2557
|
-
id,
|
|
2558
|
-
items,
|
|
2559
|
-
focusedIndex: menuFocusedIndex,
|
|
2560
|
-
level: 0,
|
|
2561
|
-
x: menuX,
|
|
2562
|
-
y: menuY,
|
|
2563
|
-
width,
|
|
2564
|
-
height
|
|
2565
|
-
};
|
|
2566
|
-
const menus = [menu];
|
|
2567
|
-
return {
|
|
2568
|
-
...state,
|
|
2569
|
-
isMenuOpen: true,
|
|
2570
|
-
focusedIndex: index,
|
|
2571
|
-
menus
|
|
2572
|
-
};
|
|
2573
|
-
};
|
|
2574
|
-
|
|
2575
|
-
const focusIndex = async (state, index) => {
|
|
2576
|
-
object(state);
|
|
2577
|
-
number(index);
|
|
2578
|
-
const {
|
|
2579
|
-
isMenuOpen
|
|
2580
|
-
} = state;
|
|
2581
|
-
if (isMenuOpen) {
|
|
2582
|
-
return openMenuAtIndex(state, index, /* focus */false);
|
|
2583
|
-
}
|
|
2584
|
-
return {
|
|
2585
|
-
...state,
|
|
2586
|
-
focusedIndex: index
|
|
2587
|
-
};
|
|
2588
|
-
};
|
|
2589
|
-
|
|
2590
2724
|
const focusFirst = state => {
|
|
2591
2725
|
const indexToFocus = first();
|
|
2592
2726
|
return focusIndex(state, indexToFocus);
|
|
@@ -2624,7 +2758,7 @@ const focusPrevious = state => {
|
|
|
2624
2758
|
|
|
2625
2759
|
const LeftClick = 0;
|
|
2626
2760
|
|
|
2627
|
-
const toggleIndex = (state, index) => {
|
|
2761
|
+
const toggleIndex = async (state, index) => {
|
|
2628
2762
|
const {
|
|
2629
2763
|
isMenuOpen,
|
|
2630
2764
|
focusedIndex
|
|
@@ -2635,7 +2769,7 @@ const toggleIndex = (state, index) => {
|
|
|
2635
2769
|
return openMenuAtIndex(state, index, /* focus */false);
|
|
2636
2770
|
};
|
|
2637
2771
|
|
|
2638
|
-
const handleClick = (state, button, index) => {
|
|
2772
|
+
const handleClick = async (state, button, index) => {
|
|
2639
2773
|
if (button !== LeftClick) {
|
|
2640
2774
|
return state;
|
|
2641
2775
|
}
|
|
@@ -2686,19 +2820,6 @@ const handleKeyArrowDownMenuOpen = state => {
|
|
|
2686
2820
|
};
|
|
2687
2821
|
};
|
|
2688
2822
|
|
|
2689
|
-
const ifElse = (menuOpenFunction, menuClosedFunction) => {
|
|
2690
|
-
const ifElseFunction = (state, ...args) => {
|
|
2691
|
-
const {
|
|
2692
|
-
isMenuOpen
|
|
2693
|
-
} = state;
|
|
2694
|
-
if (isMenuOpen) {
|
|
2695
|
-
return menuOpenFunction(state, ...args);
|
|
2696
|
-
}
|
|
2697
|
-
return menuClosedFunction(state, ...args);
|
|
2698
|
-
};
|
|
2699
|
-
return ifElseFunction;
|
|
2700
|
-
};
|
|
2701
|
-
|
|
2702
2823
|
const handleKeyArrowDown = ifElse(handleKeyArrowDownMenuOpen, handleKeyArrowDownMenuClosed);
|
|
2703
2824
|
|
|
2704
2825
|
const handleKeyArrowLeftMenuClosed = state => {
|
|
@@ -3023,29 +3144,6 @@ const handleMenuMouseOver = async (state, level, index) => {
|
|
|
3023
3144
|
};
|
|
3024
3145
|
};
|
|
3025
3146
|
|
|
3026
|
-
const handleMouseOutMenuClosed = state => {
|
|
3027
|
-
return focusIndex(state, -1);
|
|
3028
|
-
};
|
|
3029
|
-
|
|
3030
|
-
const handleMouseOutMenuOpen = state => {
|
|
3031
|
-
return state;
|
|
3032
|
-
};
|
|
3033
|
-
|
|
3034
|
-
const handleMouseOut = ifElse(handleMouseOutMenuOpen, handleMouseOutMenuClosed);
|
|
3035
|
-
|
|
3036
|
-
const handleMouseOverMenuClosed = (state, index) => {
|
|
3037
|
-
return focusIndex(state, index);
|
|
3038
|
-
};
|
|
3039
|
-
|
|
3040
|
-
const handleMouseOverMenuOpen = async (state, index) => {
|
|
3041
|
-
if (index === -1) {
|
|
3042
|
-
return state;
|
|
3043
|
-
}
|
|
3044
|
-
return focusIndex(state, index);
|
|
3045
|
-
};
|
|
3046
|
-
|
|
3047
|
-
const handleMouseOver = ifElse(handleMouseOverMenuOpen, handleMouseOverMenuClosed);
|
|
3048
|
-
|
|
3049
3147
|
const toggleMenu = state => {
|
|
3050
3148
|
const {
|
|
3051
3149
|
isMenuOpen
|
|
@@ -3069,6 +3167,7 @@ const wrapCommand = fn => {
|
|
|
3069
3167
|
|
|
3070
3168
|
const commandMap = {
|
|
3071
3169
|
'TitleBar.getButtonsVirtualDom': getTitleBarButtonsVirtualDom,
|
|
3170
|
+
'TitleBar.handleContextMenu': handleContextMenu,
|
|
3072
3171
|
'TitleBar.getIconVirtualDom': getTitleBarIconVirtualDom,
|
|
3073
3172
|
'TitleBar.getMenuEntries': getMenuEntries$1,
|
|
3074
3173
|
'TitleBar.getMenuIds': getMenuIds,
|
|
@@ -3093,8 +3192,10 @@ const commandMap = {
|
|
|
3093
3192
|
'TitleBarMenuBar.handleKeyArrowLeft': wrapCommand(handleKeyArrowLeft),
|
|
3094
3193
|
'TitleBarMenuBar.handleKeyArrowRight': wrapCommand(handleKeyArrowRight),
|
|
3095
3194
|
'TitleBarMenuBar.handleKeyArrowUp': wrapCommand(handleKeyArrowUp),
|
|
3195
|
+
'TitleBarMenuBar.handlePointerOver': wrapCommand(handlePointerOver),
|
|
3096
3196
|
'TitleBarMenuBar.handleKeyEnd': wrapCommand(handleKeyEnd),
|
|
3097
3197
|
'TitleBarMenuBar.handleKeyEnter': wrapCommand(handleKeyEnter),
|
|
3198
|
+
'TitleBarMenuBar.handlePointerOut': wrapCommand(handlePointerOut),
|
|
3098
3199
|
'TitleBarMenuBar.handleKeyEscape': wrapCommand(handleKeyEscape),
|
|
3099
3200
|
'TitleBarMenuBar.handleKeyHome': wrapCommand(handleKeyHome),
|
|
3100
3201
|
'TitleBarMenuBar.handleKeySpace': wrapCommand(handleKeySpace),
|