OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 cr.define('ntp', function() { | 5 cr.define('ntp', function() { |
6 'use strict'; | 6 'use strict'; |
7 | 7 |
8 var APP_LAUNCH = { | 8 var APP_LAUNCH = { |
9 // The histogram buckets (keep in sync with extension_constants.h). | 9 // The histogram buckets (keep in sync with extension_constants.h). |
10 NTP_APPS_MAXIMIZED: 0, | 10 NTP_APPS_MAXIMIZED: 0, |
11 NTP_APPS_COLLAPSED: 1, | 11 NTP_APPS_COLLAPSED: 1, |
12 NTP_APPS_MENU: 2, | 12 NTP_APPS_MENU: 2, |
13 NTP_MOST_VISITED: 3, | 13 NTP_MOST_VISITED: 3, |
14 NTP_RECENTLY_CLOSED: 4, | 14 NTP_RECENTLY_CLOSED: 4, |
15 NTP_APP_RE_ENABLE: 16, | 15 NTP_APP_RE_ENABLE: 16, |
16 NTP_WEBSTORE_FOOTER: 18, | 16 NTP_WEBSTORE_FOOTER: 18, |
17 NTP_WEBSTORE_PLUS_ICON: 19, | 17 NTP_WEBSTORE_PLUS_ICON: 19, |
18 }; | 18 }; |
19 | 19 |
20 // Histogram buckets for UMA tracking of where a DnD drop came from. | 20 // Histogram buckets for UMA tracking of where a DnD drop came from. |
21 var DRAG_SOURCE = { | 21 var DRAG_SOURCE = { |
22 SAME_APPS_PANE: 0, | 22 SAME_APPS_PANE: 0, |
23 OTHER_APPS_PANE: 1, | 23 OTHER_APPS_PANE: 1, |
24 MOST_VISITED_PANE: 2, | 24 MOST_VISITED_PANE: 2, |
25 BOOKMARKS_PANE: 3, | 25 BOOKMARKS_PANE: 3, |
26 OUTSIDE_NTP: 4 | 26 OUTSIDE_NTP: 4 |
27 }; | 27 }; |
28 var DRAG_SOURCE_LIMIT = DRAG_SOURCE.OUTSIDE_NTP + 1; | 28 var DRAG_SOURCE_LIMIT = DRAG_SOURCE.OUTSIDE_NTP + 1; |
29 | 29 |
30 /** @const */ var appInstallHintTileLimit = 10; | |
31 | |
32 /** | 30 /** |
33 * App context menu. The class is designed to be used as a singleton with | 31 * App context menu. The class is designed to be used as a singleton with |
34 * the app that is currently showing a context menu stored in this.app_. | 32 * the app that is currently showing a context menu stored in this.app_. |
35 * @constructor | 33 * @constructor |
36 */ | 34 */ |
37 function AppContextMenu() { | 35 function AppContextMenu() { |
38 this.__proto__ = AppContextMenu.prototype; | 36 this.__proto__ = AppContextMenu.prototype; |
39 this.initialize(); | 37 this.initialize(); |
40 } | 38 } |
41 cr.addSingletonGetter(AppContextMenu); | 39 cr.addSingletonGetter(AppContextMenu); |
(...skipping 599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 | 639 |
642 return el; | 640 return el; |
643 } | 641 } |
644 | 642 |
645 AppsPage.prototype = { | 643 AppsPage.prototype = { |
646 __proto__: TilePage.prototype, | 644 __proto__: TilePage.prototype, |
647 | 645 |
648 initialize: function() { | 646 initialize: function() { |
649 this.classList.add('apps-page'); | 647 this.classList.add('apps-page'); |
650 | 648 |
651 if (loadTimeData.getBoolean('appInstallHintEnabled')) { | |
652 this.appInstallHint_ = $('app-install-hint-template').cloneNode(true); | |
653 this.appInstallHint_.addEventListener('click', function(e) { | |
654 chrome.send('recordAppLaunchByURL', | |
655 [encodeURIComponent(this.href), | |
656 APP_LAUNCH.NTP_WEBSTORE_PLUS_ICON]); | |
657 }); | |
658 this.content_.appendChild(this.appInstallHint_); | |
659 } | |
660 | |
661 this.addEventListener('cardselected', this.onCardSelected_); | 649 this.addEventListener('cardselected', this.onCardSelected_); |
662 // Add event listeners for two events, so we can temporarily suppress | 650 // Add event listeners for two events, so we can temporarily suppress |
663 // the app notification bubbles when the app card slides in and out of | 651 // the app notification bubbles when the app card slides in and out of |
664 // view. | 652 // view. |
665 this.addEventListener('carddeselected', this.onCardDeselected_); | 653 this.addEventListener('carddeselected', this.onCardDeselected_); |
666 this.addEventListener('cardSlider:card_change_ended', | 654 this.addEventListener('cardSlider:card_change_ended', |
667 this.onCardChangeEnded_); | 655 this.onCardChangeEnded_); |
668 | 656 |
669 this.addEventListener('tilePage:tile_added', this.onTileAdded_); | 657 this.addEventListener('tilePage:tile_added', this.onTileAdded_); |
670 | 658 |
671 this.content_.addEventListener('scroll', this.onScroll_.bind(this)); | 659 this.content_.addEventListener('scroll', this.onScroll_.bind(this)); |
672 }, | 660 }, |
673 | 661 |
674 /** | 662 /** |
675 * Creates an app DOM element and places it at the last position on the | 663 * Creates an app DOM element and places it at the last position on the |
676 * page. | 664 * page. |
677 * @param {Object} appData The data object that describes the app. | 665 * @param {Object} appData The data object that describes the app. |
678 * @param {boolean=} animate If true, the app tile plays an animation. | 666 * @param {boolean=} animate If true, the app tile plays an animation. |
679 */ | 667 */ |
680 appendApp: function(appData, animate) { | 668 appendApp: function(appData, animate) { |
681 if (animate) { | 669 if (animate) { |
682 // Select the page and scroll all the way down so the animation is | 670 // Select the page and scroll all the way down so the animation is |
683 // visible. | 671 // visible. |
684 ntp.getCardSlider().selectCardByValue(this); | 672 ntp.getCardSlider().selectCardByValue(this); |
685 this.content_.scrollTop = this.content_.scrollHeight; | 673 this.content_.scrollTop = this.content_.scrollHeight; |
686 } | 674 } |
687 | 675 |
688 this.appendTile(new App(appData), animate); | 676 this.appendTile(new App(appData), animate); |
689 this.hintStateMayHaveChanged_(); | |
690 }, | 677 }, |
691 | 678 |
692 /** | 679 /** |
693 * Similar to appendApp, but it respects the app_launch_ordinal field of | 680 * Similar to appendApp, but it respects the app_launch_ordinal field of |
694 * |appData|. | 681 * |appData|. |
695 * @param {Object} appData The data that describes the app. | 682 * @param {Object} appData The data that describes the app. |
696 */ | 683 */ |
697 insertApp: function(appData) { | 684 insertApp: function(appData) { |
698 var index = 0; | 685 var index = 0; |
699 for (var i = 0; i < this.tileElements_.length; i++) { | 686 for (var i = 0; i < this.tileElements_.length; i++) { |
700 if (appData.app_launch_ordinal < | 687 if (appData.app_launch_ordinal < |
701 this.tileElements_[i].firstChild.appData.app_launch_ordinal) { | 688 this.tileElements_[i].firstChild.appData.app_launch_ordinal) { |
702 index = i; | 689 index = i; |
703 break; | 690 break; |
704 } | 691 } |
705 } | 692 } |
706 | 693 |
707 this.addTileAt(new App(appData), index, false); | 694 this.addTileAt(new App(appData), index, false); |
708 this.hintStateMayHaveChanged_(); | |
709 }, | 695 }, |
710 | 696 |
711 /** | 697 /** |
712 * Handler for 'cardselected' event, fired when |this| is selected. The | 698 * Handler for 'cardselected' event, fired when |this| is selected. The |
713 * first time this is called, we load all the app icons. | 699 * first time this is called, we load all the app icons. |
714 * @private | 700 * @private |
715 */ | 701 */ |
716 onCardSelected_: function(e) { | 702 onCardSelected_: function(e) { |
717 var apps = this.querySelectorAll('.app.icon-loading'); | 703 var apps = this.querySelectorAll('.app.icon-loading'); |
718 for (var i = 0; i < apps.length; i++) { | 704 for (var i = 0; i < apps.length; i++) { |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
896 }, | 882 }, |
897 | 883 |
898 /** @inheritDoc */ | 884 /** @inheritDoc */ |
899 setDropEffect: function(dataTransfer) { | 885 setDropEffect: function(dataTransfer) { |
900 var tile = ntp.getCurrentlyDraggingTile(); | 886 var tile = ntp.getCurrentlyDraggingTile(); |
901 if (tile && tile.querySelector('.app')) | 887 if (tile && tile.querySelector('.app')) |
902 ntp.setCurrentDropEffect(dataTransfer, 'move'); | 888 ntp.setCurrentDropEffect(dataTransfer, 'move'); |
903 else | 889 else |
904 ntp.setCurrentDropEffect(dataTransfer, 'copy'); | 890 ntp.setCurrentDropEffect(dataTransfer, 'copy'); |
905 }, | 891 }, |
906 | |
907 /** | |
908 * Called when we may need to change app install hint visibility. | |
909 * @private | |
910 */ | |
911 hintStateMayHaveChanged_: function() { | |
912 if (this.updateHintState_()) | |
913 this.repositionTiles_(); | |
914 else | |
915 this.repositionHint_(); | |
916 }, | |
917 | |
918 /** | |
919 * Updates whether the app install hint is visible. Returns true if we need | |
920 * to reposition other tiles (because webstore app changed visibility). | |
921 * @private | |
922 */ | |
923 updateHintState_: function() { | |
924 if (!this.appInstallHint_) | |
925 return; | |
926 | |
927 var appsPages = document.querySelectorAll('.apps-page'); | |
928 var numTiles = this.tileElements_.length; | |
929 var showHint = | |
930 numTiles < appInstallHintTileLimit && appsPages.length == 1; | |
931 this.appInstallHint_.hidden = !showHint; | |
932 | |
933 var webstoreApp = this.querySelector('.webstore'); | |
934 if (!webstoreApp) | |
935 return false; | |
936 | |
937 var webstoreTile = findAncestorByClass(webstoreApp, 'tile'); | |
938 if (showHint) { | |
939 if (!webstoreTile.classList.contains('real')) | |
940 return false; | |
941 | |
942 webstoreTile.classList.remove('real'); | |
943 return true; | |
944 } | |
945 | |
946 if (webstoreTile.classList.contains('real')) | |
947 return false; | |
948 | |
949 webstoreTile.classList.add('real'); | |
950 return true; | |
951 }, | |
952 | |
953 /** | |
954 * Repositions the app tile hint (to be called when tiles move). | |
955 * @private | |
956 */ | |
957 repositionHint_: function() { | |
958 if (!this.appInstallHint_ || this.appInstallHint_.hidden) | |
959 return; | |
960 | |
961 var index = this.tileElements_.length; | |
962 var layout = this.layoutValues_; | |
963 var col = index % layout.numRowTiles; | |
964 var row = Math.floor(index / layout.numRowTiles); | |
965 var realX = this.tileGrid_.offsetLeft + | |
966 col * layout.colWidth + layout.leftMargin; | |
967 | |
968 var realY = | |
969 this.topMarginPx_ + row * layout.rowHeight + this.contentPadding; | |
970 | |
971 this.appInstallHint_.style.left = realX + 'px'; | |
972 this.appInstallHint_.style.right = realX + 'px'; | |
973 this.appInstallHint_.style.top = realY + 'px'; | |
974 this.appInstallHint_.style.width = layout.tileWidth + 'px'; | |
975 this.appInstallHint_.style.height = layout.tileWidth + 'px'; | |
976 }, | |
977 | |
978 /** @inheritDoc */ | |
979 repositionTiles_: function(ignoreNode) { | |
980 TilePage.prototype.repositionTiles_.call(this, ignoreNode); | |
981 this.repositionHint_(); | |
982 }, | |
983 }; | 892 }; |
984 | 893 |
985 AppsPage.setPromo = function(data) { | 894 AppsPage.setPromo = function(data) { |
986 var store = document.querySelector('.webstore'); | 895 var store = document.querySelector('.webstore'); |
987 if (store) | 896 if (store) |
988 store.setAppsPromoData(data); | 897 store.setAppsPromoData(data); |
989 }; | 898 }; |
990 | 899 |
991 /** | 900 /** |
992 * Launches the specified app using the APP_LAUNCH_NTP_APP_RE_ENABLE | 901 * Launches the specified app using the APP_LAUNCH_NTP_APP_RE_ENABLE |
(...skipping 11 matching lines...) Expand all Loading... |
1004 app.setupNotification_(notification); | 913 app.setupNotification_(notification); |
1005 } | 914 } |
1006 | 915 |
1007 return { | 916 return { |
1008 APP_LAUNCH: APP_LAUNCH, | 917 APP_LAUNCH: APP_LAUNCH, |
1009 appNotificationChanged: appNotificationChanged, | 918 appNotificationChanged: appNotificationChanged, |
1010 AppsPage: AppsPage, | 919 AppsPage: AppsPage, |
1011 launchAppAfterEnable: launchAppAfterEnable, | 920 launchAppAfterEnable: launchAppAfterEnable, |
1012 }; | 921 }; |
1013 }); | 922 }); |
OLD | NEW |