15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @fileoverview PageListView implementation.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PageListView manages page list, dot list, switcher buttons and handles apps
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * pages callbacks from backend.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Note that you need to have AppLauncherHandler in your WebUI to use this code.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cr.define('ntp', function() {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  'use strict';
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * Creates a PageListView object.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @constructor
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @extends {Object}
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function PageListView() {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PageListView.prototype = {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The CardSlider object to use for changing app pages.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {CardSlider|undefined}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cardSlider: undefined,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The frame div for this.cardSlider.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!Element|undefined}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sliderFrame: undefined,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The 'page-list' element.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!Element|undefined}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pageList: undefined,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * A list of all 'tile-page' elements.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!NodeList|undefined}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tilePages: undefined,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * A list of all 'apps-page' elements.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!NodeList|undefined}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appsPages: undefined,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The Suggestions page.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!Element|undefined}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suggestionsPage: undefined,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The Most Visited page.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!Element|undefined}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mostVisitedPage: undefined,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The 'dots-list' element.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!Element|undefined}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dotList: undefined,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The left and right paging buttons.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!Element|undefined}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pageSwitcherStart: undefined,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pageSwitcherEnd: undefined,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The 'trash' element.  Note that technically this is unnecessary,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * JavaScript creates the object for us based on the id.  But I don't want
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * to rely on the ID being the same, and JSCompiler doesn't know about it.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!Element|undefined}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    trash: undefined,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The type of page that is currently shown. The value is a numerical ID.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {number}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shownPage: 0,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The index of the page that is currently shown, within the page type.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * For example if the third Apps page is showing, this will be 2.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {number}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shownPageIndex: 0,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * EventTracker for managing event listeners for page events.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!EventTracker}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    eventTracker: new EventTracker,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * If non-null, this is the ID of the app to highlight to the user the next
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * time getAppsCallback runs. "Highlight" in this case means to switch to
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * the page and run the new tile animation.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {?string}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    highlightAppId: null,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Initializes page list view.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Element} pageList A DIV element to host all pages.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Element} dotList An UL element to host nav dots. Each dot
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     represents a page.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Element} cardSliderFrame The card slider frame that hosts
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     pageList and switcher buttons.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Element|undefined} opt_trash Optional trash element.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Element|undefined} opt_pageSwitcherStart Optional start page
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     switcher button.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Element|undefined} opt_pageSwitcherEnd Optional end page
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     switcher button.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialize: function(pageList, dotList, cardSliderFrame, opt_trash,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         opt_pageSwitcherStart, opt_pageSwitcherEnd) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageList = pageList;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.dotList = dotList;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cr.ui.decorate(this.dotList, ntp.DotList);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.trash = opt_trash;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (this.trash)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new ntp.Trash(this.trash);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageSwitcherStart = opt_pageSwitcherStart;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (this.pageSwitcherStart)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ntp.initializePageSwitcher(this.pageSwitcherStart);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageSwitcherEnd = opt_pageSwitcherEnd;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (this.pageSwitcherEnd)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ntp.initializePageSwitcher(this.pageSwitcherEnd);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.shownPage = loadTimeData.getInteger('shown_page_type');
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.shownPageIndex = loadTimeData.getInteger('shown_page_index');
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (loadTimeData.getBoolean('showApps')) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Request data on the apps so we can fill them in.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Note that this is kicked off asynchronously.  'getAppsCallback' will
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // be invoked at some point after this function returns.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chrome.send('getApps');
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // No apps page.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (this.shownPage == loadTimeData.getInteger('apps_page_id')) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.setShownPage_(
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              loadTimeData.getInteger('most_visited_page_id'), 0);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        document.body.classList.add('bare-minimum');
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.addEventListener('keydown', this.onDocKeyDown_.bind(this));
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.tilePages = this.pageList.getElementsByClassName('tile-page');
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.appsPages = this.pageList.getElementsByClassName('apps-page');
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Initialize the cardSlider without any cards at the moment.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.sliderFrame = cardSliderFrame;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider = new cr.ui.CardSlider(this.sliderFrame, this.pageList,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.sliderFrame.offsetWidth);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Prevent touch events from triggering any sort of native scrolling if
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // there are multiple cards in the slider frame.
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      var cardSlider = this.cardSlider;
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cardSliderFrame.addEventListener('touchmove', function(e) {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (cardSlider.cardCount <= 1)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        e.preventDefault();
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }, true);
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Handle mousewheel events anywhere in the card slider, so that wheel
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // events on the page switchers will still scroll the page.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This listener must be added before the card slider is initialized,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // because it needs to be called before the card slider's handler.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cardSliderFrame.addEventListener('mousewheel', function(e) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (cardSlider.currentCardValue.handleMouseWheel(e)) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          e.preventDefault();  // Prevent default scroll behavior.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          e.stopImmediatePropagation();  // Prevent horizontal card flipping.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      });
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.initialize(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          loadTimeData.getBoolean('isSwipeTrackingFromScrollEventsEnabled'));
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Handle events from the card slider.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageList.addEventListener('cardSlider:card_changed',
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     this.onCardChanged_.bind(this));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageList.addEventListener('cardSlider:card_added',
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     this.onCardAdded_.bind(this));
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageList.addEventListener('cardSlider:card_removed',
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     this.onCardRemoved_.bind(this));
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Ensure the slider is resized appropriately with the window.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window.addEventListener('resize', this.onWindowResize_.bind(this));
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update apps when online state changes.
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window.addEventListener('online',
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.updateOfflineEnabledApps_.bind(this));
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window.addEventListener('offline',
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.updateOfflineEnabledApps_.bind(this));
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Appends a tile page.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {TilePage} page The page element.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} title The title of the tile page.
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @param {boolean} titleIsEditable If true, the title can be changed.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {TilePage} opt_refNode Optional reference node to insert in front
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     of.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * When opt_refNode is falsey, |page| will just be appended to the end of
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * the page list.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appendTilePage: function(page, title, titleIsEditable, opt_refNode) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (opt_refNode) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        var refIndex = this.getTilePageIndex(opt_refNode);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.cardSlider.addCardAtIndex(page, refIndex);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.cardSlider.appendCard(page);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remember special MostVisitedPage.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (typeof ntp.MostVisitedPage != 'undefined' &&
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          page instanceof ntp.MostVisitedPage) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert(this.tilePages.length == 1,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               'MostVisitedPage should be added as first tile page');
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.mostVisitedPage = page;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (typeof ntp.SuggestionsPage != 'undefined' &&
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          page instanceof ntp.SuggestionsPage) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.suggestionsPage = page;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If we're appending an AppsPage and it's a temporary page, animate it.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var animate = page instanceof ntp.AppsPage &&
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    page.classList.contains('temporary');
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make a deep copy of the dot template to add a new one.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var newDot = new ntp.NavDot(page, title, titleIsEditable, animate);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page.navigationDot = newDot;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.dotList.insertBefore(newDot,
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                opt_refNode ? opt_refNode.navigationDot : null);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set a tab index on the first dot.
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (this.dotList.dots.length == 1)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        newDot.tabIndex = 3;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.eventTracker.add(page, 'pagelayout', this.onPageLayout_.bind(this));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Called by chrome when an app has changed positions.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Object} appData The data for the app. This contains page and
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     position indices.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appMoved: function(appData) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(loadTimeData.getBoolean('showApps'));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var app = $(appData.id);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(app, 'trying to move an app that doesn\'t exist');
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      app.remove(false);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.appsPages[appData.page_index].insertApp(appData, false);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Called by chrome when an existing app has been disabled or
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * removed/uninstalled from chrome.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Object} appData A data structure full of relevant information for
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     the app.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {boolean} isUninstall True if the app is being uninstalled;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     false if the app is being disabled.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {boolean} fromPage True if the removal was from the current page.
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appRemoved: function(appData, isUninstall, fromPage) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(loadTimeData.getBoolean('showApps'));
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var app = $(appData.id);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(app, 'trying to remove an app that doesn\'t exist');
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!isUninstall)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        app.replaceAppData(appData);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        app.remove(!!fromPage);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {boolean} If the page is still starting up.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    isStartingUp_: function() {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return document.documentElement.classList.contains('starting-up');
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Tracks whether apps have been loaded at least once.
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {boolean}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appsLoaded_: false,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Callback invoked by chrome with the apps available.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Note that calls to this function can occur at any time, not just in
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * response to a getApps request. For example, when a user
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * installs/uninstalls an app on another synchronized devices.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Object} data An object with all the data on available
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *        applications.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getAppsCallback: function(data) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(loadTimeData.getBoolean('showApps'));
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var startTime = Date.now();
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remember this to select the correct card when done rebuilding.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var prevCurrentCard = this.cardSlider.currentCard;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make removal of pages and dots as quick as possible with less DOM
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // operations, reflows, or repaints. We set currentCard = 0 and remove
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // from the end to not encounter any auto-magic card selections in the
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // process and we hide the card slider throughout.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.currentCard = 0;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Clear any existing apps pages and dots.
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(rbyers): It might be nice to preserve animation of dots after an
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // uninstall. Could we re-use the existing page and dot elements?  It
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // seems unfortunate to have Chrome send us the entire apps list after an
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // uninstall.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (this.appsPages.length > 0)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.removeTilePageAndDot_(this.appsPages[this.appsPages.length - 1]);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Get the array of apps and add any special synthesized entries
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var apps = data.apps;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Get a list of page names
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var pageNames = data.appPageNames;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function stringListIsEmpty(list) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (var i = 0; i < list.length; i++) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (list[i])
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Sort by launch ordinal
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      apps.sort(function(a, b) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return a.app_launch_ordinal > b.app_launch_ordinal ? 1 :
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          a.app_launch_ordinal < b.app_launch_ordinal ? -1 : 0;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      });
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // An app to animate (in case it was just installed).
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var highlightApp;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If there are any pages after the apps, add new pages before them.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var lastAppsPage = (this.appsPages.length > 0) ?
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.appsPages[this.appsPages.length - 1] : null;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var lastAppsPageIndex = (lastAppsPage != null) ?
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Array.prototype.indexOf.call(this.tilePages, lastAppsPage) : -1;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var nextPageAfterApps = lastAppsPageIndex != -1 ?
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.tilePages[lastAppsPageIndex + 1] : null;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the apps, creating pages as necessary
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (var i = 0; i < apps.length; i++) {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        var app = apps[i];
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        var pageIndex = app.page_index || 0;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        while (pageIndex >= this.appsPages.length) {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          var pageName = loadTimeData.getString('appDefaultPageName');
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (this.appsPages.length < pageNames.length)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            pageName = pageNames[this.appsPages.length];
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          var origPageCount = this.appsPages.length;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.appendTilePage(new ntp.AppsPage(), pageName, true,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              nextPageAfterApps);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Confirm that appsPages is a live object, updated when a new page is
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // added (otherwise we'd have an infinite loop)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          assert(this.appsPages.length == origPageCount + 1,
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 'expected new page');
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (app.id == this.highlightAppId)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          highlightApp = app;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.appsPages[pageIndex].insertApp(app, false);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.currentCard = prevCurrentCard;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (highlightApp)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.appAdded(highlightApp, true);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logEvent('apps.layout: ' + (Date.now() - startTime));
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Tell the slider about the pages and mark the current page.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.updateSliderCards();
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.currentCardValue.navigationDot.classList.add('selected');
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!this.appsLoaded_) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.appsLoaded_ = true;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cr.dispatchSimpleEvent(document, 'sectionready', true, true);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      this.updateAppLauncherPromoHiddenState_();
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Called by chrome when a new app has been added to chrome or has been
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * enabled if previously disabled.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Object} appData A data structure full of relevant information for
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     the app.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {boolean=} opt_highlight Whether the app about to be added should
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     be highlighted.
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appAdded: function(appData, opt_highlight) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(loadTimeData.getBoolean('showApps'));
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (appData.id == this.highlightAppId) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        opt_highlight = true;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.highlightAppId = null;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var pageIndex = appData.page_index || 0;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (pageIndex >= this.appsPages.length) {
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        while (pageIndex >= this.appsPages.length) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.appendTilePage(new ntp.AppsPage(),
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              loadTimeData.getString('appDefaultPageName'),
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              true);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.updateSliderCards();
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var page = this.appsPages[pageIndex];
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var app = $(appData.id);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (app) {
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        app.replaceAppData(appData);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (opt_highlight) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        page.insertAndHighlightApp(appData);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.setShownPage_(loadTimeData.getInteger('apps_page_id'),
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           appData.page_index);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        page.insertApp(appData, false);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Callback invoked by chrome whenever an app preference changes.
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Object} data An object with all the data on available
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     applications.
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appsPrefChangedCallback: function(data) {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(loadTimeData.getBoolean('showApps'));
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (var i = 0; i < data.apps.length; ++i) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $(data.apps[i].id).appData = data.apps[i];
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the App dot names. Skip the first dot (Most Visited).
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var dots = this.dotList.getElementsByClassName('dot');
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var start = this.mostVisitedPage ? 1 : 0;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (var i = start; i < dots.length; ++i) {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dots[i].displayTitle = data.appPageNames[i - start] || '';
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * Callback invoked by chrome whenever the app launcher promo pref changes.
480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @param {boolean} show Identifies if we should show or hide the promo.
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    appLauncherPromoPrefChangeCallback: function(show) {
483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      loadTimeData.overrideValues({showAppLauncherPromo: show});
484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      this.updateAppLauncherPromoHiddenState_();
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    },
486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * Updates the hidden state of the app launcher promo based on the page
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * shown and load data content.
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    updateAppLauncherPromoHiddenState_: function() {
492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      $('app-launcher-promo').hidden =
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          !loadTimeData.getBoolean('showAppLauncherPromo') ||
494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          this.shownPage != loadTimeData.getInteger('apps_page_id');
495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    },
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Invoked whenever the pages in apps-page-list have changed so that
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * the Slider knows about the new elements.
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    updateSliderCards: function() {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var pageNo = Math.max(0, Math.min(this.cardSlider.currentCard,
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        this.tilePages.length - 1));
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages),
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               pageNo);
506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // The shownPage property was potentially saved from a previous webui that
507c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // didn't have the same set of pages as the current one. So we cascade
508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // from suggestions, to most visited and then to apps because we can have
509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // an page with apps only (e.g., chrome://apps) or one with only the most
510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // visited, but not one with only suggestions. And we alwayd default to
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // most visited first when previously shown page is not availabel anymore.
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // If most visited isn't there either, we go to apps.
513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (this.shownPage == loadTimeData.getInteger('suggestions_page_id')) {
514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (this.suggestionsPage)
515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          this.cardSlider.selectCardByValue(this.suggestionsPage);
516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        else
517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          this.shownPage = loadTimeData.getInteger('most_visited_page_id');
518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (this.shownPage == loadTimeData.getInteger('most_visited_page_id')) {
520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (this.mostVisitedPage)
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          this.cardSlider.selectCardByValue(this.mostVisitedPage);
522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        else
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          this.shownPage = loadTimeData.getInteger('apps_page_id');
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (this.shownPage == loadTimeData.getInteger('apps_page_id') &&
526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          loadTimeData.getBoolean('showApps')) {
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        this.cardSlider.selectCardByValue(
528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            this.appsPages[Math.min(this.shownPageIndex,
529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    this.appsPages.length - 1)]);
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (this.mostVisitedPage) {
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        this.shownPage = loadTimeData.getInteger('most_visited_page_id');
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        this.cardSlider.selectCardByValue(this.mostVisitedPage);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Called whenever tiles should be re-arranging themselves out of the way
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * of a moving or insert tile.
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enterRearrangeMode: function() {
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (loadTimeData.getBoolean('showApps')) {
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        var tempPage = new ntp.AppsPage();
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tempPage.classList.add('temporary');
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        var pageName = loadTimeData.getString('appDefaultPageName');
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.appendTilePage(tempPage, pageName, true);
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (ntp.getCurrentlyDraggingTile().firstChild.canBeRemoved()) {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $('footer').classList.add('showing-trash-mode');
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        $('footer-menu-container').style.minWidth = $('trash').offsetWidth -
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            $('chrome-web-store-link').offsetWidth + 'px';
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.documentElement.classList.add('dragging-mode');
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Invoked whenever some app is released
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    leaveRearrangeMode: function() {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var tempPage = document.querySelector('.tile-page.temporary');
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (tempPage) {
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        var dot = tempPage.navigationDot;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!tempPage.tileCount &&
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            tempPage != this.cardSlider.currentCardValue) {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.removeTilePageAndDot_(tempPage, true);
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          tempPage.classList.remove('temporary');
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.saveAppPageName(tempPage,
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               loadTimeData.getString('appDefaultPageName'));
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $('footer').classList.remove('showing-trash-mode');
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      $('footer-menu-container').style.minWidth = '';
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.documentElement.classList.remove('dragging-mode');
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Callback for the 'pagelayout' event.
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Event} e The event.
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onPageLayout_: function(e) {
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (Array.prototype.indexOf.call(this.tilePages, e.currentTarget) !=
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.cardSlider.currentCard) {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.updatePageSwitchers();
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Adjusts the size and position of the page switchers according to the
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * layout of the current card, and updates the aria-label attributes of
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * the page switchers.
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    updatePageSwitchers: function() {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!this.pageSwitcherStart || !this.pageSwitcherEnd)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var page = this.cardSlider.currentCardValue;
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageSwitcherStart.hidden = !page ||
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (this.cardSlider.currentCard == 0);
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageSwitcherEnd.hidden = !page ||
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (this.cardSlider.currentCard == this.cardSlider.cardCount - 1);
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!page)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var pageSwitcherLeft = isRTL() ? this.pageSwitcherEnd :
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       this.pageSwitcherStart;
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var pageSwitcherRight = isRTL() ? this.pageSwitcherStart :
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        this.pageSwitcherEnd;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var scrollbarWidth = page.scrollbarWidth;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pageSwitcherLeft.style.width =
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (page.sideMargin + 13) + 'px';
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pageSwitcherLeft.style.left = '0';
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pageSwitcherRight.style.width =
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (page.sideMargin - scrollbarWidth + 13) + 'px';
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pageSwitcherRight.style.right = scrollbarWidth + 'px';
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px';
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pageSwitcherLeft.style.top = offsetTop;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pageSwitcherRight.style.top = offsetTop;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pageSwitcherLeft.style.paddingBottom = offsetTop;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pageSwitcherRight.style.paddingBottom = offsetTop;
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the aria-label attributes of the two page switchers.
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageSwitcherStart.updateButtonAccessibleLabel(this.dotList.dots);
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageSwitcherEnd.updateButtonAccessibleLabel(this.dotList.dots);
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Returns the index of the given apps page.
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {AppsPage} page The AppsPage we wish to find.
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {number} The index of |page| or -1 if it is not in the
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *    collection.
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getAppsPageIndex: function(page) {
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Array.prototype.indexOf.call(this.appsPages, page);
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Handler for cardSlider:card_changed events from this.cardSlider.
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Event} e The cardSlider:card_changed event.
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onCardChanged_: function(e) {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var page = e.cardSlider.currentCardValue;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Don't change shownPage until startup is done (and page changes actually
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // reflect user actions).
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!this.isStartingUp_()) {
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (page.classList.contains('apps-page')) {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.setShownPage_(loadTimeData.getInteger('apps_page_id'),
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             this.getAppsPageIndex(page));
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (page.classList.contains('most-visited-page')) {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.setShownPage_(
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              loadTimeData.getInteger('most_visited_page_id'), 0);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (page.classList.contains('suggestions-page')) {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this.setShownPage_(loadTimeData.getInteger('suggestions_page_id'), 0);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          console.error('unknown page selected');
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Update the active dot
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var curDot = this.dotList.getElementsByClassName('selected')[0];
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (curDot)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        curDot.classList.remove('selected');
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page.navigationDot.classList.add('selected');
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.updatePageSwitchers();
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Saves/updates the newly selected page to open when first loading the NTP.
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {number} shownPage The new shown page type.
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {number} shownPageIndex The new shown page index.
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    setShownPage_: function(shownPage, shownPageIndex) {
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(shownPageIndex >= 0);
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.shownPage = shownPage;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.shownPageIndex = shownPageIndex;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]);
687c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      this.updateAppLauncherPromoHiddenState_();
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Listen for card additions to update the page switchers or the current
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * card accordingly.
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Event} e A card removed or added event.
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onCardAdded_: function(e) {
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // When the second arg passed to insertBefore is falsey, it acts just like
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // appendChild.
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.pageList.insertBefore(e.addedCard, this.tilePages[e.addedIndex]);
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.onCardAddedOrRemoved_();
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Listen for card removals to update the page switchers or the current card
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * accordingly.
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Event} e A card removed or added event.
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onCardRemoved_: function(e) {
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      e.removedCard.parentNode.removeChild(e.removedCard);
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.onCardAddedOrRemoved_();
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Called when a card is removed or added.
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onCardAddedOrRemoved_: function() {
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (this.isStartingUp_())
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Without repositioning there were issues - http://crbug.com/133457.
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.repositionFrame();
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.updatePageSwitchers();
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Save the name of an apps page.
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Store the apps page name into the preferences store.
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {AppsPage} appsPage The app page for which we wish to save.
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} name The name of the page.
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saveAppPageName: function(appPage, name) {
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var index = this.getAppsPageIndex(appPage);
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(index != -1);
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome.send('saveAppPageName', [name, index]);
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Window resize handler.
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onWindowResize_: function(e) {
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.resize(this.sliderFrame.offsetWidth);
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.updatePageSwitchers();
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Listener for offline status change events. Updates apps that are
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * not offline-enabled to be grayscale if the browser is offline.
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    updateOfflineEnabledApps_: function() {
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var apps = document.querySelectorAll('.app');
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (var i = 0; i < apps.length; ++i) {
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (apps[i].appData.enabled && !apps[i].appData.offline_enabled) {
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          apps[i].setIcon();
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          apps[i].loadIcon();
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Handler for key events on the page. Ctrl-Arrow will switch the visible
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * page.
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Event} e The KeyboardEvent.
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onDocKeyDown_: function(e) {
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!e.ctrlKey || e.altKey || e.metaKey || e.shiftKey)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var direction = 0;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (e.keyIdentifier == 'Left')
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        direction = -1;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else if (e.keyIdentifier == 'Right')
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        direction = 1;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var cardIndex =
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (this.cardSlider.currentCard + direction +
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           this.cardSlider.cardCount) % this.cardSlider.cardCount;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.selectCard(cardIndex, true);
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      e.stopPropagation();
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Returns the index of a given tile page.
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {TilePage} page The TilePage we wish to find.
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {number} The index of |page| or -1 if it is not in the
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *    collection.
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getTilePageIndex: function(page) {
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Array.prototype.indexOf.call(this.tilePages, page);
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Removes a page and navigation dot (if the navdot exists).
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {TilePage} page The page to be removed.
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {boolean=} opt_animate If the removal should be animated.
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    removeTilePageAndDot_: function(page, opt_animate) {
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (page.navigationDot)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        page.navigationDot.remove(opt_animate);
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.cardSlider.removeCard(page);
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return {
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PageListView: PageListView
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)});
813