// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '/strings.m.js';
import './icons.html.js';
import './power_bookmark_row.js';
import '//bookmarks-side-panel.top-chrome/shared/sp_empty_state.js';
import '//bookmarks-side-panel.top-chrome/shared/sp_heading.js';
import '//bookmarks-side-panel.top-chrome/shared/sp_icons.html.js';
import '//resources/cr_elements/cr_button/cr_button.js';
import '//resources/cr_elements/cr_icon/cr_icon.js';
import '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
import '//resources/cr_elements/cr_lazy_list/cr_lazy_list.js';
import '//resources/cr_elements/icons.html.js';
import './power_bookmarks_add_folder_button.js';
import './power_bookmarks_list_header.js';
import { browserProxyFactory as priceTrackingBrowserProxyFactory } from '//resources/cr_components/commerce/price_tracking.mojom-webui.js';
import { getInstance as getAnnouncerInstance } from '//resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
import { FocusOutlineManager } from '//resources/js/focus_outline_manager.js';
import { loadTimeData } from '//resources/js/load_time_data.js';
import { CrLitElement } from '//resources/lit/v3_0/lit.rollup.js';
import { ActionSource, ViewType } from './bookmarks.mojom-webui.js';
import { BookmarksApiProxyImpl } from './bookmarks_api_proxy.js';
import { KeyArrowNavigationService } from './keyboard_arrow_navigation_service.js';
import { BOOKMARK_ROW_LOAD_EVENT } from './power_bookmark_row.js';
import { PowerBookmarksDragManager } from './power_bookmarks_drag_manager.js';
import { getCss } from './power_bookmarks_list.css.js';
import { getHtml } from './power_bookmarks_list.html.js';
import { editingDisabledByPolicy, PowerBookmarksService } from './power_bookmarks_service.js';
import { getFolderLabel } from './power_bookmarks_utils.js';
function getBookmarkName(bookmark) {
    return bookmark.title || bookmark.url || '';
}
import { SearchAction, recordFolderAdded, recordSearchCTR, recordViewType, recordBookmarksShown } from './power_bookmarks_metrics.js';
export class PowerBookmarksListElement extends CrLitElement {
    static get is() {
        return 'power-bookmarks-list';
    }
    static get styles() {
        return getCss();
    }
    render() {
        return getHtml.bind(this)();
    }
    static get properties() {
        return {
            displayList_: {
                type: Array,
            },
            compact_: {
                type: Boolean,
            },
            contextMenuBookmark: { type: Object },
            activeFolderPath: {
                type: Array,
                notify: true,
            },
            imageUrls_: {
                type: Object,
            },
            labels: {
                type: Array,
            },
            sortOrder: { type: Number },
            activeSortIndex: { type: Number },
            editing: {
                type: Boolean,
            },
            selectedBookmarks: {
                type: Object,
            },
            renamingId: {
                type: String,
                notify: true,
            },
            hasLoadedData_: {
                type: Boolean,
            },
            searchQuery: { type: String },
            shoppingCollectionFolderId_: { type: String },
            updatedElementIds_: {
                type: Array,
            },
            hasSomeActiveFilter: {
                type: Boolean,
            },
            hasShownBookmarks: {
                type: Boolean,
                notify: true,
            },
            canDrag_: {
                type: Boolean,
            },
            hasActiveDrag_: {
                type: Boolean,
            },
            sectionVisibility_: {
                type: Object,
            },
            hasFolders_: {
                type: Boolean,
                reflect: true,
            },
            firstSecondaryIndex_: {
                type: Number,
            },
            scrollTarget_: {
                type: Object,
            },
        };
    }
    bookmarksApi_ = BookmarksApiProxyImpl.getInstance();
    priceTrackingProxy_ = priceTrackingBrowserProxyFactory.getInstance();
    bookmarksService_ = PowerBookmarksService.getInstance();
    keyArrowNavigationService_;
    bookmarksDragManager_;
    focusOutlineManager_ = null;
    shownBookmarksResizeObserver_;
    recordCountMetricsOnNextUpdate_ = false;
    rebuildNavigationElementsTimerId_ = -1;
    expandedFolderIds_ = new Set();
    #activeFolderPath_accessor_storage = [];
    get activeFolderPath() { return this.#activeFolderPath_accessor_storage; }
    set activeFolderPath(value) { this.#activeFolderPath_accessor_storage = value; }
    #activeSortIndex_accessor_storage = 0;
    get activeSortIndex() { return this.#activeSortIndex_accessor_storage; }
    set activeSortIndex(value) { this.#activeSortIndex_accessor_storage = value; }
    #sortOrder_accessor_storage = 0;
    get sortOrder() { return this.#sortOrder_accessor_storage; }
    set sortOrder(value) { this.#sortOrder_accessor_storage = value; }
    #contextMenuBookmark_accessor_storage;
    get contextMenuBookmark() { return this.#contextMenuBookmark_accessor_storage; }
    set contextMenuBookmark(value) { this.#contextMenuBookmark_accessor_storage = value; }
    #editing_accessor_storage = false;
    get editing() { return this.#editing_accessor_storage; }
    set editing(value) { this.#editing_accessor_storage = value; }
    #hasSomeActiveFilter_accessor_storage = false;
    get hasSomeActiveFilter() { return this.#hasSomeActiveFilter_accessor_storage; }
    set hasSomeActiveFilter(value) { this.#hasSomeActiveFilter_accessor_storage = value; }
    #hasShownBookmarks_accessor_storage = false;
    get hasShownBookmarks() { return this.#hasShownBookmarks_accessor_storage; }
    set hasShownBookmarks(value) { this.#hasShownBookmarks_accessor_storage = value; }
    #labels_accessor_storage = [];
    get labels() { return this.#labels_accessor_storage; }
    set labels(value) { this.#labels_accessor_storage = value; }
    #renamingId_accessor_storage = '';
    get renamingId() { return this.#renamingId_accessor_storage; }
    set renamingId(value) { this.#renamingId_accessor_storage = value; }
    #searchQuery_accessor_storage;
    get searchQuery() { return this.#searchQuery_accessor_storage; }
    set searchQuery(value) { this.#searchQuery_accessor_storage = value; }
    #compact__accessor_storage = loadTimeData.getInteger('viewType') === 0;
    get compact_() { return this.#compact__accessor_storage; }
    set compact_(value) { this.#compact__accessor_storage = value; }
    #displayList__accessor_storage = [];
    get displayList_() { return this.#displayList__accessor_storage; }
    set displayList_(value) { this.#displayList__accessor_storage = value; }
    #imageUrls__accessor_storage = {};
    get imageUrls_() { return this.#imageUrls__accessor_storage; }
    set imageUrls_(value) { this.#imageUrls__accessor_storage = value; }
    #selectedBookmarks_accessor_storage = {};
    get selectedBookmarks() { return this.#selectedBookmarks_accessor_storage; }
    set selectedBookmarks(value) { this.#selectedBookmarks_accessor_storage = value; }
    #hasLoadedData__accessor_storage = false;
    get hasLoadedData_() { return this.#hasLoadedData__accessor_storage; }
    set hasLoadedData_(value) { this.#hasLoadedData__accessor_storage = value; }
    #canDrag__accessor_storage = true;
    get canDrag_() { return this.#canDrag__accessor_storage; }
    set canDrag_(value) { this.#canDrag__accessor_storage = value; }
    #hasActiveDrag__accessor_storage = false;
    get hasActiveDrag_() { return this.#hasActiveDrag__accessor_storage; }
    set hasActiveDrag_(value) { this.#hasActiveDrag__accessor_storage = value; }
    #sectionVisibility__accessor_storage = {};
    get sectionVisibility_() { return this.#sectionVisibility__accessor_storage; }
    set sectionVisibility_(value) { this.#sectionVisibility__accessor_storage = value; }
    #hasFolders__accessor_storage = false;
    get hasFolders_() { return this.#hasFolders__accessor_storage; }
    set hasFolders_(value) { this.#hasFolders__accessor_storage = value; }
    #scrollTarget__accessor_storage = document.documentElement;
    get scrollTarget_() { return this.#scrollTarget__accessor_storage; }
    set scrollTarget_(value) { this.#scrollTarget__accessor_storage = value; }
    #shoppingCollectionFolderId__accessor_storage = '';
    get shoppingCollectionFolderId_() { return this.#shoppingCollectionFolderId__accessor_storage; }
    set shoppingCollectionFolderId_(value) { this.#shoppingCollectionFolderId__accessor_storage = value; }
    #updatedElementIds__accessor_storage = [];
    get updatedElementIds_() { return this.#updatedElementIds__accessor_storage; }
    set updatedElementIds_(value) { this.#updatedElementIds__accessor_storage = value; }
    #firstSecondaryIndex__accessor_storage = -1;
    get firstSecondaryIndex_() { return this.#firstSecondaryIndex__accessor_storage; }
    set firstSecondaryIndex_(value) { this.#firstSecondaryIndex__accessor_storage = value; }
    constructor() {
        super();
        const keyArrowNavigationService = new KeyArrowNavigationService(this, 'power-bookmark-row:not([hidden])');
        KeyArrowNavigationService.setInstance(keyArrowNavigationService);
        this.keyArrowNavigationService_ = keyArrowNavigationService;
        this.bookmarksDragManager_ = new PowerBookmarksDragManager(this);
    }
    connectedCallback() {
        super.connectedCallback();
        this.focusOutlineManager_ = FocusOutlineManager.forDocument(document);
        this.shownBookmarksResizeObserver_ =
            new ResizeObserver(this.onShownBookmarksResize_.bind(this));
        this.shownBookmarksResizeObserver_.observe(this.$.bookmarks);
        this.updateListScrollOffset_();
        this.bookmarksDragManager_.startObserving();
        this.updateShoppingCollectionFolderId_();
        this.recordMetricsOnConnected_();
        this.keyArrowNavigationService_.startListening();
        this.addEventListener(BOOKMARK_ROW_LOAD_EVENT, () => {
            this.rebuildNavigationElements_();
        });
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.shownBookmarksResizeObserver_.disconnect();
        this.shownBookmarksResizeObserver_ = undefined;
        this.bookmarksDragManager_.stopObserving();
        this.keyArrowNavigationService_.stopListening();
        if (this.rebuildNavigationElementsTimerId_ !== -1) {
            clearTimeout(this.rebuildNavigationElementsTimerId_);
            this.rebuildNavigationElementsTimerId_ = -1;
        }
    }
    willUpdate(changedProperties) {
        super.willUpdate(changedProperties);
        const changedPrivateProperties = changedProperties;
        if (changedPrivateProperties.has('searchQuery')) {
            this.onSearchChanged_();
        }
        let displayListChanged = false;
        if (changedPrivateProperties.has('activeFolderPath') ||
            changedPrivateProperties.has('labels') ||
            changedPrivateProperties.has('sortOrder') ||
            changedPrivateProperties.has('searchQuery') ||
            changedPrivateProperties.has('hasSomeActiveFilter')) {
            this.updateDisplayList_();
            displayListChanged = true;
        }
        if (changedPrivateProperties.has('editing') ||
            changedPrivateProperties.has('renamingId') ||
            changedPrivateProperties.has('hasSomeActiveFilter')) {
            this.canDrag_ = this.computeCanDrag_();
        }
        if (changedPrivateProperties.has('hasLoadedData_') || displayListChanged) {
            this.sectionVisibility_ = this.computeSectionVisibility_();
        }
    }
    firstUpdated(changedProperties) {
        super.firstUpdated(changedProperties);
        this.scrollTarget_ = this.$.scroller;
    }
    updated(changedProperties) {
        super.updated(changedProperties);
        const changedPrivateProperties = changedProperties;
        if (changedPrivateProperties.has('compact_')) {
            this.updateListScrollOffset_();
        }
        if (changedPrivateProperties.has('canDrag_')) {
            this.onCanDragChange_();
        }
    }
    setImageUrl(bookmark, url) {
        this.imageUrls_[bookmark.id] = url;
        this.imageUrls_ = { ...this.imageUrls_ };
    }
    onBookmarksLoaded() {
        this.updateDisplayList_();
        this.hasLoadedData_ = true;
    }
    onBookmarkChanged(id) {
        const bookmark = this.bookmarksService_.findBookmarkWithId(id);
        this.updatedElementIds_ = [bookmark.id];
        if (this.bookmarkShouldShow_(bookmark) ||
            this.bookmarkIsShowing_(bookmark)) {
            this.updateDisplayList_();
        }
    }
    async scrollToBookmark_(bookmark) {
        const index = this.displayList_.findIndex(item => item.bookmark.id === bookmark.id);
        if (index === -1) {
            return;
        }
        const element = await this.$.list.ensureItemRendered(index);
        element.scrollIntoView({ block: 'nearest' });
    }
    onBookmarkAdded(bookmark, parent) {
        if (this.bookmarkShouldShow_(bookmark)) {
            this.updateShoppingCollectionFolderId_();
            this.updateDisplayList_();
            if (bookmark.url) {
                getAnnouncerInstance().announce(loadTimeData.getStringF('bookmarkCreated', getBookmarkName(bookmark)));
            }
            else {
                getAnnouncerInstance().announce(loadTimeData.getStringF('bookmarkFolderCreated', getBookmarkName(bookmark)));
            }
            this.updateComplete.then(async () => {
                await this.$.list.updateComplete;
                this.scrollToBookmark_(bookmark);
            });
        }
        this.updatedElementIds_ = [bookmark.id, parent.id];
    }
    onBookmarkMoved(bookmark, oldParent, newParent) {
        const shouldShow = this.bookmarkShouldShow_(bookmark);
        const isShowing = this.bookmarkIsShowing_(bookmark);
        let noMetrics = false;
        if (oldParent === newParent && shouldShow) {
            getAnnouncerInstance().announce(loadTimeData.getStringF('bookmarkReordered', getBookmarkName(bookmark)));
            noMetrics = true;
        }
        else if ((shouldShow !== isShowing) ||
            (shouldShow && this.hasSomeActiveFilter)) {
            const scrollTop = this.$.scroller.scrollTop;
            getAnnouncerInstance().announce(loadTimeData.getStringF('bookmarkMoved', getBookmarkName(bookmark), getBookmarkName(newParent)));
            this.updateComplete.then(() => {
                this.$.scroller.scrollTop = scrollTop;
            });
        }
        this.updateDisplayList_(noMetrics);
        this.updatedElementIds_ = [newParent.id, oldParent.id];
        // If the new parent folder is visible, notify to ensure its displayed
        // child count is updated.
        // If compact, we must resize open folders
        if (this.compact_) {
            this.notifyBookmarksListResize_();
        }
    }
    onBookmarkRemoved(bookmark) {
        getAnnouncerInstance().announce(loadTimeData.getStringF('bookmarkDeleted', getBookmarkName(bookmark)));
        const scrollTop = this.$.scroller.scrollTop;
        this.updateDisplayList_(/* noMetrics = */ true);
        this.updateComplete.then(() => {
            this.$.scroller.scrollTop = scrollTop;
        });
        if (this.shoppingCollectionFolderId_ === bookmark.id) {
            this.shoppingCollectionFolderId_ = '';
        }
        this.updatedElementIds_ = [bookmark.parentId];
    }
    /** PowerBookmarksDragDelegate */
    getFallbackBookmark() {
        // Returning other bookmarks folder allows moving bookmarks to the root
        // folder
        if (this.compact_) {
            return this.bookmarksService_.findBookmarkWithId(loadTimeData.getString('otherBookmarksId'));
        }
        return this.getParentFolder();
    }
    /** PowerBookmarksDragDelegate */
    getFallbackDropTargetElement() {
        return this;
    }
    /** PowerBookmarksDragDelegate */
    onFinishDrop(dropTarget) {
        this.updateDisplayList_();
        this.focusBookmark_(dropTarget.id);
        // Show the focus state immediately after dropping a bookmark to indicate
        // where the bookmark was moved to, and remove the state immediately after
        // the next mouse event.
        this.focusOutlineManager_.visible = true;
        document.addEventListener('mousedown', () => {
            this.focusOutlineManager_.visible = false;
        }, { once: true });
    }
    /** PowerBookmarksDragDelegate */
    setHasActiveDrag(hasActiveDrag) {
        this.hasActiveDrag_ = hasActiveDrag;
    }
    clickBookmarkRowForTests(bookmark) {
        const event = new CustomEvent('row-clicked', {
            bubbles: true,
            composed: true,
            detail: {
                bookmark: bookmark,
                event: new MouseEvent('row-clicked'),
            },
        });
        this.onRowClicked_(event);
    }
    /**
     * Returns the KeyboardNavigationService instance for testing.
     */
    getKeyboardNavigationServiceforTesting() {
        return this.keyArrowNavigationService_;
    }
    getDragManagerForTesting() {
        return this.bookmarksDragManager_;
    }
    flushNavigationElementsDebouncerForTesting() {
        if (this.rebuildNavigationElementsTimerId_ === -1) {
            return;
        }
        clearTimeout(this.rebuildNavigationElementsTimerId_);
        this.keyArrowNavigationService_.rebuildNavigationElements();
        this.rebuildNavigationElementsTimerId_ = -1;
    }
    computeHasFolders_() {
        if (!this.displayList_ || this.displayList_.length === 0) {
            return false;
        }
        return this.displayList_.some(item => !item.bookmark.url);
    }
    computeCanDrag_() {
        return !this.editing && !this.renamingId && !this.hasSomeActiveFilter;
    }
    focusBookmark_(id) {
        const bookmarkElement = this.shadowRoot.querySelector(`#bookmark-${id}`);
        if (bookmarkElement) {
            bookmarkElement.focus();
        }
    }
    bookmarkIsShowing_(bookmark) {
        return this.displayList_.some(item => item.bookmark.id === bookmark.id);
    }
    /**
     * Returns true if the given node is either the current active folder or a
     * root folder that isn't shown itself while the all bookmarks list is shown.
     */
    visibleParent_(parent) {
        const activeFolder = this.getActiveFolder();
        return (!activeFolder &&
            parent.parentId === loadTimeData.getString('rootBookmarkId') &&
            !this.bookmarkIsShowing_(parent)) ||
            parent === activeFolder;
    }
    bookmarkShouldShow_(bookmark) {
        if (this.hasSomeActiveFilter) {
            return this.bookmarksService_.bookmarkMatchesSearchQueryAndLabels(bookmark, this.labels, this.searchQuery);
        }
        return this.visibleParent_(this.bookmarksService_.findBookmarkWithId(bookmark.parentId));
    }
    getActiveFolder() {
        if (this.activeFolderPath.length) {
            return this.activeFolderPath[this.activeFolderPath.length - 1];
        }
        return undefined;
    }
    getBookmarkRowElement(id) {
        return this.shadowRoot.querySelector(`#bookmark-${id}`);
    }
    getBookmarksListRole_() {
        return this.editing ? 'listbox' : 'list';
    }
    updateShoppingCollectionFolderId_() {
        this.priceTrackingProxy_.handler.getShoppingCollectionBookmarkFolderId()
            .then(res => {
            this.shoppingCollectionFolderId_ = res.collectionId.toString();
        });
    }
    getActiveFolderLabel_() {
        return getFolderLabel(this.getActiveFolder());
    }
    /**
     * Recursively flattens the child bookmarks and sub-folders of an expanded
     * folder into the flat display list array, calculating appropriate
     * indentation depth.
     */
    flattenFolder_(folder, depth, list) {
        if (!this.expandedFolderIds_.has(folder.id) || !folder.children) {
            return;
        }
        const sortedChildren = folder.children.slice();
        this.bookmarksService_.sortBookmarks(sortedChildren, this.activeSortIndex);
        for (const child of sortedChildren) {
            list.push({ bookmark: child, depth: depth + 1 });
            if (!child.url) {
                this.flattenFolder_(child, depth + 1, list);
            }
        }
    }
    /**
     * Update the lists of bookmarks and folders displayed to the user.
     */
    updateDisplayList_(noMetrics = false) {
        const activeFolder = this.getActiveFolder();
        const primaryList = this.bookmarksService_.filterBookmarks(activeFolder, this.sortOrder, this.searchQuery, this.labels);
        this.bookmarksService_.refreshDataForBookmarks(primaryList);
        let secondaryList = [];
        if (this.hasSomeActiveFilter && !!activeFolder) {
            secondaryList = this.bookmarksService_.filterBookmarks(undefined, this.sortOrder, this.searchQuery, this.labels, activeFolder);
            this.bookmarksService_.refreshDataForBookmarks(secondaryList);
        }
        const displayList = [];
        for (const node of primaryList) {
            displayList.push({ bookmark: node, depth: 0 });
            if (!node.url) {
                this.flattenFolder_(node, 0, displayList);
            }
        }
        const firstSecondaryIndex = displayList.length;
        for (const node of secondaryList) {
            displayList.push({ bookmark: node, depth: 0 });
            if (!node.url) {
                this.flattenFolder_(node, 0, displayList);
            }
        }
        this.firstSecondaryIndex_ =
            secondaryList.length > 0 ? firstSecondaryIndex : -1;
        this.displayList_ = displayList;
        this.hasShownBookmarks = this.computeHasShownBookmarks_();
        this.hasFolders_ = this.computeHasFolders_();
        this.updateListScrollOffset_();
        // After the lists are updated and all children updates are complete,
        // notify cr-lazy-list to resize.
        this.updateComplete.then(async () => {
            // Allow time for child Lit elements to render.
            await new Promise(resolve => setTimeout(resolve, 0));
            this.notifyBookmarksListResize_();
            // Make sure the keyboard navigation tree is rebuilt whenever the
            // cr-lazy-list is updated.
            this.rebuildNavigationElements_();
            if (this.recordCountMetricsOnNextUpdate_ && this.hasLoadedData_ &&
                !noMetrics) {
                this.recordBookmarkCountMetrics_();
            }
        });
    }
    onSearchChanged_() {
        this.recordCountMetricsOnNextUpdate_ = true;
    }
    updateListScrollOffset_() {
        // Set scrollOffset so the cr-lazy-list scrolling accounts for the space the
        // other scrolling UI elements take.
        this.updateComplete.then(() => {
            const bookmarksOffsetTop = this.$.bookmarks.offsetTop;
            this.$.list.scrollOffset = this.$.list.offsetTop - bookmarksOffsetTop;
        });
    }
    onCanDragChange_() {
        if (this.canDrag_) {
            this.bookmarksDragManager_.startObserving();
        }
        else {
            this.bookmarksDragManager_.stopObserving();
        }
    }
    recordMetricsOnConnected_() {
        recordViewType(this.compact_);
        recordSearchCTR(SearchAction.SHOWN);
        this.recordCountMetricsOnNextUpdate_ = true;
    }
    rebuildNavigationElements_() {
        if (this.rebuildNavigationElementsTimerId_ !== -1) {
            clearTimeout(this.rebuildNavigationElementsTimerId_);
        }
        this.rebuildNavigationElementsTimerId_ = setTimeout(() => {
            this.rebuildNavigationElementsTimerId_ = -1;
            this.keyArrowNavigationService_.rebuildNavigationElements();
            this.fire('rebuild-navigation-elements');
            if (this.recordCountMetricsOnNextUpdate_ && this.hasLoadedData_) {
                this.recordBookmarkCountMetricsInternal_();
                this.recordCountMetricsOnNextUpdate_ = false;
            }
        }, 1);
    }
    recordBookmarkCountMetrics_() {
        this.recordCountMetricsOnNextUpdate_ = true;
        this.rebuildNavigationElements_();
    }
    recordBookmarkCountMetricsInternal_() {
        recordBookmarksShown(this.keyArrowNavigationService_.getElementCount(), this.hasSomeActiveFilter);
        this.fire('bookmark-count-recorded');
    }
    /**
     * Recursively removes all descendant folder IDs of a collapsed folder from
     * the expandedFolderIds_ Set, so they are initialized collapsed when
     * re-opened.
     */
    collapseDescendants_(folder) {
        if (!folder.children) {
            return;
        }
        for (const child of folder.children) {
            if (!child.url) {
                this.expandedFolderIds_.delete(child.id);
                this.collapseDescendants_(child);
            }
        }
    }
    onPowerBookmarkToggle_(event) {
        const { bookmark, expanded } = event.detail;
        if (expanded) {
            this.expandedFolderIds_.add(bookmark.id);
        }
        else {
            this.expandedFolderIds_.delete(bookmark.id);
            this.collapseDescendants_(bookmark);
        }
        this.updateDisplayList_(/* noMetrics =*/ true);
        this.notifyBookmarksListResize_();
        this.recordBookmarkCountMetrics_();
    }
    onListItemSizeChanged_() {
        this.notifyBookmarksListResize_();
    }
    /**
     * Focuses the parent row of a child row, delegating focus backward traversal.
     */
    onPowerBookmarkRowFocusParent_(e) {
        const parentElement = this.shadowRoot.querySelector(`#bookmark-${e.detail.parentId}`);
        if (parentElement) {
            parentElement.focus();
            this.keyArrowNavigationService_.setCurrentFocusIndex(parentElement);
        }
    }
    /**
     * Invoked when the user clicks a power bookmarks row. This will either
     * display children in the case of a folder row, or open the URL in the case
     * of a bookmark row.
     */
    onRowClicked_(event) {
        event.preventDefault();
        event.stopPropagation();
        if (!this.editing) {
            if (event.detail.bookmark.children) {
                this.recordCountMetricsOnNextUpdate_ = true;
                this.activeFolderPath =
                    [...this.activeFolderPath, event.detail.bookmark];
                this.dispatchActiveFolderPathChanged_();
                this.fire('clear-search');
                this.updateComplete.then(async () => {
                    if (this.displayList_.length > 0) {
                        const element = await this.$.list.ensureItemRendered(0);
                        element.focus();
                    }
                });
            }
            else {
                this.bookmarksApi_.openBookmark(event.detail.bookmark.id, this.activeFolderPath.length, {
                    middleButton: event.detail.event.button === 1,
                    altKey: event.detail.event.altKey,
                    ctrlKey: event.detail.event.ctrlKey,
                    metaKey: event.detail.event.metaKey,
                    shiftKey: event.detail.event.shiftKey,
                }, ActionSource.kBookmark);
            }
        }
        // TODO(crbug.com/493823435): Determine if this iron-list related workaround
        // is still necessary now that the list has been migrated to cr-lazy-list.
        if (event.target) {
            event.target.blur();
        }
    }
    onCheckboxChange_(event) {
        event.preventDefault();
        event.stopPropagation();
        const isSelected = Object.entries(this.selectedBookmarks)
            .find(([key, _val]) => key === event.detail.bookmark.id)?.[1] ??
            false;
        if ((event.detail.checked && !isSelected) ||
            (!event.detail.checked && isSelected)) {
            this.fire('row-selected-change', {
                id: event.detail.bookmark.id,
                checked: event.detail.checked,
            });
        }
    }
    onInputChange_(event) {
        const newName = event.detail.value;
        if (newName != null) {
            this.bookmarksApi_.renameBookmark(event.detail.bookmark.id, newName);
        }
        this.renamingId = '';
    }
    getRowHeading_(index) {
        const showHeadings = this.sectionVisibility_ && this.sectionVisibility_.filterHeadings;
        if (!showHeadings) {
            return '';
        }
        if (index === this.firstSecondaryIndex_) {
            return loadTimeData.getString('secondaryFilterHeading');
        }
        if (index === 0) {
            return loadTimeData.getStringF('primaryFilterHeading', this.getActiveFolderLabel_());
        }
        return '';
    }
    notifyBookmarksListResize_() {
        this.$.list.fillCurrentViewport();
    }
    getSelectedBookmarksList_() {
        const selectedEntries = Object.entries(this.selectedBookmarks).filter(([_id, selected]) => selected);
        const selectedIds = selectedEntries.map(([id, _selected]) => id);
        return selectedIds
            .map((id) => this.bookmarksService_.findBookmarkWithId(id))
            .filter(b => !!b);
    }
    /**
     * Toggles the given label between active and inactive.
     */
    /**
     * Moves the displayed folders up one level when the back button is clicked.
     */
    onBackClicked_() {
        this.recordCountMetricsOnNextUpdate_ = true;
        this.activeFolderPath = this.activeFolderPath.slice(0, -1);
        this.dispatchActiveFolderPathChanged_();
    }
    dispatchActiveFolderPathChanged_() {
        this.fire('active-folder-path-changed', { value: this.activeFolderPath });
    }
    onShowContextMenu_(event) {
        this.fire('show-context-menu', event.detail);
    }
    onTrailingIconClicked_(event) {
        this.onShowContextMenu_(event);
    }
    getParentFolder() {
        return this.getActiveFolder() ||
            this.bookmarksService_.findBookmarkWithId(loadTimeData.getString('otherBookmarksId'));
    }
    onAddNewFolderClick_(event) {
        event.preventDefault();
        event.stopPropagation();
        const newParent = this.getParentFolder();
        if (editingDisabledByPolicy([newParent])) {
            this.fire('disabled-feature');
            return;
        }
        recordFolderAdded();
        this.bookmarksApi_
            .createFolder(newParent.id, loadTimeData.getString('newFolderTitle'))
            .then((result) => {
            this.renamingId = result.newFolderId;
        });
    }
    onViewToggled_() {
        this.compact_ = !this.compact_;
        if (this.compact_) {
            this.updateDisplayList_();
        }
        this.notifyBookmarksListResize_();
        recordViewType(this.compact_);
        const viewType = this.compact_ ? ViewType.kCompact : ViewType.kExpanded;
        this.bookmarksApi_.setViewType(viewType);
    }
    computeHasShownBookmarks_() {
        return !!this.displayList_ && this.displayList_.length > 0;
    }
    computeSectionVisibility_() {
        if (!this.hasLoadedData_) {
            return {};
        }
        const hasActiveFolder = this.activeFolderPath.length > 0;
        const hasShownBookmarks = this.hasShownBookmarks;
        const hasSomeActiveFilter = this.hasSomeActiveFilter;
        return {
            heading: !hasSomeActiveFilter && (hasActiveFolder || hasShownBookmarks),
            filterHeadings: hasSomeActiveFilter,
            folderEmptyState: !hasShownBookmarks && !hasSomeActiveFilter && hasActiveFolder,
            newFolderButton: !hasSomeActiveFilter,
            bookmarksList: hasShownBookmarks,
        };
    }
    onShownBookmarksResize_() {
        // The cr-lazy-list of `displayList_` is in a dynamically sized card.
        // Any time the size changes, let cr-lazy-list know so that cr-lazy-list can
        // properly adjust to its possibly new height.
        this.notifyBookmarksListResize_();
        this.fire('has-scrollbars-changed', this.$.scroller.scrollHeight > this.$.scroller.offsetHeight);
    }
    onSortChanged_(e) {
        this.activeSortIndex = e.detail.index;
        this.sortOrder = e.detail.sortOrder;
    }
}
customElements.define(PowerBookmarksListElement.is, PowerBookmarksListElement);
