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

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

Issue 8423055: [Aura] Initial app list webui. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: move onKeyDown into PageListView onDocKeyDown Created 9 years, 1 month 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
(Empty)
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
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview PageListView implementation.
7 * PageListView manages page list, dot list, switcher buttons and glue apps
8 * pages with backend.
9 */
10
11 cr.define('ntp4', function() {
12 'use strict';
13
14 /**
15 * Object for accessing localized strings.
16 * @type {!LocalStrings}
17 */
18 var localStrings = new LocalStrings;
19
20 /**
21 * Current live PageListView instance.
22 * @type {!Object|undefined}
23 */
24 var instance;
Evan Stade 2011/11/07 23:59:20 I don't like the restriction that this class shoul
xiyuan 2011/11/08 21:09:18 Done.
25
26 /**
27 * Creates a PageListView object.
28 * @constructor
29 * @extends {Object}
30 */
31 function PageListView() {
32 }
33
34 PageListView.getInstance = function() {
35 return instance;
36 }
37
38 PageListView.prototype = {
39 /**
40 * The CardSlider object to use for changing app pages.
41 * @type {CardSlider|undefined}
42 */
43 cardSlider: undefined,
44
45 /**
46 * The frame div for cardSlider.
47 * @type {!Element|undefined}
48 */
49 sliderFrame: undefined,
50
51 /**
52 * The 'page-list' element.
53 * @type {!Element|undefined}
54 */
55 pageList: undefined,
56
57 /**
58 * A list of all 'tile-page' elements.
59 * @type {!NodeList|undefined}
60 */
61 tilePages: undefined,
62
63 /**
64 * A list of all 'apps-page' elements.
65 * @type {!NodeList|undefined}
66 */
67 appsPages: undefined,
68
69 /**
70 * The Most Visited page.
71 * @type {!Element|undefined}
72 */
73 mostVisitedPage: undefined,
74
75 /**
76 * The Bookmarks page.
77 * @type {!Element|undefined}
78 */
79 bookmarksPage: undefined,
80
81 /**
82 * The 'dots-list' element.
83 * @type {!Element|undefined}
84 */
85 dotList: undefined,
86
87 /**
88 * The left and right paging buttons.
89 * @type {!Element|undefined}
90 */
91 pageSwitcherStart: undefined,
92 pageSwitcherEnd: undefined,
93
94 /**
95 * The 'trash' element. Note that technically this is unnecessary,
96 * JavaScript creates the object for us based on the id. But I don't want
97 * to rely on the ID being the same, and JSCompiler doesn't know about it.
98 * @type {!Element|undefined}
99 */
100 trash: undefined,
101
102 /**
103 * The type of page that is currently shown. The value is a numerical ID.
104 * @type {number}
105 */
106 shownPage: 0,
107
108 /**
109 * The index of the page that is currently shown, within the page type.
110 * For example if the third Apps page is showing, this will be 2.
111 * @type {number}
112 */
113 shownPageIndex: 0,
114
115 /**
116 * EventTracker for managing event listeners for page events.
117 * @type {!EventTracker}
118 */
119 eventTracker: new EventTracker,
120
121 /**
122 * If non-null, this is the ID of the app to highlight to the user the next
123 * time getAppsCallback runs. "Highlight" in this case means to switch to
124 * the page and run the new tile animation.
125 * @type {String}
126 */
127 highlightAppId: null,
128
129 /**
130 * Initializes page list view.
131 */
132 initialize: function() {
133 instance = this;
134
135 this.pageList = getRequiredElement('page-list');
136
137 this.dotList = getRequiredElement('dot-list');
138 cr.ui.decorate(this.dotList, ntp4.DotList);
139
140 this.trash = getRequiredElement('trash');
141 new ntp4.Trash(this.trash);
142
143 this.pageSwitcherStart = $('page-switcher-start');
144 if (this.pageSwitcherStart)
145 ntp4.initializePageSwitcher(this.pageSwitcherStart);
146
147 this.pageSwitcherEnd = $('page-switcher-end');
148 if (this.pageSwitcherEnd)
149 ntp4.initializePageSwitcher(this.pageSwitcherEnd);
150
151 this.shownPage = templateData['shown_page_type'];
152 this.shownPageIndex = templateData['shown_page_index'];
153
154 // Request data on the apps so we can fill them in.
155 // Note that this is kicked off asynchronously. 'getAppsCallback' will be
156 // invoked at some point after this function returns.
157 chrome.send('getApps');
158
159 document.addEventListener('keydown', this.onDocKeyDown.bind(this));
160 // Prevent touch events from triggering any sort of native scrolling
161 document.addEventListener('touchmove', function(e) {
162 e.preventDefault();
163 }, true);
164
165 this.tilePages = this.pageList.getElementsByClassName('tile-page');
166 this.appsPages = this.pageList.getElementsByClassName('apps-page');
167
168 // Initialize the cardSlider without any cards at the moment
169 this.sliderFrame = getRequiredElement('card-slider-frame');
170 this.cardSlider = new CardSlider(this.sliderFrame, this.pageList,
171 this.sliderFrame.offsetWidth);
172 this.cardSlider.initialize();
173
174 // Ensure the slider is resized appropriately with the window
175 window.addEventListener('resize', this.onWindowResize_.bind(this));
176
177 // Handle the page being changed
178 this.pageList.addEventListener(
179 CardSlider.EventType.CARD_CHANGED,
180 this.cardChangedHandler.bind(this));
181 },
182
183 /**
184 * Appends a tile page (for bookmarks or most visited).
185 *
186 * @param {TilePage} page The page element.
187 * @param {string} title The title of the tile page.
188 * @param {bool} titleIsEditable If true, the title can be changed.
189 * @param {TilePage} opt_refNode Optional reference node to insert in front
190 * of.
191 * When opt_refNode is falsey, |page| will just be appended to the end of
192 * the page list.
193 */
194 appendTilePage: function(page, title, titleIsEditable, opt_refNode) {
195 // If no opt_refNode given, use bookmarksPage (if any).
196 if (!opt_refNode)
197 opt_refNode = this.bookmarksPage;
198
199 // When opt_refNode is falsey, insertBefore acts just like appendChild.
200 this.pageList.insertBefore(page, opt_refNode);
201
202 // Remember special MostVisitedPage and BookmarksPage.
203 if (typeof ntp4.MostVisitedPage != 'undefined' &&
204 page instanceof ntp4.MostVisitedPage) {
205 assert(this.tilePages.length == 1,
206 'MostVisitedPage should be added as first tile page');
207 this.mostVisitedPage = page;
208 }
209 if (typeof ntp4.BookmarksPage != 'undefined' &&
210 page instanceof ntp4.BookmarksPage) {
211 this.bookmarksPage = page;
212 }
213
214 // If we're appending an AppsPage and it's a temporary page, animate it.
215 var animate = page instanceof ntp4.AppsPage &&
216 page.classList.contains('temporary');
217 // Make a deep copy of the dot template to add a new one.
218 var newDot = new ntp4.NavDot(page, title, titleIsEditable, animate);
219 page.navigationDot = newDot;
220 this.dotList.insertBefore(newDot, opt_refNode ? opt_refNode.navigationDot
221 : null);
222 // Set a tab index on the first dot.
223 if (this.dotList.dots.length == 1)
224 newDot.tabIndex = 3;
225
226 this.eventTracker.add(page, 'pagelayout', this.onPageLayout_.bind(this));
227 },
228
229 /**
230 * Callback invoked by chrome with the apps available.
231 *
232 * Note that calls to this function can occur at any time, not just in
233 * response to a getApps request. For example, when a user
234 * installs/uninstalls an app on another synchronized devices.
235 * @param {Object} data An object with all the data on available
236 * applications.
237 */
238 getAppsCallback: function(data) {
239 var startTime = Date.now();
240
241 // Clear any existing apps pages and dots.
242 // TODO(rbyers): It might be nice to preserve animation of dots after an
243 // uninstall. Could we re-use the existing page and dot elements? It
244 // seems unfortunate to have Chrome send us the entire apps list after an
245 // uninstall.
246 while (this.appsPages.length > 0) {
247 var page = this.appsPages[0];
248 var dot = page.navigationDot;
249
250 this.eventTracker.remove(page);
251 page.tearDown();
252 page.parentNode.removeChild(page);
253 dot.parentNode.removeChild(dot);
254 }
255
256 // Get the array of apps and add any special synthesized entries
257 var apps = data.apps;
258
259 // Get a list of page names
260 var pageNames = data.appPageNames;
261
262 function stringListIsEmpty(list) {
263 for (var i = 0; i < list.length; i++) {
264 if (list[i])
265 return false;
266 }
267 return true;
268 }
269
270 // Sort by launch index
271 apps.sort(function(a, b) {
272 return a.app_launch_index - b.app_launch_index;
273 });
274
275 // An app to animate (in case it was just installed).
276 var highlightApp;
277
278 // Add the apps, creating pages as necessary
279 for (var i = 0; i < apps.length; i++) {
280 var app = apps[i];
281 var pageIndex = (app.page_index || 0);
282 while (pageIndex >= this.appsPages.length) {
283 var pageName = localStrings.getString('appDefaultPageName');
284 if (this.appsPages.length < pageNames.length)
285 pageName = pageNames[this.appsPages.length];
286
287 var origPageCount = this.appsPages.length;
288 this.appendTilePage(new ntp4.AppsPage(), pageName, true);
289 // Confirm that appsPages is a live object, updated when a new page is
290 // added (otherwise we'd have an infinite loop)
291 assert(this.appsPages.length == origPageCount + 1,
292 'expected new page');
293 }
294
295 if (app.id == this.highlightAppId)
296 highlightApp = app;
297 else
298 this.appsPages[pageIndex].appendApp(app);
299 }
300
301 ntp4.AppsPage.setPromo(data.showPromo ? data : null);
302
303 // Tell the slider about the pages.
304 this.updateSliderCards();
305
306 if (highlightApp)
307 this.appAdded(highlightApp, true);
308
309 // Mark the current page.
310 this.cardSlider.currentCardValue.navigationDot.classList.add('selected');
311 logEvent('apps.layout: ' + (Date.now() - startTime));
312
313 document.documentElement.classList.remove('starting-up');
314 },
315
316 /**
317 * Called by chrome when a new app has been added to chrome or has been
318 * enabled if previously disabled.
319 * @param {Object} appData A data structure full of relevant information for
320 * the app.
321 */
322 appAdded: function(appData, opt_highlight) {
323 if (appData.id == this.highlightAppId) {
324 opt_highlight = true;
325 this.highlightAppId = null;
326 }
327
328 var pageIndex = appData.page_index || 0;
329
330 if (pageIndex >= this.appsPages.length) {
331 while (pageIndex >= this.appsPages.length) {
332 this.appendTilePage(new ntp4.AppsPage(),
333 localStrings.getString('appDefaultPageName'),
334 true);
335 }
336 this.updateSliderCards();
337 }
338
339 var page = this.appsPages[pageIndex];
340 var app = $(appData.id);
341 if (app)
342 app.replaceAppData(appData);
343 else
344 page.appendApp(appData, opt_highlight);
345 },
346
347 /**
348 * Callback invoked by chrome whenever an app preference changes.
349 * @param {Object} data An object with all the data on available
350 * applications.
351 */
352 appsPrefChangeCallback: function(data) {
353 for (var i = 0; i < data.apps.length; ++i) {
354 $(data.apps[i].id).appData = data.apps[i];
355 }
356
357 // Set the App dot names. Skip the first and last dots (Most Visited and
358 // Bookmarks).
359 var dots = this.dotList.getElementsByClassName('dot');
360 // TODO(csilv): Remove this calcluation if/when we remove the flag for
361 // for the bookmarks page.
362 var start = this.mostVisitedPage ? 1 : 0;
363 var length = this.bookmarksPage ? dots.length - 1 : dots.length;
364 for (var i = start; i < length; ++i) {
365 dots[i].displayTitle = data.appPageNames[i - start] || '';
366 }
367 },
368
369 /**
370 * Invoked whenever the pages in apps-page-list have changed so that
371 * the Slider knows about the new elements.
372 */
373 updateSliderCards: function() {
374 var pageNo = Math.min(this.cardSlider.currentCard,
375 this.tilePages.length - 1);
376 this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages),
377 pageNo);
378 switch (this.shownPage) {
379 case templateData['apps_page_id']:
380 this.cardSlider.selectCardByValue(
381 this.appsPages[Math.min(this.shownPageIndex,
382 this.appsPages.length - 1)]);
383 break;
384 case templateData['bookmarks_page_id']:
385 if (this.bookmarksPage)
386 this.cardSlider.selectCardByValue(this.bookmarksPage);
387 break;
388 case templateData['most_visited_page_id']:
389 if (this.mostVisitedPage)
390 this.cardSlider.selectCardByValue(this.mostVisitedPage);
391 break;
392 }
393 },
394
395 /**
396 * Called whenever tiles should be re-arranging themselves out of the way
397 * of a moving or insert tile.
398 */
399 enterRearrangeMode: function() {
400 var tempPage = new ntp4.AppsPage();
401 tempPage.classList.add('temporary');
402 this.appendTilePage(tempPage,
403 localStrings.getString('appDefaultPageName'),
404 true);
405 var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage);
406 if (this.cardSlider.currentCard >= tempIndex)
407 this.cardSlider.currentCard += 1;
408 this.updateSliderCards();
409
410 if (ntp4.getCurrentlyDraggingTile().firstChild.canBeRemoved())
411 $('footer').classList.add('showing-trash-mode');
412 },
413
414 /**
415 * Invoked whenever some app is released
416 * @param {Grabber.Event} e The Grabber RELEASE event.
417 */
418 leaveRearrangeMode: function(e) {
419 var tempPage = document.querySelector('.tile-page.temporary');
420 var dot = tempPage.navigationDot;
421 if (!tempPage.tileCount && tempPage != this.cardSlider.currentCardValue) {
422 dot.animateRemove();
423 var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage);
424 if (this.cardSlider.currentCard > tempIndex)
425 this.cardSlider.currentCard -= 1;
426 tempPage.parentNode.removeChild(tempPage);
427 this.updateSliderCards();
428 } else {
429 tempPage.classList.remove('temporary');
430 this.saveAppPageName(tempPage,
431 localStrings.getString('appDefaultPageName'));
432 }
433
434 $('footer').classList.remove('showing-trash-mode');
435 },
436
437 /**
438 * Callback for the 'pagelayout' event.
439 * @param {Event} e The event.
440 */
441 onPageLayout_: function(e) {
442 if (Array.prototype.indexOf.call(this.tilePages, e.currentTarget) !=
443 this.cardSlider.currentCard) {
444 return;
445 }
446
447 this.updatePageSwitchers();
448 },
449
450 /**
451 * Adjusts the size and position of the page switchers according to the
452 * layout of the current card.
453 */
454 updatePageSwitchers: function() {
455 if (!this.pageSwitcherStart || !this.pageSwitcherEnd)
456 return;
457
458 var page = this.cardSlider.currentCardValue;
459
460 this.pageSwitcherStart.hidden = !page ||
461 (this.cardSlider.currentCard == 0);
462 this.pageSwitcherEnd.hidden = !page ||
463 (this.cardSlider.currentCard == this.cardSlider.cardCount - 1);
464
465 if (!page)
466 return;
467
468 var pageSwitcherLeft = isRTL() ? this.pageSwitcherEnd
469 : this.pageSwitcherStart;
470 var pageSwitcherRight = isRTL() ? this.pageSwitcherStart
471 : this.pageSwitcherEnd;
472 var scrollbarWidth = page.scrollbarWidth;
473 pageSwitcherLeft.style.width =
474 (page.sideMargin + 13) + 'px';
475 pageSwitcherLeft.style.left = '0';
476 pageSwitcherRight.style.width =
477 (page.sideMargin - scrollbarWidth + 13) + 'px';
478 pageSwitcherRight.style.right = scrollbarWidth + 'px';
479
480 var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px';
481 pageSwitcherLeft.style.top = offsetTop;
482 pageSwitcherRight.style.top = offsetTop;
483 pageSwitcherLeft.style.paddingBottom = offsetTop;
484 pageSwitcherRight.style.paddingBottom = offsetTop;
485 },
486
487 /**
488 * Returns the index of the given page.
489 * @param {AppsPage} page The AppsPage for we wish to find.
490 * @return {number} The index of |page|, or -1 if it is not here.
491 */
492 getAppsPageIndex: function(page) {
493 return Array.prototype.indexOf.call(this.appsPages, page);
494 },
495
496 /**
497 * Handler for CARD_CHANGED on cardSlider.
498 * @param {Event} e The CARD_CHANGED event.
499 */
500 cardChangedHandler: function(e) {
501 var page = e.cardSlider.currentCardValue;
502
503 // Don't change shownPage until startup is done (and page changes actually
504 // reflect user actions).
505 if (!document.documentElement.classList.contains('starting-up')) {
506 if (page.classList.contains('apps-page')) {
507 this.shownPage = templateData['apps_page_id'];
508 this.shownPageIndex = this.getAppsPageIndex(page);
509 } else if (page.classList.contains('most-visited-page')) {
510 this.shownPage = templateData['most_visited_page_id'];
511 this.shownPageIndex = 0;
512 } else if (page.classList.contains('bookmarks-page')) {
513 this.shownPage = templateData['bookmarks_page_id'];
514 this.shownPageIndex = 0;
515 } else {
516 console.error('unknown page selected');
517 }
518 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]);
519 }
520
521 // Update the active dot
522 var curDot = this.dotList.getElementsByClassName('selected')[0];
523 if (curDot)
524 curDot.classList.remove('selected');
525 page.navigationDot.classList.add('selected');
526 this.updatePageSwitchers();
527 },
528
529 /*
530 * Save the name of an app page.
531 * Store the app page name into the preferences store.
532 * @param {AppsPage} appPage The app page for which we wish to save.
533 * @param {string} name The name of the page.
534 */
535 saveAppPageName: function(appPage, name) {
536 var index = this.getAppsPageIndex(appPage);
537 assert(index != -1);
538 chrome.send('saveAppPageName', [name, index]);
539 },
540
541 /**
542 * Window resize handler.
543 * @private
544 */
545 onWindowResize_: function(e) {
546 this.cardSlider.resize(this.sliderFrame.offsetWidth);
547 this.updatePageSwitchers();
548 },
549
550 /**
551 * Handler for key events on the page. Ctrl-Arrow will switch the visible
552 * page.
553 * @param {Event} e The KeyboardEvent.
554 */
555 onDocKeyDown: function(e) {
556 if (!e.ctrlKey || e.altKey || e.metaKey || e.shiftKey)
557 return;
558
559 var direction = 0;
560 if (e.keyIdentifier == 'Left')
561 direction = -1;
562 else if (e.keyIdentifier == 'Right')
563 direction = 1;
564 else
565 return;
566
567 var cardIndex =
568 (this.cardSlider.currentCard + direction +
569 this.cardSlider.cardCount) % this.cardSlider.cardCount;
570 this.cardSlider.selectCard(cardIndex, true);
571
572 e.stopPropagation();
573 }
574 };
575
576 /**
577 * Simple common assertion API
578 * @param {*} condition The condition to test. Note that this may be used to
579 * test whether a value is defined or not, and we don't want to force a
580 * cast to Boolean.
581 * @param {string=} opt_message A message to use in any error.
582 */
583 function assert(condition, opt_message) {
Evan Stade 2011/11/07 23:59:20 some of these functions should go in util.js
xiyuan 2011/11/08 21:09:18 Done. Moved assert, getRequiredEleemnt and isRTL i
584 'use strict';
585 if (!condition) {
586 var msg = 'Assertion failed';
587 if (opt_message)
588 msg = msg + ': ' + opt_message;
589 throw new Error(msg);
590 }
591 }
592
593 /**
594 * Get an element that's known to exist by its ID. We use this instead of just
595 * calling getElementById and not checking the result because this lets us
596 * satisfy the JSCompiler type system.
597 * @param {string} id The identifier name.
598 * @return {!Element} the Element.
599 */
600 function getRequiredElement(id) {
601 var element = document.getElementById(id);
602 assert(element, 'Missing required element: ' + id);
603 return element;
604 }
605
606 /**
607 * Wrapper to forward the callback to corresponding PageListView member.
608 */
609 function getAppsCallback(data) {
610 instance.getAppsCallback(data);
611 }
612
613 /**
614 * Wrapper to forward the callback to corresponding PageListView member.
615 */
616 function appAdded(appData, opt_highlight) {
617 instance.appAdded(appData, opt_highlight);
618 }
619
620 /**
621 * Sets that an app should be highlighted if it is added. Called right before
622 * appAdded for new installs.
623 */
624 function setAppToBeHighlighted(appId) {
625 instance.highlightAppId = appId;
626 }
627
628 /**
629 * Called by chrome when an existing app has been disabled or
630 * removed/uninstalled from chrome.
631 * @param {Object} appData A data structure full of relevant information for
632 * the app.
633 * @param {boolean} isUninstall True if the app is being uninstalled;
634 * false if the app is being disabled.
635 */
636 function appRemoved(appData, isUninstall) {
637 var app = $(appData.id);
638 assert(app, 'trying to remove an app that doesn\'t exist');
639
640 if (!isUninstall)
641 app.replaceAppData(appData);
642 else
643 app.remove();
644 }
645
646 /**
647 * Wrapper to forward the callback to corresponding PageListView member.
648 */
649 function appsPrefChangeCallback(data) {
650 instance.appsPrefChangedCallback(data);
651 }
652
653 /**
654 * Listener for offline status change events. Updates apps that are
655 * not offline-enabled to be grayscale if the browser is offline.
656 */
657 function updateOfflineEnabledApps() {
658 var apps = document.querySelectorAll('.app');
659 for (var i = 0; i < apps.length; ++i) {
660 if (apps[i].appData.enabled && !apps[i].appData.offline_enabled) {
661 apps[i].setIcon();
662 apps[i].loadIcon();
663 }
664 }
665 }
666
667 function getCardSlider() {
668 return instance.cardSlider;
669 }
670
671 /**
672 * Wrapper to forward the callback to corresponding PageListView member.
673 */
674 function enterRearrangeMode() {
675 instance.enterRearrangeMode();
676 }
677
678 /**
679 * Wrapper to forward the callback to corresponding PageListView member.
680 */
681 function leaveRearrangeMode(e) {
682 instance.leaveRearrangeMode(e);
683 }
684
685 /**
686 * Check the directionality of the page.
687 * @return {boolean} True if Chrome is running an RTL UI.
688 */
689 function isRTL() {
690 return document.documentElement.dir == 'rtl';
691 }
692
693 /**
694 * Wrapper to forward the callback to corresponding PageListView member.
695 */
696 function getAppsPageIndex(page) {
697 instance.getAppsPageIndex(page);
698 }
699
700 /**
701 * Wrapper to forward the callback to corresponding PageListView member.
702 */
703 function saveAppPageName(appPage, name) {
704 instance.saveAppPageName(appPage, name);
705 }
706
707 return {
708 appAdded: appAdded,
709 appendTilePage: appendTilePage,
710 appRemoved: appRemoved,
711 appsPrefChangeCallback: appsPrefChangeCallback,
712 assert: assert,
713 enterRearrangeMode: enterRearrangeMode,
714 getAppsCallback: getAppsCallback,
715 getAppsPageIndex: getAppsPageIndex,
716 getCardSlider: getCardSlider,
717 getRequiredElement: getRequiredElement,
718 isRTL: isRTL,
719 leaveRearrangeMode: leaveRearrangeMode,
720 saveAppPageName: saveAppPageName,
721 setAppToBeHighlighted: setAppToBeHighlighted,
722 updateOfflineEnabledApps: updateOfflineEnabledApps,
723 PageListView: PageListView
724 };
725 });
726
727 var appendTilePage = ntp4.appendTilePage;
Evan Stade 2011/11/07 23:59:20 are you planning to use all of this in the aura ho
xiyuan 2011/11/08 21:09:18 I only need appsPrefChangeCallback and getAppsCall
728 var appsPrefChangeCallback = ntp4.appsPrefChangeCallback;
729 var assert = ntp4.assert;
730 var getAppsCallback = ntp4.getAppsCallback;
731 var getRequiredElement = ntp4.getRequiredElement;
732
733 window.addEventListener('online', ntp4.updateOfflineEnabledApps);
734 window.addEventListener('offline', ntp4.updateOfflineEnabledApps);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698