| // 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 }, |
| })); |
| } |
| } |