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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
50 * chrome/browser/ui/webui/history_ui.cc: | 50 * chrome/browser/ui/webui/history_ui.cc: |
51 * BrowsingHistoryHandler::HistoryEntry::ToValue() | 51 * BrowsingHistoryHandler::HistoryEntry::ToValue() |
52 * @typedef {{allTimestamps: Array<number>, | 52 * @typedef {{allTimestamps: Array<number>, |
53 * blockedVisit: (boolean|undefined), | 53 * blockedVisit: (boolean|undefined), |
54 * dateRelativeDay: (string|undefined), | 54 * dateRelativeDay: (string|undefined), |
55 * dateShort: string, | 55 * dateShort: string, |
56 * dateTimeOfDay: (string|undefined), | 56 * dateTimeOfDay: (string|undefined), |
57 * deviceName: string, | 57 * deviceName: string, |
58 * deviceType: string, | 58 * deviceType: string, |
59 * domain: string, | 59 * domain: string, |
60 * fallbackFaviconText: string, | |
Dan Beam
2016/02/05 20:42:11
is this ever more than a character?
pkotwicz
2016/02/06 02:59:55
Yes, fallbackFaviconText is "IP" for IP urls. Othe
| |
60 * hostFilteringBehavior: (number|undefined), | 61 * hostFilteringBehavior: (number|undefined), |
61 * snippet: (string|undefined), | 62 * snippet: (string|undefined), |
62 * starred: boolean, | 63 * starred: boolean, |
63 * time: number, | 64 * time: number, |
64 * title: string, | 65 * title: string, |
65 * url: string}} | 66 * url: string}} |
66 */ | 67 */ |
67 var HistoryEntry; | 68 var HistoryEntry; |
68 | 69 |
69 /** | 70 /** |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 * visit before it. | 119 * visit before it. |
119 * @param {HistoryModel} model The model object this entry belongs to. | 120 * @param {HistoryModel} model The model object this entry belongs to. |
120 * @constructor | 121 * @constructor |
121 */ | 122 */ |
122 function Visit(result, continued, model) { | 123 function Visit(result, continued, model) { |
123 this.model_ = model; | 124 this.model_ = model; |
124 this.title_ = result.title; | 125 this.title_ = result.title; |
125 this.url_ = result.url; | 126 this.url_ = result.url; |
126 this.domain_ = result.domain; | 127 this.domain_ = result.domain; |
127 this.starred_ = result.starred; | 128 this.starred_ = result.starred; |
129 this.fallbackFaviconText_ = result.fallbackFaviconText; | |
128 | 130 |
129 // These identify the name and type of the device on which this visit | 131 // These identify the name and type of the device on which this visit |
130 // occurred. They will be empty if the visit occurred on the current device. | 132 // occurred. They will be empty if the visit occurred on the current device. |
131 this.deviceName = result.deviceName; | 133 this.deviceName = result.deviceName; |
132 this.deviceType = result.deviceType; | 134 this.deviceType = result.deviceType; |
133 | 135 |
134 // The ID will be set according to when the visit was displayed, not | 136 // The ID will be set according to when the visit was displayed, not |
135 // received. Set to -1 to show that it has not been set yet. | 137 // received. Set to -1 to show that it has not been set yet. |
136 this.id_ = -1; | 138 this.id_ = -1; |
137 | 139 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
245 bookmarkSection.removeEventListener('click', f); | 247 bookmarkSection.removeEventListener('click', f); |
246 e.preventDefault(); | 248 e.preventDefault(); |
247 }.bind(this)); | 249 }.bind(this)); |
248 } | 250 } |
249 | 251 |
250 if (focusless) | 252 if (focusless) |
251 bookmarkSection.tabIndex = -1; | 253 bookmarkSection.tabIndex = -1; |
252 | 254 |
253 entryBox.appendChild(bookmarkSection); | 255 entryBox.appendChild(bookmarkSection); |
254 | 256 |
257 if (addTitleFavicon || this.blockedVisit) { | |
258 var faviconSection = createElementWithClassName('div', 'favicon'); | |
259 if (this.blockedVisit) | |
260 faviconSection.classList.add('blocked-icon'); | |
261 else | |
262 this.loadFavicon_(faviconSection); | |
263 entryBox.appendChild(faviconSection); | |
264 } | |
265 | |
255 var visitEntryWrapper = /** @type {HTMLElement} */( | 266 var visitEntryWrapper = /** @type {HTMLElement} */( |
256 entryBox.appendChild(document.createElement('div'))); | 267 entryBox.appendChild(document.createElement('div'))); |
257 if (addTitleFavicon || this.blockedVisit) | 268 if (addTitleFavicon || this.blockedVisit) |
258 visitEntryWrapper.classList.add('visit-entry'); | 269 visitEntryWrapper.classList.add('visit-entry'); |
259 if (this.blockedVisit) { | 270 if (this.blockedVisit) { |
260 visitEntryWrapper.classList.add('blocked-indicator'); | 271 visitEntryWrapper.classList.add('blocked-indicator'); |
261 visitEntryWrapper.appendChild(this.getVisitAttemptDOM_()); | 272 visitEntryWrapper.appendChild(this.getVisitAttemptDOM_()); |
262 } else { | 273 } else { |
263 var title = visitEntryWrapper.appendChild( | 274 var title = visitEntryWrapper.appendChild( |
264 this.getTitleDOM_(isSearchResult)); | 275 this.getTitleDOM_(isSearchResult)); |
265 | 276 |
266 if (addTitleFavicon) | |
267 this.addFaviconToElement_(visitEntryWrapper); | |
268 | |
269 if (focusless) | 277 if (focusless) |
270 title.querySelector('a').tabIndex = -1; | 278 title.querySelector('a').tabIndex = -1; |
271 | 279 |
272 visitEntryWrapper.appendChild(domain); | 280 visitEntryWrapper.appendChild(domain); |
273 } | 281 } |
274 | 282 |
275 if (isMobileVersion()) { | 283 if (isMobileVersion()) { |
276 if (this.model_.editingEntriesAllowed) { | 284 if (this.model_.editingEntriesAllowed) { |
277 var removeButton = createElementWithClassName('button', 'remove-entry'); | 285 var removeButton = createElementWithClassName('button', 'remove-entry'); |
278 removeButton.setAttribute('aria-label', | 286 removeButton.setAttribute('aria-label', |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
466 Visit.prototype.getVisitAttemptDOM_ = function() { | 474 Visit.prototype.getVisitAttemptDOM_ = function() { |
467 var node = createElementWithClassName('div', 'title'); | 475 var node = createElementWithClassName('div', 'title'); |
468 node.innerHTML = loadTimeData.getStringF('blockedVisitText', | 476 node.innerHTML = loadTimeData.getStringF('blockedVisitText', |
469 this.url_, | 477 this.url_, |
470 this.id_, | 478 this.id_, |
471 this.domain_); | 479 this.domain_); |
472 return node; | 480 return node; |
473 }; | 481 }; |
474 | 482 |
475 /** | 483 /** |
476 * Set the favicon for an element. | 484 * Load the favicon for an element. |
477 * @param {Element} el The DOM element to which to add the icon. | 485 * @param {Element} faviconDiv The DOM element for which to load the icon. |
478 * @private | 486 * @private |
479 */ | 487 */ |
480 Visit.prototype.addFaviconToElement_ = function(el) { | 488 Visit.prototype.loadFavicon_ = function(faviconDiv) { |
481 var url = isMobileVersion() ? | 489 if (cr.isAndroid) { |
482 getFaviconImageSet(this.url_, 32, 'touch-icon') : | 490 // On Android, if a large icon is unavailable, a fallback favicon is |
483 getFaviconImageSet(this.url_); | 491 // generated in Javascript because Android does not yet support text |
newt (away)
2016/01/25 19:43:35
Maybe: "an HTML/CSS fallback favicon is generated"
pkotwicz
2016/02/06 02:59:55
Done.
| |
484 el.style.backgroundImage = url; | 492 // drawing in native. |
Dan Beam
2016/02/05 20:42:12
well, that's not really true...
https://developer
pkotwicz
2016/02/06 02:59:55
I was referring to Android using canvas_notimpleme
| |
493 | |
494 // Check whether a fallback favicon needs to be generated. | |
495 var desiredPixelSize = 32 * window.devicePixelRatio; | |
496 var img = new Image(); | |
497 img.onload = this.onLargeFaviconLoadedAndroid_.bind(this, faviconDiv, img); | |
Dan Beam
2016/02/05 20:42:11
you probably don't need to bind img because you ca
Dan Beam
2016/02/05 20:42:12
can we just trigger onerror in the case we fail to
pkotwicz
2016/02/06 02:59:55
On 2016/02/05 20:42:11, Dan Beam wrote:
> you prob
pkotwicz
2016/02/06 02:59:55
Currently, when there is no large enough favicon,
| |
498 img.src = 'chrome://large-icon/' + desiredPixelSize + '/' + this.url_; | |
499 } else { | |
500 faviconDiv.style.backgroundImage = getFaviconImageSet(this.url_); | |
501 } | |
485 }; | 502 }; |
486 | 503 |
487 /** | 504 /** |
505 * Called when the chrome://large-icon image has finished loading. | |
506 * @param {Element} faviconDiv The DOM element to add the favicon to. | |
507 * @param {HTMLImageElement} loadedImg The image which finished loading. | |
508 * @private | |
509 */ | |
510 Visit.prototype.onLargeFaviconLoadedAndroid_ = function(faviconDiv, loadedImg) { | |
511 // The loaded image should either: | |
512 // - Have the desired size. | |
513 // OR | |
514 // - Be 1x1 px with the background color for the fallback icon. | |
515 if (loadedImg.width == 1 && loadedImg.height == 1) { | |
Dan Beam
2016/02/05 20:42:12
is it likely that width == 1 and height != 1?
pkotwicz
2016/02/06 02:59:55
It is not likely. I changed the if() to check just
| |
516 faviconDiv.classList.add('fallback-favicon'); | |
Dan Beam
2016/02/05 20:42:11
can we just create a wrapper div *if* the icon fai
pkotwicz
2016/02/06 02:59:55
Creating the wrapper div only if the icon fails to
| |
517 faviconDiv.innerHTML = this.fallbackFaviconText_; | |
Dan Beam
2016/02/05 20:42:11
can you use textContent instead? (innerHTML is ba
pkotwicz
2016/02/06 02:59:55
Done.
| |
518 } | |
519 faviconDiv.style.backgroundImage = url(loadedImg.src); | |
520 }; | |
521 | |
522 /** | |
488 * Launch a search for more history entries from the same domain. | 523 * Launch a search for more history entries from the same domain. |
489 * @private | 524 * @private |
490 */ | 525 */ |
491 Visit.prototype.showMoreFromSite_ = function() { | 526 Visit.prototype.showMoreFromSite_ = function() { |
492 recordUmaAction('HistoryPage_EntryMenuShowMoreFromSite'); | 527 recordUmaAction('HistoryPage_EntryMenuShowMoreFromSite'); |
493 historyView.setSearch(this.domain_); | 528 historyView.setSearch(this.domain_); |
494 $('search-field').focus(); | 529 $('search-field').focus(); |
495 }; | 530 }; |
496 | 531 |
497 /** | 532 /** |
(...skipping 844 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1342 | 1377 |
1343 /** | 1378 /** |
1344 * Generates and adds the grouped visits DOM for a certain domain. This | 1379 * Generates and adds the grouped visits DOM for a certain domain. This |
1345 * includes the clickable arrow and domain name and the visit entries for | 1380 * includes the clickable arrow and domain name and the visit entries for |
1346 * that domain. | 1381 * that domain. |
1347 * @param {Element} results DOM object to which to add the elements. | 1382 * @param {Element} results DOM object to which to add the elements. |
1348 * @param {string} domain Current domain name. | 1383 * @param {string} domain Current domain name. |
1349 * @param {Array} domainVisits Array of visits for this domain. | 1384 * @param {Array} domainVisits Array of visits for this domain. |
1350 * @private | 1385 * @private |
1351 */ | 1386 */ |
1352 HistoryView.prototype.getGroupedVisitsDOM_ = function( | 1387 HistoryView.prototype.getGroupedVisitsDOM_ = function( |
Dan Beam
2016/02/05 20:42:11
ah, you did check the grouped view :) sorry for no
| |
1353 results, domain, domainVisits) { | 1388 results, domain, domainVisits) { |
1354 // Add a new domain entry. | 1389 // Add a new domain entry. |
1355 var siteResults = results.appendChild( | 1390 var siteResults = results.appendChild( |
1356 createElementWithClassName('li', 'site-entry')); | 1391 createElementWithClassName('li', 'site-entry')); |
1357 | 1392 |
1358 var siteDomainWrapper = siteResults.appendChild( | 1393 var siteDomainWrapper = siteResults.appendChild( |
1359 createElementWithClassName('div', 'site-domain-wrapper')); | 1394 createElementWithClassName('div', 'site-domain-wrapper')); |
1360 // Make a row that will contain the arrow, the favicon and the domain. | 1395 // Make a row that will contain the arrow, the favicon and the domain. |
1361 var siteDomainRow = siteDomainWrapper.appendChild( | 1396 var siteDomainRow = siteDomainWrapper.appendChild( |
1362 createElementWithClassName('div', 'site-domain-row')); | 1397 createElementWithClassName('div', 'site-domain-row')); |
1363 | 1398 |
1364 if (this.model_.editingEntriesAllowed) { | 1399 if (this.model_.editingEntriesAllowed) { |
1365 var siteDomainCheckbox = | 1400 var siteDomainCheckbox = |
1366 createElementWithClassName('input', 'domain-checkbox'); | 1401 createElementWithClassName('input', 'domain-checkbox'); |
1367 | 1402 |
1368 siteDomainCheckbox.type = 'checkbox'; | 1403 siteDomainCheckbox.type = 'checkbox'; |
1369 siteDomainCheckbox.addEventListener('click', domainCheckboxClicked); | 1404 siteDomainCheckbox.addEventListener('click', domainCheckboxClicked); |
1370 siteDomainCheckbox.domain_ = domain; | 1405 siteDomainCheckbox.domain_ = domain; |
1371 siteDomainCheckbox.setAttribute('aria-label', domain); | 1406 siteDomainCheckbox.setAttribute('aria-label', domain); |
1372 siteDomainRow.appendChild(siteDomainCheckbox); | 1407 siteDomainRow.appendChild(siteDomainCheckbox); |
1373 } | 1408 } |
1374 | 1409 |
1375 var siteArrow = siteDomainRow.appendChild( | 1410 var siteArrow = siteDomainRow.appendChild( |
1376 createElementWithClassName('div', 'site-domain-arrow')); | 1411 createElementWithClassName('div', 'site-domain-arrow')); |
1412 var siteFavicon = siteDomainRow.appendChild( | |
1413 createElementWithClassName('div', 'favicon')); | |
Dan Beam
2016/02/05 20:42:12
is it necessary to add this wrapper on desktop?
| |
1377 var siteDomain = siteDomainRow.appendChild( | 1414 var siteDomain = siteDomainRow.appendChild( |
1378 createElementWithClassName('div', 'site-domain')); | 1415 createElementWithClassName('div', 'site-domain')); |
1379 var siteDomainLink = siteDomain.appendChild(new ActionLink); | 1416 var siteDomainLink = siteDomain.appendChild(new ActionLink); |
1380 siteDomainLink.textContent = domain; | 1417 siteDomainLink.textContent = domain; |
1381 var numberOfVisits = createElementWithClassName('span', 'number-visits'); | 1418 var numberOfVisits = createElementWithClassName('span', 'number-visits'); |
1382 var domainElement = document.createElement('span'); | 1419 var domainElement = document.createElement('span'); |
1383 | 1420 |
1384 numberOfVisits.textContent = loadTimeData.getStringF('numberVisits', | 1421 numberOfVisits.textContent = loadTimeData.getStringF('numberVisits', |
1385 domainVisits.length); | 1422 domainVisits.length); |
1386 siteDomain.appendChild(numberOfVisits); | 1423 siteDomain.appendChild(numberOfVisits); |
1387 | 1424 |
1388 domainVisits[0].addFaviconToElement_(siteDomain); | 1425 domainVisits[0].loadFavicon_(siteFavicon); |
1389 | 1426 |
1390 siteDomainWrapper.addEventListener( | 1427 siteDomainWrapper.addEventListener( |
1391 'click', this.toggleGroupedVisits_.bind(this)); | 1428 'click', this.toggleGroupedVisits_.bind(this)); |
1392 | 1429 |
1393 if (this.model_.isSupervisedProfile) { | 1430 if (this.model_.isSupervisedProfile) { |
1394 siteDomainRow.appendChild( | 1431 siteDomainRow.appendChild( |
1395 getFilteringStatusDOM(domainVisits[0].hostFilteringBehavior)); | 1432 getFilteringStatusDOM(domainVisits[0].hostFilteringBehavior)); |
1396 } | 1433 } |
1397 | 1434 |
1398 siteResults.appendChild(siteDomainWrapper); | 1435 siteResults.appendChild(siteDomainWrapper); |
(...skipping 980 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2379 historyView.reload(); | 2416 historyView.reload(); |
2380 } | 2417 } |
2381 | 2418 |
2382 // Add handlers to HTML elements. | 2419 // Add handlers to HTML elements. |
2383 document.addEventListener('DOMContentLoaded', load); | 2420 document.addEventListener('DOMContentLoaded', load); |
2384 | 2421 |
2385 // This event lets us enable and disable menu items before the menu is shown. | 2422 // This event lets us enable and disable menu items before the menu is shown. |
2386 document.addEventListener('canExecute', function(e) { | 2423 document.addEventListener('canExecute', function(e) { |
2387 e.canExecute = true; | 2424 e.canExecute = true; |
2388 }); | 2425 }); |
OLD | NEW |