Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 }); |
| OLD | NEW |