// Copyright 2017 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import {assert} from 'chrome://resources/js/assert_ts.js'; import {Action} from 'chrome://resources/js/store_ts.js'; import {IncognitoAvailability, ROOT_NODE_ID} from './constants.js'; import {BookmarkNode, BookmarksPageState, NodeMap} from './types.js'; import {getDescendants, getDisplayedList, normalizeNode} from './util.js'; /** * @fileoverview Module for functions which produce action objects. These are * listed in one place to document available actions and their parameters. */ export type CreateBookmarkAction = Action&{ id: string, parentId: string, parentIndex: number, node: BookmarkNode, }; export function createBookmark( id: string, treeNode: chrome.bookmarks.BookmarkTreeNode): CreateBookmarkAction { return { name: 'create-bookmark', id: id, parentId: treeNode.parentId!, parentIndex: treeNode.index!, node: normalizeNode(treeNode), }; } export type EditBookmarkAction = Action&{ id: string, changeInfo: {title: string, url?: string}, }; export function editBookmark( id: string, changeInfo: {title: string, url?: string}): EditBookmarkAction { return { name: 'edit-bookmark', id: id, changeInfo: changeInfo, }; } export type MoveBookmarkAction = Action&{ id: string, parentId: string, index: number, oldParentId: string, oldIndex: number, }; export function moveBookmark( id: string, parentId: string, index: number, oldParentId: string, oldIndex: number): MoveBookmarkAction { return { name: 'move-bookmark', id: id, parentId: parentId, index: index, oldParentId: oldParentId, oldIndex: oldIndex, }; } export type ReorderChildrenAction = Action&{ id: string, children: string[], }; export function reorderChildren( id: string, newChildIds: string[]): ReorderChildrenAction { return { name: 'reorder-children', id: id, children: newChildIds, }; } export type RemoveBookmarkAction = Action&{ id: string, parentId: string, index: number, descendants: Set, }; export function removeBookmark( id: string, parentId: string, index: number, nodes: NodeMap): RemoveBookmarkAction { const descendants = getDescendants(nodes, id); return { name: 'remove-bookmark', id: id, descendants: descendants, parentId: parentId, index: index, }; } export type RefreshNodesAction = Action&{ nodes: NodeMap, }; export function refreshNodes(nodeMap: NodeMap): RefreshNodesAction { return { name: 'refresh-nodes', nodes: nodeMap, }; } export type SelectFolderAction = Action&{ id: string, }; export function selectFolder(id: string, nodes?: NodeMap): SelectFolderAction| null { if (nodes && (id === ROOT_NODE_ID || !nodes[id] || nodes[id]!.url)) { console.warn('Tried to select invalid folder: ' + id); return null; } return { name: 'select-folder', id: id, }; } export type ChangeFolderOpenAction = Action&{ id: string, open: boolean, }; export function changeFolderOpen( id: string, open: boolean): ChangeFolderOpenAction { return { name: 'change-folder-open', id: id, open: open, }; } export function clearSearch(): Action { return { name: 'clear-search', }; } export function deselectItems(): Action { return { name: 'deselect-items', }; } export type SelectItemsAction = Action&{ clear: boolean, toggle: boolean, anchor: string, items: string[], }; export function selectItem( id: string, state: BookmarksPageState, config: {clear: boolean, range: boolean, toggle: boolean}): SelectItemsAction { assert(!config.toggle || !config.range); assert(!config.toggle || !config.clear); const anchor = state.selection.anchor; const toSelect: string[] = []; let newAnchor = id; if (config.range && anchor) { const displayedList = getDisplayedList(state); const selectedIndex = displayedList.indexOf(id); assert(selectedIndex !== -1); let anchorIndex = displayedList.indexOf(anchor); if (anchorIndex === -1) { anchorIndex = selectedIndex; } // When performing a range selection, don't change the anchor from what // was used in this selection. newAnchor = displayedList[anchorIndex]!; const startIndex = Math.min(anchorIndex, selectedIndex); const endIndex = Math.max(anchorIndex, selectedIndex); for (let i = startIndex; i <= endIndex; i++) { toSelect.push(displayedList[i]!); } } else { toSelect.push(id); } return { name: 'select-items', clear: config.clear, toggle: config.toggle, anchor: newAnchor, items: toSelect, }; } export function selectAll( ids: string[], state: BookmarksPageState, anchor?: string): SelectItemsAction { const finalAnchor: string = anchor ? anchor! : state.selection!.anchor!; return { name: 'select-items', clear: true, toggle: false, anchor: finalAnchor, items: ids, }; } export type UpdateAnchorAction = Action&{ anchor: string, }; export function updateAnchor(id: string): UpdateAnchorAction { return { name: 'update-anchor', anchor: id, }; } export type StartSearchAction = Action&{ term: string, }; export function setSearchTerm(term: string): (Action|StartSearchAction) { if (!term) { return clearSearch(); } return { name: 'start-search', term: term, }; } export type FinishSearchAction = Action&{ results: string[], }; export function setSearchResults(ids: string[]): FinishSearchAction { return { name: 'finish-search', results: ids, }; } export type SetPrefAction = Action&{ value: IncognitoAvailability | boolean, }; export function setIncognitoAvailability(availability: IncognitoAvailability): SetPrefAction { assert(availability !== IncognitoAvailability.FORCED); return { name: 'set-incognito-availability', value: availability, }; } export function setCanEditBookmarks(canEdit: boolean): SetPrefAction { return { name: 'set-can-edit', value: canEdit, }; }