chrome-devtools-frontend
Version:
Chrome DevTools UI
229 lines (199 loc) • 7.19 kB
text/typescript
// Copyright (c) 2020 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 * as i18n from '../i18n/i18n.js';
import * as LitHtml from '../third_party/lit-html/lit-html.js';
import * as Components from '../ui/components/components.js';
export const UIStrings = {
/**
*@description Tooltip text that appears when hovering over a valid address in the address line in the Linear Memory Inspector
*/
enterAddress: 'Enter address',
/**
*@description Tooltip text that appears when hovering over the button to go back in history in the Linear Memory Navigator
*/
goBackInAddressHistory: 'Go back in address history',
/**
*@description Tooltip text that appears when hovering over the button to go forward in history in the Linear Memory Navigator
*/
goForwardInAddressHistory: 'Go forward in address history',
/**
*@description Tooltip text that appears when hovering over the page back icon in the Linear Memory Navigator
*/
previousPage: 'Previous page',
/**
*@description Tooltip text that appears when hovering over the next page icon in the Linear Memory Navigator
*/
nextPage: 'Next page',
/**
*@description Text to refresh the page
*/
refresh: 'Refresh',
};
const str_ = i18n.i18n.registerUIStrings('linear_memory_inspector/LinearMemoryNavigator.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const {render, html} = LitHtml;
export const enum Navigation {
Backward = 'Backward',
Forward = 'Forward',
}
export class AddressInputChangedEvent extends Event {
data: {address: string, mode: Mode};
constructor(address: string, mode: Mode) {
super('address-input-changed');
this.data = {address, mode};
}
}
export class PageNavigationEvent extends Event {
data: Navigation;
constructor(navigation: Navigation) {
super('page-navigation', {});
this.data = navigation;
}
}
export class HistoryNavigationEvent extends Event {
data: Navigation;
constructor(navigation: Navigation) {
super('history-navigation', {});
this.data = navigation;
}
}
export class RefreshRequestedEvent extends Event {
constructor() {
super('refresh-requested', {});
}
}
export interface LinearMemoryNavigatorData {
address: string;
mode: Mode;
valid: boolean;
error: string|undefined;
}
export const enum Mode {
Edit = 'Edit',
Submitted = 'Submitted',
InvalidSubmit = 'InvalidSubmit',
}
export class LinearMemoryNavigator extends HTMLElement {
private readonly shadow = this.attachShadow({mode: 'open'});
private address = '0';
private error: string|undefined = undefined;
private valid = true;
set data(data: LinearMemoryNavigatorData) {
this.address = data.address;
this.error = data.error;
this.valid = data.valid;
this.render();
const addressInput = this.shadow.querySelector<HTMLInputElement>('.address-input');
if (addressInput) {
if (data.mode === Mode.Submitted) {
addressInput.blur();
} else if (data.mode === Mode.InvalidSubmit) {
addressInput.select();
}
}
}
private render(): void {
// Disabled until https://crbug.com/1079231 is fixed.
// clang-format off
const result = html`
<style>
.navigator {
min-height: 24px;
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
overflow: hidden;
align-items: center;
background-color: var(--color-background);
color: var(--color-text-primary);
}
.navigator-item {
display: flex;
white-space: nowrap;
overflow: hidden;
}
.address-input {
text-align: center;
outline: none;
color: var(--color-text-primary);
border: 1px solid var(--color-background-elevation-2);
background: transparent;
}
.address-input.invalid {
color: var(--color-accent-red);
}
.navigator-button {
display: flex;
width: 20px;
height: 20px;
background: transparent;
overflow: hidden;
border: none;
padding: 0;
outline: none;
justify-content: center;
align-items: center;
cursor: pointer;
}
.navigator-button devtools-icon {
height: 14px;
width: 14px;
min-height: 14px;
min-width: 14px;
}
.navigator-button:hover devtools-icon {
--icon-color: var(--color-text-primary);
}
.navigator-button:focus devtools-icon {
--icon-color: var(--color-text-secondary);
}
</style>
<div class="navigator">
<div class="navigator-item">
${this.createButton('ic_undo_16x16_icon', i18nString(UIStrings.goBackInAddressHistory), new HistoryNavigationEvent(Navigation.Backward))}
${this.createButton('ic_redo_16x16_icon', i18nString(UIStrings.goForwardInAddressHistory), new HistoryNavigationEvent(Navigation.Forward))}
</div>
<div class="navigator-item">
${this.createButton('ic_page_prev_16x16_icon', i18nString(UIStrings.previousPage), new PageNavigationEvent(Navigation.Backward))}
${this.createAddressInput()}
${this.createButton('ic_page_next_16x16_icon', i18nString(UIStrings.nextPage), new PageNavigationEvent(Navigation.Forward))}
</div>
${this.createButton('refresh_12x12_icon', i18nString(UIStrings.refresh), new RefreshRequestedEvent())}
</div>
`;
render(result, this.shadow, {eventContext: this});
// clang-format on
}
private createAddressInput(): LitHtml.TemplateResult {
const classMap = {
'address-input': true,
invalid: !this.valid,
};
return html`
<input class=${LitHtml.Directives.classMap(classMap)} data-input="true" .value=${this.address}
title=${this.valid ? i18nString(UIStrings.enterAddress) : this.error} @change=${
this.onAddressChange.bind(this, Mode.Submitted)} @input=${this.onAddressChange.bind(this, Mode.Edit)}/>`;
}
private onAddressChange(mode: Mode, event: Event): void {
const addressInput = event.target as HTMLInputElement;
this.dispatchEvent(new AddressInputChangedEvent(addressInput.value, mode));
}
private createButton(name: string, title: string, event: Event): LitHtml.TemplateResult {
return html`
<button class="navigator-button"
data-button=${event.type} title=${title}
@click=${this.dispatchEvent.bind(this, event)}>
<devtools-icon .data=${
{iconName: name, color: 'var(--color-text-secondary)', width: '14px'} as Components.Icon.IconWithName}>
</devtools-icon>
</button>`;
}
}
customElements.define('devtools-linear-memory-inspector-navigator', LinearMemoryNavigator);
declare global {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface HTMLElementTagNameMap {
'devtools-linear-memory-inspector-navigator': LinearMemoryNavigator;
}
}