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 | 6 |
| 7 /////////////////////////////////////////////////////////////////////////////// | 7 /////////////////////////////////////////////////////////////////////////////// |
| 8 // Globals: | 8 // Globals: |
| 9 /** @const */ var RESULTS_PER_PAGE = 150; | 9 /** @const */ var RESULTS_PER_PAGE = 150; |
| 10 | 10 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 63 this.dateShort = result.dateShort || ''; | 63 this.dateShort = result.dateShort || ''; |
| 64 | 64 |
| 65 // Whether this is the continuation of a previous day. | 65 // Whether this is the continuation of a previous day. |
| 66 this.continued = continued; | 66 this.continued = continued; |
| 67 } | 67 } |
| 68 | 68 |
| 69 // Visit, public: ------------------------------------------------------------- | 69 // Visit, public: ------------------------------------------------------------- |
| 70 | 70 |
| 71 /** | 71 /** |
| 72 * Returns a dom structure for a browse page result or a search page result. | 72 * Returns a dom structure for a browse page result or a search page result. |
| 73 * @param {boolean} searchResultFlag Indicates whether the result is a search | 73 * @param {Object} propertyBag A bag of configuration properties, false by |
| 74 * result or not. | 74 * default: |
| 75 * <ul> | |
| 76 * <li>isSearchResult: Whether or not the result is a search result.</li> | |
| 77 * <li>addTitleFavicon: Whether or not the favicon should be added.</li> | |
| 78 * </ul> | |
| 75 * @return {Node} A DOM node to represent the history entry or search result. | 79 * @return {Node} A DOM node to represent the history entry or search result. |
| 76 */ | 80 */ |
| 77 Visit.prototype.getResultDOM = function(searchResultFlag) { | 81 Visit.prototype.getResultDOM = function(propertyBag) { |
| 82 var isSearchResult = propertyBag.isSearchResult || false; | |
| 83 var addTitleFavicon = propertyBag.addTitleFavicon || false; | |
| 78 var node = createElementWithClassName('li', 'entry'); | 84 var node = createElementWithClassName('li', 'entry'); |
| 79 var time = createElementWithClassName('div', 'time'); | 85 var time = createElementWithClassName('div', 'time'); |
| 80 var entryBox = createElementWithClassName('label', 'entry-box'); | 86 var entryBox = createElementWithClassName('label', 'entry-box'); |
| 81 var domain = createElementWithClassName('div', 'domain'); | 87 var domain = createElementWithClassName('div', 'domain'); |
| 82 | 88 |
| 83 var dropDown = createElementWithClassName('button', 'drop-down'); | 89 var dropDown = createElementWithClassName('button', 'drop-down'); |
| 84 dropDown.value = 'Open action menu'; | 90 dropDown.value = 'Open action menu'; |
| 85 dropDown.title = loadTimeData.getString('actionMenuDescription'); | 91 dropDown.title = loadTimeData.getString('actionMenuDescription'); |
| 86 dropDown.setAttribute('menu', '#action-menu'); | 92 dropDown.setAttribute('menu', '#action-menu'); |
| 87 cr.ui.decorate(dropDown, MenuButton); | 93 cr.ui.decorate(dropDown, MenuButton); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 106 | 112 |
| 107 domain.textContent = this.getDomainFromURL_(this.url_); | 113 domain.textContent = this.getDomainFromURL_(this.url_); |
| 108 | 114 |
| 109 // Clicking anywhere in the entryBox will check/uncheck the checkbox. | 115 // Clicking anywhere in the entryBox will check/uncheck the checkbox. |
| 110 entryBox.setAttribute('for', checkbox.id); | 116 entryBox.setAttribute('for', checkbox.id); |
| 111 entryBox.addEventListener('mousedown', entryBoxMousedown); | 117 entryBox.addEventListener('mousedown', entryBoxMousedown); |
| 112 | 118 |
| 113 // Prevent clicks on the drop down from affecting the checkbox. | 119 // Prevent clicks on the drop down from affecting the checkbox. |
| 114 dropDown.addEventListener('click', function(e) { e.preventDefault(); }); | 120 dropDown.addEventListener('click', function(e) { e.preventDefault(); }); |
| 115 | 121 |
| 116 // We use a wrapper div so that the entry contents will be shinkwrapped. | 122 // We use a wrapper div so that the entry contents will be shrinkwrapped. |
| 117 entryBox.appendChild(time); | 123 entryBox.appendChild(time); |
| 118 entryBox.appendChild(this.getTitleDOM_()); | 124 entryBox.appendChild(this.getTitleDOM_(addTitleFavicon)); |
| 119 entryBox.appendChild(domain); | 125 entryBox.appendChild(domain); |
| 120 entryBox.appendChild(dropDown); | 126 entryBox.appendChild(dropDown); |
| 121 | 127 |
| 122 // Let the entryBox be styled appropriately when it contains keyboard focus. | 128 // Let the entryBox be styled appropriately when it contains keyboard focus. |
| 123 entryBox.addEventListener('focus', function() { | 129 entryBox.addEventListener('focus', function() { |
| 124 this.classList.add('contains-focus'); | 130 this.classList.add('contains-focus'); |
| 125 }, true); | 131 }, true); |
| 126 entryBox.addEventListener('blur', function() { | 132 entryBox.addEventListener('blur', function() { |
| 127 this.classList.remove('contains-focus'); | 133 this.classList.remove('contains-focus'); |
| 128 }, true); | 134 }, true); |
| 129 | 135 |
| 130 node.appendChild(entryBox); | 136 node.appendChild(entryBox); |
| 131 | 137 |
| 132 if (searchResultFlag) { | 138 if (isSearchResult) { |
| 133 time.appendChild(document.createTextNode(this.dateShort)); | 139 time.appendChild(document.createTextNode(this.dateShort)); |
| 134 var snippet = createElementWithClassName('div', 'snippet'); | 140 var snippet = createElementWithClassName('div', 'snippet'); |
| 135 this.addHighlightedText_(snippet, | 141 this.addHighlightedText_(snippet, |
| 136 this.snippet_, | 142 this.snippet_, |
| 137 this.model_.getSearchText()); | 143 this.model_.getSearchText()); |
| 138 node.appendChild(snippet); | 144 node.appendChild(snippet); |
| 139 } else { | 145 } else { |
| 140 time.appendChild(document.createTextNode(this.dateTimeOfDay)); | 146 time.appendChild(document.createTextNode(this.dateTimeOfDay)); |
| 141 } | 147 } |
| 142 | 148 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 184 var b = document.createElement('b'); | 190 var b = document.createElement('b'); |
| 185 b.textContent = content.substring(match.index, i); | 191 b.textContent = content.substring(match.index, i); |
| 186 node.appendChild(b); | 192 node.appendChild(b); |
| 187 } | 193 } |
| 188 } | 194 } |
| 189 if (i < content.length) | 195 if (i < content.length) |
| 190 node.appendChild(document.createTextNode(content.slice(i))); | 196 node.appendChild(document.createTextNode(content.slice(i))); |
| 191 }; | 197 }; |
| 192 | 198 |
| 193 /** | 199 /** |
| 194 * @return {DOMObject} DOM representation for the title block. | 200 * Returns the DOM element containing a link on the title of the URL for the |
| 201 * current visit. Optionally sets the favicon as well. | |
| 202 * @param {boolean} addFavicon Whether to add a favicon or not. | |
| 203 * @return {Element} DOM representation for the title block. | |
| 195 * @private | 204 * @private |
| 196 */ | 205 */ |
| 197 Visit.prototype.getTitleDOM_ = function() { | 206 Visit.prototype.getTitleDOM_ = function(addFavicon) { |
| 198 var node = createElementWithClassName('div', 'title'); | 207 var node = createElementWithClassName('div', 'title'); |
| 199 node.style.backgroundImage = getFaviconImageSet(this.url_); | 208 if (addFavicon) { |
| 200 node.style.backgroundSize = '16px'; | 209 node.style.backgroundImage = getFaviconImageSet(this.url_); |
| 210 node.style.backgroundSize = '16px'; | |
| 211 } | |
| 201 | 212 |
| 202 var link = document.createElement('a'); | 213 var link = document.createElement('a'); |
| 203 link.href = this.url_; | 214 link.href = this.url_; |
| 204 link.id = 'id-' + this.id_; | 215 link.id = 'id-' + this.id_; |
| 205 link.target = '_top'; | 216 link.target = '_top'; |
| 206 | 217 |
| 207 // Add a tooltip, since it might be ellipsized. | 218 // Add a tooltip, since it might be ellipsized. |
| 208 // TODO(dubroy): Find a way to show the tooltip only when necessary. | 219 // TODO(dubroy): Find a way to show the tooltip only when necessary. |
| 209 link.title = this.title_; | 220 link.title = this.title_; |
| 210 | 221 |
| 211 this.addHighlightedText_(link, this.title_, this.model_.getSearchText()); | 222 this.addHighlightedText_(link, this.title_, this.model_.getSearchText()); |
| 212 node.appendChild(link); | 223 node.appendChild(link); |
| 213 | 224 |
| 214 if (this.starred_) { | 225 if (this.starred_) { |
| 215 var star = createElementWithClassName('div', 'starred'); | 226 var star = createElementWithClassName('div', 'starred'); |
| 216 node.appendChild(star); | 227 node.appendChild(star); |
| 217 star.addEventListener('click', this.starClicked_.bind(this)); | 228 star.addEventListener('click', this.starClicked_.bind(this)); |
| 218 } | 229 } |
| 219 | 230 |
| 220 return node; | 231 return node; |
| 221 }; | 232 }; |
| 222 | 233 |
| 223 /** | 234 /** |
| 235 * Set the favicon for an element. | |
| 236 * @param {Element} el The DOM element to which to add the icon. | |
| 237 * @private | |
| 238 */ | |
| 239 Visit.prototype.addFaviconToElement_ = function(el) { | |
| 240 el.style.backgroundImage = getFaviconImageSet(this.url_); | |
| 241 }; | |
| 242 | |
| 243 /** | |
| 224 * Launch a search for more history entries from the same domain. | 244 * Launch a search for more history entries from the same domain. |
| 225 * @private | 245 * @private |
| 226 */ | 246 */ |
| 227 Visit.prototype.showMoreFromSite_ = function() { | 247 Visit.prototype.showMoreFromSite_ = function() { |
| 228 setSearch(this.getDomainFromURL_(this.url_)); | 248 setSearch(this.getDomainFromURL_(this.url_)); |
| 229 }; | 249 }; |
| 230 | 250 |
| 231 /** | 251 /** |
| 232 * Remove a single entry from the history. | 252 * Remove a single entry from the history. |
| 233 * @private | 253 * @private |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 301 * up an initial view, use #requestPage otherwise. | 321 * up an initial view, use #requestPage otherwise. |
| 302 */ | 322 */ |
| 303 HistoryModel.prototype.setSearchText = function(searchText, opt_page) { | 323 HistoryModel.prototype.setSearchText = function(searchText, opt_page) { |
| 304 this.clearModel_(); | 324 this.clearModel_(); |
| 305 this.searchText_ = searchText; | 325 this.searchText_ = searchText; |
| 306 this.requestedPage_ = opt_page ? opt_page : 0; | 326 this.requestedPage_ = opt_page ? opt_page : 0; |
| 307 this.queryHistory_(); | 327 this.queryHistory_(); |
| 308 }; | 328 }; |
| 309 | 329 |
| 310 /** | 330 /** |
| 331 * Clear the search text. | |
| 332 */ | |
| 333 HistoryModel.prototype.clearSearchText = function() { | |
| 334 this.searchText_ = ''; | |
| 335 }; | |
| 336 | |
| 337 /** | |
| 311 * Reload our model with the current parameters. | 338 * Reload our model with the current parameters. |
| 312 */ | 339 */ |
| 313 HistoryModel.prototype.reload = function() { | 340 HistoryModel.prototype.reload = function() { |
| 341 // Save user-visible state, clear the model, and restore the state. | |
| 314 var search = this.searchText_; | 342 var search = this.searchText_; |
| 315 var page = this.requestedPage_; | 343 var page = this.requestedPage_; |
| 344 var groupByDomain = this.groupByDomain_; | |
| 345 | |
| 316 this.clearModel_(); | 346 this.clearModel_(); |
| 317 this.searchText_ = search; | 347 this.searchText_ = search; |
| 318 this.requestedPage_ = page; | 348 this.requestedPage_ = page; |
| 349 this.groupByDomain_ = groupByDomain; | |
| 319 this.queryHistory_(); | 350 this.queryHistory_(); |
| 320 }; | 351 }; |
| 321 | 352 |
| 322 /** | 353 /** |
| 323 * @return {string} The current search text. | 354 * @return {string} The current search text. |
| 324 */ | 355 */ |
| 325 HistoryModel.prototype.getSearchText = function() { | 356 HistoryModel.prototype.getSearchText = function() { |
| 326 return this.searchText_; | 357 return this.searchText_; |
| 327 }; | 358 }; |
| 328 | 359 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 341 * Receiver for history query. | 372 * Receiver for history query. |
| 342 * @param {Object} info An object containing information about the query. | 373 * @param {Object} info An object containing information about the query. |
| 343 * @param {Array} results A list of results. | 374 * @param {Array} results A list of results. |
| 344 */ | 375 */ |
| 345 HistoryModel.prototype.addResults = function(info, results) { | 376 HistoryModel.prototype.addResults = function(info, results) { |
| 346 $('loading-spinner').hidden = true; | 377 $('loading-spinner').hidden = true; |
| 347 this.inFlight_ = false; | 378 this.inFlight_ = false; |
| 348 this.isQueryFinished_ = info.finished; | 379 this.isQueryFinished_ = info.finished; |
| 349 this.queryCursor_ = info.cursor; | 380 this.queryCursor_ = info.cursor; |
| 350 | 381 |
| 351 // If there are no results, or they're not for the current search term, | 382 // If the results are not for the current search term there's nothing more |
| 352 // there's nothing more to do. | 383 // to do. |
| 353 if (!results || !results.length || info.term != this.searchText_) | 384 if (info.term != this.searchText_) |
| 354 return; | 385 return; |
| 355 | 386 |
| 356 // If necessary, sort the results from newest to oldest. | 387 // If necessary, sort the results from newest to oldest. |
| 357 if (!results.sorted) | 388 if (!results.sorted) |
| 358 results.sort(function(a, b) { return b.time - a.time; }); | 389 results.sort(function(a, b) { return b.time - a.time; }); |
| 359 | 390 |
| 360 var lastVisit = this.visits_.slice(-1)[0]; | 391 var lastVisit = this.visits_.slice(-1)[0]; |
| 361 var lastDay = lastVisit ? lastVisit.dateRelativeDay : null; | 392 var lastDay = lastVisit ? lastVisit.dateRelativeDay : null; |
| 362 | 393 |
| 363 for (var i = 0, thisResult; thisResult = results[i]; i++) { | 394 for (var i = 0, thisResult; thisResult = results[i]; i++) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 408 | 439 |
| 409 // HistoryModel, Private: ----------------------------------------------------- | 440 // HistoryModel, Private: ----------------------------------------------------- |
| 410 | 441 |
| 411 /** | 442 /** |
| 412 * Clear the history model. | 443 * Clear the history model. |
| 413 * @private | 444 * @private |
| 414 */ | 445 */ |
| 415 HistoryModel.prototype.clearModel_ = function() { | 446 HistoryModel.prototype.clearModel_ = function() { |
| 416 this.inFlight_ = false; // Whether a query is inflight. | 447 this.inFlight_ = false; // Whether a query is inflight. |
| 417 this.searchText_ = ''; | 448 this.searchText_ = ''; |
| 449 // Flag to show that the results are grouped by domain or not. | |
| 450 this.groupByDomain_ = false; | |
| 418 | 451 |
| 419 this.visits_ = []; // Date-sorted list of visits (most recent first). | 452 this.visits_ = []; // Date-sorted list of visits (most recent first). |
| 420 this.last_id_ = 0; | 453 this.last_id_ = 0; |
| 421 selectionAnchor = -1; | 454 selectionAnchor = -1; |
| 422 | 455 |
| 423 // The page that the view wants to see - we only fetch slightly past this | 456 // The page that the view wants to see - we only fetch slightly past this |
| 424 // point. If the view requests a page that we don't have data for, we try | 457 // point. If the view requests a page that we don't have data for, we try |
| 425 // to fetch it and call back when we're done. | 458 // to fetch it and call back when we're done. |
| 426 this.requestedPage_ = 0; | 459 this.requestedPage_ = 0; |
| 427 | 460 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 438 // visit to a URL on any day. | 471 // visit to a URL on any day. |
| 439 this.urlsFromLastSeenDay_ = {}; | 472 this.urlsFromLastSeenDay_ = {}; |
| 440 | 473 |
| 441 if (this.view_) | 474 if (this.view_) |
| 442 this.view_.clear_(); | 475 this.view_.clear_(); |
| 443 }; | 476 }; |
| 444 | 477 |
| 445 /** | 478 /** |
| 446 * Figure out if we need to do more queries to fill the currently requested | 479 * Figure out if we need to do more queries to fill the currently requested |
| 447 * page. If we think we can fill the page, call the view and let it know | 480 * page. If we think we can fill the page, call the view and let it know |
| 448 * we're ready to show something. | 481 * we're ready to show something. This only applies to the daily time-based |
| 482 * view. | |
| 449 * @private | 483 * @private |
| 450 */ | 484 */ |
| 451 HistoryModel.prototype.updateSearch_ = function() { | 485 HistoryModel.prototype.updateSearch_ = function() { |
| 452 var doneLoading = | 486 var doneLoading = this.isQueryFinished_ || |
| 453 this.canFillPage_(this.requestedPage_) || this.isQueryFinished_; | 487 this.canFillPage_(this.requestedPage_); |
| 454 | 488 |
| 455 // Try to fetch more results if the current page isn't full. | 489 // Try to fetch more results if the results are not grouped by domain and |
| 490 // the current page isn't full. | |
| 456 if (!doneLoading && !this.inFlight_) | 491 if (!doneLoading && !this.inFlight_) |
| 457 this.queryHistory_(); | 492 this.queryHistory_(); |
| 458 | 493 |
| 459 // If we have any data for the requested page, show it. | 494 // Show the result or a message if no results were returned. |
| 460 if (this.changed && this.haveDataForPage_(this.requestedPage_)) { | 495 this.view_.onModelReady(); |
| 461 this.view_.onModelReady(); | |
| 462 this.changed = false; | |
| 463 } | |
| 464 }; | 496 }; |
| 465 | 497 |
| 466 /** | 498 /** |
| 467 * Query for history, either for a search or time-based browsing. | 499 * Query for history, either for a search or time-based browsing. |
| 468 * @private | 500 * @private |
| 469 */ | 501 */ |
| 470 HistoryModel.prototype.queryHistory_ = function() { | 502 HistoryModel.prototype.queryHistory_ = function() { |
| 471 var endTime = 0; | 503 var endTime = 0; |
| 472 | 504 // Do the time-based search. |
| 473 // If there are already some visits, pick up the previous query where it | 505 // If there are already some visits, pick up the previous query where it |
| 474 // left off. | 506 // left off. |
| 475 if (this.visits_.length > 0) { | 507 if (this.visits_.length > 0) { |
| 476 var lastVisit = this.visits_.slice(-1)[0]; | 508 var lastVisit = this.visits_.slice(-1)[0]; |
| 477 endTime = lastVisit.date.getTime(); | 509 endTime = lastVisit.date.getTime(); |
| 478 cursor = this.queryCursor_; | 510 cursor = this.queryCursor_; |
| 479 } | 511 } |
| 480 | 512 |
| 481 $('loading-spinner').hidden = false; | 513 $('loading-spinner').hidden = false; |
| 482 this.inFlight_ = true; | 514 this.inFlight_ = true; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 497 /** | 529 /** |
| 498 * Check to see if we have data to fill the given page. | 530 * Check to see if we have data to fill the given page. |
| 499 * @param {number} page The page number. | 531 * @param {number} page The page number. |
| 500 * @return {boolean} Whether we have data to fill the page. | 532 * @return {boolean} Whether we have data to fill the page. |
| 501 * @private | 533 * @private |
| 502 */ | 534 */ |
| 503 HistoryModel.prototype.canFillPage_ = function(page) { | 535 HistoryModel.prototype.canFillPage_ = function(page) { |
| 504 return ((page + 1) * RESULTS_PER_PAGE <= this.getSize()); | 536 return ((page + 1) * RESULTS_PER_PAGE <= this.getSize()); |
| 505 }; | 537 }; |
| 506 | 538 |
| 539 /** | |
| 540 * Enables or disables grouping by domain. | |
| 541 * @param {boolean} groupByDomain New groupByDomain_ value. | |
| 542 */ | |
| 543 HistoryModel.prototype.setGroupByDomain = function(groupByDomain) { | |
| 544 this.groupByDomain_ = groupByDomain; | |
| 545 }; | |
| 546 | |
| 547 /** | |
| 548 * Gets whether we are grouped by domain. | |
| 549 * @return {boolean} Whether the results are grouped by domain. | |
| 550 */ | |
| 551 HistoryModel.prototype.getGroupByDomain = function() { | |
| 552 return this.groupByDomain_; | |
| 553 }; | |
| 554 | |
| 507 /////////////////////////////////////////////////////////////////////////////// | 555 /////////////////////////////////////////////////////////////////////////////// |
| 508 // HistoryView: | 556 // HistoryView: |
| 509 | 557 |
| 510 /** | 558 /** |
| 511 * Functions and state for populating the page with HTML. This should one-day | 559 * Functions and state for populating the page with HTML. This should one-day |
| 512 * contain the view and use event handlers, rather than pushing HTML out and | 560 * contain the view and use event handlers, rather than pushing HTML out and |
| 513 * getting called externally. | 561 * getting called externally. |
| 514 * @param {HistoryModel} model The model backing this view. | 562 * @param {HistoryModel} model The model backing this view. |
| 515 * @constructor | 563 * @constructor |
| 516 */ | 564 */ |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 535 // Add handlers for the page navigation buttons at the bottom. | 583 // Add handlers for the page navigation buttons at the bottom. |
| 536 $('newest-button').addEventListener('click', function() { | 584 $('newest-button').addEventListener('click', function() { |
| 537 self.setPage(0); | 585 self.setPage(0); |
| 538 }); | 586 }); |
| 539 $('newer-button').addEventListener('click', function() { | 587 $('newer-button').addEventListener('click', function() { |
| 540 self.setPage(self.pageIndex_ - 1); | 588 self.setPage(self.pageIndex_ - 1); |
| 541 }); | 589 }); |
| 542 $('older-button').addEventListener('click', function() { | 590 $('older-button').addEventListener('click', function() { |
| 543 self.setPage(self.pageIndex_ + 1); | 591 self.setPage(self.pageIndex_ + 1); |
| 544 }); | 592 }); |
| 593 | |
| 594 $('display-filter-sites').addEventListener('click', function(e) { | |
| 595 self.setGroupByDomain($('display-filter-sites').checked); | |
| 596 }); | |
| 545 } | 597 } |
| 546 | 598 |
| 547 // HistoryView, public: ------------------------------------------------------- | 599 // HistoryView, public: ------------------------------------------------------- |
| 548 /** | 600 /** |
| 549 * Do a search and optionally view a certain page. | 601 * Do a search and optionally view a certain page. |
| 550 * @param {string} term The string to search for. | 602 * @param {string} term The string to search for. |
| 551 * @param {number} opt_page The page we wish to view, only use this for | 603 * @param {number} opt_page The page we wish to view, only use this for |
| 552 * setting up initial views, as this triggers a search. | 604 * setting up initial views, as this triggers a search. |
| 553 */ | 605 */ |
| 554 HistoryView.prototype.setSearch = function(term, opt_page) { | 606 HistoryView.prototype.setSearch = function(term, opt_page) { |
| 555 this.pageIndex_ = parseInt(opt_page || 0, 10); | 607 this.pageIndex_ = parseInt(opt_page || 0, 10); |
| 556 window.scrollTo(0, 0); | 608 window.scrollTo(0, 0); |
| 557 this.model_.setSearchText(term, this.pageIndex_); | 609 this.model_.setSearchText(term, this.pageIndex_); |
| 558 pageState.setUIState(term, this.pageIndex_); | 610 pageState.setUIState(term, this.pageIndex_, this.model_.getGroupByDomain()); |
| 559 }; | 611 }; |
| 560 | 612 |
| 561 /** | 613 /** |
| 614 * Enable or disable results as being grouped by domain. | |
| 615 * @param {boolean} groupedByDomain Whether to group by domain or not. | |
| 616 */ | |
| 617 HistoryView.prototype.setGroupByDomain = function(groupedByDomain) { | |
| 618 // Group by domain is not currently supported for search results, so reset | |
| 619 // the search term if there was one. | |
| 620 this.model_.clearSearchText(); | |
| 621 this.model_.setGroupByDomain(groupedByDomain); | |
| 622 this.model_.reload(); | |
| 623 pageState.setUIState(this.model_.getSearchText(), | |
| 624 this.pageIndex_, | |
| 625 this.model_.getGroupByDomain()); | |
| 626 }; | |
| 627 | |
| 628 /** | |
| 562 * Reload the current view. | 629 * Reload the current view. |
| 563 */ | 630 */ |
| 564 HistoryView.prototype.reload = function() { | 631 HistoryView.prototype.reload = function() { |
| 565 this.model_.reload(); | 632 this.model_.reload(); |
| 566 this.updateRemoveButton(); | 633 this.updateRemoveButton(); |
| 567 }; | 634 }; |
| 568 | 635 |
| 569 /** | 636 /** |
| 570 * Switch to a specified page. | 637 * Switch to a specified page. |
| 571 * @param {number} page The page we wish to view. | 638 * @param {number} page The page we wish to view. |
| 572 */ | 639 */ |
| 573 HistoryView.prototype.setPage = function(page) { | 640 HistoryView.prototype.setPage = function(page) { |
| 574 this.clear_(); | 641 this.clear_(); |
| 575 this.pageIndex_ = parseInt(page, 10); | 642 this.pageIndex_ = parseInt(page, 10); |
| 576 window.scrollTo(0, 0); | 643 window.scrollTo(0, 0); |
| 577 this.model_.requestPage(page); | 644 this.model_.requestPage(page); |
| 578 pageState.setUIState(this.model_.getSearchText(), this.pageIndex_); | 645 pageState.setUIState(this.model_.getSearchText(), |
| 646 this.pageIndex_, | |
| 647 this.model_.getGroupByDomain()); | |
| 579 }; | 648 }; |
| 580 | 649 |
| 581 /** | 650 /** |
| 582 * @return {number} The page number being viewed. | 651 * @return {number} The page number being viewed. |
| 583 */ | 652 */ |
| 584 HistoryView.prototype.getPage = function() { | 653 HistoryView.prototype.getPage = function() { |
| 585 return this.pageIndex_; | 654 return this.pageIndex_; |
| 586 }; | 655 }; |
| 587 | 656 |
| 588 /** | 657 /** |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 622 * Record that the given visit has been rendered. | 691 * Record that the given visit has been rendered. |
| 623 * @param {Visit} visit The visit that was rendered. | 692 * @param {Visit} visit The visit that was rendered. |
| 624 * @private | 693 * @private |
| 625 */ | 694 */ |
| 626 HistoryView.prototype.setVisitRendered_ = function(visit) { | 695 HistoryView.prototype.setVisitRendered_ = function(visit) { |
| 627 visit.isRendered = true; | 696 visit.isRendered = true; |
| 628 this.currentVisits_.push(visit); | 697 this.currentVisits_.push(visit); |
| 629 }; | 698 }; |
| 630 | 699 |
| 631 /** | 700 /** |
| 701 * This function generates and adds the grouped visits DOM for a certain | |
| 702 * domain. This includes the clickable arrow and domain name and the visit | |
| 703 * entries for that domain. | |
| 704 * @param {Element} results DOM object to which to add the elements. | |
| 705 * @param {string} domain Current domain name. | |
| 706 * @param {Array} domainVisits Array of visits for this domain. | |
| 707 * @private | |
| 708 */ | |
| 709 HistoryView.prototype.getGroupedVisitsDOM_ = function( | |
| 710 results, domain, domainVisits) { | |
| 711 // Add a new domain entry. | |
| 712 var siteResults = results.appendChild( | |
| 713 createElementWithClassName('li', 'site-entry')); | |
| 714 // Make a wrapper that will contain the arrow, the favicon and the domain. | |
| 715 var siteDomainWrapper = siteResults.appendChild( | |
| 716 createElementWithClassName('div', 'site-domain-wrapper')); | |
| 717 var siteArrow = siteDomainWrapper.appendChild( | |
| 718 createElementWithClassName('div', 'site-domain-arrow collapse')); | |
| 719 var siteDomain = siteDomainWrapper.appendChild( | |
| 720 createElementWithClassName('div', 'site-domain')); | |
| 721 var numberOfVisits = createElementWithClassName('span', 'number-visits'); | |
| 722 numberOfVisits.textContent = loadTimeData.getStringF('numbervisits', | |
| 723 domainVisits.length); | |
| 724 siteDomain.textContent = domain; | |
| 725 siteDomain.appendChild(numberOfVisits); | |
| 726 siteResults.appendChild(siteDomainWrapper); | |
| 727 var resultsList = siteResults.appendChild( | |
| 728 createElementWithClassName('ol', 'site-results')); | |
| 729 | |
| 730 domainVisits[0].addFaviconToElement_(siteDomain); | |
| 731 | |
| 732 siteDomainWrapper.addEventListener('click', toggleHandler); | |
| 733 // Collapse until it gets toggled. | |
| 734 resultsList.style.height = 0; | |
| 735 | |
| 736 // Add the results for each of the domain. | |
| 737 for (var j = 0, visit; visit = domainVisits[j]; j++) { | |
| 738 resultsList.appendChild(visit.getResultDOM({})); | |
| 739 this.setVisitRendered_(visit); | |
| 740 } | |
| 741 }; | |
| 742 | |
| 743 /** | |
| 744 * Groups visits by domain, sorting them by the number of visits. | |
| 745 * @param {Array} visits Visits received from the query results. | |
| 746 * @param {Element} results Object where the results are added to. | |
| 747 * @private | |
| 748 */ | |
| 749 HistoryView.prototype.groupVisitsByDomain_ = function(visits, results) { | |
| 750 var visitsByDomain = {}; | |
| 751 var domains = []; | |
| 752 | |
| 753 // Group the visits into a dictionary and generate a list of domains. | |
| 754 for (var i = 0, visit; visit = visits[i]; i++) { | |
| 755 var domain = visit.getDomainFromURL_(visit.url_); | |
| 756 if (!visitsByDomain[domain]) { | |
| 757 visitsByDomain[domain] = []; | |
| 758 domains.push(domain); | |
| 759 } | |
| 760 visitsByDomain[domain].push(visit); | |
| 761 } | |
| 762 var sortByVisits = function(a, b) { | |
| 763 return visitsByDomain[b].length - visitsByDomain[a].length; | |
| 764 }; | |
| 765 domains.sort(sortByVisits); | |
| 766 | |
| 767 for (var i = 0, domain; domain = domains[i]; i++) { | |
| 768 this.getGroupedVisitsDOM_(results, domain, visitsByDomain[domain]); | |
| 769 } | |
| 770 }; | |
| 771 | |
| 772 /** | |
| 773 * Adds the results grouped by days, grouping them if needed. | |
| 774 * @param {Array} visits Visits returned by the query. | |
| 775 * @param {Element} parentElement Element to which to add the results to. | |
| 776 * @private | |
| 777 */ | |
| 778 HistoryView.prototype.addDayResults_ = function(visits, parentElement) { | |
| 779 if (visits.length == 0) | |
| 780 return; | |
| 781 | |
| 782 var firstVisit = visits[0]; | |
| 783 var day = parentElement.appendChild(createElementWithClassName('h3', 'day')); | |
| 784 day.appendChild(document.createTextNode(firstVisit.dateRelativeDay)); | |
| 785 if (firstVisit.continued) { | |
| 786 day.appendChild(document.createTextNode(' ' + | |
| 787 loadTimeData.getString('cont'))); | |
| 788 } | |
| 789 var dayResults = parentElement.appendChild( | |
| 790 createElementWithClassName('ol', 'day-results')); | |
| 791 | |
| 792 if (this.model_.getGroupByDomain()) { | |
| 793 this.groupVisitsByDomain_(visits, dayResults); | |
| 794 } else { | |
| 795 var lastTime; | |
| 796 | |
| 797 for (var i = 0, visit; visit = visits[i]; i++) { | |
| 798 // If enough time has passed between visits, indicate a gap in browsing. | |
| 799 var thisTime = visit.date.getTime(); | |
| 800 if (lastTime && lastTime - thisTime > BROWSING_GAP_TIME) | |
| 801 dayResults.appendChild(createElementWithClassName('li', 'gap')); | |
| 802 | |
| 803 // Insert the visit into the DOM. | |
| 804 dayResults.appendChild(visit.getResultDOM({ | |
| 805 addTitleFavicon: true | |
| 806 })); | |
| 807 this.setVisitRendered_(visit); | |
| 808 | |
| 809 lastTime = thisTime; | |
| 810 } | |
| 811 } | |
| 812 }; | |
| 813 | |
| 814 /** | |
| 632 * Update the page with results. | 815 * Update the page with results. |
| 633 * @private | 816 * @private |
| 634 */ | 817 */ |
| 635 HistoryView.prototype.displayResults_ = function() { | 818 HistoryView.prototype.displayResults_ = function() { |
| 636 var rangeStart = this.pageIndex_ * RESULTS_PER_PAGE; | 819 var rangeStart = this.pageIndex_ * RESULTS_PER_PAGE; |
| 637 var rangeEnd = rangeStart + RESULTS_PER_PAGE; | 820 var rangeEnd = rangeStart + RESULTS_PER_PAGE; |
| 638 var results = this.model_.getNumberedRange(rangeStart, rangeEnd); | 821 var results = this.model_.getNumberedRange(rangeStart, rangeEnd); |
| 639 | 822 |
| 640 var searchText = this.model_.getSearchText(); | 823 var searchText = this.model_.getSearchText(); |
| 824 var groupByDomain = this.model_.getGroupByDomain(); | |
| 825 | |
| 641 if (searchText) { | 826 if (searchText) { |
| 642 // Add a header for the search results, if there isn't already one. | 827 // Add a header for the search results, if there isn't already one. |
| 643 if (!this.resultDiv_.querySelector('h3')) { | 828 if (!this.resultDiv_.querySelector('h3')) { |
| 644 var header = document.createElement('h3'); | 829 var header = document.createElement('h3'); |
| 645 header.textContent = loadTimeData.getStringF('searchresultsfor', | 830 header.textContent = loadTimeData.getStringF('searchresultsfor', |
| 646 searchText); | 831 searchText); |
| 647 this.resultDiv_.appendChild(header); | 832 this.resultDiv_.appendChild(header); |
| 648 } | 833 } |
| 649 | 834 |
| 650 var searchResults = createElementWithClassName('ol', 'search-results'); | 835 var searchResults = createElementWithClassName('ol', 'search-results'); |
| 651 if (results.length == 0) { | 836 if (results.length == 0) { |
| 652 var noResults = document.createElement('div'); | 837 var noResults = document.createElement('div'); |
| 653 noResults.textContent = loadTimeData.getString('noresults'); | 838 noResults.textContent = loadTimeData.getString('noresults'); |
| 654 searchResults.appendChild(noResults); | 839 searchResults.appendChild(noResults); |
| 655 } else { | 840 } else { |
| 656 for (var i = 0, visit; visit = results[i]; i++) { | 841 for (var i = 0, visit; visit = results[i]; i++) { |
| 657 if (!visit.isRendered) { | 842 if (!visit.isRendered) { |
| 658 searchResults.appendChild(visit.getResultDOM(true)); | 843 searchResults.appendChild(visit.getResultDOM({ |
| 844 isSearchResult: true, | |
| 845 addTitleFavicon: true | |
| 846 })); | |
| 659 this.setVisitRendered_(visit); | 847 this.setVisitRendered_(visit); |
| 660 } | 848 } |
| 661 } | 849 } |
| 662 } | 850 } |
| 663 this.resultDiv_.appendChild(searchResults); | 851 this.resultDiv_.appendChild(searchResults); |
| 664 } else { | 852 } else { |
| 853 if (results.length == 0) { | |
| 854 var noResults = document.createElement('div'); | |
| 855 noResults.textContent = loadTimeData.getString('noresultsinterval'); | |
|
Patrick Dubroy
2013/01/21 09:42:40
This message doesn't make sense for the normal his
Sergiu
2013/01/21 10:38:29
Done, renamed all the strings related to "no resul
| |
| 856 this.resultDiv_.appendChild(noResults); | |
| 857 this.updateNavBar_(); | |
| 858 return; | |
| 859 } | |
| 860 | |
| 665 var resultsFragment = document.createDocumentFragment(); | 861 var resultsFragment = document.createDocumentFragment(); |
| 666 var lastTime = Math.infinity; | |
| 667 var dayResults; | |
| 668 | 862 |
| 669 for (var i = 0, visit; visit = results[i]; i++) { | 863 var dayStart = 0; |
| 670 if (visit.isRendered) | 864 var dayEnd = 0; |
| 671 continue; | 865 // Go through all of the visits and process them in chunks of one day. |
| 866 while (dayEnd < results.length) { | |
| 867 // Skip over the ones that are already rendered. | |
| 868 while (dayStart < results.length && results[dayStart].isRendered) | |
| 869 ++dayStart; | |
| 870 var dayEnd = dayStart + 1; | |
| 871 while (dayEnd < results.length && results[dayEnd].continued) | |
| 872 ++dayEnd; | |
| 672 | 873 |
| 673 var thisTime = visit.date.getTime(); | 874 this.addDayResults_( |
| 875 results.slice(dayStart, dayEnd), resultsFragment, groupByDomain); | |
| 876 } | |
| 674 | 877 |
| 675 // Break across day boundaries and insert gaps for browsing pauses. | 878 // Add all the days and their visits to the page. |
| 676 // Create a dayResults element to contain results for each day. | |
| 677 if ((i == 0 && visit.continued) || !visit.continued) { | |
| 678 // It's the first visit of the day, or the day is continued from | |
| 679 // the previous page. Create a header for the day on the current page. | |
| 680 var day = createElementWithClassName('h3', 'day'); | |
| 681 day.appendChild(document.createTextNode(visit.dateRelativeDay)); | |
| 682 if (visit.continued) { | |
| 683 day.appendChild(document.createTextNode(' ' + | |
| 684 loadTimeData.getString('cont'))); | |
| 685 } | |
| 686 | |
| 687 resultsFragment.appendChild(day); | |
| 688 dayResults = createElementWithClassName('ol', 'day-results'); | |
| 689 resultsFragment.appendChild(dayResults); | |
| 690 } else if (dayResults && lastTime - thisTime > BROWSING_GAP_TIME) { | |
| 691 dayResults.appendChild(createElementWithClassName('li', 'gap')); | |
| 692 } | |
| 693 lastTime = thisTime; | |
| 694 | |
| 695 // Add the entry to the appropriate day. | |
| 696 dayResults.appendChild(visit.getResultDOM(false)); | |
| 697 this.setVisitRendered_(visit); | |
| 698 } | |
| 699 this.resultDiv_.appendChild(resultsFragment); | 879 this.resultDiv_.appendChild(resultsFragment); |
| 700 } | 880 } |
| 881 this.updateNavBar_(); | |
| 701 }; | 882 }; |
| 702 | 883 |
| 703 /** | 884 /** |
| 704 * Update the visibility of the page navigation buttons. | 885 * Update the visibility of the page navigation buttons. |
| 705 * @private | 886 * @private |
| 706 */ | 887 */ |
| 707 HistoryView.prototype.updateNavBar_ = function() { | 888 HistoryView.prototype.updateNavBar_ = function() { |
| 708 $('newest-button').hidden = this.pageIndex_ == 0; | 889 $('newest-button').hidden = this.pageIndex_ == 0; |
| 709 $('newer-button').hidden = this.pageIndex_ == 0; | 890 $('newer-button').hidden = this.pageIndex_ == 0; |
| 710 $('older-button').hidden = !this.model_.hasMoreResults(); | 891 $('older-button').hidden = !this.model_.hasMoreResults(); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 732 } | 913 } |
| 733 | 914 |
| 734 // TODO(glen): Replace this with a bound method so we don't need | 915 // TODO(glen): Replace this with a bound method so we don't need |
| 735 // public model and view. | 916 // public model and view. |
| 736 this.checker_ = setInterval((function(state_obj) { | 917 this.checker_ = setInterval((function(state_obj) { |
| 737 var hashData = state_obj.getHashData(); | 918 var hashData = state_obj.getHashData(); |
| 738 if (hashData.q != state_obj.model.getSearchText()) { | 919 if (hashData.q != state_obj.model.getSearchText()) { |
| 739 state_obj.view.setSearch(hashData.q, parseInt(hashData.p, 10)); | 920 state_obj.view.setSearch(hashData.q, parseInt(hashData.p, 10)); |
| 740 } else if (parseInt(hashData.p, 10) != state_obj.view.getPage()) { | 921 } else if (parseInt(hashData.p, 10) != state_obj.view.getPage()) { |
| 741 state_obj.view.setPage(hashData.p); | 922 state_obj.view.setPage(hashData.p); |
| 923 } else if ((hashData.g == 'true') != | |
| 924 state_obj.view.model_.getGroupByDomain()) { | |
| 925 state_obj.view.setGroupByDomain(hashData.g); | |
| 742 } | 926 } |
| 743 }), 50, this); | 927 }), 50, this); |
| 744 } | 928 } |
| 745 | 929 |
| 746 /** | 930 /** |
| 747 * Holds the singleton instance. | 931 * Holds the singleton instance. |
| 748 */ | 932 */ |
| 749 PageState.instance = null; | 933 PageState.instance = null; |
| 750 | 934 |
| 751 /** | 935 /** |
| 752 * @return {Object} An object containing parameters from our window hash. | 936 * @return {Object} An object containing parameters from our window hash. |
| 753 */ | 937 */ |
| 754 PageState.prototype.getHashData = function() { | 938 PageState.prototype.getHashData = function() { |
| 755 var result = { | 939 var result = { |
| 756 e: 0, | 940 e: 0, |
| 757 q: '', | 941 q: '', |
| 758 p: 0 | 942 p: 0, |
| 943 g: false | |
| 759 }; | 944 }; |
| 760 | 945 |
| 761 if (!window.location.hash) { | 946 if (!window.location.hash) |
| 762 return result; | 947 return result; |
| 763 } | |
| 764 | 948 |
| 765 var hashSplit = window.location.hash.substr(1).split('&'); | 949 var hashSplit = window.location.hash.substr(1).split('&'); |
| 766 for (var i = 0; i < hashSplit.length; i++) { | 950 for (var i = 0; i < hashSplit.length; i++) { |
| 767 var pair = hashSplit[i].split('='); | 951 var pair = hashSplit[i].split('='); |
| 768 if (pair.length > 1) { | 952 if (pair.length > 1) { |
| 769 result[pair[0]] = decodeURIComponent(pair[1].replace(/\+/g, ' ')); | 953 result[pair[0]] = decodeURIComponent(pair[1].replace(/\+/g, ' ')); |
| 770 } | 954 } |
| 771 } | 955 } |
| 772 | 956 |
| 773 return result; | 957 return result; |
| 774 }; | 958 }; |
| 775 | 959 |
| 776 /** | 960 /** |
| 777 * Set the hash to a specified state, this will create an entry in the | 961 * Set the hash to a specified state, this will create an entry in the |
| 778 * session history so the back button cycles through hash states, which | 962 * session history so the back button cycles through hash states, which |
| 779 * are then picked up by our listener. | 963 * are then picked up by our listener. |
| 780 * @param {string} term The current search string. | 964 * @param {string} term The current search string. |
| 781 * @param {string} page The page currently being viewed. | 965 * @param {number} page The page currently being viewed. |
| 966 * @param {boolean} grouped Whether the results are grouped or not. | |
| 782 */ | 967 */ |
| 783 PageState.prototype.setUIState = function(term, page) { | 968 PageState.prototype.setUIState = function(term, page, grouped) { |
| 784 // Make sure the form looks pretty. | 969 // Make sure the form looks pretty. |
| 785 $('search-field').value = term; | 970 $('search-field').value = term; |
| 786 var currentHash = this.getHashData(); | 971 if (grouped) { |
| 787 if (currentHash.q != term || currentHash.p != page) { | 972 $('display-filter-sites').checked = true; |
| 788 window.location.hash = PageState.getHashString(term, page); | 973 } else { |
| 974 $('display-filter-sites').checked = false; | |
| 975 } | |
| 976 var hash = this.getHashData(); | |
| 977 if (hash.q != term || hash.p != page || hash.g != grouped) { | |
| 978 window.location.hash = PageState.getHashString( | |
| 979 term, page, grouped); | |
| 789 } | 980 } |
| 790 }; | 981 }; |
| 791 | 982 |
| 792 /** | 983 /** |
| 793 * Static method to get the hash string for a specified state | 984 * Static method to get the hash string for a specified state |
| 794 * @param {string} term The current search string. | 985 * @param {string} term The current search string. |
| 795 * @param {string} page The page currently being viewed. | 986 * @param {number} page The page currently being viewed. |
| 987 * @param {boolean} grouped Whether the results are grouped or not. | |
| 796 * @return {string} The string to be used in a hash. | 988 * @return {string} The string to be used in a hash. |
| 797 */ | 989 */ |
| 798 PageState.getHashString = function(term, page) { | 990 PageState.getHashString = function(term, page, grouped) { |
| 991 // Omit elements that are empty. | |
| 799 var newHash = []; | 992 var newHash = []; |
| 800 if (term) { | 993 |
| 994 if (term) | |
| 801 newHash.push('q=' + encodeURIComponent(term)); | 995 newHash.push('q=' + encodeURIComponent(term)); |
| 802 } | 996 |
| 803 if (page != undefined) { | 997 if (page) |
| 804 newHash.push('p=' + page); | 998 newHash.push('p=' + page); |
| 805 } | 999 |
| 1000 if (grouped) | |
| 1001 newHash.push('g=' + grouped); | |
| 806 | 1002 |
| 807 return newHash.join('&'); | 1003 return newHash.join('&'); |
| 808 }; | 1004 }; |
| 809 | 1005 |
| 810 /////////////////////////////////////////////////////////////////////////////// | 1006 /////////////////////////////////////////////////////////////////////////////// |
| 811 // Document Functions: | 1007 // Document Functions: |
| 812 /** | 1008 /** |
| 813 * Window onload handler, sets up the page. | 1009 * Window onload handler, sets up the page. |
| 814 */ | 1010 */ |
| 815 function load() { | 1011 function load() { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 833 | 1029 |
| 834 $('remove-visit').addEventListener('activate', function(e) { | 1030 $('remove-visit').addEventListener('activate', function(e) { |
| 835 activeVisit.removeFromHistory_(); | 1031 activeVisit.removeFromHistory_(); |
| 836 activeVisit = null; | 1032 activeVisit = null; |
| 837 }); | 1033 }); |
| 838 $('more-from-site').addEventListener('activate', function(e) { | 1034 $('more-from-site').addEventListener('activate', function(e) { |
| 839 activeVisit.showMoreFromSite_(); | 1035 activeVisit.showMoreFromSite_(); |
| 840 activeVisit = null; | 1036 activeVisit = null; |
| 841 }); | 1037 }); |
| 842 | 1038 |
| 1039 // Only show the controls if the command line switch is activated. | |
| 1040 if (loadTimeData.getBoolean('historyGroupEnabled')) { | |
| 1041 $('filter-controls').hidden = false; | |
| 1042 } | |
| 1043 | |
| 843 var title = loadTimeData.getString('title'); | 1044 var title = loadTimeData.getString('title'); |
| 844 uber.invokeMethodOnParent('setTitle', {title: title}); | 1045 uber.invokeMethodOnParent('setTitle', {title: title}); |
| 845 | 1046 |
| 846 window.addEventListener('message', function(e) { | 1047 window.addEventListener('message', function(e) { |
| 847 if (e.data.method == 'frameSelected') | 1048 if (e.data.method == 'frameSelected') |
| 848 searchField.focus(); | 1049 searchField.focus(); |
| 849 }); | 1050 }); |
| 850 } | 1051 } |
| 851 | 1052 |
| 852 /** | 1053 /** |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1022 removeNode(previousEntry); | 1223 removeNode(previousEntry); |
| 1023 } | 1224 } |
| 1024 | 1225 |
| 1025 // if both the next and previous entries are gaps, remove one | 1226 // if both the next and previous entries are gaps, remove one |
| 1026 if (nextEntry && nextEntry.className == 'gap' && | 1227 if (nextEntry && nextEntry.className == 'gap' && |
| 1027 previousEntry && previousEntry.className == 'gap') { | 1228 previousEntry && previousEntry.className == 'gap') { |
| 1028 removeNode(nextEntry); | 1229 removeNode(nextEntry); |
| 1029 } | 1230 } |
| 1030 } | 1231 } |
| 1031 | 1232 |
| 1233 /** | |
| 1234 * Toggles an element in the grouped history. | |
| 1235 * @param {Element} e The element which was clicked on. | |
| 1236 */ | |
| 1237 function toggleHandler(e) { | |
| 1238 var innerResultList = e.currentTarget.parentElement.querySelector( | |
| 1239 '.site-results'); | |
| 1240 var innerArrow = e.currentTarget.parentElement.querySelector( | |
| 1241 '.site-domain-arrow'); | |
| 1242 if (innerArrow.classList.contains('collapse')) { | |
| 1243 innerResultList.style.height = 'auto'; | |
| 1244 // -webkit-transition does not work on height:auto elements so first set | |
| 1245 // the height to auto so that it is computed and then set it to the | |
| 1246 // computed value in pixels so the transition works properly. | |
| 1247 var height = innerResultList.clientHeight; | |
| 1248 innerResultList.style.height = height + 'px'; | |
| 1249 innerArrow.classList.remove('collapse'); | |
| 1250 innerArrow.classList.add('expand'); | |
| 1251 } else { | |
| 1252 innerResultList.style.height = 0; | |
| 1253 innerArrow.classList.remove('expand'); | |
| 1254 innerArrow.classList.add('collapse'); | |
| 1255 } | |
| 1256 } | |
| 1257 | |
| 1032 /////////////////////////////////////////////////////////////////////////////// | 1258 /////////////////////////////////////////////////////////////////////////////// |
| 1033 // Chrome callbacks: | 1259 // Chrome callbacks: |
| 1034 | 1260 |
| 1035 /** | 1261 /** |
| 1036 * Our history system calls this function with results from searches. | 1262 * Our history system calls this function with results from searches. |
| 1037 * @param {Object} info An object containing information about the query. | 1263 * @param {Object} info An object containing information about the query. |
| 1038 * @param {Array} results A list of results. | 1264 * @param {Array} results A list of results. |
| 1039 */ | 1265 */ |
| 1040 function historyResult(info, results) { | 1266 function historyResult(info, results) { |
| 1041 historyModel.addResults(info, results); | 1267 historyModel.addResults(info, results); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1079 historyView.reload(); | 1305 historyView.reload(); |
| 1080 } | 1306 } |
| 1081 | 1307 |
| 1082 // Add handlers to HTML elements. | 1308 // Add handlers to HTML elements. |
| 1083 document.addEventListener('DOMContentLoaded', load); | 1309 document.addEventListener('DOMContentLoaded', load); |
| 1084 | 1310 |
| 1085 // This event lets us enable and disable menu items before the menu is shown. | 1311 // This event lets us enable and disable menu items before the menu is shown. |
| 1086 document.addEventListener('canExecute', function(e) { | 1312 document.addEventListener('canExecute', function(e) { |
| 1087 e.canExecute = true; | 1313 e.canExecute = true; |
| 1088 }); | 1314 }); |
| OLD | NEW |