Index: chrome/browser/resources/new_tab.js |
diff --git a/chrome/browser/resources/new_tab.js b/chrome/browser/resources/new_tab.js |
deleted file mode 100644 |
index bd013f0612d169e5b4b764a26dd6cb02da807ddf..0000000000000000000000000000000000000000 |
--- a/chrome/browser/resources/new_tab.js |
+++ /dev/null |
@@ -1,1489 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-// To avoid creating tons of unnecessary nodes. We assume we cannot fit more |
-// than this many items in the miniview. |
-var MAX_MINIVIEW_ITEMS = 15; |
- |
-// Extra spacing at the top of the layout. |
-var LAYOUT_SPACING_TOP = 25; |
- |
-// The visible height of the expanded maxiview. |
-var maxiviewVisibleHeight = 0; |
- |
-var APP_LAUNCH = { |
- // The histogram buckets (keep in sync with extension_constants.h). |
- NTP_APPS_MAXIMIZED: 0, |
- NTP_APPS_COLLAPSED: 1, |
- NTP_APPS_MENU: 2, |
- NTP_MOST_VISITED: 3, |
- NTP_RECENTLY_CLOSED: 4, |
- NTP_APP_RE_ENABLE: 16 |
-}; |
- |
-var APP_LAUNCH_URL = { |
- // The URL prefix for pings that record app launches by URL. |
- PING_BY_URL: 'record-app-launch-by-url', |
- |
- // The URL prefix for pings that record app launches by ID. |
- PING_BY_ID: 'record-app-launch-by-id', |
- |
- // The URL prefix used by the webstore link 'ping' attributes. |
- PING_WEBSTORE: 'record-webstore-launch' |
-}; |
- |
-function getAppPingUrl(prefix, data, bucket) { |
- return [APP_LAUNCH_URL[prefix], |
- encodeURIComponent(data), |
- APP_LAUNCH[bucket]].join('+'); |
-} |
- |
-function getSectionCloseButton(sectionId) { |
- return document.querySelector('#' + sectionId + ' .section-close-button'); |
-} |
- |
-function getSectionMenuButton(sectionId) { |
- return $(sectionId + '-button'); |
-} |
- |
-function getSectionMenuButtonTextId(sectionId) { |
- return sectionId.replace(/-/g, ''); |
-} |
- |
-function setSectionMenuMode(sectionId, section, menuModeEnabled, menuModeMask) { |
- var el = $(sectionId); |
- if (!menuModeEnabled) { |
- // Because sections are collapsed when they are in menu mode, it is not |
- // necessary to restore the maxiview here. It will happen if the section |
- // header is clicked. |
- // TODO(aa): Sections should maintain their collapse state when minimized. |
- el.classList.remove('menu'); |
- shownSections &= ~menuModeMask; |
- } else { |
- if (section) { |
- hideSection(section); // To hide the maxiview. |
- } |
- el.classList.add('menu'); |
- shownSections |= menuModeMask; |
- } |
- layoutSections(); |
-} |
- |
-function clearClosedMenu(menu) { |
- menu.innerHTML = ''; |
-} |
- |
-function addClosedMenuEntryWithLink(menu, a) { |
- var span = document.createElement('span'); |
- a.className += ' item menuitem'; |
- span.appendChild(a); |
- menu.appendChild(span); |
-} |
- |
-function addClosedMenuEntry(menu, url, title, imageUrl, opt_pingUrl) { |
- var a = document.createElement('a'); |
- a.href = url; |
- a.textContent = title; |
- a.style.backgroundImage = 'url(' + imageUrl + ')'; |
- if (opt_pingUrl) |
- a.ping = opt_pingUrl; |
- addClosedMenuEntryWithLink(menu, a); |
-} |
- |
-function addClosedMenuFooter(menu, sectionId, mask, opt_section) { |
- menu.appendChild(document.createElement('hr')); |
- |
- var span = document.createElement('span'); |
- var a = span.appendChild(document.createElement('a')); |
- a.href = ''; |
- if (cr.isChromeOS) { |
- a.textContent = localStrings.getString('expandMenu'); |
- } else { |
- a.textContent = |
- localStrings.getString(getSectionMenuButtonTextId(sectionId)); |
- } |
- a.className = 'item'; |
- a.addEventListener( |
- 'click', |
- function(e) { |
- getSectionMenuButton(sectionId).hideMenu(); |
- e.preventDefault(); |
- setSectionMenuMode(sectionId, opt_section, false, mask); |
- shownSections &= ~mask; |
- saveShownSections(); |
- }); |
- menu.appendChild(span); |
-} |
- |
-function initializeSection(sectionId, mask, opt_section) { |
- var button = getSectionCloseButton(sectionId); |
- button.addEventListener( |
- 'click', |
- function() { |
- setSectionMenuMode(sectionId, opt_section, true, mask); |
- saveShownSections(); |
- }); |
-} |
- |
-function updateSimpleSection(id, section) { |
- var elm = $(id); |
- var maxiview = getSectionMaxiview(elm); |
- var miniview = getSectionMiniview(elm); |
- if (shownSections & section) { |
- // The section is expanded, so the maxiview should be opaque (visible) and |
- // the miniview should be hidden. |
- elm.classList.remove('collapsed'); |
- if (maxiview) { |
- maxiview.classList.remove('collapsed'); |
- maxiview.classList.add('opaque'); |
- } |
- if (miniview) |
- miniview.classList.remove('opaque'); |
- } else { |
- // The section is collapsed, so the maxiview should be hidden and the |
- // miniview should be opaque. |
- elm.classList.add('collapsed'); |
- if (maxiview) { |
- maxiview.classList.add('collapsed'); |
- maxiview.classList.remove('opaque'); |
- } |
- if (miniview) |
- miniview.classList.add('opaque'); |
- } |
-} |
- |
-var sessionItems = []; |
- |
-function foreignSessions(data) { |
- logEvent('received foreign sessions'); |
- // We need to store the foreign sessions so we can update the layout on a |
- // resize. |
- sessionItems = data; |
- renderForeignSessions(); |
- layoutSections(); |
-} |
- |
-function renderForeignSessions() { |
- // Remove all existing items and create new items. |
- var sessionElement = $('foreign-sessions'); |
- var parentSessionElement = sessionElement.lastElementChild; |
- parentSessionElement.textContent = ''; |
- |
- // For each client, create entries and append the lists together. |
- sessionItems.forEach(function(item, i) { |
- // TODO(zea): Get real client names. See crbug/59672. |
- var name = 'Client ' + i; |
- parentSessionElement.appendChild(createForeignSession(item, name)); |
- }); |
- |
- layoutForeignSessions(); |
-} |
- |
-function layoutForeignSessions() { |
- var sessionElement = $('foreign-sessions'); |
- // We cannot use clientWidth here since the width has a transition. |
- var availWidth = useSmallGrid() ? 692 : 920; |
- var parentSessEl = sessionElement.lastElementChild; |
- |
- if (parentSessEl.hasChildNodes()) { |
- sessionElement.classList.remove('disabled'); |
- sessionElement.classList.remove('opaque'); |
- } else { |
- sessionElement.classList.add('disabled'); |
- sessionElement.classList.add('opaque'); |
- } |
-} |
- |
-function createForeignSession(client, name) { |
- // Vertically stack the windows in a client. |
- var stack = document.createElement('div'); |
- stack.className = 'foreign-session-client item link'; |
- stack.textContent = name; |
- stack.sessionTag = client[0].sessionTag; |
- |
- client.forEach(function(win, i) { |
- // Create a window entry. |
- var winSpan = document.createElement('span'); |
- var winEl = document.createElement('p'); |
- winEl.className = 'item link window'; |
- winEl.tabItems = win.tabs; |
- winEl.tabIndex = 0; |
- winEl.textContent = formatTabsText(win.tabs.length); |
- winEl.xtitle = win.title; |
- winEl.sessionTag = win.sessionTag; |
- winEl.winNum = i; |
- winEl.addEventListener('click', maybeOpenForeignWindow); |
- winEl.addEventListener('keydown', |
- handleIfEnterKey(maybeOpenForeignWindow)); |
- winSpan.appendChild(winEl); |
- |
- // Sort tabs by MRU order |
- win.tabs.sort(function(a, b) { |
- return a.timestamp < b.timestamp; |
- }); |
- |
- // Create individual tab information. |
- win.tabs.forEach(function(data) { |
- var tabEl = document.createElement('a'); |
- tabEl.className = 'item link tab'; |
- tabEl.href = data.timestamp; |
- tabEl.style.backgroundImage = url('chrome://favicon/' + data.url); |
- tabEl.dir = data.direction; |
- tabEl.textContent = data.title; |
- tabEl.sessionTag = win.sessionTag; |
- tabEl.winNum = i; |
- tabEl.sessionId = data.sessionId; |
- tabEl.addEventListener('click', maybeOpenForeignTab); |
- tabEl.addEventListener('keydown', |
- handleIfEnterKey(maybeOpenForeignTab)); |
- |
- winSpan.appendChild(tabEl); |
- }); |
- |
- // Append the window. |
- stack.appendChild(winSpan); |
- }); |
- return stack; |
-} |
- |
-var recentItems = []; |
- |
-function recentlyClosedTabs(data) { |
- logEvent('received recently closed tabs'); |
- // We need to store the recent items so we can update the layout on a resize. |
- recentItems = data; |
- renderRecentlyClosed(); |
- layoutSections(); |
-} |
- |
-function renderRecentlyClosed() { |
- // Remove all existing items and create new items. |
- var recentElement = $('recently-closed'); |
- var parentEl = recentElement.lastElementChild; |
- parentEl.textContent = ''; |
- var recentMenu = $('recently-closed-menu'); |
- clearClosedMenu(recentMenu); |
- |
- recentItems.forEach(function(item) { |
- parentEl.appendChild(createRecentItem(item)); |
- addRecentMenuItem(recentMenu, item); |
- }); |
- addClosedMenuFooter(recentMenu, 'recently-closed', MENU_RECENT); |
- |
- layoutRecentlyClosed(); |
-} |
- |
-function createRecentItem(data) { |
- var isWindow = data.type == 'window'; |
- var el; |
- if (isWindow) { |
- el = document.createElement('span'); |
- el.className = 'item link window'; |
- el.tabItems = data.tabs; |
- el.tabIndex = 0; |
- el.textContent = formatTabsText(data.tabs.length); |
- } else { |
- el = document.createElement('a'); |
- el.className = 'item'; |
- el.href = data.url; |
- el.ping = getAppPingUrl( |
- 'PING_BY_URL', data.url, 'NTP_RECENTLY_CLOSED'); |
- el.style.backgroundImage = url('chrome://favicon/' + data.url); |
- el.dir = data.direction; |
- el.textContent = data.title; |
- } |
- el.sessionId = data.sessionId; |
- el.xtitle = data.title; |
- el.sessionTag = data.sessionTag; |
- var wrapperEl = document.createElement('span'); |
- wrapperEl.appendChild(el); |
- return wrapperEl; |
-} |
- |
-function addRecentMenuItem(menu, data) { |
- var isWindow = data.type == 'window'; |
- var a = document.createElement('a'); |
- if (isWindow) { |
- a.textContent = formatTabsText(data.tabs.length); |
- a.className = 'window'; // To get the icon from the CSS .window rule. |
- a.href = ''; // To make underline show up. |
- } else { |
- a.href = data.url; |
- a.ping = getAppPingUrl( |
- 'PING_BY_URL', data.url, 'NTP_RECENTLY_CLOSED'); |
- a.style.backgroundImage = 'url(chrome://favicon/' + data.url + ')'; |
- a.textContent = data.title; |
- } |
- function clickHandler(e) { |
- chrome.send('reopenTab', [String(data.sessionId)]); |
- e.preventDefault(); |
- } |
- a.addEventListener('click', clickHandler); |
- addClosedMenuEntryWithLink(menu, a); |
-} |
- |
-function saveShownSections() { |
- chrome.send('setShownSections', [shownSections]); |
-} |
- |
-var LayoutMode = { |
- SMALL: 1, |
- NORMAL: 2 |
-}; |
- |
-var layoutMode = useSmallGrid() ? LayoutMode.SMALL : LayoutMode.NORMAL; |
- |
-function handleWindowResize() { |
- if (window.innerWidth < 10) { |
- // We're probably a background tab, so don't do anything. |
- return; |
- } |
- |
- // TODO(jstritar): Remove the small-layout class and revert back to the |
- // @media (max-width) directive once http://crbug.com/70930 is fixed. |
- var oldLayoutMode = layoutMode; |
- var b = useSmallGrid(); |
- if (b) { |
- layoutMode = LayoutMode.SMALL; |
- document.body.classList.add('small-layout'); |
- } else { |
- layoutMode = LayoutMode.NORMAL; |
- document.body.classList.remove('small-layout'); |
- } |
- |
- if (layoutMode != oldLayoutMode){ |
- mostVisited.useSmallGrid = b; |
- mostVisited.layout(); |
- apps.layout({force:true}); |
- renderRecentlyClosed(); |
- renderForeignSessions(); |
- updateAllMiniviewClippings(); |
- } |
- |
- layoutSections(); |
-} |
- |
-// Stores some information about each section necessary to layout. A new |
-// instance is constructed for each section on each layout. |
-function SectionLayoutInfo(section) { |
- this.section = section; |
- this.header = section.querySelector('h2'); |
- this.miniview = section.querySelector('.miniview'); |
- this.maxiview = getSectionMaxiview(section); |
- this.expanded = this.maxiview && !section.classList.contains('collapsed'); |
- this.fixedHeight = this.section.offsetHeight; |
- this.scrollingHeight = 0; |
- |
- if (this.expanded) |
- this.scrollingHeight = this.maxiview.offsetHeight; |
-} |
- |
-// Get all sections to be layed out. |
-SectionLayoutInfo.getAll = function() { |
- var sections = document.querySelectorAll( |
- '.section:not(.disabled):not(.menu)'); |
- var result = []; |
- for (var i = 0, section; section = sections[i]; i++) { |
- result.push(new SectionLayoutInfo(section)); |
- } |
- return result; |
-}; |
- |
-// Ensure the miniview sections don't have any clipped items. |
-function updateMiniviewClipping(miniview) { |
- var clipped = false; |
- for (var j = 0, item; item = miniview.children[j]; j++) { |
- item.style.display = ''; |
- if (clipped || |
- (item.offsetLeft + item.offsetWidth) > miniview.offsetWidth) { |
- item.style.display = 'none'; |
- clipped = true; |
- } else { |
- item.style.display = ''; |
- } |
- } |
-} |
- |
-// Ensure none of the miniviews have any clipped items. |
-function updateAllMiniviewClippings() { |
- var miniviews = document.querySelectorAll('.section.collapsed .miniview'); |
- for (var i = 0, miniview; miniview = miniviews[i]; i++) { |
- updateMiniviewClipping(miniview); |
- } |
-} |
- |
-// Returns whether or not vertical scrollbars are present. |
-function hasScrollBars() { |
- return window.innerHeight != document.body.clientHeight; |
-} |
- |
-// Enables scrollbars (they will only show up if needed). |
-function showScrollBars() { |
- document.body.classList.remove('noscroll'); |
-} |
- |
-// Hides all scrollbars. |
-function hideScrollBars() { |
- document.body.classList.add('noscroll'); |
-} |
- |
-// Returns whether or not the sections are currently animating due to a |
-// section transition. |
-function isAnimating() { |
- var de = document.documentElement; |
- return de.getAttribute('enable-section-animations') == 'true'; |
-} |
- |
-// Layout the sections in a modified accordion. The header and miniview, if |
-// visible are fixed within the viewport. If there is an expanded section, its |
-// it scrolls. |
-// |
-// ============================= |
-// | collapsed section | <- Any collapsed sections are fixed position. |
-// | and miniview | |
-// |---------------------------| |
-// | expanded section | |
-// | | <- There can be one expanded section and it |
-// | and maxiview | is absolutely positioned so that it can |
-// | | scroll "underneath" the fixed elements. |
-// | | |
-// |---------------------------| |
-// | another collapsed section | |
-// |---------------------------| |
-// |
-// We want the main frame scrollbar to be the one that scrolls the expanded |
-// region. To get this effect, we make the fixed elements position:fixed and the |
-// scrollable element position:absolute. We also artificially increase the |
-// height of the document so that it is possible to scroll down enough to |
-// display the end of the document, even with any fixed elements at the bottom |
-// of the viewport. |
-// |
-// There is a final twist: If the intrinsic height of the expanded section is |
-// less than the available height (because the window is tall), any collapsed |
-// sections sinch up and sit below the expanded section. This is so that we |
-// don't have a bunch of dead whitespace in the case of expanded sections that |
-// aren't very tall. |
-function layoutSections() { |
- // While transitioning sections, we only want scrollbars to appear if they're |
- // already present or the window is being resized (so there's no animation). |
- if (!hasScrollBars() && isAnimating()) |
- hideScrollBars(); |
- |
- var sections = SectionLayoutInfo.getAll(); |
- var expandedSection = null; |
- var headerHeight = LAYOUT_SPACING_TOP; |
- var footerHeight = 0; |
- |
- // Calculate the height of the fixed elements above the expanded section. Also |
- // take note of the expanded section, if there is one. |
- var i; |
- var section; |
- for (i = 0; section = sections[i]; i++) { |
- headerHeight += section.fixedHeight; |
- if (section.expanded) { |
- expandedSection = section; |
- i++; |
- break; |
- } |
- } |
- |
- // Include the height of the sync promo bar. |
- var sync_promo_height = $('sync-promo').offsetHeight; |
- headerHeight += sync_promo_height; |
- |
- // Calculate the height of the fixed elements below the expanded section, if |
- // any. |
- for (; section = sections[i]; i++) { |
- footerHeight += section.fixedHeight; |
- } |
- // Leave room for bottom bar if it's visible. |
- footerHeight += $('closed-sections-bar').offsetHeight; |
- |
- |
- // Determine the height to use for the expanded section. If there isn't enough |
- // space to show the expanded section completely, this will be the available |
- // height. Otherwise, we use the intrinsic height of the expanded section. |
- var expandedSectionHeight; |
- var expandedSectionIsClipped = false; |
- if (expandedSection) { |
- var flexHeight = window.innerHeight - headerHeight - footerHeight; |
- if (flexHeight < expandedSection.scrollingHeight) { |
- expandedSectionHeight = flexHeight; |
- |
- // Also, artificially expand the height of the document so that we can see |
- // the entire expanded section. |
- // |
- // TODO(aa): Where does this come from? It is the difference between what |
- // we set document.body.style.height to and what |
- // document.body.scrollHeight measures afterward. I expect them to be the |
- // same if document.body has no margins. |
- var fudge = 44; |
- document.body.style.height = |
- headerHeight + |
- expandedSection.scrollingHeight + |
- footerHeight + |
- fudge + |
- 'px'; |
- expandedSectionIsClipped = true; |
- } else { |
- expandedSectionHeight = expandedSection.scrollingHeight; |
- document.body.style.height = ''; |
- } |
- } else { |
- // We only set the document height when a section is expanded. If |
- // all sections are collapsed, then get rid of the previous height. |
- document.body.style.height = ''; |
- } |
- |
- maxiviewVisibleHeight = expandedSectionHeight; |
- |
- // Now position all the elements. |
- var y = LAYOUT_SPACING_TOP + sync_promo_height; |
- for (i = 0, section; section = sections[i]; i++) { |
- section.section.style.top = y + 'px'; |
- y += section.fixedHeight; |
- |
- if (section.maxiview) { |
- if (section == expandedSection) { |
- section.maxiview.style.top = y + 'px'; |
- } else { |
- // The miniviews fade out gradually, so it may have height at this |
- // point. We position the maxiview as if the miniview was not displayed |
- // by subtracting off the miniview's total height (height + margin). |
- var miniviewFudge = 40; // miniview margin-bottom + margin-top |
- var miniviewHeight = section.miniview.offsetHeight + miniviewFudge; |
- section.maxiview.style.top = y - miniviewHeight + 'px'; |
- } |
- } |
- |
- if (section.maxiview && section == expandedSection) |
- updateMask( |
- section.maxiview, expandedSectionHeight, expandedSectionIsClipped); |
- |
- if (section == expandedSection) |
- y += expandedSectionHeight; |
- } |
- if (cr.isChromeOS) |
- $('closed-sections-bar').style.top = y + 'px'; |
- |
- // Position the notification container below the sync promo. |
- $('notification-container').style.top = sync_promo_height + 'px'; |
- |
- updateMenuSections(); |
- updateAttributionDisplay(y); |
-} |
- |
-function updateMask(maxiview, visibleHeightPx, isClipped) { |
- // If the section isn't actually clipped, then we don't want to use a mask at |
- // all, since enabling one turns off subpixel anti-aliasing. |
- if (!isClipped) { |
- maxiview.style.WebkitMaskImage = 'none'; |
- return; |
- } |
- |
- // We want to end up with 10px gradients at the top and bottom of |
- // visibleHeight, but webkit-mask only supports expression in terms of |
- // percentages. |
- |
- // We might not have enough room to do 10px gradients on each side. To get the |
- // right effect, we don't want to make the gradients smaller, but make them |
- // appear to mush into each other. |
- var gradientHeightPx = Math.min(10, Math.floor(visibleHeightPx / 2)); |
- var gradientDestination = 'rgba(0,0,0,' + (gradientHeightPx / 10) + ')'; |
- |
- var bottomSpacing = 15; |
- var first = parseFloat(maxiview.style.top) / window.innerHeight; |
- var second = first + gradientHeightPx / window.innerHeight; |
- var fourth = first + (visibleHeightPx - bottomSpacing) / window.innerHeight; |
- var third = fourth - gradientHeightPx / window.innerHeight; |
- |
- var gradientArguments = [ |
- 'transparent', |
- getColorStopString(first, 'transparent'), |
- getColorStopString(second, gradientDestination), |
- getColorStopString(third, gradientDestination), |
- getColorStopString(fourth, 'transparent'), |
- 'transparent' |
- ]; |
- |
- var gradient = '-webkit-linear-gradient(' + gradientArguments.join(',') + ')'; |
- maxiview.style.WebkitMaskImage = gradient; |
-} |
- |
-function getColorStopString(height, color) { |
- // TODO(arv): The CSS3 gradient syntax allows px units so we should simplify |
- // this to use pixels instead. |
- return color + ' ' + height * 100 + '%'; |
-} |
- |
-// Updates the visibility of the menu buttons for each section, based on |
-// whether they are currently enabled and in menu mode. |
-function updateMenuSections() { |
- var elms = document.getElementsByClassName('section'); |
- for (var i = 0, elm; elm = elms[i]; i++) { |
- var button = getSectionMenuButton(elm.id); |
- if (!button) |
- continue; |
- |
- if (!elm.classList.contains('disabled') && |
- elm.classList.contains('menu')) { |
- button.style.display = 'inline-block'; |
- } else { |
- button.style.display = 'none'; |
- } |
- } |
-} |
- |
-window.addEventListener('resize', handleWindowResize); |
- |
-var sectionToElementMap; |
-function getSectionElement(section) { |
- if (!sectionToElementMap) { |
- sectionToElementMap = {}; |
- for (var key in Section) { |
- sectionToElementMap[Section[key]] = |
- document.querySelector('.section[section=' + key + ']'); |
- } |
- } |
- return sectionToElementMap[section]; |
-} |
- |
-function getSectionMaxiview(section) { |
- return $(section.id + '-maxiview'); |
-} |
- |
-function getSectionMiniview(section) { |
- return section.querySelector('.miniview'); |
-} |
- |
-// You usually want to call |showOnlySection()| instead of this. |
-function showSection(section) { |
- if (!(section & shownSections)) { |
- shownSections |= section; |
- var el = getSectionElement(section); |
- if (el) { |
- el.classList.remove('collapsed'); |
- |
- var maxiview = getSectionMaxiview(el); |
- if (maxiview) { |
- maxiview.classList.remove('collapsing'); |
- maxiview.classList.remove('collapsed'); |
- // The opacity won't transition if you toggle the display property |
- // at the same time. To get a fade effect, we set the opacity |
- // asynchronously from another function, after the display is toggled. |
- // 1) 'collapsed' (display: none, opacity: 0) |
- // 2) none (display: block, opacity: 0) |
- // 3) 'opaque' (display: block, opacity: 1) |
- setTimeout(function () { |
- maxiview.classList.add('opaque'); |
- }, 0); |
- } |
- |
- var miniview = getSectionMiniview(el); |
- if (miniview) { |
- // The miniview is hidden immediately (no need to set this async). |
- miniview.classList.remove('opaque'); |
- } |
- } |
- |
- switch (section) { |
- case Section.THUMB: |
- mostVisited.visible = true; |
- mostVisited.layout(); |
- break; |
- case Section.APPS: |
- apps.visible = true; |
- apps.layout({disableAnimations:true}); |
- break; |
- } |
- } |
-} |
- |
-// Show this section and hide all other sections - at most one section can |
-// be open at one time. |
-function showOnlySection(section) { |
- for (var p in Section) { |
- if (p == section) |
- showSection(Section[p]); |
- else |
- hideSection(Section[p]); |
- } |
-} |
- |
-function hideSection(section) { |
- if (section & shownSections) { |
- shownSections &= ~section; |
- |
- switch (section) { |
- case Section.THUMB: |
- mostVisited.visible = false; |
- mostVisited.layout(); |
- break; |
- case Section.APPS: |
- apps.visible = false; |
- apps.layout(); |
- break; |
- } |
- |
- var el = getSectionElement(section); |
- if (el) { |
- el.classList.add('collapsed'); |
- |
- var maxiview = getSectionMaxiview(el); |
- if (maxiview) { |
- maxiview.classList.add((isDoneLoading() && isAnimating()) ? |
- 'collapsing' : 'collapsed'); |
- maxiview.classList.remove('opaque'); |
- } |
- |
- var miniview = getSectionMiniview(el); |
- if (miniview) { |
- // We need to set this asynchronously to properly get the fade effect. |
- setTimeout(function() { |
- miniview.classList.add('opaque'); |
- }, 0); |
- updateMiniviewClipping(miniview); |
- } |
- } |
- } |
-} |
- |
-window.addEventListener('webkitTransitionEnd', function(e) { |
- if (e.target.classList.contains('collapsing')) { |
- e.target.classList.add('collapsed'); |
- e.target.classList.remove('collapsing'); |
- } |
- |
- if (e.target.classList.contains('maxiview') || |
- e.target.classList.contains('miniview')) { |
- document.documentElement.removeAttribute('enable-section-animations'); |
- showScrollBars(); |
- } |
-}); |
- |
-/** |
- * Callback when the shown sections changes in another NTP. |
- * @param {number} newShownSections Bitmask of the shown sections. |
- */ |
-function setShownSections(newShownSections) { |
- for (var key in Section) { |
- if (newShownSections & Section[key]) |
- showSection(Section[key]); |
- else |
- hideSection(Section[key]); |
- } |
- setSectionMenuMode('apps', Section.APPS, newShownSections & MENU_APPS, |
- MENU_APPS); |
- setSectionMenuMode('most-visited', Section.THUMB, |
- newShownSections & MENU_THUMB, MENU_THUMB); |
- setSectionMenuMode('recently-closed', undefined, |
- newShownSections & MENU_RECENT, MENU_RECENT); |
- layoutSections(); |
-} |
- |
-// Recently closed |
- |
-function layoutRecentlyClosed() { |
- var recentElement = $('recently-closed'); |
- var miniview = getSectionMiniview(recentElement); |
- |
- updateMiniviewClipping(miniview); |
- |
- if (miniview.hasChildNodes()) { |
- recentElement.classList.remove('disabled'); |
- miniview.classList.add('opaque'); |
- } else { |
- recentElement.classList.add('disabled'); |
- miniview.classList.remove('opaque'); |
- } |
- |
- layoutSections(); |
-} |
- |
-/** |
- * This function is called by the backend whenever the sync status section |
- * needs to be updated to reflect recent sync state changes. The backend passes |
- * the new status information in the newMessage parameter. The state includes |
- * the following: |
- * |
- * syncsectionisvisible: true if the sync section needs to show up on the new |
- * tab page and false otherwise. |
- * title: the header for the sync status section. |
- * msg: the actual message (e.g. "Synced to foo@gmail.com"). |
- * linkisvisible: true if the link element should be visible within the sync |
- * section and false otherwise. |
- * linktext: the text to display as the link in the sync status (only used if |
- * linkisvisible is true). |
- * linkurlisset: true if an URL should be set as the href for the link and false |
- * otherwise. If this field is false, then clicking on the link |
- * will result in sending a message to the backend (see |
- * 'SyncLinkClicked'). |
- * linkurl: the URL to use as the element's href (only used if linkurlisset is |
- * true). |
- */ |
-function syncMessageChanged(newMessage) { |
- var syncStatusElement = $('sync-status'); |
- |
- // Hide the section if the message is emtpy. |
- if (!newMessage['syncsectionisvisible']) { |
- syncStatusElement.classList.add('disabled'); |
- return; |
- } |
- |
- syncStatusElement.classList.remove('disabled'); |
- |
- var content = syncStatusElement.children[0]; |
- |
- // Set the sync section background color based on the state. |
- if (newMessage.msgtype == 'error') { |
- content.style.backgroundColor = 'tomato'; |
- } else { |
- content.style.backgroundColor = ''; |
- } |
- |
- // Set the text for the header and sync message. |
- var titleElement = content.firstElementChild; |
- titleElement.textContent = newMessage.title; |
- var messageElement = titleElement.nextElementSibling; |
- messageElement.textContent = newMessage.msg; |
- |
- // Remove what comes after the message |
- while (messageElement.nextSibling) { |
- content.removeChild(messageElement.nextSibling); |
- } |
- |
- if (newMessage.linkisvisible) { |
- var el; |
- if (newMessage.linkurlisset) { |
- // Use a link |
- el = document.createElement('a'); |
- el.href = newMessage.linkurl; |
- } else { |
- el = document.createElement('button'); |
- el.className = 'link'; |
- el.addEventListener('click', syncSectionLinkClicked); |
- } |
- el.textContent = newMessage.linktext; |
- content.appendChild(el); |
- fixLinkUnderline(el); |
- } |
- |
- layoutSections(); |
-} |
- |
-/** |
- * Invoked when the link in the sync promo or sync status section is clicked. |
- */ |
-function syncSectionLinkClicked(e) { |
- chrome.send('SyncLinkClicked'); |
- e.preventDefault(); |
-} |
- |
-/** |
- * Invoked when link to start sync in the promo message is clicked, and Chrome |
- * has already been synced to an account. |
- */ |
-function syncAlreadyEnabled(message) { |
- showNotification(message.syncEnabledMessage); |
-} |
- |
-/** |
- * Returns the text used for a recently closed window. |
- * @param {number} numTabs Number of tabs in the window. |
- * @return {string} The text to use. |
- */ |
-function formatTabsText(numTabs) { |
- if (numTabs == 1) |
- return localStrings.getString('closedwindowsingle'); |
- return localStrings.getStringF('closedwindowmultiple', numTabs); |
-} |
- |
-// Theme related |
- |
-function themeChanged(hasAttribution) { |
- document.documentElement.setAttribute('hasattribution', hasAttribution); |
- $('themecss').href = 'chrome://theme/css/newtab.css?' + Date.now(); |
- updateAttribution(); |
-} |
- |
-function updateAttribution() { |
- // Default value for standard NTP with no theme attribution or custom logo. |
- logEvent('updateAttribution called'); |
- var imageId = 'IDR_PRODUCT_LOGO'; |
- // Theme attribution always overrides custom logos. |
- if (document.documentElement.getAttribute('hasattribution') == 'true') { |
- logEvent('updateAttribution called with THEME ATTR'); |
- imageId = 'IDR_THEME_NTP_ATTRIBUTION'; |
- } else if (document.documentElement.getAttribute('customlogo') == 'true') { |
- logEvent('updateAttribution with CUSTOMLOGO'); |
- imageId = 'IDR_CUSTOM_PRODUCT_LOGO'; |
- } |
- |
- $('attribution-img').src = 'chrome://theme/' + imageId + '?' + Date.now(); |
-} |
- |
-// If the content overlaps with the attribution, we bump its opacity down. |
-function updateAttributionDisplay(contentBottom) { |
- var attribution = $('attribution'); |
- var main = $('main'); |
- var rtl = document.documentElement.dir == 'rtl'; |
- var contentRect = main.getBoundingClientRect(); |
- var attributionRect = attribution.getBoundingClientRect(); |
- |
- // Hack. See comments for '.haslayout' in new_tab.css. |
- if (attributionRect.width == 0) |
- return; |
- else |
- attribution.classList.remove('nolayout'); |
- |
- if (contentBottom > attribution.offsetTop) { |
- if ((!rtl && contentRect.right > attributionRect.left) || |
- (rtl && attributionRect.right > contentRect.left)) { |
- attribution.classList.add('obscured'); |
- return; |
- } |
- } |
- |
- attribution.classList.remove('obscured'); |
-} |
- |
-function bookmarkBarAttached() { |
- document.documentElement.setAttribute('bookmarkbarattached', 'true'); |
-} |
- |
-function bookmarkBarDetached() { |
- document.documentElement.setAttribute('bookmarkbarattached', 'false'); |
-} |
- |
-function viewLog() { |
- var lines = []; |
- var start = log[0][1]; |
- |
- for (var i = 0; i < log.length; i++) { |
- lines.push((log[i][1] - start) + ': ' + log[i][0]); |
- } |
- |
- console.log(lines.join('\n')); |
-} |
- |
-// We apply the size class here so that we don't trigger layout animations |
-// onload. |
- |
-handleWindowResize(); |
- |
-var localStrings = new LocalStrings(); |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// Things we know are not needed at startup go below here |
- |
-function afterTransition(f) { |
- if (!isDoneLoading()) { |
- // Make sure we do not use a timer during load since it slows down the UI. |
- f(); |
- } else { |
- // The duration of all transitions are .15s |
- window.setTimeout(f, 150); |
- } |
-} |
- |
-// Notification |
- |
- |
-var notificationTimeout; |
- |
-/* |
- * Displays a message (either a string or a document fragment) in the |
- * notification slot at the top of the NTP. A close button ("x") will be |
- * inserted at the end of the message. |
- * @param {string|Node} message String or node to use as message. |
- * @param {string} actionText The text to show as a link next to the message. |
- * @param {function=} opt_f Function to call when the user clicks the action |
- * link. |
- * @param {number=} opt_delay The time in milliseconds before hiding the |
- * notification. |
- */ |
-function showNotification(message, actionText, opt_f, opt_delay) { |
-// TODO(arv): Create a notification component. |
- var notificationElement = $('notification'); |
- var f = opt_f || function() {}; |
- var delay = opt_delay || 10000; |
- |
- function show() { |
- window.clearTimeout(notificationTimeout); |
- notificationElement.classList.add('show'); |
- document.body.classList.add('notification-shown'); |
- } |
- |
- function delayedHide() { |
- notificationTimeout = window.setTimeout(hideNotification, delay); |
- } |
- |
- function doAction() { |
- f(); |
- closeNotification(); |
- } |
- |
- function closeNotification() { |
- if (notification.classList.contains('promo')) |
- chrome.send('closePromo'); |
- hideNotification(); |
- } |
- |
- // Remove classList entries from previous notifications. |
- notification.classList.remove('first-run'); |
- notification.classList.remove('promo'); |
- |
- var messageContainer = notificationElement.firstElementChild; |
- var actionLink = notificationElement.querySelector('#action-link'); |
- var closeButton = notificationElement.querySelector('#notification-close'); |
- |
- // Remove any previous actionLink entry. |
- actionLink.textContent = ''; |
- |
- $('notification-close').onclick = closeNotification; |
- |
- if (typeof message == 'string') { |
- messageContainer.textContent = message; |
- } else { |
- messageContainer.textContent = ''; // Remove all children. |
- messageContainer.appendChild(message); |
- } |
- |
- if (actionText) { |
- actionLink.style.display = ''; |
- actionLink.textContent = actionText; |
- } else { |
- actionLink.style.display = 'none'; |
- } |
- |
- actionLink.onclick = doAction; |
- actionLink.onkeydown = handleIfEnterKey(doAction); |
- notificationElement.onmouseover = show; |
- notificationElement.onmouseout = delayedHide; |
- actionLink.onfocus = show; |
- actionLink.onblur = delayedHide; |
- // Enable tabbing to the link now that it is shown. |
- actionLink.tabIndex = 0; |
- |
- show(); |
- delayedHide(); |
-} |
- |
-/** |
- * Hides the notifier. |
- */ |
-function hideNotification() { |
- var notificationElement = $('notification'); |
- notificationElement.classList.remove('show'); |
- document.body.classList.remove('notification-shown'); |
- var actionLink = notificationElement.querySelector('#actionlink'); |
- var closeButton = notificationElement.querySelector('#notification-close'); |
- // Prevent tabbing to the hidden link. |
- // Setting tabIndex to -1 only prevents future tabbing to it. If, however, the |
- // user switches window or a tab and then moves back to this tab the element |
- // may gain focus. We therefore make sure that we blur the element so that the |
- // element focus is not restored when coming back to this window. |
- if (actionLink) { |
- actionLink.tabIndex = -1; |
- actionLink.blur(); |
- } |
- if (closeButton) { |
- closeButton.tabIndex = -1; |
- closeButton.blur(); |
- } |
-} |
- |
-function showPromoNotification() { |
- showNotification(parseHtmlSubset(localStrings.getString('serverpromo')), |
- localStrings.getString('syncpromotext'), |
- function () { chrome.send('SyncLinkClicked'); }, |
- 60000); |
- var notificationElement = $('notification'); |
- notification.classList.add('promo'); |
-} |
- |
-$('main').addEventListener('click', function(e) { |
- var p = e.target; |
- while (p && p.tagName != 'H2') { |
- // In case the user clicks on a button we do not want to expand/collapse a |
- // section. |
- if (p.tagName == 'BUTTON') |
- return; |
- p = p.parentNode; |
- } |
- |
- if (!p) |
- return; |
- |
- p = p.parentNode; |
- if (!getSectionMaxiview(p)) |
- return; |
- |
- toggleSectionVisibilityAndAnimate(p.getAttribute('section')); |
-}); |
- |
-$('most-visited-settings').addEventListener('click', function() { |
- $('clear-all-blacklisted').execute(); |
-}); |
- |
-function toggleSectionVisibilityAndAnimate(section) { |
- if (!section) |
- return; |
- |
- // It looks better to return the scroll to the top when toggling sections. |
- document.body.scrollTop = 0; |
- |
- // We set it back in webkitTransitionEnd. |
- document.documentElement.setAttribute('enable-section-animations', 'true'); |
- if (shownSections & Section[section]) { |
- hideSection(Section[section]); |
- } else { |
- showOnlySection(section); |
- } |
- layoutSections(); |
- saveShownSections(); |
-} |
- |
-function handleIfEnterKey(f) { |
- return function(e) { |
- if (e.keyIdentifier == 'Enter') |
- f(e); |
- }; |
-} |
- |
-function maybeReopenTab(e) { |
- var el = findAncestor(e.target, function(el) { |
- return el.sessionId !== undefined; |
- }); |
- if (el) { |
- chrome.send('reopenTab', [String(el.sessionId)]); |
- e.preventDefault(); |
- |
- setWindowTooltipTimeout(); |
- } |
-} |
- |
-// Note that the openForeignSession calls can fail, resulting this method to |
-// not have any action (hence the maybe). |
-function maybeOpenForeignSession(e) { |
- var el = findAncestor(e.target, function(el) { |
- return el.sessionTag !== undefined; |
- }); |
- if (el) { |
- chrome.send('openForeignSession', [String(el.sessionTag)]); |
- e.stopPropagation(); |
- e.preventDefault(); |
- setWindowTooltipTimeout(); |
- } |
-} |
- |
-function maybeOpenForeignWindow(e) { |
- var el = findAncestor(e.target, function(el) { |
- return el.winNum !== undefined; |
- }); |
- if (el) { |
- chrome.send('openForeignSession', [String(el.sessionTag), |
- String(el.winNum)]); |
- e.stopPropagation(); |
- e.preventDefault(); |
- setWindowTooltipTimeout(); |
- } |
-} |
- |
-function maybeOpenForeignTab(e) { |
- var el = findAncestor(e.target, function(el) { |
- return el.sessionId !== undefined; |
- }); |
- if (el) { |
- chrome.send('openForeignSession', [String(el.sessionTag), String(el.winNum), |
- String(el.sessionId)]); |
- e.stopPropagation(); |
- e.preventDefault(); |
- setWindowTooltipTimeout(); |
- } |
-} |
- |
-// HACK(arv): After the window onblur event happens we get a mouseover event |
-// on the next item and we want to make sure that we do not show a tooltip |
-// for that. |
-function setWindowTooltipTimeout(e) { |
- window.setTimeout(function() { |
- windowTooltip.hide(); |
- }, 2 * WindowTooltip.DELAY); |
-} |
- |
-function maybeShowWindowTooltip(e) { |
- var f = function(el) { |
- return el.tabItems !== undefined; |
- }; |
- var el = findAncestor(e.target, f); |
- var relatedEl = findAncestor(e.relatedTarget, f); |
- if (el && el != relatedEl) { |
- windowTooltip.handleMouseOver(e, el, el.tabItems); |
- } |
-} |
- |
- |
-var recentlyClosedElement = $('recently-closed'); |
- |
-recentlyClosedElement.addEventListener('click', maybeReopenTab); |
-recentlyClosedElement.addEventListener('keydown', |
- handleIfEnterKey(maybeReopenTab)); |
- |
-recentlyClosedElement.addEventListener('mouseover', maybeShowWindowTooltip); |
-recentlyClosedElement.addEventListener('focus', maybeShowWindowTooltip, true); |
- |
-var foreignSessionElement = $('foreign-sessions'); |
- |
-foreignSessionElement.addEventListener('click', maybeOpenForeignSession); |
-foreignSessionElement.addEventListener('keydown', |
- handleIfEnterKey( |
- maybeOpenForeignSession)); |
- |
-foreignSessionElement.addEventListener('mouseover', maybeShowWindowTooltip); |
-foreignSessionElement.addEventListener('focus', maybeShowWindowTooltip, true); |
- |
-/** |
- * This object represents a tooltip representing a closed window. It is |
- * shown when hovering over a closed window item or when the item is focused. It |
- * gets hidden when blurred or when mousing out of the menu or the item. |
- * @param {Element} tooltipEl The element to use as the tooltip. |
- * @constructor |
- */ |
-function WindowTooltip(tooltipEl) { |
- this.tooltipEl = tooltipEl; |
- this.boundHide_ = this.hide.bind(this); |
- this.boundHandleMouseOut_ = this.handleMouseOut.bind(this); |
-} |
- |
-WindowTooltip.trackMouseMove_ = function(e) { |
- WindowTooltip.clientX = e.clientX; |
- WindowTooltip.clientY = e.clientY; |
-}; |
- |
-/** |
- * Time in ms to delay before the tooltip is shown. |
- * @type {number} |
- */ |
-WindowTooltip.DELAY = 300; |
- |
-WindowTooltip.prototype = { |
- timer: 0, |
- handleMouseOver: function(e, linkEl, tabs) { |
- this.linkEl_ = linkEl; |
- if (e.type == 'mouseover') { |
- this.linkEl_.addEventListener('mousemove', WindowTooltip.trackMouseMove_); |
- this.linkEl_.addEventListener('mouseout', this.boundHandleMouseOut_); |
- } else { // focus |
- this.linkEl_.addEventListener('blur', this.boundHide_); |
- } |
- this.timer = window.setTimeout(this.show.bind(this, e.type, linkEl, tabs), |
- WindowTooltip.DELAY); |
- }, |
- show: function(type, linkEl, tabs) { |
- window.addEventListener('blur', this.boundHide_); |
- this.linkEl_.removeEventListener('mousemove', |
- WindowTooltip.trackMouseMove_); |
- window.clearTimeout(this.timer); |
- |
- this.renderItems(tabs); |
- var rect = linkEl.getBoundingClientRect(); |
- var bodyRect = document.body.getBoundingClientRect(); |
- var rtl = document.documentElement.dir == 'rtl'; |
- |
- this.tooltipEl.style.display = 'block'; |
- var tooltipRect = this.tooltipEl.getBoundingClientRect(); |
- var x, y; |
- |
- // When focused show below, like a drop down menu. |
- if (type == 'focus') { |
- x = rtl ? |
- rect.left + bodyRect.left + rect.width - this.tooltipEl.offsetWidth : |
- rect.left + bodyRect.left; |
- y = rect.top + bodyRect.top + rect.height; |
- } else { |
- x = bodyRect.left + (rtl ? |
- WindowTooltip.clientX - this.tooltipEl.offsetWidth : |
- WindowTooltip.clientX); |
- // Offset like a tooltip |
- y = 20 + WindowTooltip.clientY + bodyRect.top; |
- } |
- |
- // We need to ensure that the tooltip is inside the window viewport. |
- x = Math.min(x, bodyRect.width - tooltipRect.width); |
- x = Math.max(x, 0); |
- y = Math.min(y, bodyRect.height - tooltipRect.height); |
- y = Math.max(y, 0); |
- |
- this.tooltipEl.style.left = x + 'px'; |
- this.tooltipEl.style.top = y + 'px'; |
- }, |
- handleMouseOut: function(e) { |
- // Don't hide when move to another item in the link. |
- var f = function(el) { |
- return el.tabItems !== undefined; |
- }; |
- var el = findAncestor(e.target, f); |
- var relatedEl = findAncestor(e.relatedTarget, f); |
- if (el && el != relatedEl) { |
- this.hide(); |
- } |
- }, |
- hide: function() { |
- window.clearTimeout(this.timer); |
- window.removeEventListener('blur', this.boundHide_); |
- this.linkEl_.removeEventListener('mousemove', |
- WindowTooltip.trackMouseMove_); |
- this.linkEl_.removeEventListener('mouseout', this.boundHandleMouseOut_); |
- this.linkEl_.removeEventListener('blur', this.boundHide_); |
- this.linkEl_ = null; |
- |
- this.tooltipEl.style.display = 'none'; |
- }, |
- renderItems: function(tabs) { |
- var tooltip = this.tooltipEl; |
- tooltip.textContent = ''; |
- |
- tabs.forEach(function(tab) { |
- var span = document.createElement('span'); |
- span.className = 'item'; |
- span.style.backgroundImage = url('chrome://favicon/' + tab.url); |
- span.dir = tab.direction; |
- span.textContent = tab.title; |
- tooltip.appendChild(span); |
- }); |
- } |
-}; |
- |
-var windowTooltip = new WindowTooltip($('window-tooltip')); |
- |
-window.addEventListener('load', |
- logEvent.bind(global, 'Tab.NewTabOnload', true)); |
- |
-window.addEventListener('resize', handleWindowResize); |
-document.addEventListener('DOMContentLoaded', |
- logEvent.bind(global, 'Tab.NewTabDOMContentLoaded', true)); |
- |
-// Whether or not we should send the initial 'GetSyncMessage' to the backend |
-// depends on the value of the attribue 'syncispresent' which the backend sets |
-// to indicate if there is code in the backend which is capable of processing |
-// this message. This attribute is loaded by the JSTemplate and therefore we |
-// must make sure we check the attribute after the DOM is loaded. |
-document.addEventListener('DOMContentLoaded', |
- callGetSyncMessageIfSyncIsPresent); |
- |
-/** |
- * The sync code is not yet built by default on all platforms so we have to |
- * make sure we don't send the initial sync message to the backend unless the |
- * backend told us that the sync code is present. |
- */ |
-function callGetSyncMessageIfSyncIsPresent() { |
- if (document.documentElement.getAttribute('syncispresent') == 'true') { |
- chrome.send('GetSyncMessage'); |
- } |
-} |
- |
-// Tooltip for elements that have text that overflows. |
-document.addEventListener('mouseover', function(e) { |
- // We don't want to do this while we are dragging because it makes things very |
- // janky |
- if (mostVisited.isDragging()) { |
- return; |
- } |
- |
- var el = findAncestor(e.target, function(el) { |
- return el.xtitle; |
- }); |
- if (el && el.xtitle != el.title) { |
- if (el.scrollWidth > el.clientWidth) { |
- el.title = el.xtitle; |
- } else { |
- el.title = ''; |
- } |
- } |
-}); |
- |
-/** |
- * Makes links and buttons support a different underline color. |
- * @param {Node} node The node to search for links and buttons in. |
- */ |
-function fixLinkUnderlines(node) { |
- var elements = node.querySelectorAll('a,button'); |
- Array.prototype.forEach.call(elements, fixLinkUnderline); |
-} |
- |
-/** |
- * Wraps the content of an element in a a link-color span. |
- * @param {Element} el The element to wrap. |
- */ |
-function fixLinkUnderline(el) { |
- var span = document.createElement('span'); |
- span.className = 'link-color'; |
- while (el.hasChildNodes()) { |
- span.appendChild(el.firstChild); |
- } |
- el.appendChild(span); |
-} |
- |
-updateAttribution(); |
- |
-function initializeLogin() { |
- chrome.send('initializeLogin', []); |
-} |
- |
-function updateLogin(login) { |
- $('login-container').style.display = login ? 'block' : ''; |
- if (login) |
- $('login-username').textContent = login; |
-} |
- |
-var mostVisited = new MostVisited( |
- $('most-visited-maxiview'), |
- document.querySelector('#most-visited .miniview'), |
- $('most-visited-menu'), |
- useSmallGrid(), |
- shownSections & Section.THUMB); |
- |
-function setMostVisitedPages(data, hasBlacklistedUrls) { |
- logEvent('received most visited pages'); |
- |
- mostVisited.updateSettingsLink(hasBlacklistedUrls); |
- mostVisited.data = data; |
- mostVisited.layout(); |
- layoutSections(); |
- |
- // Remove class name in a timeout so that changes done in this JS thread are |
- // not animated. |
- window.setTimeout(function() { |
- mostVisited.ensureSmallGridCorrect(); |
- maybeDoneLoading(); |
- }, 1); |
- |
- if (localStrings.getString('serverpromo')) { |
- showPromoNotification(); |
- } |
- |
-} |
- |
-function maybeDoneLoading() { |
- if (mostVisited.data && apps.loaded) |
- document.body.classList.remove('loading'); |
-} |
- |
-function isDoneLoading() { |
- return !document.body.classList.contains('loading'); |
-} |
- |
-document.addEventListener('DOMContentLoaded', function() { |
- cr.enablePlatformSpecificCSSRules(); |
- |
- // Initialize the listener for the "hide this" link on the apps promo. We do |
- // this outside of getAppsCallback because it only needs to be done once per |
- // NTP load. |
- $('apps-promo-hide').addEventListener('click', function() { |
- chrome.send('hideAppsPromo', []); |
- document.documentElement.classList.remove('apps-promo-visible'); |
- layoutSections(); |
- }); |
-}); |