chromium/chrome/browser/resources/password_manager/searchable_label.ts

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {quoteString} from 'chrome://resources/js/util.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

export class SearchableLabelElement extends PolymerElement {
  static get is() {
    return 'searchable-label';
  }

  static get template() {
    return null;
  }

  static get properties() {
    return {
      // The text to show in this label.
      title: String,

      // The search term to bold within the title.
      searchTerm: String,
    };
  }

  searchTerm: string;

  static get observers() {
    return ['setSearchedTextToBold_(title, searchTerm)'];
  }

  /**
   * Updates the page title. If a search term is specified, highlights any
   * occurrences of the search term in bold.
   */
  private setSearchedTextToBold_() {
    if (this.title === undefined) {
      return;
    }

    const titleText = this.title;

    if (!this.searchTerm) {
      this.textContent = ` ${titleText} `;
      return;
    }

    const re = new RegExp(quoteString(this.searchTerm), 'gim');
    let i = 0;
    let match;
    this.textContent = '';
    while (match = re.exec(titleText)) {
      if (match.index > i) {
        this.appendTextElement('span', titleText.slice(i, match.index));
      }
      i = re.lastIndex;
      // Mark the highlighted text in bold.
      this.appendTextElement('b', titleText.substring(match.index, i));
    }
    if (i < titleText.length) {
      this.appendTextElement('span', titleText.slice(i));
    }
  }

  private appendTextElement(type: string, text: string) {
    const element = document.createElement(type);
    element.textContent = text;
    this.appendChild(element);
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'searchable-label': SearchableLabelElement;
  }
}

customElements.define(SearchableLabelElement.is, SearchableLabelElement);