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

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

Issue 269095: NTP: Fix startup visual state ... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « chrome/browser/resources/new_new_tab.html ('k') | chrome/common/jstemplate_builder.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 // Helpers 2 // Helpers
3 3
4 function $(id) {
5 return document.getElementById(id);
6 }
7
8 // TODO(arv): Remove these when classList is available in HTML5. 4 // TODO(arv): Remove these when classList is available in HTML5.
9 // https://bugs.webkit.org/show_bug.cgi?id=20709 5 // https://bugs.webkit.org/show_bug.cgi?id=20709
10 function hasClass(el, name) { 6 function hasClass(el, name) {
11 return el.nodeType == 1 && el.className.split(/\s+/).indexOf(name) != -1; 7 return el.nodeType == 1 && el.className.split(/\s+/).indexOf(name) != -1;
12 } 8 }
13 9
14 function addClass(el, name) { 10 function addClass(el, name) {
15 el.className += ' ' + name; 11 el.className += ' ' + name;
16 } 12 }
17 13
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 return function() { 57 return function() {
62 var args = Array.prototype.slice.call(arguments); 58 var args = Array.prototype.slice.call(arguments);
63 args.unshift.apply(args, boundArgs); 59 args.unshift.apply(args, boundArgs);
64 return fn.apply(selfObj, args); 60 return fn.apply(selfObj, args);
65 } 61 }
66 } 62 }
67 63
68 var loading = true; 64 var loading = true;
69 var mostVisitedData = []; 65 var mostVisitedData = [];
70 var gotMostVisited = false; 66 var gotMostVisited = false;
71 var gotShownSections = false;
72 67
73 function mostVisitedPages(data, firstRun) { 68 function mostVisitedPages(data, firstRun) {
74 logEvent('received most visited pages'); 69 logEvent('received most visited pages');
75 70
76 // We append the class name with the "filler" so that we can style fillers 71 // We append the class name with the "filler" so that we can style fillers
77 // differently. 72 // differently.
78 var maxItems = 8; 73 var maxItems = 8;
79 data.length = Math.min(maxItems, data.length); 74 data.length = Math.min(maxItems, data.length);
80 var len = data.length; 75 var len = data.length;
81 for (var i = len; i < maxItems; i++) { 76 for (var i = len; i < maxItems; i++) {
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 shownSections = mask; 177 shownSections = mask;
183 178
184 // Only invalidate most visited if needed. 179 // Only invalidate most visited if needed.
185 if ((mask & Section.THUMB) != (oldShownSections & Section.THUMB) || 180 if ((mask & Section.THUMB) != (oldShownSections & Section.THUMB) ||
186 (mask & Section.LIST) != (oldShownSections & Section.LIST)) { 181 (mask & Section.LIST) != (oldShownSections & Section.LIST)) {
187 mostVisited.invalidate(); 182 mostVisited.invalidate();
188 } 183 }
189 184
190 mostVisited.updateDisplayMode(); 185 mostVisited.updateDisplayMode();
191 renderRecentlyClosed(); 186 renderRecentlyClosed();
192 updateOptionMenu();
193 } 187 }
194
195 gotShownSections = true;
196 onDataLoaded();
197 } 188 }
198 189
199 function saveShownSections() { 190 function saveShownSections() {
200 chrome.send('setShownSections', [String(shownSections)]); 191 chrome.send('setShownSections', [String(shownSections)]);
201 } 192 }
202 193
203 function getThumbnailClassName(data) { 194 function getThumbnailClassName(data) {
204 return 'thumbnail-container' + 195 return 'thumbnail-container' +
205 (data.pinned ? ' pinned' : '') + 196 (data.pinned ? ' pinned' : '') +
206 (data.filler ? ' filler' : ''); 197 (data.filler ? ' filler' : '');
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 global[callbackName] = function() { 259 global[callbackName] = function() {
269 // restore 260 // restore
270 global[callbackName] = old; 261 global[callbackName] = old;
271 262
272 var args = Array.prototype.slice.call(arguments); 263 var args = Array.prototype.slice.call(arguments);
273 return callback.apply(global, args); 264 return callback.apply(global, args);
274 }; 265 };
275 chrome.send(name, params); 266 chrome.send(name, params);
276 } 267 }
277 268
278 function useSmallGrid() {
279 return window.innerWidth <= 920;
280 }
281
282 var LayoutMode = { 269 var LayoutMode = {
283 SMALL: 1, 270 SMALL: 1,
284 NORMAL: 2 271 NORMAL: 2
285 }; 272 };
286 273
287 var layoutMode = useSmallGrid() ? LayoutMode.SMALL : LayoutMode.NORMAL; 274 var layoutMode = useSmallGrid() ? LayoutMode.SMALL : LayoutMode.NORMAL;
288 275
289 function handleWindowResize() { 276 function handleWindowResize() {
290 if (window.innerWidth < 10) { 277 if (window.innerWidth < 10) {
291 // We're probably a background tab, so don't do anything. 278 // We're probably a background tab, so don't do anything.
292 return; 279 return;
293 } 280 }
294 281
295 var oldLayoutMode = layoutMode; 282 var oldLayoutMode = layoutMode;
296 layoutMode = useSmallGrid() ? LayoutMode.SMALL : LayoutMode.NORMAL 283 layoutMode = useSmallGrid() ? LayoutMode.SMALL : LayoutMode.NORMAL
297 284
298 if (layoutMode != oldLayoutMode){ 285 if (layoutMode != oldLayoutMode){
299 mostVisited.invalidate(); 286 mostVisited.invalidate();
300 mostVisited.layout(); 287 mostVisited.layout();
301 renderRecentlyClosed(); 288 renderRecentlyClosed();
302 } 289 }
303 } 290 }
304 291
305 /**
306 * Bitmask for the different UI sections.
307 * This matches the Section enum in ../dom_ui/shown_sections_handler.h
308 * @enum {number}
309 */
310 var Section = {
311 THUMB: 1,
312 LIST: 2,
313 RECENT: 4
314 };
315
316 var shownSections = Section.THUMB | Section.RECENT;
317
318 function showSection(section) { 292 function showSection(section) {
319 if (!(section & shownSections)) { 293 if (!(section & shownSections)) {
320 shownSections |= section; 294 shownSections |= section;
321 295
322 // THUMBS and LIST are mutually exclusive. 296 // THUMBS and LIST are mutually exclusive.
323 if (section == Section.THUMB) { 297 if (section == Section.THUMB) {
324 // hide LIST 298 // hide LIST
325 shownSections &= ~Section.LIST; 299 shownSections &= ~Section.LIST;
326 mostVisited.invalidate(); 300 mostVisited.invalidate();
327 } else if (section == Section.LIST) { 301 } else if (section == Section.LIST) {
328 // hide THUMB 302 // hide THUMB
329 shownSections &= ~Section.THUMB; 303 shownSections &= ~Section.THUMB;
330 mostVisited.invalidate(); 304 mostVisited.invalidate();
331 } else { 305 } else {
332 renderRecentlyClosed(); 306 renderRecentlyClosed();
333 } 307 }
334 308
335 updateOptionMenu();
336 mostVisited.updateDisplayMode(); 309 mostVisited.updateDisplayMode();
337 mostVisited.layout(); 310 mostVisited.layout();
338 } 311 }
339 } 312 }
340 313
341 function hideSection(section) { 314 function hideSection(section) {
342 if (section & shownSections) { 315 if (section & shownSections) {
343 shownSections &= ~section; 316 shownSections &= ~section;
344 317
345 if (section & Section.THUMB || section & Section.LIST) { 318 if (section & Section.THUMB || section & Section.LIST) {
346 mostVisited.invalidate(); 319 mostVisited.invalidate();
347 } 320 }
348 321
349 if (section & Section.RECENT) { 322 if (section & Section.RECENT) {
350 renderRecentlyClosed(); 323 renderRecentlyClosed();
351 } 324 }
352 325
353 updateOptionMenu();
354 mostVisited.updateDisplayMode(); 326 mostVisited.updateDisplayMode();
355 mostVisited.layout(); 327 mostVisited.layout();
356 } 328 }
357 } 329 }
358 330
359 var mostVisited = { 331 var mostVisited = {
360 addPinnedUrl_: function(data, index) { 332 addPinnedUrl_: function(data, index) {
361 chrome.send('addPinnedURL', [data.url, data.title, data.faviconUrl || '', 333 chrome.send('addPinnedURL', [data.url, data.title, data.faviconUrl || '',
362 data.thumbnailUrl || '', String(index)]); 334 data.thumbnailUrl || '', String(index)]);
363 }, 335 },
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 } 473 }
502 474
503 var thumbCheckbox = $('thumb-checkbox'); 475 var thumbCheckbox = $('thumb-checkbox');
504 var listCheckbox = $('list-checkbox'); 476 var listCheckbox = $('list-checkbox');
505 var mostVisitedElement = $('most-visited'); 477 var mostVisitedElement = $('most-visited');
506 478
507 if (shownSections & Section.THUMB) { 479 if (shownSections & Section.THUMB) {
508 thumbCheckbox.checked = true; 480 thumbCheckbox.checked = true;
509 listCheckbox.checked = false; 481 listCheckbox.checked = false;
510 removeClass(mostVisitedElement, 'list'); 482 removeClass(mostVisitedElement, 'list');
483 removeClass(mostVisitedElement, 'collapsed');
511 } else if (shownSections & Section.LIST) { 484 } else if (shownSections & Section.LIST) {
512 thumbCheckbox.checked = false; 485 thumbCheckbox.checked = false;
513 listCheckbox.checked = true; 486 listCheckbox.checked = true;
514 addClass(mostVisitedElement, 'list'); 487 addClass(mostVisitedElement, 'list');
488 removeClass(mostVisitedElement, 'collapsed');
515 } else { 489 } else {
516 thumbCheckbox.checked = false; 490 thumbCheckbox.checked = false;
517 listCheckbox.checked = false; 491 listCheckbox.checked = false;
492 addClass(mostVisitedElement, 'collapsed');
518 } 493 }
519 }, 494 },
520 495
521 dirty_: false, 496 dirty_: false,
522 497
523 invalidate: function() { 498 invalidate: function() {
524 this.dirty_ = true; 499 this.dirty_ = true;
525 this.calculationsDirty_ = true;
526 }, 500 },
527 501
528 layout: function() { 502 layout: function() {
529 if (!this.dirty_) { 503 if (!this.dirty_) {
530 return; 504 return;
531 } 505 }
532 var d0 = Date.now(); 506 var d0 = Date.now();
533 507
534 this.calculateLayout_();
535
536 var mostVisitedElement = $('most-visited'); 508 var mostVisitedElement = $('most-visited');
537 var thumbnails = mostVisitedElement.children; 509 var thumbnails = mostVisitedElement.children;
510 var collapsed = false;
538 511
539 if (shownSections & Section.LIST) { 512 if (shownSections & Section.LIST) {
540 addClass(mostVisitedElement, 'list'); 513 addClass(mostVisitedElement, 'list');
541 } else if (shownSections & Section.THUMB) { 514 } else if (shownSections & Section.THUMB) {
542 removeClass(mostVisitedElement, 'list'); 515 removeClass(mostVisitedElement, 'list');
516 } else {
517 collapsed = true;
543 } 518 }
544 519
545 var cache = this.layoutCache_;
546 mostVisitedElement.style.height = cache.sumHeight + 'px';
547 mostVisitedElement.style.opacity = cache.opacity;
548 // We set overflow to hidden so that the most visited element does not 520 // We set overflow to hidden so that the most visited element does not
549 // "leak" when we hide and show it. 521 // "leak" when we hide and show it.
550 if (!cache.opacity) { 522 if (collapsed) {
551 mostVisitedElement.style.overflow = 'hidden'; 523 mostVisitedElement.style.overflow = 'hidden';
552 } 524 }
553 525
554 if (shownSections & Section.THUMB || shownSections & Section.LIST) { 526 applyMostVisitedRects();
555 for (var i = 0; i < thumbnails.length; i++) {
556 var t = thumbnails[i];
557 527
558 // Remove temporary ID that was used during startup layout. 528 // Only set overflow to visible if the element is shown.
559 t.id = ''; 529 if (!collapsed) {
560 530 afterTransition(function() {
561 var rect = cache.rects[i]; 531 mostVisitedElement.style.overflow = '';
562 t.style.left = rect.left + 'px'; 532 });
563 t.style.top = rect.top + 'px';
564 t.style.width = rect.width != undefined ? rect.width + 'px' : '';
565 var innerStyle = t.firstElementChild.style;
566 innerStyle.left = innerStyle.top = '';
567 }
568 } 533 }
569 534
570 afterTransition(function() {
571 // Only set overflow to visible if the element is shown.
572 if (cache.opacity) {
573 mostVisitedElement.style.overflow = '';
574 }
575 });
576
577 this.dirty_ = false; 535 this.dirty_ = false;
578 536
579 logEvent('mostVisited.layout: ' + (Date.now() - d0)); 537 logEvent('mostVisited.layout: ' + (Date.now() - d0));
580 }, 538 },
581 539
582 layoutCache_: {},
583 calculationsDirty_: true,
584
585 /**
586 * Calculates and caches the layout positions for the thumbnails.
587 */
588 calculateLayout_: function() {
589 if (!this.calculationsDirty_) {
590 return;
591 }
592
593 var small = useSmallGrid();
594
595 var cols = 4;
596 var rows = 2;
597 var marginWidth = 10;
598 var marginHeight = 7;
599 var borderWidth = 4;
600 var thumbWidth = small ? 150 : 207;
601 var thumbHeight = small ? 93 : 129;
602 var w = thumbWidth + 2 * borderWidth + 2 * marginWidth;
603 var h = thumbHeight + 40 + 2 * marginHeight;
604 var sumWidth = cols * w - 2 * marginWidth;
605 var sumHeight = rows * h;
606 var opacity = 1;
607 // Since the list mode does not have a toolbar move it down a little to add
608 // some spacing at the top.
609 var LIST_TOP_SPACING = 22;
610
611 if (shownSections & Section.LIST) {
612 w = sumWidth;
613 h = 34;
614 rows = 8;
615 cols = 1;
616 sumHeight = rows * h + LIST_TOP_SPACING;
617 } else if (!(shownSections & Section.THUMB)) {
618 sumHeight = 0;
619 opacity = 0;
620 }
621
622 var rtl = document.documentElement.dir == 'rtl';
623 var rects = [];
624
625 if (shownSections & Section.THUMB || shownSections & Section.LIST) {
626 for (var i = 0; i < rows * cols; i++) {
627 var row, col, left, top, width;
628 if (shownSections & Section.THUMB) {
629 row = Math.floor(i / cols);
630 col = i % cols;
631 } else {
632 col = Math.floor(i / rows);
633 row = i % rows;
634 }
635
636 if (shownSections & Section.THUMB) {
637 left = rtl ? sumWidth - col * w - thumbWidth - 2 * borderWidth :
638 col * w;
639 } else {
640 left = rtl ? sumWidth - col * w - w + 2 * marginWidth : col * w;
641 }
642 top = row * h;
643
644 if (shownSections & Section.LIST) {
645 width = w;
646 top += LIST_TOP_SPACING;
647 }
648
649 rects[i] = {left: left, top: top, width: width};
650 }
651 }
652
653 this.layoutCache_ = {
654 opacity: opacity,
655 sumHeight: sumHeight,
656 rects: rects
657 }
658
659 this.calculationsDirty_ = false;
660 },
661
662 getRectByIndex: function(index) { 540 getRectByIndex: function(index) {
663 this.calculateLayout_(); 541 return getMostVisitedLayoutRects()[index];
664 return this.layoutCache_.rects[index]
665 } 542 }
666 }; 543 };
667 544
668 // Recently closed 545 // Recently closed
669 546
670 function layoutRecentlyClosed() { 547 function layoutRecentlyClosed() {
671 var recentElement = $('recently-closed'); 548 var recentElement = $('recently-closed');
672 var recentShown = shownSections & Section.RECENT; 549 var recentShown = shownSections & Section.RECENT;
673 var style = recentElement.style; 550 var style = recentElement.style;
674 551
675 if (!recentShown) { 552 if (!recentShown) {
676 style.opacity = style.height = 0; 553 addClass(recentElement, 'collapsed');
677 } else { 554 } else {
678 style.opacity = style.height = ''; 555 removeClass(recentElement, 'collapsed');
679 556
680 // We cannot use clientWidth here since the width has a transition. 557 // We cannot use clientWidth here since the width has a transition.
681 var spacing = 20; 558 var spacing = 20;
682 var headerEl = recentElement.firstElementChild; 559 var headerEl = recentElement.firstElementChild;
683 var navEl = recentElement.lastElementChild; 560 var navEl = recentElement.lastElementChild;
684 var navWidth = navEl.offsetWidth; 561 var navWidth = navEl.offsetWidth;
685 // Subtract 10 for the padding 562 // Subtract 10 for the padding
686 var availWidth = (useSmallGrid() ? 690 : 918) - navWidth - 10; 563 var availWidth = (useSmallGrid() ? 690 : 918) - navWidth - 10;
687 564
688 // Now go backwards and hide as many elements as needed. 565 // Now go backwards and hide as many elements as needed.
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
784 if (numTabs == 1) 661 if (numTabs == 1)
785 return localStrings.getString('closedwindowsingle'); 662 return localStrings.getString('closedwindowsingle');
786 return localStrings.formatString('closedwindowmultiple', numTabs); 663 return localStrings.formatString('closedwindowmultiple', numTabs);
787 } 664 }
788 665
789 /** 666 /**
790 * We need both most visited and the shown sections to be considered loaded. 667 * We need both most visited and the shown sections to be considered loaded.
791 * @return {boolean} 668 * @return {boolean}
792 */ 669 */
793 function onDataLoaded() { 670 function onDataLoaded() {
794 if (gotMostVisited && gotShownSections) { 671 if (gotMostVisited) {
795 mostVisited.layout(); 672 mostVisited.layout();
796 loading = false; 673 loading = false;
797 // Remove class name in a timeout so that changes done in this JS thread are 674 // Remove class name in a timeout so that changes done in this JS thread are
798 // not animated. 675 // not animated.
799 window.setTimeout(function() { 676 window.setTimeout(function() {
800 removeClass(document.body, 'loading'); 677 removeClass(document.body, 'loading');
801 }, 1); 678 }, 1);
802 } 679 }
803 } 680 }
804 681
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 this.button.onkeydown = bind(this.handleKeyDown, this); 828 this.button.onkeydown = bind(this.handleKeyDown, this);
952 this.boundHideMenu_ = bind(this.hide, this); 829 this.boundHideMenu_ = bind(this.hide, this);
953 this.boundMaybeHide_ = bind(this.maybeHide_, this); 830 this.boundMaybeHide_ = bind(this.maybeHide_, this);
954 this.menu.onmouseover = bind(this.handleMouseOver, this); 831 this.menu.onmouseover = bind(this.handleMouseOver, this);
955 this.menu.onmouseout = bind(this.handleMouseOut, this); 832 this.menu.onmouseout = bind(this.handleMouseOut, this);
956 this.menu.onmouseup = bind(this.handleMouseUp, this); 833 this.menu.onmouseup = bind(this.handleMouseUp, this);
957 } 834 }
958 835
959 OptionMenu.prototype = { 836 OptionMenu.prototype = {
960 show: function() { 837 show: function() {
838 updateOptionMenu();
961 this.menu.style.display = 'block'; 839 this.menu.style.display = 'block';
962 addClass(this.button, 'open'); 840 addClass(this.button, 'open');
963 this.button.focus(); 841 this.button.focus();
964 842
965 // Listen to document and window events so that we hide the menu when the 843 // Listen to document and window events so that we hide the menu when the
966 // user clicks outside the menu or tabs away or the whole window is blurred. 844 // user clicks outside the menu or tabs away or the whole window is blurred.
967 document.addEventListener('focus', this.boundMaybeHide_, true); 845 document.addEventListener('focus', this.boundMaybeHide_, true);
968 document.addEventListener('mousedown', this.boundMaybeHide_, true); 846 document.addEventListener('mousedown', this.boundMaybeHide_, true);
969 }, 847 },
970 848
(...skipping 579 matching lines...) Expand 10 before | Expand all | Expand 10 after
1550 // The position of the item is relative to #most-visited so we need to 1428 // The position of the item is relative to #most-visited so we need to
1551 // subtract that when calculating the allowed position. 1429 // subtract that when calculating the allowed position.
1552 x = Math.max(x, -rect.left); 1430 x = Math.max(x, -rect.left);
1553 x = Math.min(x, document.body.clientWidth - rect.left - item.offsetWidth - 1431 x = Math.min(x, document.body.clientWidth - rect.left - item.offsetWidth -
1554 2); 1432 2);
1555 // The shadow is 2px 1433 // The shadow is 2px
1556 y = Math.max(-rect.top, y); 1434 y = Math.max(-rect.top, y);
1557 y = Math.min(y, document.body.clientHeight - rect.top - item.offsetHeight - 1435 y = Math.min(y, document.body.clientHeight - rect.top - item.offsetHeight -
1558 2); 1436 2);
1559 1437
1438 // Override right in case of RTL.
1439 item.style.right = 'auto';
1560 item.style.left = x + 'px'; 1440 item.style.left = x + 'px';
1561 item.style.top = y + 'px'; 1441 item.style.top = y + 'px';
1562 item.style.zIndex = 2; 1442 item.style.zIndex = 2;
1563 }, 1443 },
1564 1444
1565 // We listen to mousedown to get the relative position of the cursor for dnd. 1445 // We listen to mousedown to get the relative position of the cursor for dnd.
1566 handleMouseDown: function(e) { 1446 handleMouseDown: function(e) {
1567 var item = mostVisited.getItem(e.target); 1447 var item = mostVisited.getItem(e.target);
1568 if (item) { 1448 if (item) {
1569 this.startX = item.offsetLeft; 1449 this.startX = item.offsetLeft;
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
1682 function fixLinkUnderline(el) { 1562 function fixLinkUnderline(el) {
1683 var span = document.createElement('span'); 1563 var span = document.createElement('span');
1684 span.className = 'link-color'; 1564 span.className = 'link-color';
1685 while (el.hasChildNodes()) { 1565 while (el.hasChildNodes()) {
1686 span.appendChild(el.firstChild); 1566 span.appendChild(el.firstChild);
1687 } 1567 }
1688 el.appendChild(span); 1568 el.appendChild(span);
1689 } 1569 }
1690 1570
1691 updateAttribution(); 1571 updateAttribution();
OLDNEW
« no previous file with comments | « chrome/browser/resources/new_new_tab.html ('k') | chrome/common/jstemplate_builder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698