blob: e8fc29aa5dc044512116c32aa8810f2717af5eed [file] [log] [blame]
// Copyright 2022 The Fuchsia 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 { css, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { SEARCH_PLACEHOLDER } from '../src/constants';
import { FilterExpression, parseFilter } from '../src/filter';
import { BaseElement } from './base_element';
export const PARSE_ERROR_MSG_ID = 'parse-error-msg';
@customElement('log-control')
export class LogControl extends BaseElement {
static styles = [
BaseElement.styles,
css`
:host {
flex-grow: 5;
}
input#search {
font-family: var(--vscode-editor-font-family);
font-size: var(--vscode-editor-font-size);
font-weight: var(--vscode-editor-font-weight);
height: var(--log-action-height);
margin-bottom: var(--input-margin-vertical);
}
input#search:focus {
outline-style: solid;
outline-offset: -1px;
}
p#parse-error-msg {
color: var(--vscode-errorForeground);
}
`];
public static readonly filterChangeEvent: string = 'filter-change';
@state()
private errorMessage: string = '';
@property({ attribute: true, type: String })
public value: string = '';
constructor(filterText: string | undefined) {
super();
this.value = filterText ?? '';
if (this.value.length > 0) {
const result = parseFilter(this.value);
if (!result.ok) {
this.errorMessage = result.error;
}
}
}
render() {
return html`
<div>
<input
id="search"
type="text"
placeholder="${SEARCH_PLACEHOLDER}"
value="${this.value}"
@keypress="${this.onInputKeyPress}"
@keydown="${this.onInputKeyDown}"
>
<p id="${PARSE_ERROR_MSG_ID}">${this.errorMessage}</p>
</div>
`;
}
/**
* Resets the state of the log control.
*/
public reset() {
this.value = '';
}
/**
* Handles a keypress on the search input. On submission, it parses the filter and publishes it.
* @param event a keyboard event
*/
private onInputKeyPress(event: KeyboardEvent) {
if (event.key === 'Enter') {
const search = this.shadowRoot?.getElementById('search')! as HTMLInputElement;
const searchText = search.value.trim();
this.value = searchText;
this.errorMessage = '';
if (searchText.length === 0) {
this.dispatchFilterChangeEvent(new FilterExpression([]), '');
} else {
const searchText = this.value.trim();
const result = parseFilter(searchText);
if (result.ok) {
this.dispatchFilterChangeEvent(result.value, searchText);
} else {
this.errorMessage = result.error;
}
}
}
}
private onInputKeyDown(event: KeyboardEvent) {
if (event.key === 'Backspace'
|| event.key === 'Delete'
|| event.key === 'Clear') {
this.errorMessage = '';
}
}
/**
* Dispatches an event carrying a filter that was submitted in the search input.
* @param filter the filter that will be dispatched.
* @param text the filter in text form.
*/
private dispatchFilterChangeEvent(filter: FilterExpression, text: string) {
this.dispatchEvent(new CustomEvent(LogControl.filterChangeEvent, {
detail: { filter, text },
}));
}
}