Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2739)

Unified Diff: chrome/browser/resources/md_bookmarks/reducers.js

Issue 2704983002: MD Bookmarks: Proof-of-concept reimplementation of data storage/binding layer (Closed)
Patch Set: Add doc comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/md_bookmarks/reducers.js
diff --git a/chrome/browser/resources/md_bookmarks/reducers.js b/chrome/browser/resources/md_bookmarks/reducers.js
new file mode 100644
index 0000000000000000000000000000000000000000..209f9af1ef3daf2013157ba5d9a97ad69c63eed7
--- /dev/null
+++ b/chrome/browser/resources/md_bookmarks/reducers.js
@@ -0,0 +1,304 @@
+// 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 Module of functions which produce a new page state in response
+ * to an action. Reducers (in the same sense as Array.prototype.reduce) must be
+ * pure functions: they must not modify existing state objects, or make any API
+ * calls.
+ */
+
+cr.define('bookmarks', function() {
+
+ var SelectionState = {};
+
+ /**
+ * @param {SelectionState} selectionState
+ * @param {Action} action
+ * @return {SelectionState}
+ */
+ SelectionState.selectItems = function(selectionState, action) {
+ var newState = {};
+ if (action.add)
+ Object.assign(newState, selectionState.items);
+
+ action.items.forEach(function(id) {
+ newState[id] = true;
+ });
+
+ return /** @type {SelectionState} */ (Object.assign({}, selectionState, {
+ items: newState,
+ anchor: action.anchor,
+ }));
+ };
+
+ /**
+ * @param {SelectionState} selectionState
+ * @return {SelectionState}
+ */
+ SelectionState.deselectAll = function(selectionState) {
+ return /** @type{SelectionState} */ (Object.assign({}, selectionState, {
+ items: {},
+ anchor: null,
+ }));
+ };
+
+ /**
+ * @param {SelectionState} selection
+ * @param {Action} action
+ * @return {SelectionState}
+ */
+ SelectionState.updateSelection = function(selection, action) {
+ switch (action.name) {
+ case 'select-folder':
+ case 'finish-search':
+ return SelectionState.deselectAll(selection);
+ case 'select-items':
+ return SelectionState.selectItems(selection, action);
+ }
+ return selection;
+ };
+
+ var SearchState = {};
+
+ /**
+ * @param {SearchState} search
+ * @param {Action} action
+ * @return {SearchState}
+ */
+ SearchState.startSearch = function(search, action) {
+ return /** @type {SearchState} */ (Object.assign({}, search, {
+ term: action.term,
+ inProgress: true,
+ }));
+ };
+
+ /**
+ * @param {SearchState} search
+ * @param {Action} action
+ * @return {SearchState}
+ */
+ SearchState.finishSearch = function(search, action) {
+ return /** @type {SearchState} */ (Object.assign({}, search, {
+ inProgress: false,
+ results: action.results,
+ }));
+ };
+
+ /** @return {SearchState} */
+ SearchState.clearSearch = function() {
+ return {
+ term: '',
+ inProgress: false,
+ results: [],
+ };
+ };
+
+ /**
+ * @param {SearchState} search
+ * @param {Action} action
+ * @return {SearchState}
+ */
+ SearchState.updateSearch = function(search, action) {
+ switch (action.name) {
+ case 'start-search':
+ return SearchState.startSearch(search, action);
+ case 'select-folder':
+ case 'clear-search':
+ return SearchState.clearSearch();
+ case 'finish-search':
+ return SearchState.finishSearch(search, action);
+ default:
+ return search;
+ }
+ };
+
+ var NodeState = {};
+
+ /**
+ * @param {NodeList} nodes
+ * @param {string} id
+ * @param {function(BookmarkNode):BookmarkNode} callback
+ * @return {NodeList}
+ */
+ NodeState.modifyNode_ = function(nodes, id, callback) {
+ var nodeModification = {};
+ nodeModification[id] = callback(nodes[id]);
+ return Object.assign({}, nodes, nodeModification);
+ };
+
+ /**
+ * @param {NodeList} nodes
+ * @param {Action} action
+ * @return {NodeList}
+ */
+ NodeState.editBookmark = function(nodes, action) {
+ return NodeState.modifyNode_(nodes, action.id, function(node) {
+ return /** @type {BookmarkNode} */ (
+ Object.assign({}, node, action.changeInfo));
+ });
+ };
+
+ /**
+ * @param {NodeList} nodes
+ * @param {Action} action
+ * @return {NodeList}
+ */
+ NodeState.removeBookmark = function(nodes, action) {
+ return NodeState.modifyNode_(nodes, action.parentId, function(node) {
+ var newChildren = node.children.slice();
+ newChildren.splice(action.index, 1);
+ return /** @type {BookmarkNode} */ (
+ Object.assign({}, node, {children: newChildren}));
+ });
+ };
+
+ /**
+ * @param {NodeList} nodes
+ * @param {Action} action
+ * @return {NodeList}
+ */
+ NodeState.updateNodes = function(nodes, action) {
+ switch (action.name) {
+ case 'edit-bookmark':
+ return NodeState.editBookmark(nodes, action);
+ case 'remove-bookmark':
+ return NodeState.removeBookmark(nodes, action);
+ case 'refresh-nodes':
+ return action.nodes;
+ default:
+ return nodes;
+ }
+ };
+
+ var SelectedFolderState = {};
+
+ /**
+ * @param {NodeList} nodes
+ * @param {string} ancestorId
+ * @param {string} childId
+ * @return {boolean}
+ */
+ SelectedFolderState.isAncestorOf = function(nodes, ancestorId, childId) {
+ var currentId = childId;
+ // Work upwards through the tree from child.
+ while (currentId) {
+ if (currentId == ancestorId)
+ return true;
+ currentId = nodes[currentId].parentId;
+ }
+ return false;
+ };
+
+ /**
+ * @param {?string} selectedFolder
+ * @param {Action} action
+ * @param {NodeList} nodes
+ * @return {?string}
+ */
+ SelectedFolderState.updateSelectedFolder = function(
+ selectedFolder, action, nodes) {
+ // TODO(tsergeant): It should not be possible to select a non-folder.
+ switch (action.name) {
+ case 'select-folder':
+ return action.id;
+ case 'change-folder-open':
+ // When hiding the selected folder by closing its ancestor, select
+ // that ancestor instead.
+ if (!action.open && selectedFolder &&
+ SelectedFolderState.isAncestorOf(
+ nodes, action.id, selectedFolder)) {
+ return action.id;
+ }
+ return selectedFolder;
+ case 'finish-search':
+ return null;
+ case 'clear-search':
+ return nodes['0'].children[0];
+ default:
+ return selectedFolder;
+ }
+ };
+
+ var ClosedFolderState = {};
+
+ /**
+ * @param {ClosedFolderState} state
+ * @param {Action} action
+ * @param {NodeList} nodes
+ * @return {ClosedFolderState}
+ */
+ ClosedFolderState.openAncestorsOf = function(state, action, nodes) {
+ var id = action.id;
+ var modifications = {};
+ var parentId = nodes[id].parentId;
+ while (parentId) {
+ if (state[parentId]) {
+ modifications[parentId] = false;
+ }
+ parentId = nodes[parentId].parentId;
+ }
+
+ return Object.assign({}, state, modifications);
+ };
+
+ /**
+ * @param {ClosedFolderState} state
+ * @param {Action} action
+ * @return {ClosedFolderState}
+ */
+ ClosedFolderState.toggleFolderOpen = function(state, action) {
+ var id = action.id;
+ var closed = !action.open;
+ var modification = {};
+ modification[id] = closed;
+
+ return Object.assign({}, state, modification);
+ };
+
+ /**
+ * @param {ClosedFolderState} state
+ * @param {Action} action
+ * @param {NodeList} nodes
+ * @return {ClosedFolderState}
+ */
+ ClosedFolderState.updateClosedFolders = function(state, action, nodes) {
+ switch (action.name) {
+ case 'change-folder-open':
+ return ClosedFolderState.toggleFolderOpen(state, action);
+ case 'select-folder':
+ return ClosedFolderState.openAncestorsOf(state, action, nodes);
+ default:
+ return state;
+ };
+ };
+
+ /**
+ * Root reducer for the Bookmarks page. This is called by the store in
+ * response to an action, and the return value is used to update the UI.
+ * @param {BookmarksPageState} state
+ * @param {Action} action
+ * @return {BookmarksPageState}
+ */
+ function reduceAction(state, action) {
+ return {
+ nodes: NodeState.updateNodes(state.nodes, action),
+ selectedFolder: SelectedFolderState.updateSelectedFolder(
+ state.selectedFolder, action, state.nodes),
+ closedFolders: ClosedFolderState.updateClosedFolders(
+ state.closedFolders, action, state.nodes),
+ search: SearchState.updateSearch(state.search, action),
+ selection: SelectionState.updateSelection(state.selection, action),
+ };
+ }
+
+ return {
+ reduceAction: reduceAction,
+ ClosedFolderState: ClosedFolderState,
+ NodeState: NodeState,
+ SearchState: SearchState,
+ SelectedFolderState: SelectedFolderState,
+ SelectionState: SelectionState,
+ };
+});
« no previous file with comments | « chrome/browser/resources/md_bookmarks/reducers.html ('k') | chrome/browser/resources/md_bookmarks/router.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698