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

Side by Side Diff: chrome/browser/resources/ntp4/page_list_view.js

Issue 8637001: [NTP4] Auto-deletion of empty apps panes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: more fixes and typos from reviewing myself Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview PageListView implementation. 6 * @fileoverview PageListView implementation.
7 * PageListView manages page list, dot list, switcher buttons and handles apps 7 * PageListView manages page list, dot list, switcher buttons and handles apps
8 * pages callbacks from backend. 8 * pages callbacks from backend.
9 * 9 *
10 * Note that you need to have AppLauncherHandler in your WebUI to use this code. 10 * Note that you need to have AppLauncherHandler in your WebUI to use this code.
(...skipping 17 matching lines...) Expand all
28 } 28 }
29 29
30 PageListView.prototype = { 30 PageListView.prototype = {
31 /** 31 /**
32 * The CardSlider object to use for changing app pages. 32 * The CardSlider object to use for changing app pages.
33 * @type {CardSlider|undefined} 33 * @type {CardSlider|undefined}
34 */ 34 */
35 cardSlider: undefined, 35 cardSlider: undefined,
36 36
37 /** 37 /**
38 * The frame div for cardSlider. 38 * The frame div for this.cardSlider.
39 * @type {!Element|undefined} 39 * @type {!Element|undefined}
40 */ 40 */
41 sliderFrame: undefined, 41 sliderFrame: undefined,
42 42
43 /** 43 /**
44 * The 'page-list' element. 44 * The 'page-list' element.
45 * @type {!Element|undefined} 45 * @type {!Element|undefined}
46 */ 46 */
47 pageList: undefined, 47 pageList: undefined,
48 48
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 new ntp4.Trash(this.trash); 137 new ntp4.Trash(this.trash);
138 138
139 this.pageSwitcherStart = opt_pageSwitcherStart; 139 this.pageSwitcherStart = opt_pageSwitcherStart;
140 if (this.pageSwitcherStart) 140 if (this.pageSwitcherStart)
141 ntp4.initializePageSwitcher(this.pageSwitcherStart); 141 ntp4.initializePageSwitcher(this.pageSwitcherStart);
142 142
143 this.pageSwitcherEnd = opt_pageSwitcherEnd; 143 this.pageSwitcherEnd = opt_pageSwitcherEnd;
144 if (this.pageSwitcherEnd) 144 if (this.pageSwitcherEnd)
145 ntp4.initializePageSwitcher(this.pageSwitcherEnd); 145 ntp4.initializePageSwitcher(this.pageSwitcherEnd);
146 146
147 this.shownPage = templateData['shown_page_type']; 147 this.shownPage = templateData.shown_page_type;
148 this.shownPageIndex = templateData['shown_page_index']; 148 this.shownPageIndex = templateData.shown_page_index;
149 149
150 // Request data on the apps so we can fill them in. 150 // Request data on the apps so we can fill them in.
151 // Note that this is kicked off asynchronously. 'getAppsCallback' will be 151 // Note that this is kicked off asynchronously. 'getAppsCallback' will be
152 // invoked at some point after this function returns. 152 // invoked at some point after this function returns.
153 chrome.send('getApps'); 153 chrome.send('getApps');
154 154
155 document.addEventListener('keydown', this.onDocKeyDown_.bind(this)); 155 document.addEventListener('keydown', this.onDocKeyDown_.bind(this));
156 // Prevent touch events from triggering any sort of native scrolling 156 // Prevent touch events from triggering any sort of native scrolling
157 document.addEventListener('touchmove', function(e) { 157 document.addEventListener('touchmove', function(e) {
158 e.preventDefault(); 158 e.preventDefault();
159 }, true); 159 }, true);
160 160
161 this.tilePages = this.pageList.getElementsByClassName('tile-page'); 161 this.tilePages = this.pageList.getElementsByClassName('tile-page');
162 this.appsPages = this.pageList.getElementsByClassName('apps-page'); 162 this.appsPages = this.pageList.getElementsByClassName('apps-page');
163 163
164 // Initialize the cardSlider without any cards at the moment 164 // Initialize the cardSlider without any cards at the moment
165 this.sliderFrame = cardSliderFrame; 165 this.sliderFrame = cardSliderFrame;
166 this.cardSlider = new cr.ui.CardSlider(this.sliderFrame, this.pageList, 166 this.cardSlider = new cr.ui.CardSlider(this.sliderFrame, this.pageList,
167 this.sliderFrame.offsetWidth); 167 this.sliderFrame.offsetWidth);
168 this.cardSlider.initialize(); 168 this.cardSlider.initialize();
169 169
170 // Handle the page being changed 170 // Handle the page being changed
171 this.pageList.addEventListener( 171 this.pageList.addEventListener(
172 cr.ui.CardSlider.EventType.CARD_CHANGED, 172 cr.ui.CardSlider.EventType.CARD_CHANGED,
173 this.cardChangedHandler_.bind(this)); 173 this.cardChangedHandler_.bind(this));
174 174
175 // Handle the end of cards being changed (useful if animated).
176 this.pageList.addEventListener(
177 cr.ui.CardSlider.EventType.CARD_CHANGE_ENDED,
178 this.cardChangeEndedHandler_.bind(this));
179
180 // Handle tiles being removed from tile pages.
181 this.pageList.addEventListener(
182 ntp4.TilePage.EventType.TILE_REMOVED,
183 this.tileRemovedHandler_.bind(this));
184
175 // Ensure the slider is resized appropriately with the window 185 // Ensure the slider is resized appropriately with the window
176 window.addEventListener('resize', this.onWindowResize_.bind(this)); 186 window.addEventListener('resize', this.onWindowResize_.bind(this));
177 187
178 // Update apps when online state changes. 188 // Update apps when online state changes.
179 window.addEventListener('online', 189 window.addEventListener('online',
180 this.updateOfflineEnabledApps_.bind(this)); 190 this.updateOfflineEnabledApps_.bind(this));
181 window.addEventListener('offline', 191 window.addEventListener('offline',
182 this.updateOfflineEnabledApps_.bind(this)); 192 this.updateOfflineEnabledApps_.bind(this));
183 }, 193 },
184 194
185 /** 195 /**
186 * Appends a tile page. 196 * Appends a tile page.
187 * 197 *
188 * @param {TilePage} page The page element. 198 * @param {TilePage} page The page element.
189 * @param {string} title The title of the tile page. 199 * @param {string} title The title of the tile page.
190 * @param {bool} titleIsEditable If true, the title can be changed. 200 * @param {bool} titleIsEditable If true, the title can be changed.
191 * @param {TilePage} opt_refNode Optional reference node to insert in front 201 * @param {TilePage} opt_refNode Optional reference node to insert in front
192 * of. 202 * of.
193 * When opt_refNode is falsey, |page| will just be appended to the end of 203 * When opt_refNode is falsey, |page| will just be appended to the end of
194 * the page list. 204 * the page list.
195 */ 205 */
196 appendTilePage: function(page, title, titleIsEditable, opt_refNode) { 206 appendTilePage: function(page, title, titleIsEditable, opt_refNode) {
197 // When opt_refNode is falsey, insertBefore acts just like appendChild. 207 // When opt_refNode is falsey, insertBefore acts just like appendChild.
198 this.pageList.insertBefore(page, opt_refNode); 208 this.pageList.insertBefore(page, opt_refNode);
199 209
210 if (!document.documentElement.classList.contains('starting-up')) {
211 // If we're inserting a card in front of the current card, add 1 to the
212 // current index to adjust for the new card in the order.
213 var index = Array.prototype.indexOf.call(this.tilePages, page);
214 if (typeof this.cardSlider.currentCard != 'undefined' &&
215 index <= this.cardSlider.currentCard) {
216 this.cardSlider.currentCard += 1;
217 }
218 if (page instanceof ntp4.AppsPage &&
219 this.shownPage == templateData.apps_page_id &&
220 this.getAppsPageIndex(page) <= this.shownPageIndex) {
221 this.shownPageIndex += 1;
222 }
223 }
224
200 // Remember special MostVisitedPage. 225 // Remember special MostVisitedPage.
201 if (typeof ntp4.MostVisitedPage != 'undefined' && 226 if (typeof ntp4.MostVisitedPage != 'undefined' &&
202 page instanceof ntp4.MostVisitedPage) { 227 page instanceof ntp4.MostVisitedPage) {
203 assert(this.tilePages.length == 1, 228 assert(this.tilePages.length == 1,
204 'MostVisitedPage should be added as first tile page'); 229 'MostVisitedPage should be added as first tile page');
205 this.mostVisitedPage = page; 230 this.mostVisitedPage = page;
206 } 231 }
207 232
208 // If we're appending an AppsPage and it's a temporary page, animate it. 233 // If we're appending an AppsPage and it's a temporary page, animate it.
209 var animate = page instanceof ntp4.AppsPage && 234 var animate = page instanceof ntp4.AppsPage &&
(...skipping 10 matching lines...) Expand all
220 this.eventTracker.add(page, 'pagelayout', this.onPageLayout_.bind(this)); 245 this.eventTracker.add(page, 'pagelayout', this.onPageLayout_.bind(this));
221 }, 246 },
222 247
223 /** 248 /**
224 * Called by chrome when an existing app has been disabled or 249 * Called by chrome when an existing app has been disabled or
225 * removed/uninstalled from chrome. 250 * removed/uninstalled from chrome.
226 * @param {Object} appData A data structure full of relevant information for 251 * @param {Object} appData A data structure full of relevant information for
227 * the app. 252 * the app.
228 * @param {boolean} isUninstall True if the app is being uninstalled; 253 * @param {boolean} isUninstall True if the app is being uninstalled;
229 * false if the app is being disabled. 254 * false if the app is being disabled.
255 * @param {boolean} fromPage If the removal was from the current page.
230 */ 256 */
231 appRemoved: function(appData, isUninstall) { 257 appRemoved: function(appData, isUninstall, fromPage) {
232 var app = $(appData.id); 258 var app = $(appData.id);
233 assert(app, 'trying to remove an app that doesn\'t exist'); 259 assert(app, 'trying to remove an app that doesn\'t exist');
234 260
235 if (!isUninstall) 261 if (!isUninstall) {
236 app.replaceAppData(appData); 262 app.replaceAppData(appData);
237 else 263 } else {
238 app.remove(); 264 // Unset the ID immediately, because the app is already gone. But leave
265 // the tile on the page as it animates out.
266 app.id = '';
Evan Stade 2011/12/08 02:34:56 i think this can go inside the if (fromPage) case?
Dan Beam 2011/12/08 04:46:18 Done.
267 // If the uninstall was from this page, run the blipout animation and
268 // the tile will be removed in TilePage#onContentsAnimationEnd_.
269 // Otherwise delete the tile without auto-deleting the page to avoid
270 // re-deleting the same page (or the page that slid in to take its
271 // place).
272 if (fromPage) {
273 app.classList.add('removing-tile-contents');
274 } else {
275 var tilePage = app.tile.tilePage;
276 tilePage.removeTile(app.tile, false, true);
277 this.removeAppsPageIfEmpty_(tilePage, false, true);
278 }
279 }
239 }, 280 },
240 281
241 /** 282 /**
242 * Callback invoked by chrome with the apps available. 283 * Callback invoked by chrome with the apps available.
243 * 284 *
244 * Note that calls to this function can occur at any time, not just in 285 * Note that calls to this function can occur at any time, not just in
245 * response to a getApps request. For example, when a user 286 * response to a getApps request. For example, when a user
246 * installs/uninstalls an app on another synchronized devices. 287 * installs/uninstalls an app on another synchronized devices.
247 * @param {Object} data An object with all the data on available 288 * @param {Object} data An object with all the data on available
248 * applications. 289 * applications.
249 */ 290 */
250 getAppsCallback: function(data) { 291 getAppsCallback: function(data) {
251 var startTime = Date.now(); 292 var startTime = Date.now();
252 293
253 // Clear any existing apps pages and dots. 294 // Clear any existing apps pages and dots.
254 // TODO(rbyers): It might be nice to preserve animation of dots after an 295 // TODO(rbyers): It might be nice to preserve animation of dots after an
255 // uninstall. Could we re-use the existing page and dot elements? It 296 // uninstall. Could we re-use the existing page and dot elements? It
256 // seems unfortunate to have Chrome send us the entire apps list after an 297 // seems unfortunate to have Chrome send us the entire apps list after an
257 // uninstall. 298 // uninstall.
258 while (this.appsPages.length > 0) { 299 while (this.appsPages.length > 0) {
259 var page = this.appsPages[0]; 300 var page = this.appsPages[0];
260 var dot = page.navigationDot;
261 301
262 this.eventTracker.remove(page); 302 this.eventTracker.remove(page);
263 page.tearDown(); 303 this.removeTilePageAndDot_(page);
264 page.parentNode.removeChild(page);
265 dot.parentNode.removeChild(dot);
266 } 304 }
267 305
268 // Get the array of apps and add any special synthesized entries 306 // Get the array of apps and add any special synthesized entries
269 var apps = data.apps; 307 var apps = data.apps;
270 308
271 // Get a list of page names 309 // Get a list of page names
272 var pageNames = data.appPageNames; 310 var pageNames = data.appsPageNames;
273 311
274 function stringListIsEmpty(list) { 312 function stringListIsEmpty(list) {
275 for (var i = 0; i < list.length; i++) { 313 for (var i = 0; i < list.length; i++) {
276 if (list[i]) 314 if (list[i])
277 return false; 315 return false;
278 } 316 }
279 return true; 317 return true;
280 } 318 }
281 319
282 // Sort by launch index 320 // Sort by launch index
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 * @param {Object} appData A data structure full of relevant information for 369 * @param {Object} appData A data structure full of relevant information for
332 * the app. 370 * the app.
333 */ 371 */
334 appAdded: function(appData, opt_highlight) { 372 appAdded: function(appData, opt_highlight) {
335 if (appData.id == this.highlightAppId) { 373 if (appData.id == this.highlightAppId) {
336 opt_highlight = true; 374 opt_highlight = true;
337 this.highlightAppId = null; 375 this.highlightAppId = null;
338 } 376 }
339 377
340 var pageIndex = appData.page_index || 0; 378 var pageIndex = appData.page_index || 0;
341 379 this.ensureAppsPageAtIndex_(pageIndex);
342 if (pageIndex >= this.appsPages.length) {
343 while (pageIndex >= this.appsPages.length) {
344 this.appendTilePage(new ntp4.AppsPage(),
345 localStrings.getString('appDefaultPageName'),
346 true);
347 }
348 this.updateSliderCards();
349 }
350 380
351 var page = this.appsPages[pageIndex]; 381 var page = this.appsPages[pageIndex];
352 var app = $(appData.id); 382 var app = $(appData.id);
353 if (app) 383 if (app)
354 app.replaceAppData(appData); 384 app.replaceAppData(appData);
355 else 385 else
356 page.appendApp(appData, opt_highlight); 386 page.appendApp(appData, opt_highlight);
357 }, 387 },
358 388
359 /** 389 /**
360 * Callback invoked by chrome whenever an app preference changes. 390 * Callback invoked by chrome whenever an app preference changes.
361 * @param {Object} data An object with all the data on available 391 * @param {Object} data An object with all the data on available
362 * applications. 392 * applications.
363 */ 393 */
364 appsPrefChangedCallback: function(data) { 394 appsPrefChangedCallback: function(data) {
365 for (var i = 0; i < data.apps.length; ++i) { 395 for (var i = 0; i < data.apps.length; ++i)
366 $(data.apps[i].id).appData = data.apps[i]; 396 $(data.apps[i].id).appData = data.apps[i];
367 }
368 397
369 // Set the App dot names. Skip the first dot (Most Visited). 398 // Set the App dot names. Skip dots that don't belong to apps pages.
370 var dots = this.dotList.getElementsByClassName('dot'); 399 var dots = this.dotList.getElementsByClassName('dot');
371 var start = this.mostVisitedPage ? 1 : 0; 400 var firstAppDot = this.getTilePageIndex(this.appsPages[0]);
372 for (var i = start; i < dots.length; ++i) { 401 for (var i = 0; i < data.appsPageNames.length; ++i) {
373 dots[i].displayTitle = data.appPageNames[i - start] || ''; 402 // When we drop an app on a navigation dot or new page we first move the
403 // tile (which calls this), *then* save the page name so sometimes we'll
404 // be one short here.
405 var dot = dots[firstAppDot + i];
406 if (dot)
407 dot.displayTitle = data.appsPageNames[i];
374 } 408 }
375 }, 409 },
376 410
377 /** 411 /**
378 * Invoked whenever the pages in apps-page-list have changed so that 412 * Invoked whenever the pages in apps-page-list have changed so that
379 * the Slider knows about the new elements. 413 * the Slider knows about the new elements.
380 */ 414 */
381 updateSliderCards: function() { 415 updateSliderCards: function() {
382 var pageNo = Math.min(this.cardSlider.currentCard, 416 var index = -1;
383 this.tilePages.length - 1); 417 var prevPage = this.shownPage;
384 this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages), 418 var prevIndex = this.shownPageIndex;
385 pageNo); 419 var tiles = Array.prototype.slice.call(this.tilePages);
420 // It doesn't hurt to clamp value this every time, even if it's only
421 // applicable to apps. It helps self-heal strange / un-expected data, i.e.
Evan Stade 2011/12/08 02:34:56 strange/unexepected data most likely comes from pr
Dan Beam 2011/12/08 04:46:18 Done. (changed comment)
422 // going from an apps page to the most visited page directly without
423 // setting this.shownPageIndex = 0 somehow.
424 this.shownPageIndex = Math.max(0, Math.min(this.shownPageIndex,
425 this.appsPages.length - 1));
386 switch (this.shownPage) { 426 switch (this.shownPage) {
387 case templateData['apps_page_id']: 427 case templateData.apps_page_id:
388 this.cardSlider.selectCardByValue( 428 index = tiles.indexOf(this.appsPages[this.shownPageIndex]);
389 this.appsPages[Math.min(this.shownPageIndex,
390 this.appsPages.length - 1)]);
391 break; 429 break;
392 case templateData['most_visited_page_id']: 430 case templateData.most_visited_page_id:
393 if (this.mostVisitedPage) 431 index = tiles.indexOf(this.mostVisitedPage);
394 this.cardSlider.selectCardByValue(this.mostVisitedPage);
395 break; 432 break;
396 } 433 }
434 // If shownPage was saved as a page that's now disabled or the shownPage
435 // doesn't exist any more, index will be -1. Change to the preferred
436 // default page (first apps pane) in this case.
437 if (index < 0) {
438 this.shownPage = templateData.apps_page_id;
439 index = tiles.indexOf(this.appsPages[0]);
440 }
441 // Set the new cards and index.
442 this.cardSlider.setCards(tiles, index);
443 // If we got new page or index, update the pref.
444 if (prevIndex != this.shownPageIndex || prevPage != this.shownPage)
Evan Stade 2011/12/08 02:34:56 you should just always do this. this.shownPageInde
Dan Beam 2011/12/08 04:46:18 Done. OK, I just noticed it was often doing this
445 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]);
397 }, 446 },
398 447
399 /** 448 /**
400 * Called whenever tiles should be re-arranging themselves out of the way 449 * Called whenever tiles should be re-arranging themselves out of the way
401 * of a moving or insert tile. 450 * of a moving or insert tile.
402 */ 451 */
403 enterRearrangeMode: function() { 452 enterRearrangeMode: function() {
404 var tempPage = new ntp4.AppsPage(); 453 var tempPage = new ntp4.AppsPage();
405 tempPage.classList.add('temporary'); 454 tempPage.classList.add('temporary');
406 this.appendTilePage(tempPage, 455 var pageName = localStrings.getString('appDefaultPageName');
407 localStrings.getString('appDefaultPageName'), 456 this.appendTilePage(tempPage, pageName, true);
408 true);
409 var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage);
410 if (this.cardSlider.currentCard >= tempIndex)
411 this.cardSlider.currentCard += 1;
412 this.updateSliderCards(); 457 this.updateSliderCards();
458 this.updatePageSwitchers();
413 459
414 if (ntp4.getCurrentlyDraggingTile().firstChild.canBeRemoved()) 460 if (ntp4.getCurrentlyDraggingTile().firstChild.canBeRemoved())
415 $('footer').classList.add('showing-trash-mode'); 461 $('footer').classList.add('showing-trash-mode');
416 }, 462 },
417 463
418 /** 464 /**
419 * Invoked whenever some app is released 465 * Invoked whenever some app is released
420 */ 466 */
421 leaveRearrangeMode: function() { 467 leaveRearrangeMode: function() {
422 var tempPage = document.querySelector('.tile-page.temporary'); 468 var tempPage = document.querySelector('.tile-page.temporary');
423 var dot = tempPage.navigationDot; 469 // Either remove a temp page if it's empty or save the page name (as an
424 if (!tempPage.tileCount && tempPage != this.cardSlider.currentCardValue) { 470 // app has just been dropped on it or created somehow.
Evan Stade 2011/12/08 02:34:56 close paren
Dan Beam 2011/12/08 04:46:18 Done. http://xkcd.com/859/
425 dot.animateRemove(); 471 if (tempPage && !this.removeAppsPageIfEmpty_(tempPage, true, true)) {
426 var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage); 472 this.saveAppsPageName(tempPage, tempPage.navigationDot.displayTitle);
427 if (this.cardSlider.currentCard > tempIndex)
428 this.cardSlider.currentCard -= 1;
429 tempPage.parentNode.removeChild(tempPage);
430 this.updateSliderCards();
431 } else {
432 tempPage.classList.remove('temporary'); 473 tempPage.classList.remove('temporary');
433 this.saveAppPageName(tempPage,
434 localStrings.getString('appDefaultPageName'));
435 } 474 }
436 475
437 $('footer').classList.remove('showing-trash-mode'); 476 $('footer').classList.remove('showing-trash-mode');
438 }, 477 },
439 478
440 /** 479 /**
441 * Callback for the 'pagelayout' event. 480 * Callback for the 'pagelayout' event.
442 * @param {Event} e The event. 481 * @param {Event} e The event.
443 */ 482 */
444 onPageLayout_: function(e) { 483 onPageLayout_: function(e) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 pageSwitcherRight.style.right = scrollbarWidth + 'px'; 520 pageSwitcherRight.style.right = scrollbarWidth + 'px';
482 521
483 var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px'; 522 var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px';
484 pageSwitcherLeft.style.top = offsetTop; 523 pageSwitcherLeft.style.top = offsetTop;
485 pageSwitcherRight.style.top = offsetTop; 524 pageSwitcherRight.style.top = offsetTop;
486 pageSwitcherLeft.style.paddingBottom = offsetTop; 525 pageSwitcherLeft.style.paddingBottom = offsetTop;
487 pageSwitcherRight.style.paddingBottom = offsetTop; 526 pageSwitcherRight.style.paddingBottom = offsetTop;
488 }, 527 },
489 528
490 /** 529 /**
491 * Returns the index of the given page. 530 * Returns the index of the given apps page.
492 * @param {AppsPage} page The AppsPage for we wish to find. 531 * @param {AppsPage} page The AppsPage we wish to find.
493 * @return {number} The index of |page|, or -1 if it is not here. 532 * @return {number} The index of |page| or -1 if it is not in the
533 * collection.
494 */ 534 */
495 getAppsPageIndex: function(page) { 535 getAppsPageIndex: function(page) {
496 return Array.prototype.indexOf.call(this.appsPages, page); 536 return Array.prototype.indexOf.call(this.appsPages, page);
497 }, 537 },
498 538
499 /** 539 /**
500 * Handler for CARD_CHANGED on cardSlider. 540 * Handler for CARD_CHANGED on cardSlider.
501 * @param {Event} e The CARD_CHANGED event. 541 * @param {Event} e The CARD_CHANGED event.
502 * @private 542 * @private
503 */ 543 */
504 cardChangedHandler_: function(e) { 544 cardChangedHandler_: function(e) {
505 var page = e.cardSlider.currentCardValue; 545 var page = e.cardSlider.currentCardValue;
506 546
507 // Don't change shownPage until startup is done (and page changes actually 547 // Don't change shownPage until startup is done (and page changes actually
508 // reflect user actions). 548 // reflect user actions).
509 if (!document.documentElement.classList.contains('starting-up')) { 549 if (!document.documentElement.classList.contains('starting-up')) {
550 var prevPage = this.shownPage;
551 var prevIndex = this.shownPageIndex;
510 if (page.classList.contains('apps-page')) { 552 if (page.classList.contains('apps-page')) {
511 this.shownPage = templateData['apps_page_id']; 553 this.shownPage = templateData.apps_page_id;
512 this.shownPageIndex = this.getAppsPageIndex(page); 554 this.shownPageIndex = this.getAppsPageIndex(page);
513 } else if (page.classList.contains('most-visited-page')) { 555 } else if (page.classList.contains('most-visited-page')) {
514 this.shownPage = templateData['most_visited_page_id']; 556 this.shownPage = templateData.most_visited_page_id;
515 this.shownPageIndex = 0; 557 this.shownPageIndex = 0;
516 } else { 558 } else {
517 console.error('unknown page selected'); 559 console.error('unknown page selected');
518 } 560 }
519 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]); 561 if (prevPage != this.shownPage || prevIndex != this.shownPageIndex)
Dan Beam 2011/12/08 04:46:18 estade: I'm assuming you'll want me to remove the
562 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]);
520 } 563 }
521 564
522 // Update the active dot 565 // Update the active dot
523 var curDot = this.dotList.getElementsByClassName('selected')[0]; 566 var curDot = this.dotList.getElementsByClassName('selected')[0];
524 if (curDot) 567 if (curDot)
525 curDot.classList.remove('selected'); 568 curDot.classList.remove('selected');
526 page.navigationDot.classList.add('selected'); 569 page.navigationDot.classList.add('selected');
527 this.updatePageSwitchers(); 570 this.updatePageSwitchers();
528 }, 571 },
529 572
530 /* 573 /**
531 * Save the name of an app page. 574 * Save the name of an apps page.
532 * Store the app page name into the preferences store. 575 * Store the apps page name into the preferences store.
533 * @param {AppsPage} appPage The app page for which we wish to save. 576 * @param {AppsPage} appsPage The app page for which we wish to save.
534 * @param {string} name The name of the page. 577 * @param {string} name The name of the page.
535 */ 578 */
536 saveAppPageName: function(appPage, name) { 579 saveAppsPageName: function(appsPage, name) {
537 var index = this.getAppsPageIndex(appPage); 580 var index = this.getAppsPageIndex(appsPage);
538 assert(index != -1); 581 assert(index != -1);
539 chrome.send('saveAppPageName', [name, index]); 582 chrome.send('saveAppsPageName', [name, index]);
540 }, 583 },
541 584
542 /** 585 /**
586 * An Array of callbacks to be called on the next CARD_CHANGE_ENDED event
587 * handled from the cardSlider.
588 * @private
589 */
590 cardChangeEndedCallbacks_: [],
591
592 /**
593 * Handler for CARD_CHANGE_ENDED on cardSlider.
594 * @param {Event} e The CARD_CHANGE_ENDED event.
595 * @private
596 */
597 cardChangeEndedHandler_: function(e) {
598 if (!document.documentElement.classList.contains('starting-up')) {
599 while (this.cardChangeEndedCallbacks_.length > 0)
600 this.cardChangeEndedCallbacks_.shift().call(this, e);
601 }
602 },
603
604 /**
605 * Happens when a tile is removed from a tile page.
606 * @param {Event} e An event dispatched from a tile when it is removed.
607 */
608 tileRemovedHandler_: function(e) {
609 if (e.tilePage instanceof ntp4.AppsPage)
610 this.removeAppsPageIfEmpty_(e.tilePage, e.wasAnimated);
611 },
612
613 /**
614 * Remove an apps page if it now has no tiles (is empty).
615 * @param {AppsPage} appsPage A page to check for emptiness.
616 * @param {boolean=} opt_animate Whether the prospective removal should be
617 * animated.
618 * @param {boolean=} opt_dontNotify Whether this NTP's AppLauncherHandler
619 * shouldn't be notified of this pages' prospective removal (default is
620 * to notify).
621 * @return {boolean} If |appsPage| was removed or not.
622 */
623 removeAppsPageIfEmpty_: function(appsPage, opt_animate, opt_dontNotify) {
624 assert(appsPage instanceof ntp4.AppsPage,
625 '|appsPage| is really an AppsPage');
Evan Stade 2011/12/08 02:34:56 isn't the string an error message? Hence you would
Dan Beam 2011/12/08 04:46:18 Done.
626 if (appsPage.tileCount == 0) {
627 var whenDone = function() {
Evan Stade 2011/12/08 02:34:56 some comment about whenDone is necessary
Dan Beam 2011/12/08 04:46:18 Done.
628 if (!opt_dontNotify) {
Evan Stade 2011/12/08 02:34:56 no curlies
Dan Beam 2011/12/08 04:46:18 Done.
629 chrome.send('deleteAppsPage', [this.getAppsPageIndex(appsPage)]);
630 }
631 this.removeTilePageAndDot_(appsPage, opt_animate);
632 this.updateSliderCards();
633 this.updatePageSwitchers();
634 };
Evan Stade 2011/12/08 02:34:56 newline
Dan Beam 2011/12/08 04:46:18 Done.
635 // If currently on the empty apps pane, move off of it before deleting.
636 if (appsPage === this.cardSlider.currentCardValue) {
637 this.cardChangeEndedCallbacks_.push(whenDone);
638 this.moveOffEmptyAppsPage(appsPage, opt_animate);
639 } else {
640 whenDone.call(this);
641 }
642 return true;
643 }
644 return false;
Evan Stade 2011/12/08 02:34:56 if (appsPage.tileCount != 0) return false; ...
Dan Beam 2011/12/08 04:46:18 Done.
645 },
646
647 /**
543 * Window resize handler. 648 * Window resize handler.
544 * @private 649 * @private
545 */ 650 */
546 onWindowResize_: function(e) { 651 onWindowResize_: function(e) {
547 this.cardSlider.resize(this.sliderFrame.offsetWidth); 652 this.cardSlider.resize(this.sliderFrame.offsetWidth);
548 this.updatePageSwitchers(); 653 this.updatePageSwitchers();
549 }, 654 },
550 655
551 /** 656 /**
552 * Listener for offline status change events. Updates apps that are 657 * Listener for offline status change events. Updates apps that are
(...skipping 27 matching lines...) Expand all
580 direction = 1; 685 direction = 1;
581 else 686 else
582 return; 687 return;
583 688
584 var cardIndex = 689 var cardIndex =
585 (this.cardSlider.currentCard + direction + 690 (this.cardSlider.currentCard + direction +
586 this.cardSlider.cardCount) % this.cardSlider.cardCount; 691 this.cardSlider.cardCount) % this.cardSlider.cardCount;
587 this.cardSlider.selectCard(cardIndex, true); 692 this.cardSlider.selectCard(cardIndex, true);
588 693
589 e.stopPropagation(); 694 e.stopPropagation();
590 } 695 },
696
697 /**
698 * Re-order apps on this inactive page when an active NTP gets re-ordered.
699 * @param {Object} data Position hashmap ordered by app id with indices:
700 * {id => {page_index: ##, app_launch_index: ##}}
701 */
702 appsReordered: function(data) {
703 var pages = Object.keys(data);
704 for (var i = 0; i < pages.length; ++i) {
705 var page = data[pages[i]];
706 var indices = Object.keys(page);
707 for (var j = 0; j < indices.length; ++j) {
708 var app = $(page[indices[j]]);
709 var originalPage = app.tile.tilePage;
710 if (i != this.getAppsPageIndex(originalPage) || j != app.tile.index) {
711 originalPage.removeTile(app.tile, false, true);
712 this.ensureAppsPageAtIndex_(i);
713 this.appsPages[i].addTileAt(app, j);
714 }
715 }
716 }
717 for (var i = 0; i < this.appsPages.length; ++i) {
718 // If a page is now empty, remove it and move backward one in our
Evan Stade 2011/12/08 02:34:56 comments are nice but this code is self-documentin
Dan Beam 2011/12/08 04:46:18 Done.
719 // array-like object as it is a live NodeList and the length/indice
Evan Stade 2011/12/08 02:34:56 INDICE
Dan Beam 2011/12/08 04:46:18 DONE. (well, removed whole comment...)
720 // change when you update it. Otherwise, make sure the tiles are in the
721 // right positions (just like after a user is done dragging).
722 if (this.removeAppsPageIfEmpty_(this.appsPages[i], false, true))
723 --i;
724 else
725 this.appsPages[i].cleanupDrag();
726 }
727 },
728
729 /**
730 * Ensure there is an apps page at the given |index|. If index is smaller
Evan Stade 2011/12/08 02:34:56 smaller??
Dan Beam 2011/12/08 04:46:18 Done.
731 * than the current number of apps pages, additional apps pages will be
732 * created.
733 * @param {number} index An apps page index to ensure exists.
734 */
735 ensureAppsPageAtIndex_: function(index) {
736 if (index >= this.appsPages.length) {
737 var pageName = localStrings.getString('appDefaultPageName');
738 while (index >= this.appsPages.length)
739 this.appendTilePage(new ntp4.AppsPage(), pageName, true);
740 this.updateSliderCards();
741 }
742 },
743
744 /**
745 * Returns the index of a given tile page.
746 * @param {TilePage} page The TilePage we wish to find.
747 * @return {number} The index of |page| or -1 if it is not in the
748 * collection.
749 */
750 getTilePageIndex: function(page) {
751 return Array.prototype.indexOf.call(this.tilePages, page);
752 },
753
754 /**
755 * Move to a non-empty page before/while we delete an empty one.
756 * @param {AppsPage} appsPage An empty apps page that we want to move off of
757 * (probably because it's empty).
758 * @param {boolean=} opt_animate Whether we should animate or not.
759 */
760 moveOffEmptyAppsPage: function(appsPage, opt_animate) {
761 assert(appsPage instanceof ntp4.AppsPage,
762 '|appsPage| is really an AppsPage');
763 // Select the page further toward the end than the empty |appsPage|. If
764 // the empty |appsPage| is at the end, the apps page before it will be
765 // selected.
766 var index = this.getAppsPageIndex(appsPage);
767 assert(index >= 0, '|appsPage| is in this.appsPages');
768 var direction = (index == this.appsPages.length - 1 ? -1 : 1);
Evan Stade 2011/12/08 02:34:56 no ()
Dan Beam 2011/12/08 04:46:18 Done. (but I still don't agree that this is easier
769 this.cardSlider.selectCard(this.cardSlider.currentCard + direction,
770 opt_animate);
771 },
772
773 /**
774 * Removes a page and navigation dot (if the navdot exists).
775 * @param {TilePage} page The page to be removed.
776 * @param {boolean=} opt_animate If the removal should be animated.
777 */
778 removeTilePageAndDot_: function(page, opt_animate) {
779 if (!document.documentElement.classList.contains('starting-up')) {
780 // If the card being deleted is before the current card, keep the same
781 // spot in the list by removing 1 from the current card index.
782 var index = Array.prototype.indexOf.call(this.tilePages, page);
783 if (index < this.cardSlider.currentCard) {
Evan Stade 2011/12/08 02:34:56 no curlies
Dan Beam 2011/12/08 04:46:18 Done.
784 this.cardSlider.currentCard -= 1;
785 }
786 // If the page we're about to delete is in front of the current page,
787 // remove 1 from the shown page index.
788 if (page instanceof ntp4.AppsPage &&
789 this.shownPage == templateData.apps_page_id &&
790 this.getAppsPageIndex(page) < this.shownPageIndex) {
791 this.shownPageIndex -= 1;
Evan Stade 2011/12/08 02:34:56 this doesn't seem necessary. Wont the shownPageInd
Dan Beam 2011/12/08 04:46:18 cardSlider.currentCard is an ES5 getter but all it
Dan Beam 2011/12/08 07:27:52 Working on fixing this to be in cardSlider instead
792 }
793 }
794 if (page.navigationDot)
795 page.navigationDot.remove(opt_animate);
796 page.remove();
797 },
591 }; 798 };
592 799
593 return { 800 return {
594 PageListView: PageListView 801 PageListView: PageListView
595 }; 802 };
596 }); 803 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698