/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { html, ifDefined } from "chrome://global/content/vendor/lit.all.mjs"; import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; const MIN_SHOW_MORE_HEIGHT = 200; /** * A card container to be used in the shopping sidebar. There are three card types. * The default type where no type attribute is required and the card will have no extra functionality. * The "accordion" type will initially not show any content. The card will contain a arrow to expand the * card so all of the content is visible. * * @property {string} label - The label text that will be used for the card header * @property {string} type - (optional) The type of card. No type specified * will be the default card. The other available types are "accordion" and "show-more". */ class ShoppingCard extends MozLitElement { static properties = { label: { type: String }, type: { type: String }, _isExpanded: { type: Boolean }, }; static get queries() { return { detailsEl: "#shopping-details", contentEl: "#content", }; } labelTemplate() { if (this.label) { if (this.type === "accordion") { return html`
`; } return html`
`; } return ""; } cardTemplate() { if (this.type === "accordion") { return html`
${this.labelTemplate()}
`; } else if (this.type === "show-more") { return html` ${this.labelTemplate()}
`; } return html` ${this.labelTemplate()}
`; } onCardToggle() { const action = this.detailsEl.open ? "expanded" : "collapsed"; let l10nId = this.getAttribute("data-l10n-id"); switch (l10nId) { case "shopping-settings-label": Glean.shopping.surfaceSettingsExpandClicked.record({ action }); break; case "shopping-analysis-explainer-label": Glean.shopping.surfaceShowQualityExplainerClicked.record({ action, }); break; } } handleShowMoreButtonClick(e) { this._isExpanded = !this._isExpanded; // toggle show more/show less text e.target.setAttribute( "data-l10n-id", this._isExpanded ? "shopping-show-less-button" : "shopping-show-more-button" ); // toggle content expanded attribute this.contentEl.attributes.expanded.value = this._isExpanded; let action = this._isExpanded ? "expanded" : "collapsed"; Glean.shopping.surfaceShowMoreReviewsButtonClicked.record({ action, }); } enableShowMoreButton() { this._isExpanded = false; this.toggleAttribute("showMoreButtonDisabled", false); this.contentEl.attributes.expanded.value = false; } disableShowMoreButton() { this._isExpanded = true; this.toggleAttribute("showMoreButtonDisabled", true); this.contentEl.attributes.expanded.value = true; } handleChevronButtonClick() { this.detailsEl.open = !this.detailsEl.open; } firstUpdated() { if (this.type !== "show-more") { return; } let contentSlot = this.shadowRoot.querySelector("slot[name='content']"); let contentSlotEls = contentSlot.assignedElements(); if (!contentSlotEls.length) { return; } let slottedDiv = contentSlotEls[0]; this.handleContentSlotResize = this.handleContentSlotResize.bind(this); this.contentResizeObserver = new ResizeObserver( this.handleContentSlotResize ); this.contentResizeObserver.observe(slottedDiv); } disconnectedCallback() { this.contentResizeObserver?.disconnect(); } handleContentSlotResize(entries) { for (let entry of entries) { if (entry.contentRect.height === 0) { return; } if (entry.contentRect.height < MIN_SHOW_MORE_HEIGHT) { this.disableShowMoreButton(); } else if (this.hasAttribute("showMoreButtonDisabled")) { this.enableShowMoreButton(); } } } render() { return html`
${this.cardTemplate()}
`; } } customElements.define("shopping-card", ShoppingCard);