tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

card-container.mjs (6596B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 import {
      6  classMap,
      7  html,
      8  ifDefined,
      9  when,
     10 } from "chrome://global/content/vendor/lit.all.mjs";
     11 import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
     12 
     13 /**
     14 * A collapsible card container to be used throughout Firefox View
     15 *
     16 * @property {string} sectionLabel - The aria-label used for the section landmark if the header is hidden with hideHeader
     17 * @property {boolean} hideHeader - Optional property given if the card container should not display a header
     18 * @property {boolean} isEmptyState - Optional property given if the card is used within an empty state
     19 * @property {boolean} isInnerCard - Optional property given if the card a nested card within another card and given a border rather than box-shadow
     20 * @property {boolean} preserveCollapseState - Whether or not the expanded/collapsed state should persist
     21 * @property {string} shortPageName - Page name that the 'View all' link will navigate to and the preserveCollapseState pref will use
     22 * @property {boolean} showViewAll - True if you need to display a 'View all' header link to navigate
     23 * @property {boolean} toggleDisabled - Optional property given if the card container should not be collapsible
     24 * @property {boolean} removeBlockEndMargin - True if you need to remove the block end margin on the card container
     25 */
     26 class CardContainer extends MozLitElement {
     27  constructor() {
     28    super();
     29    this.initiallyExpanded = true;
     30    this.isExpanded = false;
     31    this.visible = false;
     32  }
     33 
     34  static properties = {
     35    sectionLabel: { type: String },
     36    hideHeader: { type: Boolean },
     37    isExpanded: { type: Boolean },
     38    isEmptyState: { type: Boolean },
     39    isInnerCard: { type: Boolean },
     40    preserveCollapseState: { type: Boolean },
     41    shortPageName: { type: String },
     42    showViewAll: { type: Boolean },
     43    toggleDisabled: { type: Boolean },
     44    removeBlockEndMargin: { type: Boolean },
     45    visible: { type: Boolean },
     46  };
     47 
     48  static queries = {
     49    detailsEl: "details",
     50    mainSlot: "slot[name=main]",
     51    summaryEl: "summary",
     52    viewAllLink: ".view-all-link",
     53  };
     54 
     55  get detailsExpanded() {
     56    return this.detailsEl.hasAttribute("open");
     57  }
     58 
     59  get detailsOpenPrefValue() {
     60    const prefName = this.shortPageName
     61      ? `browser.tabs.firefox-view.ui-state.${this.shortPageName}.open`
     62      : null;
     63    if (prefName && Services.prefs.prefHasUserValue(prefName)) {
     64      return Services.prefs.getBoolPref(prefName);
     65    }
     66    return null;
     67  }
     68 
     69  connectedCallback() {
     70    super.connectedCallback();
     71    this.isExpanded = this.detailsOpenPrefValue ?? this.initiallyExpanded;
     72  }
     73 
     74  onToggleContainer() {
     75    if (this.isExpanded == this.detailsExpanded) {
     76      return;
     77    }
     78    this.isExpanded = this.detailsExpanded;
     79 
     80    this.updateTabLists();
     81 
     82    if (!this.shortPageName) {
     83      return;
     84    }
     85 
     86    if (this.preserveCollapseState) {
     87      const prefName = this.shortPageName
     88        ? `browser.tabs.firefox-view.ui-state.${this.shortPageName}.open`
     89        : null;
     90      Services.prefs.setBoolPref(prefName, this.isExpanded);
     91    }
     92 
     93    // Record telemetry
     94    Glean.firefoxviewNext[
     95      `card${this.isExpanded ? "Expanded" : "Collapsed"}CardContainer`
     96    ].record({
     97      data_type: this.shortPageName,
     98    });
     99  }
    100 
    101  viewAllClicked() {
    102    this.dispatchEvent(
    103      new CustomEvent("card-container-view-all", {
    104        bubbles: true,
    105        composed: true,
    106      })
    107    );
    108  }
    109 
    110  willUpdate(changes) {
    111    if (changes.has("visible")) {
    112      this.updateTabLists();
    113    }
    114  }
    115 
    116  updateTabLists() {
    117    let tabLists = this.querySelectorAll(
    118      "fxview-tab-list, opentabs-tab-list, syncedtabs-tab-list"
    119    );
    120    if (tabLists) {
    121      tabLists.forEach(tabList => {
    122        tabList.updatesPaused = !this.visible || !this.isExpanded;
    123      });
    124    }
    125  }
    126 
    127  render() {
    128    return html`
    129      <link
    130        rel="stylesheet"
    131        href="chrome://browser/content/firefoxview/card-container.css"
    132      />
    133      ${when(
    134        this.toggleDisabled,
    135        () =>
    136          html`<div
    137            class=${classMap({
    138              "card-container": true,
    139              inner: this.isInnerCard,
    140              "empty-state": this.isEmptyState && !this.isInnerCard,
    141            })}
    142          >
    143            <span
    144              id="header"
    145              class="card-container-header"
    146              ?hidden=${ifDefined(this.hideHeader)}
    147              toggleDisabled
    148              ?withViewAll=${this.showViewAll}
    149            >
    150              <slot name="header"></slot>
    151              <slot name="secondary-header"></slot>
    152            </span>
    153            <a
    154              href="about:firefoxview#${this.shortPageName}"
    155              @click=${this.viewAllClicked}
    156              class="view-all-link"
    157              data-l10n-id="firefoxview-view-all-link"
    158              ?hidden=${!this.showViewAll}
    159            ></a>
    160            <slot name="main"></slot>
    161            <slot name="footer" class="card-container-footer"></slot>
    162          </div>`,
    163        () =>
    164          html`<details
    165            class=${classMap({
    166              "card-container": true,
    167              inner: this.isInnerCard,
    168              "empty-state": this.isEmptyState && !this.isInnerCard,
    169            })}
    170            ?open=${this.isExpanded}
    171            ?isOpenTabsView=${this.removeBlockEndMargin}
    172            @toggle=${this.onToggleContainer}
    173            role=${this.isInnerCard ? "presentation" : "group"}
    174          >
    175            <summary
    176              class="card-container-header"
    177              ?hidden=${ifDefined(this.hideHeader)}
    178              ?withViewAll=${this.showViewAll}
    179            >
    180              <span
    181                class="icon chevron-icon"
    182                role="presentation"
    183                data-l10n-id=${this.isExpanded
    184                  ? "firefoxview-collapse-button-hide"
    185                  : "firefoxview-collapse-button-show"}
    186              ></span>
    187              <slot name="header"></slot>
    188            </summary>
    189            <a
    190              href="about:firefoxview#${this.shortPageName}"
    191              @click=${this.viewAllClicked}
    192              class="view-all-link"
    193              data-l10n-id="firefoxview-view-all-link"
    194              ?hidden=${!this.showViewAll}
    195            ></a>
    196            <slot name="main"></slot>
    197            <slot name="footer" class="card-container-footer"></slot>
    198          </details>`
    199      )}
    200    `;
    201  }
    202 }
    203 customElements.define("card-container", CardContainer);