Enable isolation mode for container query containers

screencast: https://imgur.com/a/61Tvewc

backend CL: https://crrev.com/c/3173212

Bug: chromium:1146422
Change-Id: I57abf59ae8d22927c3fb514e4dd684d5656b410a
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3175289
Reviewed-by: Alex Rudenko <alexrudenko@chromium.org>
Reviewed-by: Johan Bay <jobay@chromium.org>
Commit-Queue: Changhao Han <changhaohan@chromium.org>
This commit is contained in:
Changhao Han
2021-09-30 07:53:11 +00:00
committed by Devtools-frontend LUCI CQ
parent 3e7296ac42
commit 8709d85833
17 changed files with 547 additions and 5 deletions
+6
View File
@@ -875,6 +875,12 @@ export const SourceOrderHighlight = {
ChildOutline: Color.fromRGBA([0, 120, 212, 1]),
};
export const IsolationModeHighlight = {
Resizer: Color.fromRGBA([222, 225, 230, 1]), // --color-background-elevation-2
ResizerHandle: Color.fromRGBA([166, 166, 166, 1]),
Mask: Color.fromRGBA([248, 249, 249, 1]),
};
export class Generator {
private readonly hueSpace: number|{
min: number,
+6
View File
@@ -4235,6 +4235,12 @@
"panels/elements/ElementsTreeElement.ts | enableScrollSnap": {
"message": "Enable scroll-snap overlay"
},
"panels/elements/ElementsTreeElement.ts | enterIsolationMode": {
"message": "Enter Isolation Mode"
},
"panels/elements/ElementsTreeElement.ts | exitIsolationMode": {
"message": "Exit Isolation Mode"
},
"panels/elements/ElementsTreeElement.ts | expandRecursively": {
"message": "Expand recursively"
},
+6
View File
@@ -4235,6 +4235,12 @@
"panels/elements/ElementsTreeElement.ts | enableScrollSnap": {
"message": "Êńâb́l̂é ŝćr̂ól̂ĺ-ŝńâṕ ôv́êŕl̂áŷ"
},
"panels/elements/ElementsTreeElement.ts | enterIsolationMode": {
"message": "Êńt̂ér̂ Íŝól̂át̂íôń M̂ód̂é"
},
"panels/elements/ElementsTreeElement.ts | exitIsolationMode": {
"message": "Êx́ît́ Îśôĺât́îón̂ Ḿôd́ê"
},
"panels/elements/ElementsTreeElement.ts | expandRecursively": {
"message": "Êx́p̂án̂d́ r̂éĉúr̂śîv́êĺŷ"
},
+21
View File
@@ -467,6 +467,27 @@ export class OverlayModel extends SDKModel<EventTypes> implements ProtocolProxyA
return this.sourceOrderModeActiveInternal;
}
highlightIsolatedElementInPersistentOverlay(nodeId: Protocol.DOM.NodeId): void {
if (!this.persistentHighlighter) {
return;
}
this.persistentHighlighter.highlightIsolatedElementInOverlay(nodeId);
}
hideIsolatedElementInPersistentOverlay(nodeId: Protocol.DOM.NodeId): void {
if (!this.persistentHighlighter) {
return;
}
this.persistentHighlighter.hideIsolatedElementInOverlay(nodeId);
}
isHighlightedIsolatedElementInPersistentOverlay(nodeId: Protocol.DOM.NodeId): boolean {
if (!this.persistentHighlighter) {
return false;
}
return this.persistentHighlighter.isIsolatedElementHighlighted(nodeId);
}
private delayedHideHighlight(delay: number): void {
if (this.hideHighlightTimeout === null) {
this.hideHighlightTimeout = window.setTimeout(() => this.highlightInOverlay({clear: true}), delay);
@@ -14,6 +14,7 @@ export class OverlayPersistentHighlighter {
private readonly flexHighlights: Map<Protocol.DOM.NodeId, Protocol.Overlay.FlexContainerHighlightConfig>;
private readonly containerQueryHighlights:
Map<Protocol.DOM.NodeId, Protocol.Overlay.ContainerQueryContainerHighlightConfig>;
private readonly isolatedElementHighlights: Map<Protocol.DOM.NodeId, Protocol.Overlay.IsolationModeHighlightConfig>;
private readonly colors: Map<Protocol.DOM.NodeId, Common.Color.Color>;
private gridColorGenerator: OverlayColorGenerator;
private flexColorGenerator: OverlayColorGenerator;
@@ -41,6 +42,8 @@ export class OverlayPersistentHighlighter {
this.containerQueryHighlights = new Map();
this.isolatedElementHighlights = new Map();
this.colors = new Map();
this.gridColorGenerator = new OverlayColorGenerator();
@@ -223,11 +226,36 @@ export class OverlayPersistentHighlighter {
};
}
highlightIsolatedElementInOverlay(nodeId: Protocol.DOM.NodeId): void {
this.isolatedElementHighlights.set(nodeId, this.buildIsolationModeHighlightConfig());
this.updateHighlightsInOverlay();
}
hideIsolatedElementInOverlay(nodeId: Protocol.DOM.NodeId): void {
if (this.isolatedElementHighlights.has(nodeId)) {
this.isolatedElementHighlights.delete(nodeId);
this.updateHighlightsInOverlay();
}
}
isIsolatedElementHighlighted(nodeId: Protocol.DOM.NodeId): boolean {
return this.isolatedElementHighlights.has(nodeId);
}
private buildIsolationModeHighlightConfig(): Protocol.Overlay.IsolationModeHighlightConfig {
return {
resizerColor: Common.Color.IsolationModeHighlight.Resizer.toProtocolRGBA(),
resizerHandleColor: Common.Color.IsolationModeHighlight.ResizerHandle.toProtocolRGBA(),
maskColor: Common.Color.IsolationModeHighlight.Mask.toProtocolRGBA(),
};
}
hideAllInOverlay(): void {
this.flexHighlights.clear();
this.gridHighlights.clear();
this.scrollSnapHighlights.clear();
this.containerQueryHighlights.clear();
this.isolatedElementHighlights.clear();
this.updateHighlightsInOverlay();
}
@@ -236,7 +264,9 @@ export class OverlayPersistentHighlighter {
const flexboxesNeedUpdate = this.updateHighlightsForDeletedNodes(this.flexHighlights);
const scrollSnapsNeedUpdate = this.updateHighlightsForDeletedNodes(this.scrollSnapHighlights);
const containerQueriesNeedUpdate = this.updateHighlightsForDeletedNodes(this.containerQueryHighlights);
if (flexboxesNeedUpdate || gridsNeedUpdate || scrollSnapsNeedUpdate || containerQueriesNeedUpdate) {
const isolatedElementsNeedUpdate = this.updateHighlightsForDeletedNodes(this.isolatedElementHighlights);
if (flexboxesNeedUpdate || gridsNeedUpdate || scrollSnapsNeedUpdate || containerQueriesNeedUpdate ||
isolatedElementsNeedUpdate) {
this.updateHighlightsInOverlay();
}
}
@@ -265,17 +295,21 @@ export class OverlayPersistentHighlighter {
for (const nodeId of this.containerQueryHighlights.keys()) {
this.containerQueryHighlights.set(nodeId, this.buildContainerQueryContainerHighlightConfig());
}
for (const nodeId of this.isolatedElementHighlights.keys()) {
this.isolatedElementHighlights.set(nodeId, this.buildIsolationModeHighlightConfig());
}
this.updateHighlightsInOverlay();
}
private updateHighlightsInOverlay(): void {
const hasNodesToHighlight =
this.gridHighlights.size > 0 || this.flexHighlights.size > 0 || this.containerQueryHighlights.size > 0;
const hasNodesToHighlight = this.gridHighlights.size > 0 || this.flexHighlights.size > 0 ||
this.containerQueryHighlights.size > 0 || this.isolatedElementHighlights.size > 0;
this.model.setShowViewportSizeOnResize(!hasNodesToHighlight);
this.updateGridHighlightsInOverlay();
this.updateFlexHighlightsInOverlay();
this.updateScrollSnapHighlightsInOverlay();
this.updateContainerQueryHighlightsInOverlay();
this.updateIsolatedElementHighlightsInOverlay();
}
private updateGridHighlightsInOverlay(): void {
@@ -316,6 +350,15 @@ export class OverlayPersistentHighlighter {
}
overlayModel.target().overlayAgent().invoke_setShowContainerQueryOverlays({containerQueryHighlightConfigs});
}
updateIsolatedElementHighlightsInOverlay(): void {
const overlayModel = this.model;
const isolatedElementHighlightConfigs = [];
for (const [nodeId, isolationModeHighlightConfig] of this.isolatedElementHighlights.entries()) {
isolatedElementHighlightConfigs.push({nodeId, isolationModeHighlightConfig});
}
overlayModel.target().overlayAgent().invoke_setShowIsolatedElements({isolatedElementHighlightConfigs});
}
}
/**
@@ -362,6 +405,15 @@ export interface OverlayAgent {
containerQueryContainerHighlightConfig: Protocol.Overlay.ContainerQueryContainerHighlightConfig,
}>,
}): void;
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/naming-convention
invoke_setShowIsolatedElements(param: {
isolatedElementHighlightConfigs: Array<{
nodeId: number,
isolationModeHighlightConfig: Protocol.Overlay.IsolationModeHighlightConfig,
}>,
}): void;
}
/**
@@ -83,6 +83,14 @@ const UIStrings = {
*/
scrollIntoView: 'Scroll into view',
/**
*@description Text to enter Isolation Mode, a mode with focus on a single element and interactive resizing
*/
enterIsolationMode: 'Enter Isolation Mode',
/**
*@description Text to exit Isolation Mode, a mode with focus on a single element and interactive resizing
*/
exitIsolationMode: 'Exit Isolation Mode',
/**
*@description A context menu item in the Elements Tree Element of the Elements panel
*/
editText: 'Edit text',
@@ -636,6 +644,17 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
contextMenu.viewSection().appendItem(i18nString(UIStrings.focus), async () => {
await this.nodeInternal.focus();
});
const overlayModel = this.nodeInternal.domModel().overlayModel();
if (overlayModel.isHighlightedIsolatedElementInPersistentOverlay(this.nodeInternal.id)) {
contextMenu.viewSection().appendItem(i18nString(UIStrings.exitIsolationMode), () => {
overlayModel.hideIsolatedElementInPersistentOverlay(this.nodeInternal.id);
});
} else {
contextMenu.viewSection().appendItem(i18nString(UIStrings.enterIsolationMode), () => {
overlayModel.highlightIsolatedElementInPersistentOverlay(this.nodeInternal.id);
});
}
}
populateScrollIntoView(contextMenu: UI.ContextMenu.ContextMenu): void {
+5 -1
View File
@@ -14,10 +14,12 @@ action("build_inspector_overlay") {
"$target_gen_dir/common.css",
"$target_gen_dir/common.js",
"$target_gen_dir/css_grid_label_helpers.js",
"$target_gen_dir/drag_resize_handler.js",
"$target_gen_dir/highlight_common.js",
"$target_gen_dir/highlight_container_query.js",
"$target_gen_dir/highlight_flex_common.js",
"$target_gen_dir/highlight_grid_common.js",
"$target_gen_dir/highlight_isolated_element.js",
"$target_gen_dir/highlight_scroll_snap.js",
"$target_gen_dir/tool_distances.js",
"$target_gen_dir/tool_persistent.js",
@@ -40,7 +42,7 @@ action("build_inspector_overlay") {
args = [
"main.js",
"65000", # max_size in bytes
"70000", # max_size in bytes
"--input_path",
rebase_path(target_gen_dir, root_build_dir),
"--output_path",
@@ -77,10 +79,12 @@ ts_library("inspector_overlay") {
sources = [
"common.ts",
"css_grid_label_helpers.ts",
"drag_resize_handler.ts",
"highlight_common.ts",
"highlight_container_query.ts",
"highlight_flex_common.ts",
"highlight_grid_common.ts",
"highlight_isolated_element.ts",
"highlight_scroll_snap.ts",
"main.ts",
"tool_distances.ts",
@@ -0,0 +1,75 @@
<!--
Copyright 2021 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Debug</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script type="module" src="/out/Default/resources/inspector_overlay/main.js"></script>
</head>
<body>
<script type="module">
const viewportWidth = document.documentElement.clientWidth;
const viewportHeight = document.documentElement.clientHeight;
dispatch(["setPlatform", "other"]);
dispatch(["setOverlay", "persistent"]);
dispatch(["reset", {
viewportSize: {
width: viewportWidth,
height: viewportHeight,
},
deviceScaleFactor: 1,
pageScaleFactor: 1,
pageZoomFactor: 1,
emulationScaleFactor: 1,
scrollX: 0,
scrollY: 0,
}]);
dispatch(["drawIsolatedElementHighlight", {
"draggableWidthBorder": [
"M",
300,
100,
"L",
350,
100,
"L",
350,
300,
"L",
300,
300,
"Z"
],
"draggableHeightBorder": [
"M",
100,
300,
"L",
300,
300,
"L",
300,
350,
"L",
100,
350,
"Z"
],
"currentWidth": 200,
"currentHeight": 200,
"currentX": 100,
"currentY": 100,
"highlightIndex": 1,
}]);
</script>
</body>
</html>
+142
View File
@@ -0,0 +1,142 @@
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export const enum ResizerType {
WIDTH = 'width',
HEIGHT = 'height',
BIDIRECTION = 'bidirection',
}
export interface Draggable {
type: ResizerType;
initialWidth?: number;
initialHeight?: number;
update({width, height}: {width?: number, height?: number}): void;
}
export interface Delegate {
getDraggable(x: number, y: number): Draggable|undefined;
}
const cursorByResizerType = new Map([
[ResizerType.WIDTH, 'ew-resize'],
[ResizerType.HEIGHT, 'ns-resize'],
[ResizerType.BIDIRECTION, 'nwse-resize'],
]);
type OriginInfo = {
coord: number,
value: number,
};
export class DragResizeHandler {
private document: Document;
private delegate: Delegate;
private originX?: OriginInfo;
private originY?: OriginInfo;
private boundMousemove: (event: MouseEvent) => void;
private boundMousedown: (event: MouseEvent) => void;
constructor(document: Document, delegate: Delegate) {
this.document = document;
this.delegate = delegate;
this.boundMousemove = this.onMousemove.bind(this);
this.boundMousedown = this.onMousedown.bind(this);
}
install() {
this.document.body.addEventListener('mousemove', this.boundMousemove);
this.document.body.addEventListener('mousedown', this.boundMousedown);
}
uninstall() {
this.document.body.removeEventListener('mousemove', this.boundMousemove);
this.document.body.removeEventListener('mousedown', this.boundMousedown);
}
/**
* Updates the cursor style of the mouse is hovered over a resizeable area.
*/
private onMousemove(event: MouseEvent) {
const match = this.delegate.getDraggable(event.clientX, event.clientY);
if (!match) {
this.document.body.style.cursor = 'default';
return;
}
this.document.body.style.cursor = cursorByResizerType.get(match.type) || 'default';
}
/**
* Starts dragging
*/
private onMousedown(event: MouseEvent) {
const match = this.delegate.getDraggable(event.clientX, event.clientY);
if (!match) {
return;
}
const boundOnDrag = this.onDrag.bind(this, match);
event.stopPropagation();
event.preventDefault();
if (match.initialWidth !== undefined &&
(match.type === ResizerType.WIDTH || match.type === ResizerType.BIDIRECTION)) {
this.originX = {
coord: Math.round(event.clientX),
value: match.initialWidth,
};
}
if (match.initialHeight !== undefined &&
(match.type === ResizerType.HEIGHT || match.type === ResizerType.BIDIRECTION)) {
this.originY = {
coord: Math.round(event.clientY),
value: match.initialHeight,
};
}
this.document.body.removeEventListener('mousemove', this.boundMousemove);
this.document.body.style.cursor = cursorByResizerType.get(match.type) || 'default';
const endDrag = (event: Event) => {
event.stopPropagation();
event.preventDefault();
this.originX = undefined;
this.originY = undefined;
this.document.body.style.cursor = 'default';
this.document.body.removeEventListener('mousemove', boundOnDrag);
this.document.body.addEventListener('mousemove', this.boundMousemove);
};
this.document.body.addEventListener('mouseup', endDrag, {once: true});
window.addEventListener('mouseout', endDrag, {once: true});
this.document.body.addEventListener('mousemove', boundOnDrag);
}
/**
* Computes the new value while the cursor is being dragged and calls InspectorOverlayHost with the new value.
*/
private onDrag(match: Draggable, e: MouseEvent) {
if (!this.originX && !this.originY) {
return;
}
let width: number|undefined;
let height: number|undefined;
if (this.originX) {
const delta = this.originX.coord - e.clientX;
width = Math.round(this.originX.value - delta);
}
if (this.originY) {
const delta = this.originY.coord - e.clientY;
height = Math.round(this.originY.value - delta);
}
match.update({width, height});
}
}
@@ -0,0 +1,62 @@
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type {PathCommands} from './common.js';
import {buildPath, emptyBounds, fillPathWithBoxStyle} from './highlight_common.js';
export interface IsolatedElementHighlight {
widthResizerBorder: PathCommands;
heightResizerBorder: PathCommands;
bidirectionResizerBorder: PathCommands;
currentX: number;
currentY: number;
currentWidth: number;
currentHeight: number;
highlightIndex: number;
isolationModeHighlightConfig: {
resizerColor: string,
resizerHandleColor: string,
maskColor: string,
};
}
export function drawIsolatedElementHighlight(
highlight: IsolatedElementHighlight, context: CanvasRenderingContext2D, canvasWidth: number, canvasHeight: number,
emulationScaleFactor: number) {
const {currentX, currentY, currentWidth, currentHeight, highlightIndex} = highlight;
// Draw a mask covering other area of the canvas.
context.save();
context.fillStyle = highlight.isolationModeHighlightConfig.maskColor;
context.fillRect(0, 0, canvasWidth, canvasHeight);
context.clearRect(currentX, currentY, currentWidth, currentHeight);
context.restore();
// Draw the width resizer with handle bars.
const bounds = emptyBounds();
const widthPath = buildPath(highlight.widthResizerBorder, bounds, emulationScaleFactor);
fillPathWithBoxStyle(context, widthPath, bounds, 0 /* angle */, {
fillColor: highlight.isolationModeHighlightConfig.resizerColor,
});
// Draw the height resizer with handle bars.
const heightPath = buildPath(highlight.heightResizerBorder, bounds, emulationScaleFactor);
fillPathWithBoxStyle(context, heightPath, bounds, 0 /* angle */, {
fillColor: highlight.isolationModeHighlightConfig.resizerColor,
});
// Draw the bidirection resizer with handle bars.
const bidirectionPath = buildPath(highlight.bidirectionResizerBorder, bounds, emulationScaleFactor);
fillPathWithBoxStyle(context, bidirectionPath, bounds, 0 /* angle */, {
fillColor: highlight.isolationModeHighlightConfig.resizerColor,
});
return {
widthPath,
heightPath,
bidirectionPath,
currentWidth,
currentHeight,
highlightIndex,
};
}
+3 -1
View File
@@ -14,7 +14,9 @@ import highlightStyle from './tool_highlight.css'; // eslint-disable-line rulesd
import {HighlightOverlay} from './tool_highlight.js';
// @ts-ignore Importing CSS is handled in Rollup.
import pausedStyle from './tool_paused.css'; // eslint-disable-line rulesdir/es_modules_import
import type {PausedToolMessage} from './tool_paused.js';
import {PausedOverlay} from './tool_paused.js';
import type {PersistentToolMessage} from './tool_persistent.js';
import {PersistentOverlay} from './tool_persistent.js';
// @ts-ignore Importing CSS is handled in Rollup.
import screenshotStyle from './tool_screenshot.css'; // eslint-disable-line rulesdir/es_modules_import
@@ -28,7 +30,7 @@ declare global {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Window {
// eslint-disable-next-line @typescript-eslint/naming-convention
InspectorOverlayHost: {send(data: string): void};
InspectorOverlayHost: {send(data: PausedToolMessage|PersistentToolMessage|string): void};
}
}
+6
View File
@@ -41,6 +41,7 @@ import {drawLayoutGridHighlight} from './highlight_grid_common.js';
import type {ScrollSnapHighlight} from './highlight_scroll_snap.js';
import type {ContainerQueryHighlight} from './highlight_container_query.js';
import {drawContainerQueryHighlight} from './highlight_container_query.js';
import type {IsolatedElementHighlight} from './highlight_isolated_element.js';
import {PersistentOverlay} from './tool_persistent.js';
interface Path {
@@ -85,6 +86,7 @@ interface Highlight {
flexInfo: FlexContainerHighlight[];
flexItemInfo: FlexItemHighlight[];
containerQueryInfo: ContainerQueryHighlight[];
isolatedElementInfo: IsolatedElementHighlight[];
}
export class HighlightOverlay extends Overlay {
@@ -245,6 +247,10 @@ export class HighlightOverlay extends Overlay {
this.persistentOverlay?.drawContainerQueryHighlight(highlight);
}
drawIsolatedElementHighlight(highlight: IsolatedElementHighlight) {
this.persistentOverlay?.drawIsolatedElementHighlight(highlight);
}
private drawAxis(context: CanvasRenderingContext2D, rulerAtRight: boolean, rulerAtBottom: boolean) {
context.save();
+2
View File
@@ -4,6 +4,8 @@
import {Overlay} from './common.js';
export type PausedToolMessage = 'resume'|'stepOver';
export class PausedOverlay extends Overlay {
private container!: HTMLElement;
+110
View File
@@ -30,19 +30,74 @@
import type {ResetData} from './common.js';
import {Overlay} from './common.js';
import type {Delegate} from './drag_resize_handler.js';
import {DragResizeHandler, ResizerType} from './drag_resize_handler.js';
import type {ContainerQueryHighlight} from './highlight_container_query.js';
import {drawContainerQueryHighlight} from './highlight_container_query.js';
import type {FlexContainerHighlight} from './highlight_flex_common.js';
import {drawLayoutFlexContainerHighlight} from './highlight_flex_common.js';
import type {GridHighlight} from './highlight_grid_common.js';
import {drawLayoutGridHighlight} from './highlight_grid_common.js';
import type {IsolatedElementHighlight} from './highlight_isolated_element.js';
import {drawIsolatedElementHighlight} from './highlight_isolated_element.js';
import type {ScrollSnapHighlight} from './highlight_scroll_snap.js';
import {drawScrollSnapHighlight} from './highlight_scroll_snap.js';
export type PersistentToolMessage = {
highlightType: string,
highlightIndex: number,
newWidth: string,
newHeight: string,
resizerType: ResizerType,
};
interface DraggableMetadata {
type: ResizerType;
highlightIndex: number;
initialWidth?: number;
initialHeight?: number;
}
function makeDraggableDelegate(overlay: PersistentOverlay): Delegate {
return {
getDraggable: (x, y) => {
const result = overlay.isPointInDraggablePath(x, y);
if (!result) {
return;
}
return {
type: result.type,
initialWidth: result.initialWidth,
initialHeight: result.initialHeight,
id: result.highlightIndex,
update: ({width, height}: {width?: number, height?: number}) => {
window.InspectorOverlayHost.send({
highlightType: 'isolatedElement',
highlightIndex: result.highlightIndex,
newWidth: `${width}px`,
newHeight: `${height}px`,
resizerType: result.type,
});
},
};
},
};
}
export class PersistentOverlay extends Overlay {
private gridLabelState = {gridLayerCounter: 0};
private gridLabels!: HTMLElement;
private draggableBorders: Map<number, {
widthPath: Path2D,
heightPath: Path2D,
bidirectionPath: Path2D,
highlightIndex: number,
initialWidth: number,
initialHeight: number,
}> = new Map();
private dragHandler?: DragResizeHandler;
reset(data: ResetData) {
super.reset(data);
@@ -70,12 +125,15 @@ export class PersistentOverlay extends Overlay {
this.setCanvas(canvas);
super.install();
this.dragHandler?.install();
}
uninstall() {
this.document.body.classList.remove('fill');
this.document.body.innerHTML = '';
this.draggableBorders = new Map();
super.uninstall();
this.dragHandler?.uninstall();
}
drawGridHighlight(highlight: GridHighlight) {
@@ -105,4 +163,56 @@ export class PersistentOverlay extends Overlay {
drawContainerQueryHighlight(highlight, this.context, this.emulationScaleFactor);
this.context.restore();
}
drawIsolatedElementHighlight(highlight: IsolatedElementHighlight) {
if (!this.dragHandler) {
this.dragHandler = new DragResizeHandler(this.document, makeDraggableDelegate(this));
this.dragHandler.install();
}
this.context.save();
const {widthPath, heightPath, bidirectionPath, currentWidth, currentHeight, highlightIndex} =
drawIsolatedElementHighlight(
highlight, this.context, this.canvasWidth, this.canvasHeight, this.emulationScaleFactor);
this.draggableBorders.set(highlightIndex, {
widthPath,
heightPath,
bidirectionPath,
highlightIndex,
initialWidth: currentWidth,
initialHeight: currentHeight,
});
this.context.restore();
}
isPointInDraggablePath(x: number, y: number): DraggableMetadata|undefined {
for (const {widthPath, heightPath, bidirectionPath, highlightIndex, initialWidth, initialHeight} of this
.draggableBorders.values()) {
if (this.context.isPointInPath(widthPath, x, y)) {
return {
type: ResizerType.WIDTH,
highlightIndex,
initialWidth,
};
}
if (this.context.isPointInPath(heightPath, x, y)) {
return {
type: ResizerType.HEIGHT,
highlightIndex,
initialHeight,
};
}
if (this.context.isPointInPath(bidirectionPath, x, y)) {
return {
type: ResizerType.BIDIRECTION,
highlightIndex,
initialWidth,
initialHeight,
};
}
}
return;
}
}
+1
View File
@@ -14,6 +14,7 @@ node_ts_library("elements") {
"element-breadcrumbs_test.ts",
"flexbox-editor_test.ts",
"grid-editor_test.ts",
"isolation-mode_test.ts",
"layout-pane_test.ts",
"pseudo-states_test.ts",
"reveal-correct-node_test.ts",
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {goToResource} from '../../shared/helper.js';
import {describe, it} from '../../shared/mocha-extensions.js';
import {clickOnContextMenu} from '../helpers/sources-helpers.js';
describe('The Elements panel', async () => {
it('has a context menu item to enter Isolation Mode', async () => {
await goToResource('elements/css-container-queries.html');
await clickOnContextMenu('[aria-label="</body>"]', 'Enter Isolation Mode');
await clickOnContextMenu('[aria-label="</body>"]', 'Exit Isolation Mode');
});
});
@@ -31,6 +31,7 @@ describeWithEnvironment('OverlayColorGenerator', () => {
invoke_setShowFlexOverlays() {},
invoke_setShowScrollSnapOverlays() {},
invoke_setShowContainerQueryOverlays() {},
invoke_setShowIsolatedElements() {},
};
},
};
@@ -80,4 +81,16 @@ describeWithEnvironment('OverlayColorGenerator', () => {
highlighter.hideContainerQueryInOverlay(nodeId);
assert(!highlighter.isContainerQueryHighlighted(nodeId));
});
it('is able to highlight isolated elements', () => {
const highlighter = new SDK.OverlayPersistentHighlighter.OverlayPersistentHighlighter(mockModel);
highlighter.highlightIsolatedElementInOverlay(nodeId);
assert(highlighter.isIsolatedElementHighlighted(nodeId));
assert(!highlighter.isFlexHighlighted(nodeId));
assert(!highlighter.isGridHighlighted(nodeId));
assert(!highlighter.isScrollSnapHighlighted(nodeId));
assert(!highlighter.isContainerQueryHighlighted(nodeId));
highlighter.hideIsolatedElementInOverlay(nodeId);
assert(!highlighter.isIsolatedElementHighlighted(nodeId));
});
});