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

Side by Side 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, 9 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview Module of functions which produce a new page state in response
7 * to an action. Reducers (in the same sense as Array.prototype.reduce) must be
8 * pure functions: they must not modify existing state objects, or make any API
9 * calls.
10 */
11
12 cr.define('bookmarks', function() {
13
14 var SelectionState = {};
15
16 /**
17 * @param {SelectionState} selectionState
18 * @param {Action} action
19 * @return {SelectionState}
20 */
21 SelectionState.selectItems = function(selectionState, action) {
22 var newState = {};
23 if (action.add)
24 Object.assign(newState, selectionState.items);
25
26 action.items.forEach(function(id) {
27 newState[id] = true;
28 });
29
30 return /** @type {SelectionState} */ (Object.assign({}, selectionState, {
31 items: newState,
32 anchor: action.anchor,
33 }));
34 };
35
36 /**
37 * @param {SelectionState} selectionState
38 * @return {SelectionState}
39 */
40 SelectionState.deselectAll = function(selectionState) {
41 return /** @type{SelectionState} */ (Object.assign({}, selectionState, {
42 items: {},
43 anchor: null,
44 }));
45 };
46
47 /**
48 * @param {SelectionState} selection
49 * @param {Action} action
50 * @return {SelectionState}
51 */
52 SelectionState.updateSelection = function(selection, action) {
53 switch (action.name) {
54 case 'select-folder':
55 case 'finish-search':
56 return SelectionState.deselectAll(selection);
57 case 'select-items':
58 return SelectionState.selectItems(selection, action);
59 }
60 return selection;
61 };
62
63 var SearchState = {};
64
65 /**
66 * @param {SearchState} search
67 * @param {Action} action
68 * @return {SearchState}
69 */
70 SearchState.startSearch = function(search, action) {
71 return /** @type {SearchState} */ (Object.assign({}, search, {
72 term: action.term,
73 inProgress: true,
74 }));
75 };
76
77 /**
78 * @param {SearchState} search
79 * @param {Action} action
80 * @return {SearchState}
81 */
82 SearchState.finishSearch = function(search, action) {
83 return /** @type {SearchState} */ (Object.assign({}, search, {
84 inProgress: false,
85 results: action.results,
86 }));
87 };
88
89 /** @return {SearchState} */
90 SearchState.clearSearch = function() {
91 return {
92 term: '',
93 inProgress: false,
94 results: [],
95 };
96 };
97
98 /**
99 * @param {SearchState} search
100 * @param {Action} action
101 * @return {SearchState}
102 */
103 SearchState.updateSearch = function(search, action) {
104 switch (action.name) {
105 case 'start-search':
106 return SearchState.startSearch(search, action);
107 case 'select-folder':
108 case 'clear-search':
109 return SearchState.clearSearch();
110 case 'finish-search':
111 return SearchState.finishSearch(search, action);
112 default:
113 return search;
114 }
115 };
116
117 var NodeState = {};
118
119 /**
120 * @param {NodeList} nodes
121 * @param {string} id
122 * @param {function(BookmarkNode):BookmarkNode} callback
123 * @return {NodeList}
124 */
125 NodeState.modifyNode_ = function(nodes, id, callback) {
126 var nodeModification = {};
127 nodeModification[id] = callback(nodes[id]);
128 return Object.assign({}, nodes, nodeModification);
129 };
130
131 /**
132 * @param {NodeList} nodes
133 * @param {Action} action
134 * @return {NodeList}
135 */
136 NodeState.editBookmark = function(nodes, action) {
137 return NodeState.modifyNode_(nodes, action.id, function(node) {
138 return /** @type {BookmarkNode} */ (
139 Object.assign({}, node, action.changeInfo));
140 });
141 };
142
143 /**
144 * @param {NodeList} nodes
145 * @param {Action} action
146 * @return {NodeList}
147 */
148 NodeState.removeBookmark = function(nodes, action) {
149 return NodeState.modifyNode_(nodes, action.parentId, function(node) {
150 var newChildren = node.children.slice();
151 newChildren.splice(action.index, 1);
152 return /** @type {BookmarkNode} */ (
153 Object.assign({}, node, {children: newChildren}));
154 });
155 };
156
157 /**
158 * @param {NodeList} nodes
159 * @param {Action} action
160 * @return {NodeList}
161 */
162 NodeState.updateNodes = function(nodes, action) {
163 switch (action.name) {
164 case 'edit-bookmark':
165 return NodeState.editBookmark(nodes, action);
166 case 'remove-bookmark':
167 return NodeState.removeBookmark(nodes, action);
168 case 'refresh-nodes':
169 return action.nodes;
170 default:
171 return nodes;
172 }
173 };
174
175 var SelectedFolderState = {};
176
177 /**
178 * @param {NodeList} nodes
179 * @param {string} ancestorId
180 * @param {string} childId
181 * @return {boolean}
182 */
183 SelectedFolderState.isAncestorOf = function(nodes, ancestorId, childId) {
184 var currentId = childId;
185 // Work upwards through the tree from child.
186 while (currentId) {
187 if (currentId == ancestorId)
188 return true;
189 currentId = nodes[currentId].parentId;
190 }
191 return false;
192 };
193
194 /**
195 * @param {?string} selectedFolder
196 * @param {Action} action
197 * @param {NodeList} nodes
198 * @return {?string}
199 */
200 SelectedFolderState.updateSelectedFolder = function(
201 selectedFolder, action, nodes) {
202 // TODO(tsergeant): It should not be possible to select a non-folder.
203 switch (action.name) {
204 case 'select-folder':
205 return action.id;
206 case 'change-folder-open':
207 // When hiding the selected folder by closing its ancestor, select
208 // that ancestor instead.
209 if (!action.open && selectedFolder &&
210 SelectedFolderState.isAncestorOf(
211 nodes, action.id, selectedFolder)) {
212 return action.id;
213 }
214 return selectedFolder;
215 case 'finish-search':
216 return null;
217 case 'clear-search':
218 return nodes['0'].children[0];
219 default:
220 return selectedFolder;
221 }
222 };
223
224 var ClosedFolderState = {};
225
226 /**
227 * @param {ClosedFolderState} state
228 * @param {Action} action
229 * @param {NodeList} nodes
230 * @return {ClosedFolderState}
231 */
232 ClosedFolderState.openAncestorsOf = function(state, action, nodes) {
233 var id = action.id;
234 var modifications = {};
235 var parentId = nodes[id].parentId;
236 while (parentId) {
237 if (state[parentId]) {
238 modifications[parentId] = false;
239 }
240 parentId = nodes[parentId].parentId;
241 }
242
243 return Object.assign({}, state, modifications);
244 };
245
246 /**
247 * @param {ClosedFolderState} state
248 * @param {Action} action
249 * @return {ClosedFolderState}
250 */
251 ClosedFolderState.toggleFolderOpen = function(state, action) {
252 var id = action.id;
253 var closed = !action.open;
254 var modification = {};
255 modification[id] = closed;
256
257 return Object.assign({}, state, modification);
258 };
259
260 /**
261 * @param {ClosedFolderState} state
262 * @param {Action} action
263 * @param {NodeList} nodes
264 * @return {ClosedFolderState}
265 */
266 ClosedFolderState.updateClosedFolders = function(state, action, nodes) {
267 switch (action.name) {
268 case 'change-folder-open':
269 return ClosedFolderState.toggleFolderOpen(state, action);
270 case 'select-folder':
271 return ClosedFolderState.openAncestorsOf(state, action, nodes);
272 default:
273 return state;
274 };
275 };
276
277 /**
278 * Root reducer for the Bookmarks page. This is called by the store in
279 * response to an action, and the return value is used to update the UI.
280 * @param {BookmarksPageState} state
281 * @param {Action} action
282 * @return {BookmarksPageState}
283 */
284 function reduceAction(state, action) {
285 return {
286 nodes: NodeState.updateNodes(state.nodes, action),
287 selectedFolder: SelectedFolderState.updateSelectedFolder(
288 state.selectedFolder, action, state.nodes),
289 closedFolders: ClosedFolderState.updateClosedFolders(
290 state.closedFolders, action, state.nodes),
291 search: SearchState.updateSearch(state.search, action),
292 selection: SelectionState.updateSelection(state.selection, action),
293 };
294 }
295
296 return {
297 reduceAction: reduceAction,
298 ClosedFolderState: ClosedFolderState,
299 NodeState: NodeState,
300 SearchState: SearchState,
301 SelectedFolderState: SelectedFolderState,
302 SelectionState: SelectionState,
303 };
304 });
OLDNEW
« 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