@matdata/yasgui 5.8.1 → 5.9.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/build/ts/src/PersistentConfig.d.ts +4 -0
- package/build/ts/src/PersistentConfig.js +20 -0
- package/build/ts/src/PersistentConfig.js.map +1 -1
- package/build/ts/src/Tab.d.ts +11 -0
- package/build/ts/src/Tab.js +157 -4
- package/build/ts/src/Tab.js.map +1 -1
- package/build/ts/src/TabElements.js +14 -2
- package/build/ts/src/TabElements.js.map +1 -1
- package/build/ts/src/TabSettingsModal.d.ts +2 -0
- package/build/ts/src/TabSettingsModal.js +85 -3
- package/build/ts/src/TabSettingsModal.js.map +1 -1
- package/build/ts/src/version.d.ts +1 -1
- package/build/ts/src/version.js +1 -1
- package/build/yasgui.min.css +1 -1
- package/build/yasgui.min.css.map +3 -3
- package/build/yasgui.min.js +133 -127
- package/build/yasgui.min.js.map +3 -3
- package/package.json +1 -1
- package/src/PersistentConfig.ts +34 -0
- package/src/Tab.ts +223 -6
- package/src/TabContextMenu.scss +24 -15
- package/src/TabElements.ts +16 -2
- package/src/TabSettingsModal.scss +52 -21
- package/src/TabSettingsModal.ts +112 -3
- package/src/endpointSelect.scss +98 -5
- package/src/tab.scss +13 -2
- package/src/version.ts +1 -1
package/package.json
CHANGED
package/src/PersistentConfig.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface PersistedJson {
|
|
|
15
15
|
theme?: "light" | "dark";
|
|
16
16
|
orientation?: "vertical" | "horizontal";
|
|
17
17
|
showSnippetsBar?: boolean;
|
|
18
|
+
disabledDevButtons?: string[]; // Endpoints of developer-configured buttons that are disabled by user
|
|
18
19
|
}
|
|
19
20
|
function getDefaults(): PersistedJson {
|
|
20
21
|
return {
|
|
@@ -234,4 +235,37 @@ export default class PersistentConfig {
|
|
|
234
235
|
Object.assign(this.persistedJson, config);
|
|
235
236
|
this.toStorage();
|
|
236
237
|
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get list of disabled developer-configured endpoint buttons
|
|
241
|
+
*/
|
|
242
|
+
public getDisabledDevButtons(): string[] {
|
|
243
|
+
return this.persistedJson.disabledDevButtons || [];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Set list of disabled developer-configured endpoint buttons
|
|
248
|
+
*/
|
|
249
|
+
public setDisabledDevButtons(endpoints: string[]) {
|
|
250
|
+
this.persistedJson.disabledDevButtons = endpoints;
|
|
251
|
+
this.toStorage();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Toggle a developer button enabled/disabled state
|
|
256
|
+
*/
|
|
257
|
+
public toggleDevButton(endpoint: string, enabled: boolean) {
|
|
258
|
+
const disabled = this.getDisabledDevButtons();
|
|
259
|
+
if (enabled) {
|
|
260
|
+
// Remove from disabled list
|
|
261
|
+
const filtered = disabled.filter((e) => e !== endpoint);
|
|
262
|
+
this.setDisabledDevButtons(filtered);
|
|
263
|
+
} else {
|
|
264
|
+
// Add to disabled list
|
|
265
|
+
if (!disabled.includes(endpoint)) {
|
|
266
|
+
disabled.push(endpoint);
|
|
267
|
+
this.setDisabledDevButtons(disabled);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
237
271
|
}
|
package/src/Tab.ts
CHANGED
|
@@ -12,16 +12,23 @@ import { getRandomId, default as Yasgui, YasguiRequestConfig } from "./";
|
|
|
12
12
|
import * as OAuth2Utils from "./OAuth2Utils";
|
|
13
13
|
|
|
14
14
|
// Layout orientation toggle icons
|
|
15
|
-
const HORIZONTAL_LAYOUT_ICON = `<svg viewBox="0 0 24 24"
|
|
15
|
+
const HORIZONTAL_LAYOUT_ICON = `<svg viewBox="0 0 24 24">
|
|
16
16
|
<rect x="2" y="4" width="9" height="16" stroke="currentColor" stroke-width="2" fill="none"/>
|
|
17
17
|
<rect x="13" y="4" width="9" height="16" stroke="currentColor" stroke-width="2" fill="none"/>
|
|
18
18
|
</svg>`;
|
|
19
19
|
|
|
20
|
-
const VERTICAL_LAYOUT_ICON = `<svg viewBox="0 0 24 24"
|
|
20
|
+
const VERTICAL_LAYOUT_ICON = `<svg viewBox="0 0 24 24">
|
|
21
21
|
<rect x="2" y="2" width="20" height="8" stroke="currentColor" stroke-width="2" fill="none"/>
|
|
22
22
|
<rect x="2" y="12" width="20" height="10" stroke="currentColor" stroke-width="2" fill="none"/>
|
|
23
23
|
</svg>`;
|
|
24
24
|
|
|
25
|
+
// Overflow dropdown icon (three horizontal dots / ellipsis menu)
|
|
26
|
+
const OVERFLOW_ICON = `<svg viewBox="0 0 24 24" fill="currentColor">
|
|
27
|
+
<circle cx="5" cy="12" r="2"/>
|
|
28
|
+
<circle cx="12" cy="12" r="2"/>
|
|
29
|
+
<circle cx="19" cy="12" r="2"/>
|
|
30
|
+
</svg>`;
|
|
31
|
+
|
|
25
32
|
export interface PersistedJsonYasr extends YasrPersistentConfig {
|
|
26
33
|
responseSummary: Parser.ResponseSummary;
|
|
27
34
|
}
|
|
@@ -75,6 +82,10 @@ export class Tab extends EventEmitter {
|
|
|
75
82
|
private yasrWrapperEl: HTMLDivElement | undefined;
|
|
76
83
|
private endpointSelect: EndpointSelect | undefined;
|
|
77
84
|
private endpointButtonsContainer: HTMLDivElement | undefined;
|
|
85
|
+
private endpointOverflowButton: HTMLButtonElement | undefined;
|
|
86
|
+
private endpointOverflowDropdown: HTMLDivElement | undefined;
|
|
87
|
+
private endpointButtonConfigs: Array<{ endpoint: string; label: string }> = [];
|
|
88
|
+
private resizeObserver: ResizeObserver | undefined;
|
|
78
89
|
private settingsModal?: TabSettingsModal;
|
|
79
90
|
private currentOrientation: "vertical" | "horizontal";
|
|
80
91
|
private orientationToggleButton?: HTMLButtonElement;
|
|
@@ -337,6 +348,8 @@ export class Tab extends EventEmitter {
|
|
|
337
348
|
// Refresh components to adjust to new layout
|
|
338
349
|
if (tab.yasqe) {
|
|
339
350
|
tab.yasqe.refresh();
|
|
351
|
+
// Trigger snippets overflow detection after layout change
|
|
352
|
+
tab.yasqe.refreshSnippetsBar();
|
|
340
353
|
}
|
|
341
354
|
if (tab.yasr) {
|
|
342
355
|
tab.yasr.refresh();
|
|
@@ -385,16 +398,202 @@ export class Tab extends EventEmitter {
|
|
|
385
398
|
}
|
|
386
399
|
|
|
387
400
|
this.refreshEndpointButtons();
|
|
401
|
+
this.initEndpointButtonsResizeObserver();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
private initEndpointButtonsResizeObserver() {
|
|
405
|
+
if (!this.controlBarEl || !this.endpointButtonsContainer) return;
|
|
406
|
+
|
|
407
|
+
// Clean up existing observer
|
|
408
|
+
if (this.resizeObserver) {
|
|
409
|
+
this.resizeObserver.disconnect();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Create resize observer to detect when we need to show overflow
|
|
413
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
414
|
+
this.updateEndpointButtonsOverflow();
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
this.resizeObserver.observe(this.controlBarEl);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private updateEndpointButtonsOverflow() {
|
|
421
|
+
if (!this.endpointButtonsContainer || !this.controlBarEl) return;
|
|
422
|
+
|
|
423
|
+
// Get all actual endpoint buttons (not the overflow button)
|
|
424
|
+
const buttons = Array.from(
|
|
425
|
+
this.endpointButtonsContainer.querySelectorAll(".endpointButton:not(.endpointOverflowBtn)"),
|
|
426
|
+
) as HTMLButtonElement[];
|
|
427
|
+
|
|
428
|
+
if (buttons.length === 0) {
|
|
429
|
+
this.hideOverflowButton();
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Get the container's available width
|
|
434
|
+
const containerRect = this.controlBarEl.getBoundingClientRect();
|
|
435
|
+
const containerWidth = containerRect.width;
|
|
436
|
+
|
|
437
|
+
// Calculate the space used by other elements (endpoint select, settings buttons, etc.)
|
|
438
|
+
const endpointButtonsRect = this.endpointButtonsContainer.getBoundingClientRect();
|
|
439
|
+
const buttonsContainerLeft = endpointButtonsRect.left - containerRect.left;
|
|
440
|
+
|
|
441
|
+
// Estimate available space for endpoint buttons (leave some margin for overflow button)
|
|
442
|
+
const overflowButtonWidth = 40; // Approximate width of overflow button
|
|
443
|
+
const availableWidth = containerWidth - buttonsContainerLeft - overflowButtonWidth - 20; // 20px margin
|
|
444
|
+
|
|
445
|
+
// Make all buttons temporarily visible to measure
|
|
446
|
+
buttons.forEach((btn) => btn.classList.remove("endpointButtonHidden"));
|
|
447
|
+
|
|
448
|
+
// Check if buttons overflow
|
|
449
|
+
let totalWidth = 0;
|
|
450
|
+
let overflowIndex = -1;
|
|
451
|
+
|
|
452
|
+
for (let i = 0; i < buttons.length; i++) {
|
|
453
|
+
const btn = buttons[i];
|
|
454
|
+
const btnWidth = btn.offsetWidth + 4; // Include gap
|
|
455
|
+
totalWidth += btnWidth;
|
|
456
|
+
|
|
457
|
+
if (totalWidth > availableWidth && overflowIndex === -1) {
|
|
458
|
+
overflowIndex = i;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (overflowIndex === -1) {
|
|
463
|
+
// All buttons fit, hide overflow button
|
|
464
|
+
this.hideOverflowButton();
|
|
465
|
+
buttons.forEach((btn) => btn.classList.remove("endpointButtonHidden"));
|
|
466
|
+
} else {
|
|
467
|
+
// Some buttons need to go into overflow
|
|
468
|
+
buttons.forEach((btn, index) => {
|
|
469
|
+
if (index >= overflowIndex) {
|
|
470
|
+
btn.classList.add("endpointButtonHidden");
|
|
471
|
+
} else {
|
|
472
|
+
btn.classList.remove("endpointButtonHidden");
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
this.showOverflowButton(overflowIndex);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
private showOverflowButton(overflowStartIndex: number) {
|
|
480
|
+
if (!this.endpointButtonsContainer) return;
|
|
481
|
+
|
|
482
|
+
// Create overflow button if it doesn't exist
|
|
483
|
+
if (!this.endpointOverflowButton) {
|
|
484
|
+
this.endpointOverflowButton = document.createElement("button");
|
|
485
|
+
addClass(this.endpointOverflowButton, "endpointOverflowBtn");
|
|
486
|
+
this.endpointOverflowButton.innerHTML = OVERFLOW_ICON;
|
|
487
|
+
this.endpointOverflowButton.title = "More endpoints";
|
|
488
|
+
this.endpointOverflowButton.setAttribute("aria-label", "More endpoint options");
|
|
489
|
+
this.endpointOverflowButton.setAttribute("aria-haspopup", "true");
|
|
490
|
+
this.endpointOverflowButton.setAttribute("aria-expanded", "false");
|
|
491
|
+
|
|
492
|
+
this.endpointOverflowButton.addEventListener("click", (e) => {
|
|
493
|
+
e.stopPropagation();
|
|
494
|
+
this.toggleOverflowDropdown();
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
this.endpointButtonsContainer.appendChild(this.endpointOverflowButton);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Update the overflow button's data with which buttons are hidden
|
|
501
|
+
this.endpointOverflowButton.dataset.overflowStart = String(overflowStartIndex);
|
|
502
|
+
this.endpointOverflowButton.style.display = "flex";
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
private hideOverflowButton() {
|
|
506
|
+
if (this.endpointOverflowButton) {
|
|
507
|
+
this.endpointOverflowButton.style.display = "none";
|
|
508
|
+
}
|
|
509
|
+
this.closeOverflowDropdown();
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
private toggleOverflowDropdown() {
|
|
513
|
+
if (this.endpointOverflowDropdown && this.endpointOverflowDropdown.style.display !== "none") {
|
|
514
|
+
this.closeOverflowDropdown();
|
|
515
|
+
} else {
|
|
516
|
+
this.openOverflowDropdown();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
private openOverflowDropdown() {
|
|
521
|
+
if (!this.endpointOverflowButton || !this.endpointButtonsContainer) return;
|
|
522
|
+
|
|
523
|
+
const overflowStartIndex = parseInt(this.endpointOverflowButton.dataset.overflowStart || "0", 10);
|
|
524
|
+
const overflowButtons = this.endpointButtonConfigs.slice(overflowStartIndex);
|
|
525
|
+
|
|
526
|
+
if (overflowButtons.length === 0) return;
|
|
527
|
+
|
|
528
|
+
// Create dropdown if it doesn't exist
|
|
529
|
+
if (!this.endpointOverflowDropdown) {
|
|
530
|
+
this.endpointOverflowDropdown = document.createElement("div");
|
|
531
|
+
addClass(this.endpointOverflowDropdown, "endpointOverflowDropdown");
|
|
532
|
+
this.endpointButtonsContainer.appendChild(this.endpointOverflowDropdown);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Clear and populate dropdown
|
|
536
|
+
this.endpointOverflowDropdown.innerHTML = "";
|
|
537
|
+
|
|
538
|
+
overflowButtons.forEach((buttonConfig) => {
|
|
539
|
+
const item = document.createElement("button");
|
|
540
|
+
addClass(item, "endpointOverflowItem");
|
|
541
|
+
item.textContent = buttonConfig.label;
|
|
542
|
+
item.title = `Set endpoint to ${buttonConfig.endpoint}`;
|
|
543
|
+
item.setAttribute("aria-label", `Set endpoint to ${buttonConfig.endpoint}`);
|
|
544
|
+
|
|
545
|
+
item.addEventListener("click", () => {
|
|
546
|
+
this.setEndpoint(buttonConfig.endpoint);
|
|
547
|
+
this.closeOverflowDropdown();
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
this.endpointOverflowDropdown!.appendChild(item);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// Position and show dropdown
|
|
554
|
+
this.endpointOverflowDropdown.style.display = "block";
|
|
555
|
+
this.endpointOverflowButton.setAttribute("aria-expanded", "true");
|
|
556
|
+
|
|
557
|
+
// Add click-outside listener to close dropdown
|
|
558
|
+
const closeHandler = (e: MouseEvent) => {
|
|
559
|
+
if (
|
|
560
|
+
this.endpointOverflowDropdown &&
|
|
561
|
+
!this.endpointOverflowDropdown.contains(e.target as Node) &&
|
|
562
|
+
e.target !== this.endpointOverflowButton
|
|
563
|
+
) {
|
|
564
|
+
this.closeOverflowDropdown();
|
|
565
|
+
document.removeEventListener("click", closeHandler);
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
// Delay adding listener to avoid immediate close
|
|
570
|
+
setTimeout(() => {
|
|
571
|
+
document.addEventListener("click", closeHandler);
|
|
572
|
+
}, 0);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
private closeOverflowDropdown() {
|
|
576
|
+
if (this.endpointOverflowDropdown) {
|
|
577
|
+
this.endpointOverflowDropdown.style.display = "none";
|
|
578
|
+
}
|
|
579
|
+
if (this.endpointOverflowButton) {
|
|
580
|
+
this.endpointOverflowButton.setAttribute("aria-expanded", "false");
|
|
581
|
+
}
|
|
388
582
|
}
|
|
389
583
|
|
|
390
584
|
public refreshEndpointButtons() {
|
|
391
585
|
if (!this.endpointButtonsContainer) return;
|
|
392
586
|
|
|
393
|
-
// Clear existing buttons
|
|
587
|
+
// Clear existing buttons (but keep overflow button reference)
|
|
394
588
|
this.endpointButtonsContainer.innerHTML = "";
|
|
589
|
+
this.endpointOverflowButton = undefined;
|
|
590
|
+
this.endpointOverflowDropdown = undefined;
|
|
395
591
|
|
|
396
|
-
// Get config buttons (for backwards compatibility)
|
|
397
|
-
const
|
|
592
|
+
// Get config buttons (for backwards compatibility) and filter out disabled ones
|
|
593
|
+
const disabledButtons = this.yasgui.persistentConfig.getDisabledDevButtons();
|
|
594
|
+
const configButtons = (this.yasgui.config.endpointButtons || []).filter(
|
|
595
|
+
(button) => !disabledButtons.includes(button.endpoint),
|
|
596
|
+
);
|
|
398
597
|
|
|
399
598
|
// Get endpoint configs where showAsButton is true
|
|
400
599
|
const endpointConfigs = this.yasgui.persistentConfig.getEndpointConfigs();
|
|
@@ -407,6 +606,9 @@ export class Tab extends EventEmitter {
|
|
|
407
606
|
|
|
408
607
|
const allButtons = [...configButtons, ...endpointButtons, ...customButtons];
|
|
409
608
|
|
|
609
|
+
// Store button configs for overflow dropdown
|
|
610
|
+
this.endpointButtonConfigs = allButtons;
|
|
611
|
+
|
|
410
612
|
if (allButtons.length === 0) {
|
|
411
613
|
// Hide container if no buttons
|
|
412
614
|
this.endpointButtonsContainer.style.display = "none";
|
|
@@ -429,6 +631,11 @@ export class Tab extends EventEmitter {
|
|
|
429
631
|
|
|
430
632
|
this.endpointButtonsContainer!.appendChild(button);
|
|
431
633
|
});
|
|
634
|
+
|
|
635
|
+
// Trigger overflow check after rendering
|
|
636
|
+
requestAnimationFrame(() => {
|
|
637
|
+
this.updateEndpointButtonsOverflow();
|
|
638
|
+
});
|
|
432
639
|
}
|
|
433
640
|
|
|
434
641
|
public setEndpoint(endpoint: string, endpointHistory?: string[]) {
|
|
@@ -440,12 +647,14 @@ export class Tab extends EventEmitter {
|
|
|
440
647
|
if (this.persistentJson.requestConfig.endpoint !== endpoint) {
|
|
441
648
|
this.persistentJson.requestConfig.endpoint = endpoint;
|
|
442
649
|
this.emit("change", this, this.persistentJson);
|
|
443
|
-
this.emit("endpointChange", this, endpoint);
|
|
444
650
|
|
|
445
651
|
// Auto-track this endpoint in endpoint configs (if not already present)
|
|
446
652
|
if (endpoint && !this.yasgui.persistentConfig.getEndpointConfig(endpoint)) {
|
|
447
653
|
this.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {});
|
|
448
654
|
}
|
|
655
|
+
|
|
656
|
+
// Emit after endpoint is tracked
|
|
657
|
+
this.emit("endpointChange", this, endpoint);
|
|
449
658
|
}
|
|
450
659
|
if (this.endpointSelect instanceof EndpointSelect) {
|
|
451
660
|
this.endpointSelect.setEndpoint(endpoint, endpointHistory);
|
|
@@ -1056,6 +1265,8 @@ WHERE {
|
|
|
1056
1265
|
// Refresh editors after resizing
|
|
1057
1266
|
if (this.yasqe) {
|
|
1058
1267
|
this.yasqe.refresh();
|
|
1268
|
+
// Trigger snippets overflow detection after horizontal resize
|
|
1269
|
+
this.yasqe.refreshSnippetsBar();
|
|
1059
1270
|
}
|
|
1060
1271
|
if (this.yasr) {
|
|
1061
1272
|
this.yasr.refresh();
|
|
@@ -1087,6 +1298,12 @@ WHERE {
|
|
|
1087
1298
|
document.documentElement.removeEventListener("mousemove", this.doVerticalDrag, false);
|
|
1088
1299
|
document.documentElement.removeEventListener("mouseup", this.stopVerticalDrag, false);
|
|
1089
1300
|
|
|
1301
|
+
// Clean up resize observer for endpoint buttons overflow
|
|
1302
|
+
if (this.resizeObserver) {
|
|
1303
|
+
this.resizeObserver.disconnect();
|
|
1304
|
+
this.resizeObserver = undefined;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1090
1307
|
this.removeAllListeners();
|
|
1091
1308
|
this.settingsModal?.destroy();
|
|
1092
1309
|
this.endpointSelect?.destroy();
|
package/src/TabContextMenu.scss
CHANGED
|
@@ -1,42 +1,51 @@
|
|
|
1
1
|
.yasgui.context-menu {
|
|
2
2
|
position: absolute;
|
|
3
3
|
z-index: 10;
|
|
4
|
-
background:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
background: var(--yasgui-bg-primary);
|
|
5
|
+
width: fit-content;
|
|
6
|
+
height: fit-content;
|
|
7
|
+
min-width: fit-content;
|
|
8
|
+
min-height: fit-content;
|
|
9
|
+
min-width: 140px;
|
|
10
|
+
max-width: 250px;
|
|
11
|
+
font-size: 12px;
|
|
12
|
+
border: 1px solid var(--yasgui-border-color);
|
|
8
13
|
border-bottom-right-radius: 4px;
|
|
9
14
|
border-bottom-left-radius: 4px;
|
|
10
|
-
box-shadow: 0
|
|
15
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
11
16
|
background-clip: padding-box;
|
|
12
17
|
hr {
|
|
13
|
-
margin:
|
|
18
|
+
margin: 6px auto;
|
|
14
19
|
border: none;
|
|
15
|
-
border-top: 1px solid
|
|
16
|
-
border-bottom: 1px solid #ffffff;
|
|
20
|
+
border-top: 1px solid var(--yasgui-border-color);
|
|
17
21
|
}
|
|
18
22
|
.context-menu-list {
|
|
19
23
|
padding: 0;
|
|
24
|
+
margin: 0;
|
|
25
|
+
list-style: none;
|
|
20
26
|
}
|
|
21
27
|
.context-menu-item {
|
|
22
28
|
display: block;
|
|
23
|
-
padding:
|
|
29
|
+
padding: 6px 16px;
|
|
24
30
|
clear: both;
|
|
25
31
|
font-weight: 400;
|
|
26
|
-
line-height: 1.
|
|
27
|
-
color:
|
|
32
|
+
line-height: 1.4;
|
|
33
|
+
color: var(--yasgui-text-primary);
|
|
28
34
|
white-space: nowrap;
|
|
29
35
|
cursor: pointer;
|
|
30
36
|
&:hover {
|
|
31
37
|
text-decoration: none;
|
|
32
|
-
color:
|
|
33
|
-
background-color:
|
|
38
|
+
color: var(--yasgui-button-hover);
|
|
39
|
+
background-color: var(--yasgui-bg-secondary);
|
|
34
40
|
}
|
|
35
41
|
&.disabled {
|
|
36
42
|
text-decoration: none;
|
|
37
|
-
color:
|
|
38
|
-
background-color:
|
|
43
|
+
color: var(--yasgui-text-muted);
|
|
44
|
+
background-color: transparent;
|
|
39
45
|
cursor: not-allowed;
|
|
46
|
+
&:hover {
|
|
47
|
+
background-color: transparent;
|
|
48
|
+
}
|
|
40
49
|
}
|
|
41
50
|
}
|
|
42
51
|
}
|
package/src/TabElements.ts
CHANGED
|
@@ -75,7 +75,10 @@ export class TabListEl {
|
|
|
75
75
|
};
|
|
76
76
|
addClass(this.tabEl, "tab");
|
|
77
77
|
this.tabEl.addEventListener("keydown", (e: KeyboardEvent) => {
|
|
78
|
-
if (
|
|
78
|
+
// Don't handle Delete key if we're renaming the tab (input field is active)
|
|
79
|
+
if (e.code === "Delete" && !this.tabEl.classList.contains("renaming")) {
|
|
80
|
+
handleDeleteTab();
|
|
81
|
+
}
|
|
79
82
|
});
|
|
80
83
|
|
|
81
84
|
const handleDeleteTab = (e?: MouseEvent) => {
|
|
@@ -88,6 +91,7 @@ export class TabListEl {
|
|
|
88
91
|
tabLinkEl.href = "#" + this.tabId;
|
|
89
92
|
tabLinkEl.id = "tab-" + this.tabId; // use the id for the tabpanel which is tabId to set the actual tab id
|
|
90
93
|
tabLinkEl.setAttribute("aria-controls", this.tabId); // respective tabPanel id
|
|
94
|
+
tabLinkEl.draggable = false; // Prevent default link dragging that interferes with text selection
|
|
91
95
|
tabLinkEl.addEventListener("blur", () => {
|
|
92
96
|
if (!this.tabEl) return;
|
|
93
97
|
if (this.tabEl.classList.contains("active")) {
|
|
@@ -140,6 +144,13 @@ export class TabListEl {
|
|
|
140
144
|
this.yasgui.getTab(this.tabId)?.setName(renameEl.value);
|
|
141
145
|
removeClass(this.tabEl, "renaming");
|
|
142
146
|
};
|
|
147
|
+
// Prevent sortablejs from detecting drag events on the input field
|
|
148
|
+
renameEl.addEventListener("mousedown", (e) => {
|
|
149
|
+
e.stopPropagation();
|
|
150
|
+
});
|
|
151
|
+
renameEl.addEventListener("dragstart", (e) => {
|
|
152
|
+
e.stopPropagation();
|
|
153
|
+
});
|
|
143
154
|
tabLinkEl.appendChild(this.renameEl);
|
|
144
155
|
tabLinkEl.oncontextmenu = (ev: MouseEvent) => {
|
|
145
156
|
// Close possible old
|
|
@@ -212,6 +223,8 @@ export class TabList {
|
|
|
212
223
|
}
|
|
213
224
|
private handleKeydownArrowKeys = (e: KeyboardEvent) => {
|
|
214
225
|
if (e.code === "ArrowLeft" || e.code === "ArrowRight") {
|
|
226
|
+
// Don't handle arrow keys if we're typing in the rename input field
|
|
227
|
+
if (document.activeElement?.tagName === "INPUT") return;
|
|
215
228
|
if (!this._tabsListEl) return;
|
|
216
229
|
const numOfChildren = this._tabsListEl.childElementCount;
|
|
217
230
|
if (typeof this.tabEntryIndex !== "number") return;
|
|
@@ -251,7 +264,8 @@ export class TabList {
|
|
|
251
264
|
this.yasgui.emit("tabOrderChanged", this.yasgui, tabs);
|
|
252
265
|
this.yasgui.persistentConfig.setTabOrder(tabs);
|
|
253
266
|
},
|
|
254
|
-
filter: ".addTab",
|
|
267
|
+
filter: ".addTab, input, .renaming",
|
|
268
|
+
preventOnFilter: false,
|
|
255
269
|
onMove: (ev: any, _origEv: any) => {
|
|
256
270
|
return hasClass(ev.related, "tab");
|
|
257
271
|
},
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
background: transparent;
|
|
4
4
|
color: inherit;
|
|
5
5
|
border: none;
|
|
6
|
-
padding: 6px
|
|
7
|
-
margin-left:
|
|
6
|
+
padding: 6px;
|
|
7
|
+
margin-left: 0;
|
|
8
8
|
display: flex;
|
|
9
9
|
align-items: center;
|
|
10
10
|
justify-content: center;
|
|
@@ -23,25 +23,6 @@
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
.tabPrefixButton {
|
|
27
|
-
cursor: pointer;
|
|
28
|
-
background: transparent;
|
|
29
|
-
color: inherit;
|
|
30
|
-
border: none;
|
|
31
|
-
padding: 6px 12px;
|
|
32
|
-
font-size: 12px;
|
|
33
|
-
font-weight: 600;
|
|
34
|
-
margin-left: 10px;
|
|
35
|
-
|
|
36
|
-
&:hover {
|
|
37
|
-
opacity: 0.7;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
&:active {
|
|
41
|
-
opacity: 0.5;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
26
|
.tabSettingsModalOverlay {
|
|
46
27
|
display: none;
|
|
47
28
|
position: fixed;
|
|
@@ -706,6 +687,56 @@
|
|
|
706
687
|
}
|
|
707
688
|
}
|
|
708
689
|
|
|
690
|
+
// Developer buttons table styling
|
|
691
|
+
.devButtonsTable {
|
|
692
|
+
margin-top: 15px;
|
|
693
|
+
margin-bottom: 30px;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.devButtonsTableElement {
|
|
697
|
+
width: 100%;
|
|
698
|
+
border-collapse: collapse;
|
|
699
|
+
font-size: 14px;
|
|
700
|
+
|
|
701
|
+
th,
|
|
702
|
+
td {
|
|
703
|
+
padding: 10px;
|
|
704
|
+
text-align: left;
|
|
705
|
+
border-bottom: 1px solid var(--yasgui-border-color, #e0e0e0);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
th {
|
|
709
|
+
font-weight: 600;
|
|
710
|
+
color: var(--yasgui-text-primary, #000);
|
|
711
|
+
background: var(--yasgui-bg-secondary, #f9f9f9);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
td {
|
|
715
|
+
color: var(--yasgui-text-primary, #333);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.devButtonLabelCell {
|
|
719
|
+
font-weight: 500;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.endpointCell {
|
|
723
|
+
max-width: 350px;
|
|
724
|
+
overflow: hidden;
|
|
725
|
+
text-overflow: ellipsis;
|
|
726
|
+
white-space: nowrap;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.centerCell {
|
|
730
|
+
text-align: center;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
input[type="checkbox"] {
|
|
734
|
+
width: 18px;
|
|
735
|
+
height: 18px;
|
|
736
|
+
cursor: pointer;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
709
740
|
// Endpoints table styling
|
|
710
741
|
.endpointsTable {
|
|
711
742
|
margin-top: 20px;
|