The bookmark manager (BMM) is a WebUI surface with a large amount of functionality for managing bookmarks across a relatively simple UI. This document serves as an overview of the page, both in terms of the page features, as well as the code design built up to support it.
The following are some of the main features of the BMM which impact the design of the code:
Real-time updates: The display updates in real-time in response to any change to the bookmark model, whether from the page itself or from any other part of the browser UI.
Item selection: It is possible to select items using either the mouse or keyboard, using ctrl/shift in much the same way as with a powerful file browser like Windows Explorer.
Contextual commands: All viewing/editing commands adapt to the current selection. Most commands have corresponding keyboard shortcuts.
Drag and drop: It is possible to drag bookmarks to move them between folders. This works within the BMM, as well as between native UI and the BMM, and between two different BMM instances from different Chrome profiles.
Policy support: Several policies are respected:
The BMM uses a one-way data flow model that is somewhat different to other Polymer WebUI pages. This model is inspired by Redux, with a simple layer which binds it to Polymer UI components. Designing our data flow in this way has a few primary benefits:
The following is a brief overview of how the data-flow model works. Note that this model is only used for front-end Polymer UI, and is entirely separate to the backend BookmarkModel in C++.
store.js provides a singleton class (
bookmarks.Store) which gives access to a read-only state tree for the entire page (
Any Polymer UI element which wants to be able to data-bind values from the global state should add the behavior
store_client.js). This behavior allows elements to
watch particular values in the store, and be automatically updated when they change.
Actions are the only way to modify the state tree. An
Action objects are created by functions in
To actually modify the state, call
StoreClient.dispatch(action)). This tells the store to process the action and notify UI elements about what has changed.
Note: There's also limited support for Actions which are processed asynchronously. See
dispatchAsync for details, but this probably needs more work before they are generally useful.
Reducers describe how an action affects the page state. These are pure functions located in
reducers.js which take a state and an action, and return a new state.
Importantly, reducers must never modify any part of the input state: instead, they return new objects for any part of the state tree that has changed. By doing this, it is possible for
StoreClient to quickly check for what has changed using
==, and only notify Polymer about things that have actually changed. Plus, these functions are easier to test and debug!
Context menus and keyboard shortcuts are controlled by the
CommandManager, located in
command_manager.js. This includes all logic for commands which open/edit bookmarks, including:
An enum of all possible commands is defined in