mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-09-28 13:13:37 +08:00
[GM3Restyling] Update SearchableView search bar to GM3
Before: https://i.imgur.com/42qEEUx.png After: https://i.imgur.com/k5efb7x.png Bug: 325442270 Change-Id: I57d70b8d45ac5a45e75d30326c416866dc2f342b Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5522199 Reviewed-by: Ergün Erdoğmuş <ergunsh@chromium.org> Commit-Queue: Kim-Anh Tran <kimanh@chromium.org>
This commit is contained in:
committed by
Devtools-frontend LUCI CQ
parent
628183c4a2
commit
f2e8fca99a
@@ -170,6 +170,7 @@ grd_files_release_sources = [
|
||||
"front_end/Images/lightbulb-spark.svg",
|
||||
"front_end/Images/lighthouse_logo.svg",
|
||||
"front_end/Images/list.svg",
|
||||
"front_end/Images/match-case.svg",
|
||||
"front_end/Images/match-whole-word.svg",
|
||||
"front_end/Images/memory.svg",
|
||||
"front_end/Images/minus.svg",
|
||||
@@ -193,6 +194,7 @@ grd_files_release_sources = [
|
||||
"front_end/Images/record-stop.svg",
|
||||
"front_end/Images/redo.svg",
|
||||
"front_end/Images/refresh.svg",
|
||||
"front_end/Images/regular-expression.svg",
|
||||
"front_end/Images/replace.svg",
|
||||
"front_end/Images/replay.svg",
|
||||
"front_end/Images/report.svg",
|
||||
|
||||
@@ -173,6 +173,7 @@ devtools_svg_sources = [
|
||||
"lightbulb-spark.svg",
|
||||
"lighthouse_logo.svg",
|
||||
"list.svg",
|
||||
"match-case.svg",
|
||||
"match-whole-word.svg",
|
||||
"memory.svg",
|
||||
"minus.svg",
|
||||
@@ -192,6 +193,7 @@ devtools_svg_sources = [
|
||||
"record-stop.svg",
|
||||
"redo.svg",
|
||||
"refresh.svg",
|
||||
"regular-expression.svg",
|
||||
"replace.svg",
|
||||
"replay.svg",
|
||||
"report.svg",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.04163 14.1458L6.06246 6.0625H8.02079L11.0625 14.1458H9.22913L8.58329 12.2917H5.58329L4.89579 14.1458H3.04163ZM6.06246 10.7292H8.04163L7.06246 8.02083H7.02079L6.06246 10.7292ZM13.6666 14.3333C13.0555 14.3333 12.552 14.1493 12.1562 13.7813C11.7604 13.4132 11.5625 12.9444 11.5625 12.375C11.5625 11.7917 11.7777 11.3194 12.2083 10.9583C12.6388 10.5972 13.2222 10.4167 13.9583 10.4167C14.2222 10.4167 14.5069 10.4479 14.8125 10.5104C15.118 10.5729 15.3333 10.6389 15.4583 10.7083V10.3542C15.4583 10.1458 15.3229 9.94792 15.052 9.76042C14.7812 9.57292 14.4861 9.47917 14.1666 9.47917C13.8888 9.47917 13.6284 9.53819 13.3854 9.65625C13.1423 9.77431 12.868 9.95833 12.5625 10.2083L11.7291 9.04167C11.9791 8.79167 12.3541 8.56944 12.8541 8.375C13.3541 8.18056 13.8611 8.08333 14.375 8.08333C15.1527 8.08333 15.7882 8.30208 16.2812 8.73958C16.7743 9.17708 17.0208 9.75 17.0208 10.4583V14.1042H15.4375V13.5625H15.375C15.1666 13.8264 14.9201 14.0208 14.6354 14.1458C14.3507 14.2708 14.0277 14.3333 13.6666 14.3333ZM14.0833 13C14.4861 13 14.8125 12.8785 15.0625 12.6354C15.3125 12.3924 15.4375 12.0972 15.4375 11.75C15.2986 11.6806 15.1493 11.6319 14.9895 11.6042C14.8298 11.5764 14.6388 11.5625 14.4166 11.5625C14.0555 11.5625 13.7673 11.6354 13.552 11.7813C13.3368 11.9271 13.2291 12.1042 13.2291 12.3125C13.2291 12.5486 13.3055 12.7222 13.4583 12.8333C13.6111 12.9444 13.8194 13 14.0833 13Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.33333 15.6458C3.58333 14.8958 3.00694 14.0347 2.60417 13.0625C2.20139 12.0903 2 11.0694 2 9.99998C2 8.93054 2.20139 7.9097 2.60417 6.93748C3.00694 5.96526 3.58333 5.0972 4.33333 4.33331L5.41667 5.39581C4.79167 6.00692 4.31597 6.70831 3.98958 7.49998C3.66319 8.29165 3.5 9.12498 3.5 9.99998C3.5 10.8611 3.66319 11.684 3.98958 12.4687C4.31597 13.2535 4.78472 13.9583 5.39583 14.5833L4.33333 15.6458ZM7.75 15C7.40278 15 7.10764 14.8785 6.86458 14.6354C6.62153 14.3923 6.5 14.0972 6.5 13.75C6.5 13.4028 6.62153 13.1076 6.86458 12.8646C7.10764 12.6215 7.40278 12.5 7.75 12.5C8.09722 12.5 8.39236 12.6215 8.63542 12.8646C8.87847 13.1076 9 13.4028 9 13.75C9 14.0972 8.87847 14.3923 8.63542 14.6354C8.39236 14.8785 8.09722 15 7.75 15ZM10.5 11V9.29165L9.02083 10.1458L8.27083 8.85415L9.75 7.99998L8.27083 7.14581L9.02083 5.85415L10.5 6.70831V4.99998H12V6.70831L13.4792 5.85415L14.2292 7.14581L12.75 7.99998L14.2292 8.85415L13.4792 10.1458L12 9.29165V11H10.5ZM15.6667 15.6458L14.6042 14.5833C15.2153 13.9722 15.684 13.2743 16.0104 12.4896C16.3368 11.7048 16.5 10.875 16.5 9.99998C16.5 9.12498 16.3403 8.29165 16.0208 7.49998C15.7014 6.70831 15.2292 6.00692 14.6042 5.39581L15.6667 4.33331C16.4167 5.0972 16.9931 5.96526 17.3958 6.93748C17.7986 7.9097 18 8.93054 18 9.99998C18 11.0694 17.7986 12.0903 17.3958 13.0625C16.9931 14.0347 16.4167 14.8958 15.6667 15.6458Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -190,6 +190,10 @@ export class Button extends HTMLElement {
|
||||
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
||||
}
|
||||
|
||||
get toggled(): boolean {
|
||||
return Boolean(this.#props.toggled);
|
||||
}
|
||||
|
||||
set active(active: boolean) {
|
||||
this.#props.active = active;
|
||||
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
||||
|
||||
@@ -37,14 +37,14 @@ import * as Common from '../../core/common/common.js';
|
||||
import * as i18n from '../../core/i18n/i18n.js';
|
||||
import * as Platform from '../../core/platform/platform.js';
|
||||
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
||||
import type * as Buttons from '../components/buttons/buttons.js';
|
||||
import * as Buttons from '../components/buttons/buttons.js';
|
||||
import * as IconButton from '../components/icon_button/icon_button.js';
|
||||
|
||||
import * as ARIAUtils from './ARIAUtils.js';
|
||||
import {HistoryInput} from './HistoryInput.js';
|
||||
import {InspectorView} from './InspectorView.js';
|
||||
import searchableViewStyles from './searchableView.css.legacy.js';
|
||||
import {Toolbar, ToolbarButton, ToolbarToggle} from './Toolbar.js';
|
||||
import {Tooltip} from './Tooltip.js';
|
||||
import {Toolbar, ToolbarButton, ToolbarText, ToolbarToggle} from './Toolbar.js';
|
||||
import {createTextButton} from './UIUtils.js';
|
||||
import {VBox} from './Widget.js';
|
||||
|
||||
@@ -53,30 +53,46 @@ const UIStrings = {
|
||||
*@description Text on a button to replace one instance with input text for the ctrl+F search bar
|
||||
*/
|
||||
replace: 'Replace',
|
||||
/**
|
||||
*@description Tooltip text on a toggle to enable replacing one instance with input text for the ctrl+F search bar
|
||||
*/
|
||||
enableFindAndReplace: 'Find and replace',
|
||||
/**
|
||||
*@description Tooltip text on a toggle to disable replacing one instance with input text for the ctrl+F search bar
|
||||
*/
|
||||
disableFindAndReplace: 'Disable find and replace',
|
||||
/**
|
||||
*@description Text to find an item
|
||||
*/
|
||||
findString: 'Find',
|
||||
/**
|
||||
*@description Text on a button to search previous instance for the ctrl+F search bar
|
||||
*@description Tooltip text on a button to search previous instance for the ctrl+F search bar
|
||||
*/
|
||||
searchPrevious: 'Search previous',
|
||||
searchPrevious: 'Show previous result',
|
||||
/**
|
||||
*@description Text on a button to search next instance for the ctrl+F search bar
|
||||
*@description Tooltip text on a button to search next instance for the ctrl+F search bar
|
||||
*/
|
||||
searchNext: 'Search next',
|
||||
searchNext: 'Show next result',
|
||||
/**
|
||||
*@description Text to search by matching case of the input
|
||||
*@description Tooltip text on a toggle to enable search by matching case of the input
|
||||
*/
|
||||
matchCase: 'Match Case',
|
||||
enableCaseSensitive: 'Enable case sensitive search',
|
||||
/**
|
||||
*@description Text for searching with regular expressinn
|
||||
*@description Tooltip text on a toggle to disable search by matching case of the input
|
||||
*/
|
||||
useRegularExpression: 'Use Regular Expression',
|
||||
disableCaseSensitive: 'Disable case sensitive search',
|
||||
/**
|
||||
*@description Text to cancel something
|
||||
*@description Tooltip text on a toggle to enable searching with regular expression
|
||||
*/
|
||||
cancel: 'Cancel',
|
||||
enableRegularExpression: 'Enable regular expressions',
|
||||
/**
|
||||
*@description Tooltip text on a toggle to disable searching with regular expression
|
||||
*/
|
||||
disableRegularExpression: 'Disable regular expressions',
|
||||
/**
|
||||
*@description Tooltip text on a button to close the search bar
|
||||
*/
|
||||
closeSearchBar: 'Close search bar',
|
||||
/**
|
||||
*@description Text on a button to replace all instances with input text for the ctrl+F search bar
|
||||
*/
|
||||
@@ -87,6 +103,12 @@ const UIStrings = {
|
||||
*@example {3} PH2
|
||||
*/
|
||||
dOfD: '{PH1} of {PH2}',
|
||||
/**
|
||||
*@description Tooltip text to indicate the current match index and the total number of matches for the ctrl+F search bar
|
||||
*@example {2} PH1
|
||||
*@example {3} PH2
|
||||
*/
|
||||
accessibledOfD: 'Shows result {PH1} of {PH2}',
|
||||
/**
|
||||
*@description Text to indicate search result for the ctrl+F search bar
|
||||
*/
|
||||
@@ -96,9 +118,28 @@ const UIStrings = {
|
||||
*@example {2} PH1
|
||||
*/
|
||||
dMatches: '{PH1} matches',
|
||||
/**
|
||||
*@description Text on a button to search previous instance for the ctrl+F search bar
|
||||
*/
|
||||
clearInput: 'Clear',
|
||||
};
|
||||
const str_ = i18n.i18n.registerUIStrings('ui/legacy/SearchableView.ts', UIStrings);
|
||||
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
||||
|
||||
function createClearButton(jslogContext: string): Buttons.Button.Button {
|
||||
const button = new Buttons.Button.Button();
|
||||
button.data = {
|
||||
variant: Buttons.Button.Variant.ICON,
|
||||
size: Buttons.Button.Size.SMALL,
|
||||
jslogContext: jslogContext,
|
||||
title: i18nString(UIStrings.clearInput),
|
||||
iconName: 'cross-circle-filled',
|
||||
};
|
||||
button.ariaLabel = i18nString(UIStrings.clearInput);
|
||||
button.classList.add('clear-button');
|
||||
button.tabIndex = -1;
|
||||
return button;
|
||||
}
|
||||
export class SearchableView extends VBox {
|
||||
private searchProvider: Searchable;
|
||||
private replaceProvider: Replaceable|null;
|
||||
@@ -111,13 +152,11 @@ export class SearchableView extends VBox {
|
||||
private replaceToggleButton: ToolbarToggle;
|
||||
private searchInputElement: HistoryInput;
|
||||
private matchesElement: HTMLElement;
|
||||
private searchNavigationPrevElement: HTMLElement;
|
||||
private searchNavigationNextElement: HTMLElement;
|
||||
private searchNavigationPrevElement: ToolbarButton;
|
||||
private searchNavigationNextElement: ToolbarButton;
|
||||
private readonly replaceInputElement: HTMLInputElement;
|
||||
private readonly buttonsContainer: HTMLElement;
|
||||
private caseSensitiveButton: ToolbarToggle|undefined;
|
||||
private regexButton: ToolbarToggle|undefined;
|
||||
private readonly secondRowButtons: HTMLElement;
|
||||
private caseSensitiveButton: Buttons.Button.Button|undefined;
|
||||
private regexButton: Buttons.Button.Button|undefined;
|
||||
private replaceButtonElement: Buttons.Button.Button;
|
||||
private replaceAllButtonElement: Buttons.Button.Button;
|
||||
private minimalSearchQuerySize: number;
|
||||
@@ -142,93 +181,144 @@ export class SearchableView extends VBox {
|
||||
this.footerElement.setAttribute('jslog', `${VisualLogging.toolbar('search').track({resize: true})}`);
|
||||
|
||||
const replaceToggleToolbar = new Toolbar('replace-toggle-toolbar', this.footerElement);
|
||||
this.replaceToggleButton = new ToolbarToggle(i18nString(UIStrings.replace), 'replace', undefined, 'repalce');
|
||||
this.replaceToggleButton =
|
||||
new ToolbarToggle(i18nString(UIStrings.enableFindAndReplace), 'replace', undefined, 'replace');
|
||||
ARIAUtils.setLabel(this.replaceToggleButton.element, i18nString(UIStrings.enableFindAndReplace));
|
||||
this.replaceToggleButton.addEventListener(ToolbarButton.Events.Click, this.toggleReplace, this);
|
||||
replaceToggleToolbar.appendToolbarItem(this.replaceToggleButton);
|
||||
|
||||
const searchInputElements = this.footerElement.createChild('div', 'toolbar-search-inputs');
|
||||
const searchControlElement = searchInputElements.createChild('div', 'toolbar-search-control');
|
||||
// Elements within `searchInputElements` are added according to their expected tab order.
|
||||
const searchInputElements = this.footerElement.createChild('div', 'search-inputs');
|
||||
const iconAndInput = searchInputElements.createChild('div', 'icon-and-input');
|
||||
const searchIcon = IconButton.Icon.create('search');
|
||||
iconAndInput.appendChild(searchIcon);
|
||||
|
||||
this.searchInputElement = HistoryInput.create();
|
||||
this.searchInputElement.type = 'search';
|
||||
this.searchInputElement.classList.add('search-replace', 'custom-search-input');
|
||||
this.searchInputElement.classList.add('search-replace', 'search');
|
||||
this.searchInputElement.id = 'search-input-field';
|
||||
this.searchInputElement.autocomplete = 'off';
|
||||
this.searchInputElement.placeholder = i18nString(UIStrings.findString);
|
||||
this.searchInputElement.setAttribute(
|
||||
'jslog',
|
||||
`${VisualLogging.textField('search').track({change: true, keydown: 'ArrowUp|ArrowDown|Enter|Escape'})}`);
|
||||
searchControlElement.appendChild(this.searchInputElement);
|
||||
|
||||
this.matchesElement = searchControlElement.createChild('label', 'search-results-matches');
|
||||
this.matchesElement.setAttribute('for', 'search-input-field');
|
||||
|
||||
const searchNavigationElement = searchControlElement.createChild('div', 'toolbar-search-navigation-controls');
|
||||
|
||||
this.searchNavigationPrevElement =
|
||||
searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-prev');
|
||||
this.searchNavigationPrevElement.addEventListener('click', this.onPrevButtonSearch.bind(this), false);
|
||||
Tooltip.install(this.searchNavigationPrevElement, i18nString(UIStrings.searchPrevious));
|
||||
ARIAUtils.setLabel(this.searchNavigationPrevElement, i18nString(UIStrings.searchPrevious));
|
||||
this.searchNavigationPrevElement.setAttribute(
|
||||
'jslog', `${VisualLogging.action('select-previous').track({click: true})}`);
|
||||
|
||||
this.searchNavigationNextElement =
|
||||
searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-next');
|
||||
this.searchNavigationNextElement.addEventListener('click', this.onNextButtonSearch.bind(this), false);
|
||||
Tooltip.install(this.searchNavigationNextElement, i18nString(UIStrings.searchNext));
|
||||
ARIAUtils.setLabel(this.searchNavigationNextElement, i18nString(UIStrings.searchNext));
|
||||
this.searchNavigationPrevElement.setAttribute(
|
||||
'jslog', `${VisualLogging.action('select-next').track({click: true})}`);
|
||||
|
||||
this.searchInputElement.addEventListener('keydown', this.onSearchKeyDown.bind(this), true);
|
||||
this.searchInputElement.addEventListener('input', this.onInput.bind(this), false);
|
||||
this.replaceInputElement =
|
||||
(searchInputElements.createChild('input', 'search-replace toolbar-replace-control hidden') as HTMLInputElement);
|
||||
iconAndInput.appendChild(this.searchInputElement);
|
||||
|
||||
const replaceInputElements = searchInputElements.createChild('div', 'replace-element input-line');
|
||||
this.replaceInputElement = replaceInputElements.createChild('input', 'search-replace') as HTMLInputElement;
|
||||
this.replaceInputElement.addEventListener('keydown', this.onReplaceKeyDown.bind(this), true);
|
||||
this.replaceInputElement.placeholder = i18nString(UIStrings.replace);
|
||||
this.replaceInputElement.setAttribute(
|
||||
'jslog', `${VisualLogging.textField('replace').track({change: true, keydown: 'Enter'})}`);
|
||||
|
||||
this.buttonsContainer = this.footerElement.createChild('div', 'toolbar-search-buttons');
|
||||
const firstRowButtons = this.buttonsContainer.createChild('div', 'first-row-buttons');
|
||||
const replaceInputClearButton = createClearButton('clear-replace-input');
|
||||
replaceInputClearButton.addEventListener('click', () => {
|
||||
this.replaceInputElement.value = '';
|
||||
});
|
||||
replaceInputElements.appendChild(replaceInputClearButton);
|
||||
|
||||
const toolbar = new Toolbar('toolbar-search-options', firstRowButtons);
|
||||
const searchConfigButtons = searchInputElements.createChild('div', 'search-config-buttons');
|
||||
const clearButton = createClearButton('clear-search-input');
|
||||
clearButton.addEventListener('click', () => {
|
||||
this.searchInputElement.value = '';
|
||||
this.clearSearch();
|
||||
});
|
||||
searchConfigButtons.appendChild(clearButton);
|
||||
if (this.searchProvider.supportsRegexSearch()) {
|
||||
const iconName = 'regular-expression';
|
||||
this.regexButton = new Buttons.Button.Button();
|
||||
this.regexButton.data = {
|
||||
variant: Buttons.Button.Variant.ICON_TOGGLE,
|
||||
size: Buttons.Button.Size.SMALL,
|
||||
iconName,
|
||||
toggledIconName: iconName,
|
||||
toggleType: Buttons.Button.ToggleType.PRIMARY,
|
||||
toggled: false,
|
||||
jslogContext: iconName,
|
||||
title: i18nString(UIStrings.enableCaseSensitive),
|
||||
};
|
||||
this.regexButton.addEventListener('click', () => this.toggleRegexSearch());
|
||||
searchConfigButtons.appendChild(this.regexButton);
|
||||
}
|
||||
|
||||
if (this.searchProvider.supportsCaseSensitiveSearch()) {
|
||||
this.caseSensitiveButton = new ToolbarToggle(i18nString(UIStrings.matchCase), undefined, undefined, 'match-case');
|
||||
this.caseSensitiveButton.setText('Aa');
|
||||
this.caseSensitiveButton.addEventListener(ToolbarButton.Events.Click, this.toggleCaseSensitiveSearch, this);
|
||||
toolbar.appendToolbarItem(this.caseSensitiveButton);
|
||||
const iconName = 'match-case';
|
||||
this.caseSensitiveButton = new Buttons.Button.Button();
|
||||
this.caseSensitiveButton.data = {
|
||||
variant: Buttons.Button.Variant.ICON_TOGGLE,
|
||||
size: Buttons.Button.Size.SMALL,
|
||||
iconName,
|
||||
toggledIconName: iconName,
|
||||
toggled: false,
|
||||
toggleType: Buttons.Button.ToggleType.PRIMARY,
|
||||
title: i18nString(UIStrings.enableCaseSensitive),
|
||||
jslogContext: iconName,
|
||||
};
|
||||
this.caseSensitiveButton.addEventListener('click', () => this.toggleCaseSensitiveSearch());
|
||||
searchConfigButtons.appendChild(this.caseSensitiveButton);
|
||||
}
|
||||
|
||||
if (this.searchProvider.supportsRegexSearch()) {
|
||||
this.regexButton =
|
||||
new ToolbarToggle(i18nString(UIStrings.useRegularExpression), undefined, undefined, 'regex-search');
|
||||
this.regexButton.setText('.*');
|
||||
this.regexButton.addEventListener(ToolbarButton.Events.Click, this.toggleRegexSearch, this);
|
||||
toolbar.appendToolbarItem(this.regexButton);
|
||||
}
|
||||
// Introduce a separate element for the background of the `Find` input line (instead of
|
||||
// grouping together the `Find` input together with all search config option buttons
|
||||
// and styling the parent's background).
|
||||
// This allows for a tabbing order that can jump from the `Find` input, to
|
||||
// the `Replace` input, and back to all search config option buttons.
|
||||
searchInputElements.createChild('div', 'input-line search-input-background');
|
||||
|
||||
const cancelButtonElement = createTextButton(i18nString(UIStrings.cancel), this.closeSearch.bind(this), {
|
||||
className: 'search-action-button',
|
||||
const buttonsContainer = this.footerElement.createChild('div', 'toolbar-search-buttons');
|
||||
const firstRowButtons = buttonsContainer.createChild('div', 'first-row-buttons');
|
||||
|
||||
const toolbar = new Toolbar('toolbar-search-options', firstRowButtons);
|
||||
this.searchNavigationPrevElement =
|
||||
new ToolbarButton(i18nString(UIStrings.searchPrevious), 'chevron-up', undefined, 'select-previous');
|
||||
this.searchNavigationPrevElement.addEventListener(ToolbarButton.Events.Click, () => this.onPrevButtonSearch());
|
||||
toolbar.appendToolbarItem(this.searchNavigationPrevElement);
|
||||
ARIAUtils.setLabel(this.searchNavigationPrevElement.element, i18nString(UIStrings.searchPrevious));
|
||||
|
||||
this.searchNavigationNextElement =
|
||||
new ToolbarButton(i18nString(UIStrings.searchNext), 'chevron-down', undefined, 'select-next');
|
||||
this.searchNavigationNextElement.addEventListener(ToolbarButton.Events.Click, () => this.onNextButtonSearch());
|
||||
ARIAUtils.setLabel(this.searchNavigationNextElement.element, i18nString(UIStrings.searchNext));
|
||||
toolbar.appendToolbarItem(this.searchNavigationNextElement);
|
||||
|
||||
const matchesText = new ToolbarText();
|
||||
this.matchesElement = matchesText.element;
|
||||
this.matchesElement.style.fontVariantNumeric = 'tabular-nums';
|
||||
this.matchesElement.style.color = 'var(--sys-color-on-surface-subtle)';
|
||||
this.matchesElement.style.padding = '0 var(--sys-size-3)';
|
||||
this.matchesElement.classList.add('search-results-matches');
|
||||
toolbar.appendToolbarItem(matchesText);
|
||||
|
||||
const cancelButtonElement = new Buttons.Button.Button();
|
||||
cancelButtonElement.data = {
|
||||
variant: Buttons.Button.Variant.TOOLBAR,
|
||||
size: Buttons.Button.Size.REGULAR,
|
||||
iconName: 'cross',
|
||||
title: i18nString(UIStrings.closeSearchBar),
|
||||
jslogContext: 'close-search',
|
||||
});
|
||||
};
|
||||
|
||||
cancelButtonElement.classList.add('close-search-button');
|
||||
cancelButtonElement.addEventListener('click', () => this.closeSearch());
|
||||
firstRowButtons.appendChild(cancelButtonElement);
|
||||
|
||||
this.secondRowButtons = this.buttonsContainer.createChild('div', 'second-row-buttons hidden');
|
||||
const secondRowButtons = buttonsContainer.createChild('div', 'second-row-buttons replace-element');
|
||||
|
||||
this.replaceButtonElement = createTextButton(i18nString(UIStrings.replace), this.replace.bind(this), {
|
||||
className: 'search-action-button',
|
||||
jslogContext: 'replace',
|
||||
});
|
||||
this.replaceButtonElement.disabled = true;
|
||||
this.secondRowButtons.appendChild(this.replaceButtonElement);
|
||||
secondRowButtons.appendChild(this.replaceButtonElement);
|
||||
|
||||
this.replaceAllButtonElement = createTextButton(i18nString(UIStrings.replaceAll), this.replaceAll.bind(this), {
|
||||
className: 'search-action-button',
|
||||
jslogContext: 'replace-all',
|
||||
});
|
||||
this.secondRowButtons.appendChild(this.replaceAllButtonElement);
|
||||
|
||||
secondRowButtons.appendChild(this.replaceAllButtonElement);
|
||||
this.replaceAllButtonElement.disabled = true;
|
||||
|
||||
this.minimalSearchQuerySize = 3;
|
||||
@@ -246,7 +336,8 @@ export class SearchableView extends VBox {
|
||||
|
||||
private toggleCaseSensitiveSearch(): void {
|
||||
if (this.caseSensitiveButton) {
|
||||
this.caseSensitiveButton.setToggled(!this.caseSensitiveButton.toggled());
|
||||
this.caseSensitiveButton.title = this.caseSensitiveButton.toggled ? i18nString(UIStrings.disableCaseSensitive) :
|
||||
i18nString(UIStrings.enableCaseSensitive);
|
||||
}
|
||||
this.saveSetting();
|
||||
this.performSearch(false, true);
|
||||
@@ -254,14 +345,20 @@ export class SearchableView extends VBox {
|
||||
|
||||
private toggleRegexSearch(): void {
|
||||
if (this.regexButton) {
|
||||
this.regexButton.setToggled(!this.regexButton.toggled());
|
||||
this.regexButton.title = this.regexButton.toggled ? i18nString(UIStrings.disableRegularExpression) :
|
||||
i18nString(UIStrings.enableRegularExpression);
|
||||
}
|
||||
this.saveSetting();
|
||||
this.performSearch(false, true);
|
||||
}
|
||||
|
||||
private toggleReplace(): void {
|
||||
this.replaceToggleButton.setToggled(!this.replaceToggleButton.toggled());
|
||||
const replaceEnabled = !this.replaceToggleButton.toggled();
|
||||
this.replaceToggleButton.setToggled(replaceEnabled);
|
||||
const label =
|
||||
replaceEnabled ? i18nString(UIStrings.disableFindAndReplace) : i18nString(UIStrings.enableFindAndReplace);
|
||||
ARIAUtils.setLabel(this.replaceToggleButton.element, label);
|
||||
this.replaceToggleButton.element.title = label;
|
||||
this.updateSecondRowVisibility();
|
||||
}
|
||||
|
||||
@@ -271,10 +368,10 @@ export class SearchableView extends VBox {
|
||||
}
|
||||
const settingValue = this.setting.get() || {};
|
||||
if (this.caseSensitiveButton) {
|
||||
settingValue.caseSensitive = this.caseSensitiveButton.toggled();
|
||||
settingValue.caseSensitive = this.caseSensitiveButton.toggled;
|
||||
}
|
||||
if (this.regexButton) {
|
||||
settingValue.isRegex = this.regexButton.toggled();
|
||||
settingValue.isRegex = this.regexButton.toggled;
|
||||
}
|
||||
this.setting.set(settingValue);
|
||||
}
|
||||
@@ -282,10 +379,18 @@ export class SearchableView extends VBox {
|
||||
private loadSetting(): void {
|
||||
const settingValue = this.setting ? (this.setting.get() || {}) : {};
|
||||
if (this.searchProvider.supportsCaseSensitiveSearch() && this.caseSensitiveButton) {
|
||||
this.caseSensitiveButton.setToggled(Boolean(settingValue.caseSensitive));
|
||||
this.caseSensitiveButton.toggled = Boolean(settingValue.caseSensitive);
|
||||
const label = settingValue.caseSensitive ? i18nString(UIStrings.disableCaseSensitive) :
|
||||
i18nString(UIStrings.enableCaseSensitive);
|
||||
this.caseSensitiveButton.title = label;
|
||||
ARIAUtils.setLabel(this.caseSensitiveButton, label);
|
||||
}
|
||||
if (this.searchProvider.supportsRegexSearch() && this.regexButton) {
|
||||
this.regexButton.setToggled(Boolean(settingValue.isRegex));
|
||||
this.regexButton.toggled = Boolean(settingValue.isRegex);
|
||||
const label = settingValue.regular ? i18nString(UIStrings.disableRegularExpression) :
|
||||
i18nString(UIStrings.enableRegularExpression);
|
||||
this.regexButton.title = label;
|
||||
ARIAUtils.setLabel(this.regexButton, label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,8 +500,8 @@ export class SearchableView extends VBox {
|
||||
private updateSearchNavigationButtonState(enabled: boolean): void {
|
||||
this.replaceButtonElement.disabled = !enabled;
|
||||
this.replaceAllButtonElement.disabled = !enabled;
|
||||
this.searchNavigationPrevElement.classList.toggle('enabled', enabled);
|
||||
this.searchNavigationNextElement.classList.toggle('enabled', enabled);
|
||||
this.searchNavigationPrevElement.setEnabled(enabled);
|
||||
this.searchNavigationNextElement.setEnabled(enabled);
|
||||
}
|
||||
|
||||
private updateSearchMatchesCountAndCurrentMatchIndex(matches: number, currentMatchIndex: number): void {
|
||||
@@ -404,6 +509,8 @@ export class SearchableView extends VBox {
|
||||
this.matchesElement.textContent = '';
|
||||
} else if (matches === 0 || currentMatchIndex >= 0) {
|
||||
this.matchesElement.textContent = i18nString(UIStrings.dOfD, {PH1: currentMatchIndex + 1, PH2: matches});
|
||||
ARIAUtils.setLabel(
|
||||
this.matchesElement, i18nString(UIStrings.accessibledOfD, {PH1: currentMatchIndex + 1, PH2: matches}));
|
||||
} else if (matches === 1) {
|
||||
this.matchesElement.textContent = i18nString(UIStrings.matchString);
|
||||
} else {
|
||||
@@ -480,20 +587,12 @@ export class SearchableView extends VBox {
|
||||
}
|
||||
}
|
||||
|
||||
private onNextButtonSearch(_event: Event): void {
|
||||
if (!this.searchNavigationNextElement.classList.contains('enabled')) {
|
||||
return;
|
||||
}
|
||||
private onNextButtonSearch(): void {
|
||||
this.jumpToNextSearchResult();
|
||||
this.searchInputElement.focus();
|
||||
}
|
||||
|
||||
private onPrevButtonSearch(_event: Event): void {
|
||||
if (!this.searchNavigationPrevElement.classList.contains('enabled')) {
|
||||
return;
|
||||
}
|
||||
private onPrevButtonSearch(): void {
|
||||
this.jumpToNextSearchResult(true);
|
||||
this.searchInputElement.focus();
|
||||
}
|
||||
|
||||
private clearSearch(): void {
|
||||
@@ -526,16 +625,14 @@ export class SearchableView extends VBox {
|
||||
|
||||
private currentSearchConfig(): SearchConfig {
|
||||
const query = this.searchInputElement.value;
|
||||
const caseSensitive = this.caseSensitiveButton ? this.caseSensitiveButton.toggled() : false;
|
||||
const isRegex = this.regexButton ? this.regexButton.toggled() : false;
|
||||
const caseSensitive = this.caseSensitiveButton ? this.caseSensitiveButton.toggled : false;
|
||||
const isRegex = this.regexButton ? this.regexButton.toggled : false;
|
||||
return new SearchConfig(query, caseSensitive, isRegex);
|
||||
}
|
||||
|
||||
private updateSecondRowVisibility(): void {
|
||||
const secondRowVisible = this.replaceToggleButton.toggled();
|
||||
this.footerElementContainer.classList.toggle('replaceable', secondRowVisible);
|
||||
this.secondRowButtons.classList.toggle('hidden', !secondRowVisible);
|
||||
this.replaceInputElement.classList.toggle('hidden', !secondRowVisible);
|
||||
|
||||
if (secondRowVisible) {
|
||||
this.replaceInputElement.focus();
|
||||
@@ -563,7 +660,7 @@ export class SearchableView extends VBox {
|
||||
this.replaceProvider.replaceAllWith(searchConfig, this.replaceInputElement.value);
|
||||
}
|
||||
|
||||
private onInput(_event: Event): void {
|
||||
private onInput(): void {
|
||||
if (!Common.Settings.Settings.instance().moduleSetting('search-as-you-type').get()) {
|
||||
this.clearSearch();
|
||||
return;
|
||||
|
||||
@@ -5,154 +5,155 @@
|
||||
*/
|
||||
|
||||
.search-bar {
|
||||
flex: 0 0 31px;
|
||||
background-color: var(--sys-color-cdt-base-container);
|
||||
flex: 0 0 33px;
|
||||
border-top: 1px solid var(--sys-color-divider);
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.search-bar.replaceable {
|
||||
flex: 0 0 57px;
|
||||
}
|
||||
|
||||
.search-replace {
|
||||
appearance: none;
|
||||
border: 0;
|
||||
/* prevents the input background from going over the border of toolbar-search-control */
|
||||
border-radius: 4px;
|
||||
padding: 0 3px;
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-replace:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.toolbar-search {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.toolbar-search > div {
|
||||
margin: 2px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.toolbar-search-control {
|
||||
display: flex;
|
||||
position: relative;
|
||||
background-color: var(--sys-color-cdt-base-container);
|
||||
}
|
||||
|
||||
.toolbar-search-control,
|
||||
.toolbar-replace-control {
|
||||
border: 1px solid var(--sys-color-neutral-outline);
|
||||
height: 22px;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--sys-color-state-focus-ring);
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-search-inputs {
|
||||
flex-grow: 1;
|
||||
min-width: 150px;
|
||||
|
||||
& input {
|
||||
line-height: 17px;
|
||||
devtools-icon[name="search"] {
|
||||
width: var(--sys-size-8);
|
||||
height: var(--sys-size-8);
|
||||
color: var(--sys-color-on-surface-subtle);
|
||||
margin-right: var(--sys-size-3);
|
||||
}
|
||||
|
||||
&:hover:not(:focus-within) {
|
||||
& .toolbar-search-control {
|
||||
&.replaceable {
|
||||
& devtools-icon[name="search"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.replaceable) .replace-element {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-replace {
|
||||
appearance: none;
|
||||
color: var(--sys-color-on-surface);
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
z-index: 1;
|
||||
flex: 1;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--sys-color-on-surface-subtle);
|
||||
}
|
||||
|
||||
&:placeholder-shown + .clear-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::-webkit-search-cancel-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.search-input-background {
|
||||
grid-row: 1/2;
|
||||
}
|
||||
|
||||
.icon-and-input {
|
||||
margin-left: var(--sys-size-5);
|
||||
grid-row: 1/2;
|
||||
grid-column: 1/2;
|
||||
display: inline-flex;
|
||||
|
||||
&:hover ~ .search-input-background {
|
||||
background-color: var(--sys-color-state-hover-on-subtle);
|
||||
}
|
||||
|
||||
& input {
|
||||
background: none;
|
||||
&:has(.search-replace:placeholder-shown) ~ .search-config-buttons > .clear-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-search-navigation-controls {
|
||||
align-self: stretch;
|
||||
}
|
||||
.toolbar-search {
|
||||
display: flex;
|
||||
margin: var(--sys-size-2);
|
||||
}
|
||||
|
||||
.toolbar-search-navigation {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-repeat: no-repeat;
|
||||
border-left: 1px solid var(--sys-color-divider);
|
||||
opacity: 30%;
|
||||
}
|
||||
.second-row-buttons {
|
||||
height: var(--sys-size-12);
|
||||
display: inline-flex;
|
||||
|
||||
.toolbar-search-navigation.enabled {
|
||||
opacity: 100%;
|
||||
}
|
||||
& > devtools-button {
|
||||
margin-right: var(--sys-size-3);
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-search button.search-action-button {
|
||||
font-weight: 400;
|
||||
height: 22px;
|
||||
width: 87px;
|
||||
}
|
||||
.input-line {
|
||||
grid-column: 1/3;
|
||||
display: inline-flex;
|
||||
padding: 0 var(--sys-size-2) 0 var(--sys-size-5);
|
||||
border-radius: 100px;
|
||||
height: var(--sys-size-10);
|
||||
position: relative;
|
||||
|
||||
.toolbar-search-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
&:not(:has(devtools-button:hover)):hover {
|
||||
background-color: var(--sys-color-state-hover-on-subtle);
|
||||
}
|
||||
|
||||
.toolbar-search-navigation.enabled:active {
|
||||
background-position: 4px 7px, 0 0;
|
||||
}
|
||||
&::before {
|
||||
content: "";
|
||||
box-sizing: inherit;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
background: var(--sys-color-cdt-base);
|
||||
z-index: -10;
|
||||
border-radius: 100px;
|
||||
padding: var(--sys-size-2);
|
||||
}
|
||||
|
||||
.toolbar-search-navigation.toolbar-search-navigation-prev {
|
||||
background-image: var(--image-file-chevron-up);
|
||||
border-left: 1px solid var(--sys-color-neutral-outline);
|
||||
}
|
||||
& > devtools-button {
|
||||
width: var(--sys-size-11);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:host-context(.-theme-with-dark-background) .toolbar-search-navigation {
|
||||
filter: invert(90%);
|
||||
}
|
||||
& devtools-button:last-child(devtools-button) {
|
||||
margin-right: var(--sys-size-4);
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-search-navigation.toolbar-search-navigation-prev.enabled:active {
|
||||
background-image: var(--image-file-chevron-up), var(--sys-color-neutral-container);
|
||||
}
|
||||
.search-inputs {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr min-content;
|
||||
grid-auto-rows: var(--sys-size-12);
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.toolbar-search-navigation.toolbar-search-navigation-next {
|
||||
background-image: var(--image-file-chevron-down);
|
||||
border-left: 1px solid var(--sys-color-neutral-outline);
|
||||
}
|
||||
.first-row-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.toolbar-search-navigation.toolbar-search-navigation-next.enabled:active {
|
||||
background-image: var(--image-file-chevron-down), var(--sys-color-neutral-container);
|
||||
}
|
||||
.toolbar {
|
||||
padding: 0;
|
||||
height: var(--sys-size-12);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-results-matches {
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
padding: 0 4px;
|
||||
color: var(--sys-color-token-subtle);
|
||||
align-self: center;
|
||||
}
|
||||
.search-config-buttons {
|
||||
margin: 0 var(--sys-size-3) 0 auto;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
grid-row: 1/2;
|
||||
grid-column: 2/3;
|
||||
}
|
||||
|
||||
.first-row-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.toolbar-search-buttons {
|
||||
margin-left: var(--sys-size-3);
|
||||
}
|
||||
|
||||
.toolbar-search > .replace-toggle-toolbar {
|
||||
margin: 2px -2px 0 0;
|
||||
}
|
||||
.replace-element:has(input:focus) {
|
||||
box-shadow: inset 0 0 0 2px var(--sys-color-state-focus-ring);
|
||||
}
|
||||
|
||||
.toolbar-search-options {
|
||||
margin: 0 auto;
|
||||
.search-inputs:has(input[type="search"]:focus) .search-input-background {
|
||||
box-shadow: inset 0 0 0 2px var(--sys-color-state-focus-ring);
|
||||
}
|
||||
}
|
||||
|
||||
:host-context(#sources-panel-sources-view) .search-bar {
|
||||
|
||||
@@ -132,7 +132,7 @@ export async function setSearchFilter(text: string) {
|
||||
|
||||
export async function waitForSearchResultNumber(results: number) {
|
||||
const findMatch = async () => {
|
||||
const currentMatch = await waitFor('label[for=\'search-input-field\']');
|
||||
const currentMatch = await waitFor('.search-results-matches');
|
||||
const currentTextContent = currentMatch && await currentMatch.evaluate(el => el.textContent);
|
||||
if (currentTextContent && currentTextContent.endsWith(` ${results}`)) {
|
||||
return currentMatch;
|
||||
@@ -145,7 +145,7 @@ export async function waitForSearchResultNumber(results: number) {
|
||||
export async function findSearchResult(searchResult: string, pollIntrerval: number = 500) {
|
||||
const {frontend} = getBrowserAndPages();
|
||||
const match = await waitFor('#profile-views table.data');
|
||||
const matches = await waitFor('label.search-results-matches');
|
||||
const matches = await waitFor(' .search-results-matches');
|
||||
const matchesText = await matches.evaluate(async element => {
|
||||
return element.textContent;
|
||||
});
|
||||
@@ -154,7 +154,7 @@ export async function findSearchResult(searchResult: string, pollIntrerval: numb
|
||||
} else {
|
||||
await waitForFunction(async () => {
|
||||
const selectedBefore = await waitFor(SELECTED_RESULT);
|
||||
await click('[aria-label="Search next"]');
|
||||
await click('[aria-label="Show next result"]');
|
||||
// Wait until the click has taken effect by checking that the selected
|
||||
// result has changed. This is done to prevent the assertion afterwards
|
||||
// from happening before the next result is fully loaded.
|
||||
|
||||
Reference in New Issue
Block a user