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

Side by Side Diff: chrome/browser/resources/history/history.js

Issue 807593005: Make downloads list keyboard shortcuts more consistent. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Apply feedback Created 5 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 <include src="../uber/uber_utils.js"> 5 <include src="../uber/uber_utils.js">
6 <include src="history_focus_manager.js"> 6 <include src="history_focus_manager.js">
7 7
8 /////////////////////////////////////////////////////////////////////////////// 8 ///////////////////////////////////////////////////////////////////////////////
9 // Globals: 9 // Globals:
10 /** @const */ var RESULTS_PER_PAGE = 150; 10 /** @const */ var RESULTS_PER_PAGE = 150;
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 chrome.send('removeBookmark', [self.url_]); 243 chrome.send('removeBookmark', [self.url_]);
244 244
245 this.model_.getView().onBeforeUnstarred(this); 245 this.model_.getView().onBeforeUnstarred(this);
246 bookmarkSection.classList.remove('starred'); 246 bookmarkSection.classList.remove('starred');
247 this.model_.getView().onAfterUnstarred(this); 247 this.model_.getView().onAfterUnstarred(this);
248 248
249 bookmarkSection.removeEventListener('click', f); 249 bookmarkSection.removeEventListener('click', f);
250 e.preventDefault(); 250 e.preventDefault();
251 }.bind(this)); 251 }.bind(this));
252 } 252 }
253
254 if (focusless)
255 bookmarkSection.tabIndex = -1;
256
253 entryBox.appendChild(bookmarkSection); 257 entryBox.appendChild(bookmarkSection);
254 258
255 var visitEntryWrapper = /** @type {HTMLElement} */( 259 var visitEntryWrapper = /** @type {HTMLElement} */(
256 entryBox.appendChild(document.createElement('div'))); 260 entryBox.appendChild(document.createElement('div')));
257 if (addTitleFavicon || this.blockedVisit) 261 if (addTitleFavicon || this.blockedVisit)
258 visitEntryWrapper.classList.add('visit-entry'); 262 visitEntryWrapper.classList.add('visit-entry');
259 if (this.blockedVisit) { 263 if (this.blockedVisit) {
260 visitEntryWrapper.classList.add('blocked-indicator'); 264 visitEntryWrapper.classList.add('blocked-indicator');
261 visitEntryWrapper.appendChild(this.getVisitAttemptDOM_()); 265 visitEntryWrapper.appendChild(this.getVisitAttemptDOM_());
262 } else { 266 } else {
(...skipping 614 matching lines...) Expand 10 before | Expand all | Expand 10 after
877 881
878 /** 882 /**
879 * Gets whether we are grouped by domain. 883 * Gets whether we are grouped by domain.
880 * @return {boolean} Whether the results are grouped by domain. 884 * @return {boolean} Whether the results are grouped by domain.
881 */ 885 */
882 HistoryModel.prototype.getGroupByDomain = function() { 886 HistoryModel.prototype.getGroupByDomain = function() {
883 return this.groupByDomain_; 887 return this.groupByDomain_;
884 }; 888 };
885 889
886 /////////////////////////////////////////////////////////////////////////////// 890 ///////////////////////////////////////////////////////////////////////////////
887 // HistoryFocusObserver: 891 // HistoryFocusRow:
888 892
889 /** 893 /**
894 * Provides an implementation for a single column grid.
890 * @constructor 895 * @constructor
891 * @implements {cr.ui.FocusRow.Observer} 896 * @extends {cr.ui.FocusRow}
892 */ 897 */
893 function HistoryFocusObserver() {} 898 HistoryFocusRow = function() {};
Dan Beam 2015/01/27 22:32:23 why did you change from function Declaration() {}
hcarmona 2015/01/29 00:00:37 Must have happened when I moved the code around. C
894 899
895 HistoryFocusObserver.prototype = { 900 /**
901 * Decorates |rowElement| so that it can be treated as a HistoryFocusRow item.
902 * @param {Element} rowElement The element representing this row.
903 * @param {Node} boundary Focus events are ignored outside of this node.
904 */
905 HistoryFocusRow.decorate = function(rowElement, boundary) {
906 rowElement.__proto__ = HistoryFocusRow.prototype;
907 rowElement.decorate(boundary);
908
909 /**
910 * Both of these elements are checkboxes and a history focusRow will only
911 * have 1 of the two. By giving them both the same type we can ensure
912 * that a checkbox remains focused when focus changes.
913 */
914 rowElement.addFocusRow_('.entry-box input', 'checkbox');
915 rowElement.addFocusRow_('.domain-checkbox', 'checkbox');
916
917 // Add the remaining elements.
918 rowElement.addFocusRow_('.bookmark-section.starred', 'star');
919 rowElement.addFocusRow_('[is="action-link"]', 'domain');
920 rowElement.addFocusRow_('.title a', 'title');
921 rowElement.addFocusRow_('.drop-down', 'menu');
922 };
923
924 HistoryFocusRow.prototype = {
925 __proto__: cr.ui.FocusRow.prototype,
926
896 /** @override */ 927 /** @override */
897 onActivate: function(row) { 928 onActiveStateChanged: function(state) {
898 this.getActiveRowElement_(row).classList.add('active'); 929 this.classList.toggle('active', state);
899 }, 930 },
900 931
901 /** @override */ 932 /** @override */
902 onDeactivate: function(row) { 933 getEquivalentElement: function(element) {
903 this.getActiveRowElement_(row).classList.remove('active'); 934 if (this.contains(element))
935 return element;
936
937 // All elements default to another element with the same type.
938 var ret = this.getColumn_(element.getAttribute('column-type'));
939
940 if (!ret) {
941 switch (element.getAttribute('column-type')) {
942 case 'star':
943 ret = this.getColumn_('title') || this.getColumn_('domain');
944 break;
945 case 'domain':
946 ret = this.getColumn_('title');
947 break;
948 case 'title':
949 ret = this.getColumn_('domain');
950 break;
951 case 'menu':
952 ret = this.focusableElements[this.focusableElements.length - 1];
953 }
954 }
955
956 return ret || this.focusableElements[0];
904 }, 957 },
905 958
906 /** 959 /**
907 * @param {cr.ui.FocusRow} row The row to find an element for. 960 * @param {string} type The type of column to return.
908 * @return {Element} |row|'s "active" element. 961 * @return {Element?} The column matching the type.
Dan Beam 2015/01/27 22:32:23 nit: ?Element
hcarmona 2015/01/29 00:00:37 Done.
909 * @private 962 * @private
910 */ 963 */
911 getActiveRowElement_: function(row) { 964 getColumn_: function(type) {
912 return findAncestorByClass(row.items[0], 'entry') || 965 return this.querySelector('[column-type=' + type + ']');
913 findAncestorByClass(row.items[0], 'site-domain-wrapper'); 966 },
967
968 /**
969 * Add a focusable element if it exists in this FocusRow.
970 * @param {string} query A query to select the appropriate element.
971 * @param {string} type The type to use for the element.
972 * @private
973 */
974 addFocusRow_: function(query, type) {
975 var element = this.querySelector(query);
976 if (element) {
977 this.addFocusableElement(element);
978 element.setAttribute('column-type', type);
979 }
914 }, 980 },
915 }; 981 };
916 982
917 ///////////////////////////////////////////////////////////////////////////////
918 // HistoryFocusGrid:
919
920 /**
921 * @param {Node=} opt_boundary
922 * @param {cr.ui.FocusRow.Observer=} opt_observer
923 * @constructor
924 * @extends {cr.ui.FocusGrid}
925 */
926 function HistoryFocusGrid(opt_boundary, opt_observer) {
927 cr.ui.FocusGrid.apply(this, arguments);
928 }
929
930 HistoryFocusGrid.prototype = {
931 __proto__: cr.ui.FocusGrid.prototype,
932
933 /** @override */
934 onMousedown: function(row, e) {
935 // TODO(dbeam): Can cr.ui.FocusGrid know about cr.ui.MenuButton? If so, bake
936 // this logic into the base class directly.
937 var menuButton = findAncestorByClass(e.target, 'menu-button');
938 if (menuButton) {
939 // Deactivate any other active row.
940 this.rows.some(function(r) {
941 if (r.activeIndex >= 0 && r != row) {
942 r.activeIndex = -1;
943 return true;
944 }
945 });
946 // Activate only the row with a pressed menu button.
947 row.activeIndex = row.items.indexOf(menuButton);
948 }
949 return !!menuButton;
950 },
951 };
952
953 /////////////////////////////////////////////////////////////////////////////// 983 ///////////////////////////////////////////////////////////////////////////////
954 // HistoryView: 984 // HistoryView:
955 985
956 /** 986 /**
957 * Functions and state for populating the page with HTML. This should one-day 987 * Functions and state for populating the page with HTML. This should one-day
958 * contain the view and use event handlers, rather than pushing HTML out and 988 * contain the view and use event handlers, rather than pushing HTML out and
959 * getting called externally. 989 * getting called externally.
960 * @param {HistoryModel} model The model backing this view. 990 * @param {HistoryModel} model The model backing this view.
961 * @constructor 991 * @constructor
962 */ 992 */
963 function HistoryView(model) { 993 function HistoryView(model) {
964 this.editButtonTd_ = $('edit-button'); 994 this.editButtonTd_ = $('edit-button');
965 this.editingControlsDiv_ = $('editing-controls'); 995 this.editingControlsDiv_ = $('editing-controls');
966 this.resultDiv_ = $('results-display'); 996 this.resultDiv_ = $('results-display');
967 this.focusGrid_ = new HistoryFocusGrid(this.resultDiv_, 997 this.focusGrid_ = new cr.ui.FocusGrid();
968 new HistoryFocusObserver);
969 this.pageDiv_ = $('results-pagination'); 998 this.pageDiv_ = $('results-pagination');
970 this.model_ = model; 999 this.model_ = model;
971 this.pageIndex_ = 0; 1000 this.pageIndex_ = 0;
972 this.lastDisplayed_ = []; 1001 this.lastDisplayed_ = [];
973 1002
974 this.model_.setView(this); 1003 this.model_.setView(this);
975 1004
976 this.currentVisits_ = []; 1005 this.currentVisits_ = [];
977 1006
978 // If there is no search button, use the search button label as placeholder 1007 // If there is no search button, use the search button label as placeholder
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
1190 1219
1191 this.positionNotificationBar(); 1220 this.positionNotificationBar();
1192 }; 1221 };
1193 1222
1194 /** 1223 /**
1195 * @param {Visit} visit The visit about to be removed from this view. 1224 * @param {Visit} visit The visit about to be removed from this view.
1196 */ 1225 */
1197 HistoryView.prototype.onBeforeRemove = function(visit) { 1226 HistoryView.prototype.onBeforeRemove = function(visit) {
1198 assert(this.currentVisits_.indexOf(visit) >= 0); 1227 assert(this.currentVisits_.indexOf(visit) >= 0);
1199 1228
1200 var pos = this.focusGrid_.getPositionForTarget(document.activeElement); 1229 var rowIndex = this.focusGrid_.getRowIndexForTarget(document.activeElement);
1201 if (!pos) 1230 if (rowIndex == -1)
1202 return; 1231 return;
1203 1232
1204 var row = this.focusGrid_.rows[pos.row + 1] || 1233 var rowToFocus = this.focusGrid_.rows[rowIndex + 1] ||
1205 this.focusGrid_.rows[pos.row - 1]; 1234 this.focusGrid_.rows[rowIndex - 1];
1206 if (row) 1235 if (rowToFocus)
1207 row.focusIndex(Math.min(pos.col, row.items.length - 1)); 1236 rowToFocus.getEquivalentElement(document.activeElement).focus();
1208 }; 1237 };
1209 1238
1210 /** @param {Visit} visit The visit about to be unstarred. */ 1239 /** @param {Visit} visit The visit about to be unstarred. */
1211 HistoryView.prototype.onBeforeUnstarred = function(visit) { 1240 HistoryView.prototype.onBeforeUnstarred = function(visit) {
1212 assert(this.currentVisits_.indexOf(visit) >= 0); 1241 assert(this.currentVisits_.indexOf(visit) >= 0);
1213 assert(visit.bookmarkStar == document.activeElement); 1242 assert(visit.bookmarkStar == document.activeElement);
1214 1243
1215 var pos = this.focusGrid_.getPositionForTarget(document.activeElement); 1244 var rowIndex = this.focusGrid_.getRowIndexForTarget(document.activeElement);
1216 var row = this.focusGrid_.rows[pos.row]; 1245 var row = this.focusGrid_.rows[rowIndex];
1217 row.focusIndex(Math.min(pos.col + 1, row.items.length - 1)); 1246
1247 // Focus the title or domain when the bookmarked star is removed because the
1248 // star will no longer be focusable.
1249 var newFocus = row.querySelector('[column-type="title"]') ||
1250 row.querySelector('[column-type="domain"]');
Dan Beam 2015/01/27 22:32:23 nit: arguably combine querySelector() calls into 1
hcarmona 2015/01/29 00:00:37 Done.
1251 newFocus.focus();
1218 }; 1252 };
1219 1253
1220 /** @param {Visit} visit The visit that was just unstarred. */ 1254 /** @param {Visit} visit The visit that was just unstarred. */
1221 HistoryView.prototype.onAfterUnstarred = function(visit) { 1255 HistoryView.prototype.onAfterUnstarred = function(visit) {
1222 this.updateFocusGrid_(); 1256 this.updateFocusGrid_();
1223 }; 1257 };
1224 1258
1225 /** 1259 /**
1226 * Removes a single entry from the view. Also removes gaps before and after 1260 * Removes a single entry from the view. Also removes gaps before and after
1227 * entry if necessary. 1261 * entry if necessary.
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1305 } else { 1339 } else {
1306 bar.classList.remove('alone'); 1340 bar.classList.remove('alone');
1307 } 1341 }
1308 }; 1342 };
1309 1343
1310 /** 1344 /**
1311 * @param {Element} el An element to look for. 1345 * @param {Element} el An element to look for.
1312 * @return {boolean} Whether |el| is in |this.focusGrid_|. 1346 * @return {boolean} Whether |el| is in |this.focusGrid_|.
1313 */ 1347 */
1314 HistoryView.prototype.isInFocusGrid = function(el) { 1348 HistoryView.prototype.isInFocusGrid = function(el) {
1315 return !!this.focusGrid_.getPositionForTarget(el); 1349 return this.focusGrid_.getRowIndexForTarget(el) != -1;
1316 }; 1350 };
1317 1351
1318 // HistoryView, private: ------------------------------------------------------ 1352 // HistoryView, private: ------------------------------------------------------
1319 1353
1320 /** 1354 /**
1321 * Clear the results in the view. Since we add results piecemeal, we need 1355 * Clear the results in the view. Since we add results piecemeal, we need
1322 * to clear them out when we switch to a new page or reload. 1356 * to clear them out when we switch to a new page or reload.
1323 * @private 1357 * @private
1324 */ 1358 */
1325 HistoryView.prototype.clear_ = function() { 1359 HistoryView.prototype.clear_ = function() {
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
1667 // time column. 1701 // time column.
1668 this.setTimeColumnWidth_(); 1702 this.setTimeColumnWidth_();
1669 }; 1703 };
1670 1704
1671 var focusGridRowSelector = [ 1705 var focusGridRowSelector = [
1672 ':-webkit-any(.day-results, .search-results) > .entry:not(.fade-out)', 1706 ':-webkit-any(.day-results, .search-results) > .entry:not(.fade-out)',
1673 '.expand .grouped .entry:not(.fade-out)', 1707 '.expand .grouped .entry:not(.fade-out)',
1674 '.site-domain-wrapper' 1708 '.site-domain-wrapper'
1675 ].join(', '); 1709 ].join(', ');
1676 1710
1677 var focusGridColumnSelector = [
1678 '.entry-box input',
1679 '.bookmark-section.starred',
1680 '.title a',
1681 '.drop-down',
1682 '.domain-checkbox',
1683 '[is="action-link"]',
1684 ].join(', ');
1685
1686 /** @private */ 1711 /** @private */
1687 HistoryView.prototype.updateFocusGrid_ = function() { 1712 HistoryView.prototype.updateFocusGrid_ = function() {
1688 var rows = this.resultDiv_.querySelectorAll(focusGridRowSelector); 1713 var rows = this.resultDiv_.querySelectorAll(focusGridRowSelector);
1689 var grid = []; 1714 this.focusGrid_.destroy();
1690 1715
1691 for (var i = 0; i < rows.length; ++i) { 1716 for (var i = 0; i < rows.length; ++i) {
1692 assert(rows[i].parentNode); 1717 assert(rows[i].parentNode);
1693 grid.push(rows[i].querySelectorAll(focusGridColumnSelector)); 1718 HistoryFocusRow.decorate(rows[i], this.resultDiv_);
1719 this.focusGrid_.addRow(rows[i]);
1694 } 1720 }
1695
1696 this.focusGrid_.setGrid(grid);
1697 }; 1721 };
1698 1722
1699 /** 1723 /**
1700 * Update the visibility of the page navigation buttons. 1724 * Update the visibility of the page navigation buttons.
1701 * @private 1725 * @private
1702 */ 1726 */
1703 HistoryView.prototype.updateNavBar_ = function() { 1727 HistoryView.prototype.updateNavBar_ = function() {
1704 this.updateRangeButtons_(); 1728 this.updateRangeButtons_();
1705 1729
1706 // If grouping by domain is enabled, there's a control bar on top, don't show 1730 // If grouping by domain is enabled, there's a control bar on top, don't show
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
2381 historyView.reload(); 2405 historyView.reload();
2382 } 2406 }
2383 2407
2384 // Add handlers to HTML elements. 2408 // Add handlers to HTML elements.
2385 document.addEventListener('DOMContentLoaded', load); 2409 document.addEventListener('DOMContentLoaded', load);
2386 2410
2387 // This event lets us enable and disable menu items before the menu is shown. 2411 // This event lets us enable and disable menu items before the menu is shown.
2388 document.addEventListener('canExecute', function(e) { 2412 document.addEventListener('canExecute', function(e) {
2389 e.canExecute = true; 2413 e.canExecute = true;
2390 }); 2414 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698