/* 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, when, } from "chrome://global/content/vendor/lit.all.mjs"; import { escapeHtmlEntities, isSearchEnabled, navigateToLink, } from "./helpers.mjs"; import { ViewPage } from "./viewpage.mjs"; // eslint-disable-next-line import/no-unassigned-import import "chrome://browser/content/migration/migration-wizard.mjs"; import { HistoryController } from "./HistoryController.mjs"; // eslint-disable-next-line import/no-unassigned-import import "chrome://global/content/elements/moz-button.mjs"; const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { ProfileAge: "resource://gre/modules/ProfileAge.sys.mjs", }); let XPCOMUtils = ChromeUtils.importESModule( "resource://gre/modules/XPCOMUtils.sys.mjs" ).XPCOMUtils; const NEVER_REMEMBER_HISTORY_PREF = "browser.privatebrowsing.autostart"; const HAS_IMPORTED_HISTORY_PREF = "browser.migrate.interactions.history"; const IMPORT_HISTORY_DISMISSED_PREF = "browser.tabs.firefox-view.importHistory.dismissed"; const SEARCH_RESULTS_LIMIT = 300; class HistoryInView extends ViewPage { constructor() { super(); this._started = false; // Setting maxTabsLength to -1 for no max this.maxTabsLength = -1; this.profileAge = 8; this.fullyUpdated = false; this.cumulativeSearches = 0; } controller = new HistoryController(this, { searchResultsLimit: SEARCH_RESULTS_LIMIT, }); start() { if (this._started) { return; } this._started = true; this.controller.updateAllHistoryItems(); this.toggleVisibilityInCardContainer(); } async connectedCallback() { super.connectedCallback(); XPCOMUtils.defineLazyPreferenceGetter( this, "importHistoryDismissedPref", IMPORT_HISTORY_DISMISSED_PREF, false, () => { this.requestUpdate(); } ); XPCOMUtils.defineLazyPreferenceGetter( this, "hasImportedHistoryPref", HAS_IMPORTED_HISTORY_PREF, false, () => { this.requestUpdate(); } ); if (!this.importHistoryDismissedPref && !this.hasImportedHistoryPrefs) { let profileAccessor = await lazy.ProfileAge(); let profileCreateTime = await profileAccessor.created; let timeNow = new Date().getTime(); let profileAge = timeNow - profileCreateTime; // Convert milliseconds to days this.profileAge = profileAge / 1000 / 60 / 60 / 24; } } stop() { if (!this._started) { return; } this._started = false; this.toggleVisibilityInCardContainer(); } disconnectedCallback() { super.disconnectedCallback(); this.stop(); this.migrationWizardDialog?.removeEventListener( "MigrationWizard:Close", this.migrationWizardDialog ); } viewVisibleCallback() { this.start(); } viewHiddenCallback() { this.stop(); } static queries = { cards: { all: "card-container:not([hidden])" }, migrationWizardDialog: "#migrationWizardDialog", emptyState: "fxview-empty-state", lists: { all: "fxview-tab-list" }, showAllHistoryBtn: ".show-all-history-button", searchTextbox: "fxview-search-textbox", sortInputs: { all: "input[name=history-sort-option]" }, panelList: "panel-list", }; static properties = { // Making profileAge a reactive property for testing profileAge: { type: Number }, }; async getUpdateComplete() { await super.getUpdateComplete(); await Promise.all(Array.from(this.cards).map(card => card.updateComplete)); } onPrimaryAction(e) { navigateToLink(e); // Record telemetry Services.telemetry.recordEvent( "firefoxview_next", "history", "visits", null, {} ); if (this.controller.searchQuery) { const searchesHistogram = Services.telemetry.getKeyedHistogramById( "FIREFOX_VIEW_CUMULATIVE_SEARCHES" ); searchesHistogram.add("history", this.cumulativeSearches); this.cumulativeSearches = 0; } } onSecondaryAction(e) { this.triggerNode = e.originalTarget; e.target.querySelector("panel-list").toggle(e.detail.originalEvent); } deleteFromHistory(e) { this.controller.deleteFromHistory(); this.recordContextMenuTelemetry("delete-from-history", e); } async onChangeSortOption(e) { await this.controller.onChangeSortOption(e); Services.telemetry.recordEvent( "firefoxview_next", "sort_history", "tabs", null, { sort_type: this.controller.sortOption, search_start: this.controller.searchQuery ? "true" : "false", } ); } async onSearchQuery(e) { await this.controller.onSearchQuery(e); this.cumulativeSearches = this.controller.searchQuery ? this.cumulativeSearches + 1 : 0; } showAllHistory() { // Record telemetry Services.telemetry.recordEvent( "firefoxview_next", "show_all_history", "tabs", null, {} ); // Open History view in Library window this.getWindow().PlacesCommandHook.showPlacesOrganizer("History"); } async openMigrationWizard() { let migrationWizardDialog = this.migrationWizardDialog; if (migrationWizardDialog.open) { return; } await customElements.whenDefined("migration-wizard"); // If we've been opened before, remove the old wizard and insert a // new one to put it back into its starting state. if (!migrationWizardDialog.firstElementChild) { let wizard = document.createElement("migration-wizard"); wizard.toggleAttribute("dialog-mode", true); migrationWizardDialog.appendChild(wizard); } migrationWizardDialog.firstElementChild.requestState(); this.migrationWizardDialog.addEventListener( "MigrationWizard:Close", function (e) { e.currentTarget.close(); } ); migrationWizardDialog.showModal(); } shouldShowImportBanner() { return ( this.profileAge < 8 && !this.hasImportedHistoryPref && !this.importHistoryDismissedPref ); } dismissImportHistory() { Services.prefs.setBoolPref(IMPORT_HISTORY_DISMISSED_PREF, true); } updated() { this.fullyUpdated = true; if (this.lists?.length) { this.toggleVisibilityInCardContainer(); } } panelListTemplate() { return html`

`; } /** * The template to use for cards-container. */ get cardsTemplate() { if (this.controller.searchResults) { return this.#searchResultsTemplate(); } else if (this.controller.allHistoryItems.size) { return this.#historyCardsTemplate(); } return this.#emptyMessageTemplate(); } #historyCardsTemplate() { let cardsTemplate = []; if ( this.controller.sortOption === "date" && this.controller.historyMapByDate.length ) { this.controller.historyMapByDate.forEach(historyItem => { if (historyItem.items.length) { let dateArg = JSON.stringify({ date: historyItem.items[0].time }); cardsTemplate.push(html`

${this.panelListTemplate()}
`); } }); } else if (this.controller.historyMapBySite.length) { this.controller.historyMapBySite.forEach(historyItem => { if (historyItem.items.length) { cardsTemplate.push(html`

${historyItem.domain}

${this.panelListTemplate()}
`); } }); } return cardsTemplate; } #emptyMessageTemplate() { let descriptionHeader; let descriptionLabels; let descriptionLink; if (Services.prefs.getBoolPref(NEVER_REMEMBER_HISTORY_PREF, false)) { // History pref set to never remember history descriptionHeader = "firefoxview-dont-remember-history-empty-header"; descriptionLabels = [ "firefoxview-dont-remember-history-empty-description", "firefoxview-dont-remember-history-empty-description-two", ]; descriptionLink = { url: "about:preferences#privacy", name: "history-settings-url-two", }; } else { descriptionHeader = "firefoxview-history-empty-header"; descriptionLabels = [ "firefoxview-history-empty-description", "firefoxview-history-empty-description-two", ]; descriptionLink = { url: "about:preferences#privacy", name: "history-settings-url", }; } return html` `; } #searchResultsTemplate() { return html`

${when( this.controller.searchResults.length, () => html`

` )} ${this.panelListTemplate()}
`; } render() { if (!this.selectedTab) { return null; } return html`
${when( isSearchEnabled(), () => html`
` )}
${this.cardsTemplate}
`; } willUpdate() { this.fullyUpdated = false; if (this.controller.allHistoryItems.size) { // onChangeSortOption() will update history data once it has been fetched // from the API. this.controller.createHistoryMaps(); } } } customElements.define("view-history", HistoryInView);