blob: 2432d5959b50641063a75122941d5da0e7075036 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Listener functions which translate events from the
* chrome.bookmarks API into actions to modify the local page state.
*/
cr.define('bookmarks.ApiListener', function() {
/** @type {boolean} */
let trackUpdates = false;
/** @type {!Array<string>} */
let updatedItems = [];
let debouncer;
/**
* Batches UI updates so that no changes will be made to UI until the next
* task after the last call to this method. This is useful for listeners which
* can be called in a tight loop by UI actions.
*/
function batchUIUpdates() {
if (!debouncer) {
debouncer = new bookmarks.Debouncer(
() => bookmarks.Store.getInstance().endBatchUpdate());
}
if (debouncer.done()) {
bookmarks.Store.getInstance().beginBatchUpdate();
debouncer.reset();
}
debouncer.restartTimeout();
}
/**
* Tracks any items that are created or moved.
*/
function trackUpdatedItems() {
trackUpdates = true;
}
function highlightUpdatedItemsImpl() {
if (!trackUpdates)
return;
document.dispatchEvent(new CustomEvent('highlight-items', {
detail: updatedItems,
}));
updatedItems = [];
trackUpdates = false;
}
/**
* Highlights any items that have been updated since |trackUpdatedItems| was
* called. Should be called after a user action causes new items to appear in
* the main list.
*/
function highlightUpdatedItems() {
// Ensure that the items are highlighted after the current batch update (if
// there is one) is completed.
assert(debouncer);
debouncer.promise.then(highlightUpdatedItemsImpl);
}
/** @param {cr.ui.Action} action */
function dispatch(action) {
bookmarks.Store.getInstance().dispatch(action);
}
/**
* @param {string} id
* @param {{title: string, url: (string|undefined)}} changeInfo
*/
function onBookmarkChanged(id, changeInfo) {
dispatch(bookmarks.actions.editBookmark(id, changeInfo));
}
/**
* @param {string} id
* @param {BookmarkTreeNode} treeNode
*/
function onBookmarkCreated(id, treeNode) {
batchUIUpdates();
if (trackUpdates)
updatedItems.push(id);
dispatch(bookmarks.actions.createBookmark(id, treeNode));
}
/**
* @param {string} id
* @param {{parentId: string, index: number}} removeInfo
*/
function onBookmarkRemoved(id, removeInfo) {
batchUIUpdates();
const nodes = bookmarks.Store.getInstance().data.nodes;
dispatch(bookmarks.actions.removeBookmark(
id, removeInfo.parentId, removeInfo.index, nodes));
}
/**
* @param {string} id
* @param {{
* parentId: string,
* index: number,
* oldParentId: string,
* oldIndex: number
* }} moveInfo
*/
function onBookmarkMoved(id, moveInfo) {
batchUIUpdates();
if (trackUpdates)
updatedItems.push(id);
dispatch(bookmarks.actions.moveBookmark(
id, moveInfo.parentId, moveInfo.index, moveInfo.oldParentId,
moveInfo.oldIndex));
}
/**
* @param {string} id
* @param {{childIds: !Array<string>}} reorderInfo
*/
function onChildrenReordered(id, reorderInfo) {
dispatch(bookmarks.actions.reorderChildren(id, reorderInfo.childIds));
}
/**
* Pauses the Created handler during an import. The imported nodes will all be
* loaded at once when the import is finished.
*/
function onImportBegan() {
chrome.bookmarks.onCreated.removeListener(onBookmarkCreated);
}
function onImportEnded() {
chrome.bookmarks.getTree(function(results) {
dispatch(bookmarks.actions.refreshNodes(
bookmarks.util.normalizeNodes(results[0])));
});
chrome.bookmarks.onCreated.addListener(onBookmarkCreated);
}
/**
* @param {IncognitoAvailability} availability
*/
function onIncognitoAvailabilityChanged(availability) {
dispatch(bookmarks.actions.setIncognitoAvailability(availability));
}
/**
* @param {boolean} canEdit
*/
function onCanEditBookmarksChanged(canEdit) {
dispatch(bookmarks.actions.setCanEditBookmarks(canEdit));
}
const listeners = [
{api: chrome.bookmarks.onChanged, fn: onBookmarkChanged},
{api: chrome.bookmarks.onChildrenReordered, fn: onChildrenReordered},
{api: chrome.bookmarks.onCreated, fn: onBookmarkCreated},
{api: chrome.bookmarks.onMoved, fn: onBookmarkMoved},
{api: chrome.bookmarks.onRemoved, fn: onBookmarkRemoved},
{api: chrome.bookmarks.onImportBegan, fn: onImportBegan},
{api: chrome.bookmarks.onImportEnded, fn: onImportEnded},
];
function init() {
listeners.forEach((listener) => listener.api.addListener(listener.fn));
cr.sendWithPromise('getIncognitoAvailability')
.then(onIncognitoAvailabilityChanged);
cr.addWebUIListener(
'incognito-availability-changed', onIncognitoAvailabilityChanged);
cr.sendWithPromise('getCanEditBookmarks').then(onCanEditBookmarksChanged);
cr.addWebUIListener(
'can-edit-bookmarks-changed', onCanEditBookmarksChanged);
}
function destroy() {
listeners.forEach((listener) => listener.api.removeListener(listener.fn));
cr.removeWebUIListener(
'incognito-availability-changed', onIncognitoAvailabilityChanged);
cr.removeWebUIListener(
'can-edit-bookmarks-changed', onCanEditBookmarksChanged);
}
return {
init: init,
destroy: destroy,
trackUpdatedItems: trackUpdatedItems,
highlightUpdatedItems: highlightUpdatedItems,
};
});