chrome-devtools-frontend 1.0.1703574 → 1.0.1704172
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/AUTHORS +1 -0
- package/front_end/core/common/ParsedURL.ts +54 -0
- package/front_end/core/platform/StringUtilities.ts +65 -0
- package/front_end/core/sdk/CPUThrottlingManager.ts +3 -3
- package/front_end/core/sdk/SourceMap.ts +3 -3
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +4 -3
- package/front_end/core/sdk/SourceMapScopesInfo.ts +17 -5
- package/front_end/entrypoints/main/MainImpl.ts +3 -3
- package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
- package/front_end/models/har/HARFormat.ts +7 -2
- package/front_end/models/source_map_scopes/NamesResolver.ts +13 -5
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingListView.ts +33 -1
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +4 -12
- package/front_end/panels/application/ApplicationPanelSidebar.ts +58 -60
- package/front_end/panels/application/BackForwardCacheTreeElement.ts +1 -1
- package/front_end/panels/application/FrameDetailsView.ts +64 -82
- package/front_end/panels/application/OpenedWindowDetailsView.ts +20 -21
- package/front_end/panels/application/PreloadingTreeElement.ts +3 -3
- package/front_end/panels/common/CommentsOverlayWidget.ts +145 -72
- package/front_end/panels/common/commentsOverlay.css +34 -23
- package/front_end/panels/elements/DOMTreeWidget.ts +29 -10
- package/front_end/panels/network/RequestPayloadView.ts +7 -2
- package/front_end/panels/network/ShowMoreDetailsWidget.ts +12 -9
- package/front_end/panels/sources/DebuggerPlugin.ts +49 -16
- package/front_end/panels/sources/SourcesPanel.ts +1 -1
- package/front_end/panels/sources/SourcesView.ts +3 -12
- package/front_end/panels/sources/TabbedEditorContainer.ts +0 -3
- package/front_end/panels/sources/components/HeadersView.ts +193 -123
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +24 -32
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.js +15 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.js +8 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts +0 -8
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js +0 -24
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.d.ts +12 -0
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js +79 -17
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node-env-setup.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node-env-setup.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/package.json +4 -4
- package/front_end/third_party/puppeteer/package/src/api/ElementHandle.ts +15 -2
- package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +10 -1
- package/front_end/third_party/puppeteer/package/src/common/Debug.ts +0 -27
- package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +96 -17
- package/front_end/third_party/puppeteer/package/src/node-env-setup.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/comments/CommentAnchorResolver.ts +60 -22
- package/front_end/ui/comments/CommentOverlayManager.ts +78 -25
- package/front_end/ui/legacy/components/data_grid/DataGridExporter.ts +7 -13
- package/front_end/ui/legacy/components/inline_editor/PositionAreaEditor.ts +51 -57
- package/front_end/ui/legacy/components/source_frame/ImageView.ts +101 -42
- package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
- package/package.json +1 -1
|
@@ -662,15 +662,57 @@ function isClippingOverflow(overflow: string): boolean {
|
|
|
662
662
|
return overflow === 'hidden' || overflow === 'auto' || overflow === 'scroll' || overflow === 'clip';
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
+
interface ClippingAncestor {
|
|
666
|
+
element: Element;
|
|
667
|
+
clipsX: boolean;
|
|
668
|
+
clipsY: boolean;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
let clippingAncestorsCache = new WeakMap<Element, ClippingAncestor[]>();
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Clears the cached clipping ancestor chains for elements.
|
|
675
|
+
* Called when DOM mutations or comment rematches occur.
|
|
676
|
+
*/
|
|
677
|
+
export function clearClippingAncestorsCache(): void {
|
|
678
|
+
clippingAncestorsCache = new WeakMap<Element, ClippingAncestor[]>();
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function getClippingAncestors(element: Element, doc: Document, win: Window): ClippingAncestor[] {
|
|
682
|
+
const cached = clippingAncestorsCache.get(element);
|
|
683
|
+
if (cached && cached.every(item => item.element.isConnected)) {
|
|
684
|
+
return cached;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const ancestors: ClippingAncestor[] = [];
|
|
688
|
+
let current = element.parentElementOrShadowHost();
|
|
689
|
+
while (current && current !== doc.documentElement && current !== doc.body) {
|
|
690
|
+
const style = win.getComputedStyle(current);
|
|
691
|
+
const clipsX = isClippingOverflow(style.overflowX);
|
|
692
|
+
const clipsY = isClippingOverflow(style.overflowY);
|
|
693
|
+
if (clipsX || clipsY) {
|
|
694
|
+
ancestors.push({element: current, clipsX, clipsY});
|
|
695
|
+
}
|
|
696
|
+
current = current.parentElementOrShadowHost();
|
|
697
|
+
}
|
|
698
|
+
clippingAncestorsCache.set(element, ancestors);
|
|
699
|
+
return ancestors;
|
|
700
|
+
}
|
|
701
|
+
|
|
665
702
|
/**
|
|
666
703
|
* Computes the visible viewport-relative bounding box of an element after clipping against
|
|
667
704
|
* all ancestor scroll/overflow containers and viewport boundaries across shadow DOM roots.
|
|
668
705
|
*
|
|
669
706
|
* @param element The source DOM element.
|
|
670
707
|
* @param targetRect Optional explicit bounding box (e.g. for sub-lines or custom targets).
|
|
708
|
+
* @param rectCache Optional per-frame cache of element bounding client rects to avoid redundant queries.
|
|
671
709
|
* @returns The clipped viewport-relative rectangle or null if the element is completely clipped out of view or invisible.
|
|
672
710
|
*/
|
|
673
|
-
export function computeVisibleRect(
|
|
711
|
+
export function computeVisibleRect(
|
|
712
|
+
element: Element,
|
|
713
|
+
targetRect?: DOMRect,
|
|
714
|
+
rectCache?: Map<Element, DOMRect>,
|
|
715
|
+
): VisibleRect|null {
|
|
674
716
|
if (!element.isConnected) {
|
|
675
717
|
return null;
|
|
676
718
|
}
|
|
@@ -702,29 +744,25 @@ export function computeVisibleRect(element: Element, targetRect?: DOMRect): Visi
|
|
|
702
744
|
return null;
|
|
703
745
|
}
|
|
704
746
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
visibleBottom = Math.min(visibleBottom, parentRect.bottom);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
if (visibleLeft >= visibleRight || visibleTop >= visibleBottom) {
|
|
723
|
-
return null;
|
|
724
|
-
}
|
|
747
|
+
const clippingAncestors = getClippingAncestors(element, doc, win);
|
|
748
|
+
for (const {element: ancestor, clipsX, clipsY} of clippingAncestors) {
|
|
749
|
+
let parentRect = rectCache?.get(ancestor);
|
|
750
|
+
if (!parentRect) {
|
|
751
|
+
parentRect = ancestor.getBoundingClientRect();
|
|
752
|
+
rectCache?.set(ancestor, parentRect);
|
|
753
|
+
}
|
|
754
|
+
if (clipsX) {
|
|
755
|
+
visibleLeft = Math.max(visibleLeft, parentRect.left);
|
|
756
|
+
visibleRight = Math.min(visibleRight, parentRect.right);
|
|
757
|
+
}
|
|
758
|
+
if (clipsY) {
|
|
759
|
+
visibleTop = Math.max(visibleTop, parentRect.top);
|
|
760
|
+
visibleBottom = Math.min(visibleBottom, parentRect.bottom);
|
|
725
761
|
}
|
|
726
762
|
|
|
727
|
-
|
|
763
|
+
if (visibleLeft >= visibleRight || visibleTop >= visibleBottom) {
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
728
766
|
}
|
|
729
767
|
|
|
730
768
|
const width = visibleRight - visibleLeft;
|
|
@@ -6,6 +6,7 @@ import * as Common from '../../core/common/common.js';
|
|
|
6
6
|
import * as CommentManager from '../../models/comment_manager/comment_manager.js';
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
+
clearClippingAncestorsCache,
|
|
9
10
|
closestAcrossShadow,
|
|
10
11
|
COMMENT_THREAD_UI_SELECTOR,
|
|
11
12
|
type CommentAnchorSignature,
|
|
@@ -69,6 +70,7 @@ export interface EventTypes {
|
|
|
69
70
|
[Events.POSITIONS_UPDATED]: {
|
|
70
71
|
pins: PinPositionData[],
|
|
71
72
|
highlights: HighlightRectData[],
|
|
73
|
+
isRealtimeSync?: boolean,
|
|
72
74
|
};
|
|
73
75
|
[Events.HOVER_HIGHLIGHT_CHANGED]: HoverHighlightData|null;
|
|
74
76
|
}
|
|
@@ -113,11 +115,13 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
113
115
|
#scrollListener?: (event: Event) => void;
|
|
114
116
|
#scrollTarget?: EventTarget;
|
|
115
117
|
#scrollRafId?: number;
|
|
118
|
+
#observedScrollRoots = new Set<ShadowRoot>();
|
|
116
119
|
|
|
117
120
|
#devToolsResizeObserver?: ResizeObserver;
|
|
118
|
-
#
|
|
121
|
+
#resizeObservedElements = new WeakSet<Element>();
|
|
119
122
|
|
|
120
123
|
#mutationObserver?: MutationObserver;
|
|
124
|
+
#mutationRafId?: number;
|
|
121
125
|
#rematchTimeoutId?: ReturnType<typeof setTimeout>;
|
|
122
126
|
#cursorElement: HTMLElement|null = null;
|
|
123
127
|
#isCreatingComment = false;
|
|
@@ -162,7 +166,7 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
162
166
|
#getIntersectionObserver(): IntersectionObserver {
|
|
163
167
|
if (!this.#intersectionObserver) {
|
|
164
168
|
this.#intersectionObserver = new IntersectionObserver(() => {
|
|
165
|
-
this.#updatePositions();
|
|
169
|
+
this.#updatePositions(true);
|
|
166
170
|
});
|
|
167
171
|
}
|
|
168
172
|
return this.#intersectionObserver;
|
|
@@ -287,6 +291,7 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
287
291
|
const observer = this.#getIntersectionObserver();
|
|
288
292
|
observer.observe(anchorElement);
|
|
289
293
|
this.#observedThreads.add(anchorElement);
|
|
294
|
+
this.#trackElementAncestors(anchorElement);
|
|
290
295
|
}
|
|
291
296
|
|
|
292
297
|
this.#updatePositions();
|
|
@@ -294,6 +299,25 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
294
299
|
return thread;
|
|
295
300
|
}
|
|
296
301
|
|
|
302
|
+
#trackElementAncestors(element: Element): void {
|
|
303
|
+
if (!this.#devToolsResizeObserver || !this.#scrollListener) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
let current: Element|null = element;
|
|
307
|
+
while (current) {
|
|
308
|
+
if (this.#resizeObservedElements.has(current)) {
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
this.#devToolsResizeObserver.observe(current);
|
|
312
|
+
this.#resizeObservedElements.add(current);
|
|
313
|
+
if (current.parentNode instanceof ShadowRoot && !this.#observedScrollRoots.has(current.parentNode)) {
|
|
314
|
+
current.parentNode.addEventListener('scroll', this.#scrollListener, {capture: true, passive: true});
|
|
315
|
+
this.#observedScrollRoots.add(current.parentNode);
|
|
316
|
+
}
|
|
317
|
+
current = current.parentElementOrShadowHost();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
297
321
|
#resolveAnchor(element: Element, options?: {clientX: number, clientY: number}):
|
|
298
322
|
{anchor: CommentAnchorSignature, anchorElement: Element}|null {
|
|
299
323
|
let anchorElement: Element|null = null;
|
|
@@ -355,6 +379,7 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
355
379
|
* during batch rematching, and cleans up unobserved IntersectionObserver nodes in O(N) time.
|
|
356
380
|
*/
|
|
357
381
|
#rematchAllComments(root: Document|Element = document): void {
|
|
382
|
+
clearClippingAncestorsCache();
|
|
358
383
|
const jslogElements = deepQuerySelectorAll(root, '[jslog]');
|
|
359
384
|
const oldElements = new Set<Element>();
|
|
360
385
|
const newElements = new Set<Element>();
|
|
@@ -392,13 +417,14 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
392
417
|
this.#updatePositions();
|
|
393
418
|
}
|
|
394
419
|
|
|
395
|
-
#updatePositions(): void {
|
|
420
|
+
#updatePositions(isRealtimeSync = false): void {
|
|
396
421
|
const scrollX = window.scrollX;
|
|
397
422
|
const scrollY = window.scrollY;
|
|
398
423
|
|
|
399
424
|
const newPins: PinPositionData[] = [];
|
|
400
425
|
const newHighlights: HighlightRectData[] = [];
|
|
401
426
|
const elementPinCounts = new Map<Element, number>();
|
|
427
|
+
const rectCache = new Map<Element, DOMRect>();
|
|
402
428
|
|
|
403
429
|
for (const thread of this.#commentManager.getCommentThreads()) {
|
|
404
430
|
// Non-DOM anchors have their positions managed by their respective panels,
|
|
@@ -423,8 +449,9 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
423
449
|
observer.observe(el);
|
|
424
450
|
this.#observedThreads.add(el);
|
|
425
451
|
}
|
|
452
|
+
this.#trackElementAncestors(el);
|
|
426
453
|
|
|
427
|
-
const visibleRect = computeVisibleRect(el);
|
|
454
|
+
const visibleRect = computeVisibleRect(el, undefined, rectCache);
|
|
428
455
|
if (!visibleRect) {
|
|
429
456
|
continue;
|
|
430
457
|
}
|
|
@@ -458,6 +485,7 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
458
485
|
this.dispatchEventToListeners(Events.POSITIONS_UPDATED, {
|
|
459
486
|
pins: newPins,
|
|
460
487
|
highlights: newHighlights,
|
|
488
|
+
isRealtimeSync,
|
|
461
489
|
});
|
|
462
490
|
}
|
|
463
491
|
|
|
@@ -492,6 +520,7 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
492
520
|
this.#installScrollListener(scrollTarget);
|
|
493
521
|
this.#installResizeObserver(resizeTarget);
|
|
494
522
|
this.#installMutationObserver(root);
|
|
523
|
+
this.#updatePositions();
|
|
495
524
|
}
|
|
496
525
|
|
|
497
526
|
/**
|
|
@@ -499,6 +528,7 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
499
528
|
*/
|
|
500
529
|
stop(): void {
|
|
501
530
|
document.body.style.cursor = '';
|
|
531
|
+
clearClippingAncestorsCache();
|
|
502
532
|
this.clearDraftThreads();
|
|
503
533
|
this.#removeClickListener();
|
|
504
534
|
this.#removeScrollListener();
|
|
@@ -693,22 +723,36 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
693
723
|
#installScrollListener(target: EventTarget = window): void {
|
|
694
724
|
this.#removeScrollListener();
|
|
695
725
|
this.#scrollTarget = target;
|
|
726
|
+
let needsTrailingUpdate = false;
|
|
696
727
|
this.#scrollListener = (): void => {
|
|
697
728
|
this.#clearHover();
|
|
698
|
-
if (this.#scrollRafId
|
|
699
|
-
|
|
729
|
+
if (this.#scrollRafId === undefined) {
|
|
730
|
+
// Leading-edge synchronous update so pins and highlights move immediately in the current frame.
|
|
731
|
+
this.#updatePositions(true);
|
|
732
|
+
needsTrailingUpdate = false;
|
|
733
|
+
this.#scrollRafId = requestAnimationFrame(() => {
|
|
734
|
+
this.#scrollRafId = undefined;
|
|
735
|
+
if (needsTrailingUpdate) {
|
|
736
|
+
needsTrailingUpdate = false;
|
|
737
|
+
this.#updatePositions(true);
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
} else {
|
|
741
|
+
needsTrailingUpdate = true;
|
|
700
742
|
}
|
|
701
|
-
this.#scrollRafId = requestAnimationFrame(() => {
|
|
702
|
-
this.#scrollRafId = undefined;
|
|
703
|
-
this.#updatePositions();
|
|
704
|
-
});
|
|
705
743
|
};
|
|
706
744
|
target.addEventListener('scroll', this.#scrollListener, {capture: true, passive: true});
|
|
707
745
|
}
|
|
708
746
|
|
|
709
747
|
#removeScrollListener(): void {
|
|
710
|
-
if (this.#
|
|
711
|
-
this.#scrollTarget
|
|
748
|
+
if (this.#scrollListener) {
|
|
749
|
+
if (this.#scrollTarget) {
|
|
750
|
+
this.#scrollTarget.removeEventListener('scroll', this.#scrollListener, {capture: true});
|
|
751
|
+
}
|
|
752
|
+
for (const root of this.#observedScrollRoots) {
|
|
753
|
+
root.removeEventListener('scroll', this.#scrollListener, {capture: true});
|
|
754
|
+
}
|
|
755
|
+
this.#observedScrollRoots.clear();
|
|
712
756
|
this.#scrollListener = undefined;
|
|
713
757
|
this.#scrollTarget = undefined;
|
|
714
758
|
}
|
|
@@ -729,15 +773,10 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
729
773
|
this.#removeResizeObserver();
|
|
730
774
|
this.#devToolsResizeObserver = new ResizeObserver(() => {
|
|
731
775
|
this.#clearHover();
|
|
732
|
-
|
|
733
|
-
cancelAnimationFrame(this.#resizeRafId);
|
|
734
|
-
}
|
|
735
|
-
this.#resizeRafId = requestAnimationFrame(() => {
|
|
736
|
-
this.#resizeRafId = undefined;
|
|
737
|
-
this.#updatePositions();
|
|
738
|
-
});
|
|
776
|
+
this.#updatePositions(true);
|
|
739
777
|
});
|
|
740
778
|
this.#devToolsResizeObserver.observe(element);
|
|
779
|
+
this.#resizeObservedElements.add(element);
|
|
741
780
|
}
|
|
742
781
|
|
|
743
782
|
#removeResizeObserver(): void {
|
|
@@ -745,16 +784,19 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
745
784
|
this.#devToolsResizeObserver.disconnect();
|
|
746
785
|
this.#devToolsResizeObserver = undefined;
|
|
747
786
|
}
|
|
748
|
-
|
|
749
|
-
cancelAnimationFrame(this.#resizeRafId);
|
|
750
|
-
this.#resizeRafId = undefined;
|
|
751
|
-
}
|
|
787
|
+
this.#resizeObservedElements = new WeakSet();
|
|
752
788
|
}
|
|
753
789
|
|
|
754
790
|
/**
|
|
755
791
|
* Debounces rematching of comments across dynamic DOM updates.
|
|
756
792
|
*/
|
|
757
793
|
#scheduleRematch(root: Document|Element = document): void {
|
|
794
|
+
if (this.#mutationRafId === undefined) {
|
|
795
|
+
this.#mutationRafId = requestAnimationFrame(() => {
|
|
796
|
+
this.#mutationRafId = undefined;
|
|
797
|
+
this.#updatePositions(true);
|
|
798
|
+
});
|
|
799
|
+
}
|
|
758
800
|
if (this.#rematchTimeoutId) {
|
|
759
801
|
clearTimeout(this.#rematchTimeoutId);
|
|
760
802
|
}
|
|
@@ -774,8 +816,15 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
774
816
|
*/
|
|
775
817
|
#installMutationObserver(root: Document|Element = document): void {
|
|
776
818
|
this.#removeMutationObserver();
|
|
777
|
-
this.#mutationObserver = new MutationObserver(
|
|
778
|
-
|
|
819
|
+
this.#mutationObserver = new MutationObserver(records => {
|
|
820
|
+
const hasExternalMutation = records.some(record => {
|
|
821
|
+
const target = record.target;
|
|
822
|
+
const element = target instanceof Element ? target : target.parentElement;
|
|
823
|
+
return !(element && element.closest('.comments-overlay-container'));
|
|
824
|
+
});
|
|
825
|
+
if (hasExternalMutation) {
|
|
826
|
+
this.#scheduleRematch(root);
|
|
827
|
+
}
|
|
779
828
|
});
|
|
780
829
|
const targetNode = root instanceof Document ? (root.body || root.documentElement) : root;
|
|
781
830
|
this.#mutationObserver.observe(targetNode, {
|
|
@@ -797,6 +846,10 @@ export class CommentOverlayManager extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
797
846
|
this.#mutationObserver.disconnect();
|
|
798
847
|
this.#mutationObserver = undefined;
|
|
799
848
|
}
|
|
849
|
+
if (this.#mutationRafId !== undefined) {
|
|
850
|
+
cancelAnimationFrame(this.#mutationRafId);
|
|
851
|
+
this.#mutationRafId = undefined;
|
|
852
|
+
}
|
|
800
853
|
if (this.#rematchTimeoutId) {
|
|
801
854
|
clearTimeout(this.#rematchTimeoutId);
|
|
802
855
|
this.#rematchTimeoutId = undefined;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import * as Platform from '../../../../core/platform/platform.js';
|
|
6
|
+
|
|
5
7
|
import type {DataGridImpl} from './DataGrid.js';
|
|
6
8
|
|
|
7
9
|
/**
|
|
@@ -72,18 +74,10 @@ function escapeMarkdown(val: string): string {
|
|
|
72
74
|
.replace(/\r?\n/g, '<br>');
|
|
73
75
|
}
|
|
74
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Escapes a string for CSV export (handling both RFC 4180 quoting and
|
|
79
|
+
* prefixing spreadsheet formula characters like `=`, `+`, `-`, `@` with `'`).
|
|
80
|
+
*/
|
|
75
81
|
function escapeCSV(val: string): string {
|
|
76
|
-
|
|
77
|
-
let escaped = val;
|
|
78
|
-
if (escaped.includes('"')) {
|
|
79
|
-
escaped = escaped.replace(/"/g, '""');
|
|
80
|
-
needQuotes = true;
|
|
81
|
-
}
|
|
82
|
-
if (escaped.includes(',') || escaped.includes('\n') || escaped.includes('\r')) {
|
|
83
|
-
needQuotes = true;
|
|
84
|
-
}
|
|
85
|
-
if (needQuotes) {
|
|
86
|
-
return `"${escaped}"`;
|
|
87
|
-
}
|
|
88
|
-
return escaped;
|
|
82
|
+
return Platform.StringUtilities.escapeCsvCell(val);
|
|
89
83
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import * as Common from '../../../../core/common/common.js';
|
|
5
5
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
6
6
|
import * as Lit from '../../../../ui/lit/lit.js';
|
|
7
|
+
import * as VisualLogging from '../../../../ui/visual_logging/visual_logging.js';
|
|
7
8
|
import * as UI from '../../legacy.js';
|
|
8
9
|
|
|
9
10
|
import positionAreaEditorStyles from './positionAreaEditor.css.js';
|
|
@@ -19,21 +20,9 @@ const UIStrings = {
|
|
|
19
20
|
*/
|
|
20
21
|
positionAreaGrid: 'position-area grid',
|
|
21
22
|
/**
|
|
22
|
-
* @description Title for the
|
|
23
|
+
* @description Title for the mode section and accessible label for the mode radio button group in the position-area editor.
|
|
23
24
|
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @description Title for the inline axis section in the position-area editor.
|
|
27
|
-
*/
|
|
28
|
-
inline: 'Inline',
|
|
29
|
-
/**
|
|
30
|
-
* @description Accessible label for the block axis mode radio button group.
|
|
31
|
-
*/
|
|
32
|
-
blockAxisMode: 'Block axis mode',
|
|
33
|
-
/**
|
|
34
|
-
* @description Accessible label for the inline axis mode radio button group.
|
|
35
|
-
*/
|
|
36
|
-
inlineAxisMode: 'Inline axis mode',
|
|
25
|
+
mode: 'Mode',
|
|
37
26
|
/**
|
|
38
27
|
* @description Label for physical mode radio button in the position-area editor.
|
|
39
28
|
*/
|
|
@@ -299,14 +288,15 @@ export interface ViewInput {
|
|
|
299
288
|
onSelectStart: (x: number, y: number) => void;
|
|
300
289
|
onSelect: (x: number, y: number) => void;
|
|
301
290
|
onSelectEnd: (x?: number, y?: number) => void;
|
|
302
|
-
onModeChange: (
|
|
303
|
-
onSelfChange: (
|
|
291
|
+
onModeChange: (mode: Mode) => void;
|
|
292
|
+
onSelfChange: (self: boolean) => void;
|
|
304
293
|
}
|
|
305
294
|
export type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
|
|
306
295
|
export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
307
296
|
const container = {
|
|
308
297
|
attributes: {
|
|
309
298
|
tabindex: '0',
|
|
299
|
+
jslog: `${VisualLogging.dialog('position-area-editor').parent('mapped').track({keydown: 'Enter|Escape'})}`,
|
|
310
300
|
},
|
|
311
301
|
};
|
|
312
302
|
if (!input.area) {
|
|
@@ -486,35 +476,42 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
486
476
|
|
|
487
477
|
const blockAxis = input.area.primaryAxis === Axis.BLOCK ? input.area.first : input.area.second;
|
|
488
478
|
const inlineAxis = input.area.primaryAxis === Axis.INLINE ? input.area.first : input.area.second;
|
|
479
|
+
const currentMode = blockAxis.mode === inlineAxis.mode ? blockAxis.mode : undefined;
|
|
480
|
+
const selfDisabled = (isGeneric(blockAxis) || blockAxis.mode === Mode.PHYSICAL) &&
|
|
481
|
+
(isGeneric(inlineAxis) || inlineAxis.mode === Mode.PHYSICAL);
|
|
482
|
+
const selfIndeterminate = !isGeneric(blockAxis) && !isGeneric(inlineAxis) && blockAxis.self !== inlineAxis.self;
|
|
483
|
+
const selfChecked = !selfIndeterminate && (blockAxis.self || inlineAxis.self);
|
|
489
484
|
|
|
490
|
-
function renderModeRadioGroup(
|
|
485
|
+
function renderModeRadioGroup(currentMode: Mode|undefined): Lit.TemplateResult {
|
|
491
486
|
const modes = [
|
|
492
487
|
{mode: Mode.PHYSICAL, label: i18nString(UIStrings.physical)},
|
|
493
488
|
{mode: Mode.COORDINATE, label: i18nString(UIStrings.coordinate)},
|
|
494
489
|
{mode: Mode.LOGICAL, label: i18nString(UIStrings.logical)},
|
|
495
490
|
{mode: Mode.AUTO, label: i18nString(UIStrings.auto)},
|
|
496
491
|
];
|
|
497
|
-
const axisModeLabel =
|
|
498
|
-
axis === Axis.BLOCK ? i18nString(UIStrings.blockAxisMode) : i18nString(UIStrings.inlineAxisMode);
|
|
499
492
|
|
|
493
|
+
// clang-format off
|
|
500
494
|
return html`
|
|
501
|
-
<fieldset class="chip-radio-group" aria-label=${
|
|
495
|
+
<fieldset class="chip-radio-group" aria-label=${i18nString(UIStrings.mode)}>
|
|
502
496
|
${modes.map(({mode, label}) => {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
497
|
+
const id = `mode-${mode}`;
|
|
498
|
+
return html`
|
|
499
|
+
<input
|
|
500
|
+
type="radio"
|
|
501
|
+
id=${id}
|
|
502
|
+
name="mode"
|
|
503
|
+
value=${mode}
|
|
504
|
+
.checked=${currentMode === mode}
|
|
505
|
+
@change=${() => input.onModeChange(mode)}
|
|
506
|
+
>
|
|
507
|
+
<label
|
|
508
|
+
for=${id}
|
|
509
|
+
jslog=${VisualLogging.toggle(mode).track({click: true})}
|
|
510
|
+
>${label}</label>
|
|
511
|
+
`;
|
|
512
|
+
})}
|
|
513
|
+
</fieldset>`;
|
|
514
|
+
// clang-format on
|
|
518
515
|
}
|
|
519
516
|
|
|
520
517
|
// clang-format off
|
|
@@ -531,6 +528,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
531
528
|
aria-label=${i18nString(UIStrings.positionAreaGrid)}
|
|
532
529
|
aria-description=${i18nString(UIStrings.positionAreaGridDescription)}
|
|
533
530
|
aria-multiselectable="true"
|
|
531
|
+
jslog=${VisualLogging.canvas('position-area-grid').track({click: true, drag: true, keydown: 'ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Enter|Space'})}
|
|
534
532
|
data-x-start=${x.start} data-x-end=${x.end} data-y-start=${y.start} data-y-end=${y.end}
|
|
535
533
|
@pointerdown=${onPointerDown}
|
|
536
534
|
@pointermove=${onPointerMove}
|
|
@@ -558,27 +556,17 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
558
556
|
<div class=position-area-controls>
|
|
559
557
|
<div class=axis-section>
|
|
560
558
|
<div class=axis-header>
|
|
561
|
-
<span class=axis-title>${i18nString(UIStrings.
|
|
562
|
-
<devtools-checkbox
|
|
563
|
-
.checked=${blockAxis.self}
|
|
564
|
-
?disabled=${isGeneric(blockAxis)}
|
|
565
|
-
@change=${(e: Event) => input.onSelfChange(Axis.BLOCK, (e.target as UI.UIUtils.CheckboxLabel).checked)}>
|
|
566
|
-
<span class="self-checkbox-label source-code">self</span>
|
|
567
|
-
</devtools-checkbox>
|
|
568
|
-
</div>
|
|
569
|
-
${renderModeRadioGroup(Axis.BLOCK, blockAxis.mode)}
|
|
570
|
-
</div>
|
|
571
|
-
<div class=axis-section>
|
|
572
|
-
<div class=axis-header>
|
|
573
|
-
<span class=axis-title>${i18nString(UIStrings.inline)}</span>
|
|
559
|
+
<span class=axis-title>${i18nString(UIStrings.mode)}</span>
|
|
574
560
|
<devtools-checkbox
|
|
575
|
-
.checked=${
|
|
576
|
-
|
|
577
|
-
|
|
561
|
+
.checked=${selfChecked}
|
|
562
|
+
.indeterminate=${selfIndeterminate}
|
|
563
|
+
?disabled=${selfDisabled}
|
|
564
|
+
jslog=${VisualLogging.toggle('self').track({change: true})}
|
|
565
|
+
@change=${(e: Event) => input.onSelfChange((e.target as UI.UIUtils.CheckboxLabel).checked)}>
|
|
578
566
|
<span class="self-checkbox-label source-code">self</span>
|
|
579
567
|
</devtools-checkbox>
|
|
580
568
|
</div>
|
|
581
|
-
${renderModeRadioGroup(
|
|
569
|
+
${renderModeRadioGroup(currentMode)}
|
|
582
570
|
</div>
|
|
583
571
|
</div>
|
|
584
572
|
`,
|
|
@@ -725,10 +713,10 @@ export class PositionAreaEditor extends PositionAreaEditorBase {
|
|
|
725
713
|
other.mode = mode === Mode.COORDINATE ? Mode.COORDINATE : (other.self ? Mode.COORDINATE : Mode.PHYSICAL);
|
|
726
714
|
}
|
|
727
715
|
} else {
|
|
716
|
+
const self = current.self || other.self;
|
|
717
|
+
current.self = !isGeneric(current) && self;
|
|
728
718
|
other.mode = mode;
|
|
729
|
-
|
|
730
|
-
other.self = current.self;
|
|
731
|
-
}
|
|
719
|
+
other.self = !isGeneric(other) && self;
|
|
732
720
|
}
|
|
733
721
|
} else {
|
|
734
722
|
other.mode = mode;
|
|
@@ -779,8 +767,14 @@ export class PositionAreaEditor extends PositionAreaEditorBase {
|
|
|
779
767
|
onSelectStart: this.#startSelection.bind(this),
|
|
780
768
|
onSelect: this.#select.bind(this),
|
|
781
769
|
onSelectEnd: this.#finishSelection.bind(this),
|
|
782
|
-
onModeChange:
|
|
783
|
-
|
|
770
|
+
onModeChange: (mode: Mode) => {
|
|
771
|
+
this.#setAxisMode(Axis.BLOCK, mode);
|
|
772
|
+
this.#setAxisMode(Axis.INLINE, mode);
|
|
773
|
+
},
|
|
774
|
+
onSelfChange: (self: boolean) => {
|
|
775
|
+
this.#setAxisSelf(Axis.BLOCK, self);
|
|
776
|
+
this.#setAxisSelf(Axis.INLINE, self);
|
|
777
|
+
},
|
|
784
778
|
},
|
|
785
779
|
undefined, this.contentElement);
|
|
786
780
|
}
|