Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 /////////////////////////////////////////////////////////////////////////////// | 5 /////////////////////////////////////////////////////////////////////////////// |
| 6 // Globals: | 6 // Globals: |
| 7 var RESULTS_PER_PAGE = 150; | 7 var RESULTS_PER_PAGE = 150; |
| 8 var MAX_SEARCH_DEPTH_MONTHS = 18; | 8 var MAX_SEARCH_DEPTH_MONTHS = 18; |
| 9 | 9 |
| 10 // Amount of time between pageviews that we consider a 'break' in browsing, | 10 // Amount of time between pageviews that we consider a 'break' in browsing, |
| 11 // measured in milliseconds. | 11 // measured in milliseconds. |
| 12 var BROWSING_GAP_TIME = 15 * 60 * 1000; | 12 var BROWSING_GAP_TIME = 15 * 60 * 1000; |
| 13 | 13 |
| 14 function $(o) {return document.getElementById(o);} | 14 function $(o) {return document.getElementById(o);} |
| 15 | 15 |
| 16 function createElementWithClassName(type, className) { | 16 function createElementWithClassName(type, className) { |
| 17 var elm = document.createElement(type); | 17 var elm = document.createElement(type); |
| 18 elm.className = className; | 18 elm.className = className; |
| 19 return elm; | 19 return elm; |
| 20 } | 20 } |
| 21 | 21 |
| 22 // Escapes a URI as appropriate for CSS. | 22 // Escapes a URI as appropriate for CSS. |
| 23 function encodeURIForCSS(uri) { | 23 function encodeURIForCSS(uri) { |
| 24 // CSS uris need to have '(' and ')' escaped. | 24 // CSS URIs need to have '(' and ')' escaped. |
| 25 return uri.replace(/\(/g, "\\(").replace(/\)/g, "\\)"); | 25 return uri.replace(/\(/g, "\\(").replace(/\)/g, "\\)"); |
| 26 } | 26 } |
| 27 | 27 |
| 28 function findAncestorWithClass(node, className) { | |
| 29 while ((node = node.parentNode)) { | |
| 30 if (node.classList.contains(className)) return node; | |
| 31 } | |
| 32 return null; | |
| 33 } | |
| 34 | |
| 28 // TODO(glen): Get rid of these global references, replace with a controller | 35 // TODO(glen): Get rid of these global references, replace with a controller |
| 29 // or just make the classes own more of the page. | 36 // or just make the classes own more of the page. |
| 30 var historyModel; | 37 var historyModel; |
| 31 var historyView; | 38 var historyView; |
| 32 var localStrings; | 39 var localStrings; |
| 33 var pageState; | 40 var pageState; |
| 34 var deleteQueue = []; | 41 var deleteQueue = []; |
| 35 var selectionAnchor = -1; | 42 var selectionAnchor = -1; |
| 36 var activePage = null; | 43 var activePage = null; |
| 37 | 44 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 | 103 |
| 97 // Page, Public: -------------------------------------------------------------- | 104 // Page, Public: -------------------------------------------------------------- |
| 98 /** | 105 /** |
| 99 * Returns a dom structure for a browse page result or a search page result. | 106 * Returns a dom structure for a browse page result or a search page result. |
| 100 * @param {boolean} Flag to indicate if result is a search result. | 107 * @param {boolean} Flag to indicate if result is a search result. |
| 101 * @return {Element} The dom structure. | 108 * @return {Element} The dom structure. |
| 102 */ | 109 */ |
| 103 Page.prototype.getResultDOM = function(searchResultFlag) { | 110 Page.prototype.getResultDOM = function(searchResultFlag) { |
| 104 var node = createElementWithClassName('li', 'entry'); | 111 var node = createElementWithClassName('li', 'entry'); |
| 105 var time = createElementWithClassName('div', 'time'); | 112 var time = createElementWithClassName('div', 'time'); |
| 106 var entryBox = createElementWithClassName('div', 'entry-box'); | 113 var entryBox = createElementWithClassName('label', 'entry-box'); |
| 107 var domain = createElementWithClassName('div', 'domain'); | 114 var domain = createElementWithClassName('div', 'domain'); |
| 108 | 115 |
| 109 var dropDown = createElementWithClassName('button', 'drop-down'); | 116 var dropDown = createElementWithClassName('button', 'drop-down'); |
| 110 dropDown.value = 'Open action menu'; | 117 dropDown.value = 'Open action menu'; |
| 111 dropDown.title = localStrings.getString('actionMenuDescription'); | 118 dropDown.title = localStrings.getString('actionMenuDescription'); |
| 112 dropDown.setAttribute('menu', '#action-menu'); | 119 dropDown.setAttribute('menu', '#action-menu'); |
| 113 cr.ui.decorate(dropDown, MenuButton); | 120 cr.ui.decorate(dropDown, MenuButton); |
| 114 | 121 |
| 115 // Checkbox is always created, but only visible on hover & when checked. | 122 // Checkbox is always created, but only visible on hover & when checked. |
| 116 var checkbox = document.createElement('input'); | 123 var checkbox = document.createElement('input'); |
| 117 checkbox.type = 'checkbox'; | 124 checkbox.type = 'checkbox'; |
| 118 checkbox.id = 'checkbox-' + this.id_; | 125 checkbox.id = 'checkbox-' + this.id_; |
| 119 checkbox.time = this.time.getTime(); | 126 checkbox.time = this.time.getTime(); |
| 120 checkbox.addEventListener('click', checkboxClicked); | 127 checkbox.addEventListener('click', checkboxClicked); |
| 121 time.appendChild(checkbox); | 128 time.appendChild(checkbox); |
| 122 | 129 |
| 123 // Keep track of the drop down that triggered the menu, so we know | 130 // Keep track of the drop down that triggered the menu, so we know |
| 124 // which element to apply the command to. | 131 // which element to apply the command to. |
| 125 // TODO(dubroy): Ideally we'd use 'activate', but MenuButton swallows it. | 132 // TODO(dubroy): Ideally we'd use 'activate', but MenuButton swallows it. |
| 126 var self = this; | 133 var self = this; |
| 127 var setActivePage = function(e) { | 134 var setActivePage = function(e) { |
| 128 activePage = self; | 135 activePage = self; |
| 129 }; | 136 }; |
| 130 dropDown.addEventListener('mousedown', setActivePage); | 137 dropDown.addEventListener('mousedown', setActivePage); |
| 131 dropDown.addEventListener('focus', setActivePage); | 138 dropDown.addEventListener('focus', setActivePage); |
| 132 | 139 |
| 133 domain.style.backgroundImage = | |
| 134 'url(chrome://favicon/' + encodeURIForCSS(this.url_) + ')'; | |
| 135 domain.textContent = this.domain_; | 140 domain.textContent = this.domain_; |
| 136 | 141 |
| 137 // Clicking anywhere in the entryBox will check/uncheck the checkbox. | 142 // Clicking anywhere in the entryBox will check/uncheck the checkbox. |
| 143 entryBox.setAttribute('for', checkbox.id); | |
| 138 entryBox.addEventListener('mousedown', entryBoxMousedown, false); | 144 entryBox.addEventListener('mousedown', entryBoxMousedown, false); |
| 139 | 145 |
| 140 // Prevent clicks on the drop down from affecting the checkbox. | 146 // Prevent clicks on the drop down from affecting the checkbox. |
| 141 dropDown.addEventListener('click', function(e) { e.preventDefault(); }); | 147 dropDown.addEventListener('click', function(e) { e.preventDefault(); }); |
| 142 | 148 |
| 143 // A label around the parts that should be clicked to activate the check box. | |
| 144 var label = document.createElement('label'); | |
| 145 label.appendChild(time); | |
| 146 label.appendChild(domain); | |
| 147 | |
| 148 // We use a wrapper div so that the entry contents will be shinkwrapped. | 149 // We use a wrapper div so that the entry contents will be shinkwrapped. |
| 149 entryBox.appendChild(label); | 150 entryBox.appendChild(time); |
| 150 entryBox.appendChild(this.getTitleDOM_()); | 151 entryBox.appendChild(this.getTitleDOM_()); |
| 152 entryBox.appendChild(domain); | |
| 151 entryBox.appendChild(dropDown); | 153 entryBox.appendChild(dropDown); |
| 152 | 154 |
| 153 // Let the entryBox be styled appropriately when it contains keyboard focus. | 155 // Let the entryBox be styled appropriately when it contains keyboard focus. |
| 154 entryBox.addEventListener('focus', function() { | 156 entryBox.addEventListener('focus', function() { |
| 155 this.classList.add('contains-focus'); | 157 this.classList.add('contains-focus'); |
| 156 }, true); | 158 }, true); |
| 157 entryBox.addEventListener('blur', function() { | 159 entryBox.addEventListener('blur', function() { |
| 158 this.classList.remove('contains-focus'); | 160 this.classList.remove('contains-focus'); |
| 159 }, true); | 161 }, true); |
| 160 | 162 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 } | 221 } |
| 220 if (i < content.length) | 222 if (i < content.length) |
| 221 node.appendChild(document.createTextNode(content.slice(i))); | 223 node.appendChild(document.createTextNode(content.slice(i))); |
| 222 }; | 224 }; |
| 223 | 225 |
| 224 /** | 226 /** |
| 225 * @return {DOMObject} DOM representation for the title block. | 227 * @return {DOMObject} DOM representation for the title block. |
| 226 */ | 228 */ |
| 227 Page.prototype.getTitleDOM_ = function() { | 229 Page.prototype.getTitleDOM_ = function() { |
| 228 var node = createElementWithClassName('div', 'title'); | 230 var node = createElementWithClassName('div', 'title'); |
| 231 node.style.backgroundImage = | |
| 232 'url(chrome://favicon/' + encodeURIForCSS(this.url_) + ')'; | |
| 233 | |
| 229 var link = document.createElement('a'); | 234 var link = document.createElement('a'); |
| 230 link.href = this.url_; | 235 link.href = this.url_; |
| 231 link.id = "id-" + this.id_; | 236 link.id = "id-" + this.id_; |
| 232 | 237 |
| 233 // Add a tooltip, since it might be ellipsized. | 238 // Add a tooltip, since it might be ellipsized. |
| 234 // TODO(dubroy): Find a way to show the tooltip only when necessary. | 239 // TODO(dubroy): Find a way to show the tooltip only when necessary. |
| 235 link.title = this.title_; | 240 link.title = this.title_; |
| 236 | 241 |
| 237 this.addHighlightedText_(link, this.title_, this.model_.getSearchText()); | 242 this.addHighlightedText_(link, this.title_, this.model_.getSearchText()); |
| 238 node.appendChild(link); | 243 node.appendChild(link); |
| 239 | 244 |
| 240 if (this.starred_) { | 245 if (this.starred_) |
| 241 node.className += ' starred'; | |
| 242 node.appendChild(createElementWithClassName('div', 'starred')); | 246 node.appendChild(createElementWithClassName('div', 'starred')); |
| 243 } | |
| 244 | 247 |
| 245 return node; | 248 return node; |
| 246 }; | 249 }; |
| 247 | 250 |
| 248 /** | 251 /** |
| 249 * Launch a search for more history entries from the same domain. | 252 * Launch a search for more history entries from the same domain. |
| 250 */ | 253 */ |
| 251 Page.prototype.showMoreFromSite_ = function() { | 254 Page.prototype.showMoreFromSite_ = function() { |
| 252 setSearch(this.domain_); | 255 setSearch(this.domain_); |
| 253 }; | 256 }; |
| (...skipping 723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 977 var cbDate = new Date(checkbox.time); | 980 var cbDate = new Date(checkbox.time); |
| 978 if (date.getFullYear() != cbDate.getFullYear() || | 981 if (date.getFullYear() != cbDate.getFullYear() || |
| 979 date.getMonth() != cbDate.getMonth() || | 982 date.getMonth() != cbDate.getMonth() || |
| 980 date.getDate() != cbDate.getDate()) { | 983 date.getDate() != cbDate.getDate()) { |
| 981 if (urls.length > 0) { | 984 if (urls.length > 0) { |
| 982 queue.push([date, urls]); | 985 queue.push([date, urls]); |
| 983 } | 986 } |
| 984 urls = []; | 987 urls = []; |
| 985 date = cbDate; | 988 date = cbDate; |
| 986 } | 989 } |
| 987 var link = checkbox.parentNode.parentNode.parentNode.querySelector('a'); | 990 var link = findAncestorWithClass(checkbox, 'entry-box').querySelector('a'); |
|
Evan Stade
2011/12/01 19:43:32
thumbsup
| |
| 988 checkbox.disabled = true; | 991 checkbox.disabled = true; |
| 989 link.classList.add('to-be-removed'); | 992 link.classList.add('to-be-removed'); |
| 990 disabledItems.push(checkbox); | 993 disabledItems.push(checkbox); |
| 991 urls.push(link.href); | 994 urls.push(link.href); |
| 992 } | 995 } |
| 993 if (urls.length > 0) { | 996 if (urls.length > 0) { |
| 994 queue.push([date, urls]); | 997 queue.push([date, urls]); |
| 995 } | 998 } |
| 996 if (checked.length > 0 && confirm(localStrings.getString('deletewarning'))) { | 999 if (checked.length > 0 && confirm(localStrings.getString('deletewarning'))) { |
| 997 for (var i = 0; i < queue.length; i++) { | 1000 for (var i = 0; i < queue.length; i++) { |
| 998 // Reload the page when the final entry has been deleted. | 1001 // Reload the page when the final entry has been deleted. |
| 999 var callback = i == 0 ? reloadHistory : null; | 1002 var callback = i == 0 ? reloadHistory : null; |
| 1000 | 1003 |
| 1001 queueURLsForDeletion(queue[i][0], queue[i][1], callback); | 1004 queueURLsForDeletion(queue[i][0], queue[i][1], callback); |
| 1002 } | 1005 } |
| 1003 deleteNextInQueue(); | 1006 deleteNextInQueue(); |
| 1004 } else { | 1007 } else { |
| 1005 // If the remove is cancelled, return the checkboxes to their | 1008 // If the remove is cancelled, return the checkboxes to their |
| 1006 // enabled, non-line-through state. | 1009 // enabled, non-line-through state. |
| 1007 for (var i = 0; i < disabledItems.length; i++) { | 1010 for (var i = 0; i < disabledItems.length; i++) { |
| 1008 var checkbox = disabledItems[i]; | 1011 var checkbox = disabledItems[i]; |
| 1009 var link = checkbox.parentNode.parentNode.parentNode.querySelector('a'); | 1012 var link = findAncenstoreWithClass( |
| 1013 checkbox, 'entry-box').querySelector('a'); | |
| 1010 checkbox.disabled = false; | 1014 checkbox.disabled = false; |
| 1011 link.classList.remove('to-be-removed'); | 1015 link.classList.remove('to-be-removed'); |
| 1012 } | 1016 } |
| 1013 } | 1017 } |
| 1014 return false; | 1018 return false; |
| 1015 } | 1019 } |
| 1016 | 1020 |
| 1017 /** | 1021 /** |
| 1018 * Toggle state of checkbox and handle Shift modifier. | 1022 * Toggle state of checkbox and handle Shift modifier. |
| 1019 */ | 1023 */ |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1127 historyView.reload(); | 1131 historyView.reload(); |
| 1128 } | 1132 } |
| 1129 | 1133 |
| 1130 // Add handlers to HTML elements. | 1134 // Add handlers to HTML elements. |
| 1131 document.addEventListener('DOMContentLoaded', load); | 1135 document.addEventListener('DOMContentLoaded', load); |
| 1132 | 1136 |
| 1133 // This event lets us enable and disable menu items before the menu is shown. | 1137 // This event lets us enable and disable menu items before the menu is shown. |
| 1134 document.addEventListener('canExecute', function(e) { | 1138 document.addEventListener('canExecute', function(e) { |
| 1135 e.canExecute = true; | 1139 e.canExecute = true; |
| 1136 }); | 1140 }); |
| OLD | NEW |