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

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: nit Created 5 years, 11 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 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 recordUmaAction('HistoryPage_BookmarkStarClicked'); 242 recordUmaAction('HistoryPage_BookmarkStarClicked');
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 }
Dan Beam 2015/01/24 02:37:08 nit: \n
hcarmona 2015/01/27 18:30:40 Done.
253 if (focusless)
254 bookmarkSection.tabIndex = -1;
Dan Beam 2015/01/24 02:37:08 nit: \n
hcarmona 2015/01/27 18:30:40 Done.
253 entryBox.appendChild(bookmarkSection); 255 entryBox.appendChild(bookmarkSection);
254 256
255 var visitEntryWrapper = /** @type {HTMLElement} */( 257 var visitEntryWrapper = /** @type {HTMLElement} */(
256 entryBox.appendChild(document.createElement('div'))); 258 entryBox.appendChild(document.createElement('div')));
257 if (addTitleFavicon || this.blockedVisit) 259 if (addTitleFavicon || this.blockedVisit)
258 visitEntryWrapper.classList.add('visit-entry'); 260 visitEntryWrapper.classList.add('visit-entry');
259 if (this.blockedVisit) { 261 if (this.blockedVisit) {
260 visitEntryWrapper.classList.add('blocked-indicator'); 262 visitEntryWrapper.classList.add('blocked-indicator');
261 visitEntryWrapper.appendChild(this.getVisitAttemptDOM_()); 263 visitEntryWrapper.appendChild(this.getVisitAttemptDOM_());
262 } else { 264 } else {
(...skipping 614 matching lines...) Expand 10 before | Expand all | Expand 10 after
877 879
878 /** 880 /**
879 * Gets whether we are grouped by domain. 881 * Gets whether we are grouped by domain.
880 * @return {boolean} Whether the results are grouped by domain. 882 * @return {boolean} Whether the results are grouped by domain.
881 */ 883 */
882 HistoryModel.prototype.getGroupByDomain = function() { 884 HistoryModel.prototype.getGroupByDomain = function() {
883 return this.groupByDomain_; 885 return this.groupByDomain_;
884 }; 886 };
885 887
886 /////////////////////////////////////////////////////////////////////////////// 888 ///////////////////////////////////////////////////////////////////////////////
887 // HistoryFocusObserver: 889 // HistoryFocusRow:
888 890
889 /** 891 /**
892 * Provides an implementation for a single column grid.
890 * @constructor 893 * @constructor
891 * @implements {cr.ui.FocusRow.Observer} 894 * @param {Element} rowElement The element representing this row.
895 * @param {Node} boundary Focus events are ignored outside of this node.
896 * @extends {cr.ui.FocusRow}
892 */ 897 */
893 function HistoryFocusObserver() {} 898 HistoryFocusRow = function(rowElement, boundary) {
899 rowElement.__proto__ = HistoryFocusRow.prototype;
900 rowElement.decorate(boundary);
901 return rowElement;
902 };
894 903
895 HistoryFocusObserver.prototype = { 904 HistoryFocusRow.prototype = {
905 __proto__: cr.ui.FocusRow.prototype,
906
896 /** @override */ 907 /** @override */
897 onActivate: function(row) { 908 decorate: function(boundary, opt_delegate) {
898 this.getActiveRowElement_(row).classList.add('active'); 909 cr.ui.FocusRow.prototype.decorate.apply(this, arguments);
910
911 /**
912 * Both of these elements are checkboxes and a history focusRow will only
913 * have 1 of the two. By giving them both the same type we can ensure
914 * that a checkbox remains focused when focus changes.
915 */
916 this.addFocusRow_('.entry-box input', 'checkbox');
917 this.addFocusRow_('.domain-checkbox', 'checkbox');
918
919 // Add the remaining elements.
920 this.addFocusRow_('.bookmark-section.starred', 'star');
921 this.addFocusRow_('[is="action-link"]', 'domain');
922 this.addFocusRow_('.title a', 'title');
923 this.addFocusRow_('.drop-down', 'menu');
899 }, 924 },
900 925
901 /** @override */ 926 /** @override */
902 onDeactivate: function(row) { 927 onActiveStateChanged: function(state) {
903 this.getActiveRowElement_(row).classList.remove('active'); 928 this.classList.toggle('active', state);
929 },
930
931 /** @override */
932 getEquivalentElement: function(element) {
933 if (this.contains(element))
934 return element;
935
936 var ret = null;
937
938 switch (element.getAttribute('column-type')) {
939 case ('checkbox'):
940 ret = this.querySelector('[column-type="checkbox"]');
Dan Beam 2015/01/24 02:37:08 nit: getColumn_: function(type) { return t
hcarmona 2015/01/27 18:30:40 Done.
941 break;
942 case ('star'):
943 ret = this.querySelector('[column-type="star"]') ||
944 this.querySelector('[column-type="title"]') ||
945 this.querySelector('[column-type="domain"]');
946 break;
947 case ('domain'):
948 ret = this.querySelector('[column-type="domain"]') ||
949 this.querySelector('[column-type="title"]');
950 break;
951 case ('title'):
952 ret = this.querySelector('[column-type="title"]') ||
953 this.querySelector('[column-type="domain"]');
954 break;
955 case ('menu'):
956 ret = this.focusableElements[this.focusableElements.length - 1];
957 }
958
959 return ret || this.focusableElements[0];
904 }, 960 },
905 961
906 /** 962 /**
907 * @param {cr.ui.FocusRow} row The row to find an element for. 963 * Add a focusable element if it exists in this FocusRow.
908 * @return {Element} |row|'s "active" element. 964 * @param {string} query A query to select the appropriate element.
965 * @param {string} type The type to use for the element.
909 * @private 966 * @private
910 */ 967 */
911 getActiveRowElement_: function(row) { 968 addFocusRow_: function(query, type) {
912 return findAncestorByClass(row.items[0], 'entry') || 969 var element = this.querySelector(query);
913 findAncestorByClass(row.items[0], 'site-domain-wrapper'); 970 if (element) {
971 this.addFocusableElement(element);
972 element.setAttribute('column-type', type);
973 }
914 }, 974 },
915 }; 975 };
916 976
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 /////////////////////////////////////////////////////////////////////////////// 977 ///////////////////////////////////////////////////////////////////////////////
954 // HistoryView: 978 // HistoryView:
955 979
956 /** 980 /**
957 * Functions and state for populating the page with HTML. This should one-day 981 * 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 982 * contain the view and use event handlers, rather than pushing HTML out and
959 * getting called externally. 983 * getting called externally.
960 * @param {HistoryModel} model The model backing this view. 984 * @param {HistoryModel} model The model backing this view.
961 * @constructor 985 * @constructor
962 */ 986 */
963 function HistoryView(model) { 987 function HistoryView(model) {
964 this.editButtonTd_ = $('edit-button'); 988 this.editButtonTd_ = $('edit-button');
965 this.editingControlsDiv_ = $('editing-controls'); 989 this.editingControlsDiv_ = $('editing-controls');
966 this.resultDiv_ = $('results-display'); 990 this.resultDiv_ = $('results-display');
967 this.focusGrid_ = new HistoryFocusGrid(this.resultDiv_, 991 this.focusGrid_ = new cr.ui.FocusGrid();
968 new HistoryFocusObserver);
969 this.pageDiv_ = $('results-pagination'); 992 this.pageDiv_ = $('results-pagination');
970 this.model_ = model; 993 this.model_ = model;
971 this.pageIndex_ = 0; 994 this.pageIndex_ = 0;
972 this.lastDisplayed_ = []; 995 this.lastDisplayed_ = [];
973 996
974 this.model_.setView(this); 997 this.model_.setView(this);
975 998
976 this.currentVisits_ = []; 999 this.currentVisits_ = [];
977 1000
978 // If there is no search button, use the search button label as placeholder 1001 // 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 1213
1191 this.positionNotificationBar(); 1214 this.positionNotificationBar();
1192 }; 1215 };
1193 1216
1194 /** 1217 /**
1195 * @param {Visit} visit The visit about to be removed from this view. 1218 * @param {Visit} visit The visit about to be removed from this view.
1196 */ 1219 */
1197 HistoryView.prototype.onBeforeRemove = function(visit) { 1220 HistoryView.prototype.onBeforeRemove = function(visit) {
1198 assert(this.currentVisits_.indexOf(visit) >= 0); 1221 assert(this.currentVisits_.indexOf(visit) >= 0);
1199 1222
1200 var pos = this.focusGrid_.getPositionForTarget(document.activeElement); 1223 var rowIndex = this.focusGrid_.getRowIndexForTarget(document.activeElement);
1201 if (!pos) 1224 if (rowIndex == -1)
1202 return; 1225 return;
1203 1226
1204 var row = this.focusGrid_.rows[pos.row + 1] || 1227 var rowToFocus = this.focusGrid_.rows[rowIndex + 1] ||
1205 this.focusGrid_.rows[pos.row - 1]; 1228 this.focusGrid_.rows[rowIndex - 1];
1206 if (row) 1229 if (rowToFocus)
1207 row.focusIndex(Math.min(pos.col, row.items.length - 1)); 1230 rowToFocus.getEquivalentElement(document.activeElement).focus();
1208 }; 1231 };
1209 1232
1210 /** @param {Visit} visit The visit about to be unstarred. */ 1233 /** @param {Visit} visit The visit about to be unstarred. */
1211 HistoryView.prototype.onBeforeUnstarred = function(visit) { 1234 HistoryView.prototype.onBeforeUnstarred = function(visit) {
1212 assert(this.currentVisits_.indexOf(visit) >= 0); 1235 assert(this.currentVisits_.indexOf(visit) >= 0);
1213 assert(visit.bookmarkStar == document.activeElement); 1236 assert(visit.bookmarkStar == document.activeElement);
1214 1237
1215 var pos = this.focusGrid_.getPositionForTarget(document.activeElement); 1238 var rowIndex = this.focusGrid_.getRowIndexForTarget(document.activeElement);
1216 var row = this.focusGrid_.rows[pos.row]; 1239 var row = this.focusGrid_.rows[rowIndex];
1217 row.focusIndex(Math.min(pos.col + 1, row.items.length - 1)); 1240
1241 // Focus the title or domain when the bookmarked star is removed because the
1242 // star will no longer be focusable.
1243 var newFocus = row.querySelector('[column-type="title"]') ||
1244 row.querySelector('[column-type="domain"]');
1245 newFocus.focus();
1218 }; 1246 };
1219 1247
1220 /** @param {Visit} visit The visit that was just unstarred. */ 1248 /** @param {Visit} visit The visit that was just unstarred. */
1221 HistoryView.prototype.onAfterUnstarred = function(visit) { 1249 HistoryView.prototype.onAfterUnstarred = function(visit) {
1222 this.updateFocusGrid_(); 1250 this.updateFocusGrid_();
1223 }; 1251 };
1224 1252
1225 /** 1253 /**
1226 * Removes a single entry from the view. Also removes gaps before and after 1254 * Removes a single entry from the view. Also removes gaps before and after
1227 * entry if necessary. 1255 * entry if necessary.
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1305 } else { 1333 } else {
1306 bar.classList.remove('alone'); 1334 bar.classList.remove('alone');
1307 } 1335 }
1308 }; 1336 };
1309 1337
1310 /** 1338 /**
1311 * @param {Element} el An element to look for. 1339 * @param {Element} el An element to look for.
1312 * @return {boolean} Whether |el| is in |this.focusGrid_|. 1340 * @return {boolean} Whether |el| is in |this.focusGrid_|.
1313 */ 1341 */
1314 HistoryView.prototype.isInFocusGrid = function(el) { 1342 HistoryView.prototype.isInFocusGrid = function(el) {
1315 return !!this.focusGrid_.getPositionForTarget(el); 1343 return this.focusGrid_.getRowIndexForTarget(el) != -1;
1316 }; 1344 };
1317 1345
1318 // HistoryView, private: ------------------------------------------------------ 1346 // HistoryView, private: ------------------------------------------------------
1319 1347
1320 /** 1348 /**
1321 * Clear the results in the view. Since we add results piecemeal, we need 1349 * 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. 1350 * to clear them out when we switch to a new page or reload.
1323 * @private 1351 * @private
1324 */ 1352 */
1325 HistoryView.prototype.clear_ = function() { 1353 HistoryView.prototype.clear_ = function() {
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
1667 // time column. 1695 // time column.
1668 this.setTimeColumnWidth_(); 1696 this.setTimeColumnWidth_();
1669 }; 1697 };
1670 1698
1671 var focusGridRowSelector = [ 1699 var focusGridRowSelector = [
1672 ':-webkit-any(.day-results, .search-results) > .entry:not(.fade-out)', 1700 ':-webkit-any(.day-results, .search-results) > .entry:not(.fade-out)',
1673 '.expand .grouped .entry:not(.fade-out)', 1701 '.expand .grouped .entry:not(.fade-out)',
1674 '.site-domain-wrapper' 1702 '.site-domain-wrapper'
1675 ].join(', '); 1703 ].join(', ');
1676 1704
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 */ 1705 /** @private */
1687 HistoryView.prototype.updateFocusGrid_ = function() { 1706 HistoryView.prototype.updateFocusGrid_ = function() {
1688 var rows = this.resultDiv_.querySelectorAll(focusGridRowSelector); 1707 var rows = this.resultDiv_.querySelectorAll(focusGridRowSelector);
1689 var grid = []; 1708 this.focusGrid_.destroy();
1690 1709
1691 for (var i = 0; i < rows.length; ++i) { 1710 for (var i = 0; i < rows.length; ++i) {
1692 assert(rows[i].parentNode); 1711 assert(rows[i].parentNode);
1693 grid.push(rows[i].querySelectorAll(focusGridColumnSelector)); 1712 this.focusGrid_.addRow(new HistoryFocusRow(rows[i], this.resultDiv_));
1694 } 1713 }
1695
1696 this.focusGrid_.setGrid(grid);
1697 }; 1714 };
1698 1715
1699 /** 1716 /**
1700 * Update the visibility of the page navigation buttons. 1717 * Update the visibility of the page navigation buttons.
1701 * @private 1718 * @private
1702 */ 1719 */
1703 HistoryView.prototype.updateNavBar_ = function() { 1720 HistoryView.prototype.updateNavBar_ = function() {
1704 this.updateRangeButtons_(); 1721 this.updateRangeButtons_();
1705 1722
1706 // If grouping by domain is enabled, there's a control bar on top, don't show 1723 // 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(); 2398 historyView.reload();
2382 } 2399 }
2383 2400
2384 // Add handlers to HTML elements. 2401 // Add handlers to HTML elements.
2385 document.addEventListener('DOMContentLoaded', load); 2402 document.addEventListener('DOMContentLoaded', load);
2386 2403
2387 // This event lets us enable and disable menu items before the menu is shown. 2404 // This event lets us enable and disable menu items before the menu is shown.
2388 document.addEventListener('canExecute', function(e) { 2405 document.addEventListener('canExecute', function(e) {
2389 e.canExecute = true; 2406 e.canExecute = true;
2390 }); 2407 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698