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

Side by Side Diff: chrome/browser/resources/history/history.js

Issue 1596273003: [Android] Use fallback icon if there is no large favicon on the history page (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 <include src="../uber/uber_utils.js"> 5 <include src="../uber/uber_utils.js">
6 <include src="history_focus_manager.js"> 6 <include src="history_focus_manager.js">
7 7
8 /////////////////////////////////////////////////////////////////////////////// 8 ///////////////////////////////////////////////////////////////////////////////
9 // Globals: 9 // Globals:
10 /** @const */ var RESULTS_PER_PAGE = 150; 10 /** @const */ var RESULTS_PER_PAGE = 150;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698