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

Side by Side Diff: chrome/browser/resources/ntp/apps.js

Issue 6825052: Update the web store promo to be clearer and configurable at run-time. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Incorporate Aaron's feedback. Created 9 years, 8 months 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
« no previous file with comments | « chrome/browser/resources/ntp/apps.css ('k') | chrome/browser/ui/webui/app_launcher_handler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 var MAX_APPS_PER_ROW = []; 5 var MAX_APPS_PER_ROW = [];
6 MAX_APPS_PER_ROW[LayoutMode.SMALL] = 4; 6 MAX_APPS_PER_ROW[LayoutMode.SMALL] = 4;
7 MAX_APPS_PER_ROW[LayoutMode.NORMAL] = 6; 7 MAX_APPS_PER_ROW[LayoutMode.NORMAL] = 6;
8 8
9 function getAppsCallback(data) { 9 function getAppsCallback(data) {
10 logEvent('received apps'); 10 logEvent('received apps');
11 11
12 // In the case of prefchange-triggered updates, we don't receive this flag. 12 // In the case of prefchange-triggered updates, we don't receive this flag.
13 // Just leave it set as it was before in that case. 13 // Just leave it set as it was before in that case.
14 if ('showPromo' in data) 14 if ('showPromo' in data)
15 apps.showPromo = data.showPromo; 15 apps.showPromo = data.showPromo;
16 16
17 var appsSection = $('apps'); 17 var appsSection = $('apps');
18 var appsSectionContent = $('apps-content'); 18 var appsSectionContent = $('apps-content');
19 var appsMiniview = appsSection.getElementsByClassName('miniview')[0]; 19 var appsMiniview = appsSection.getElementsByClassName('miniview')[0];
20 var appsPromo = $('apps-promo'); 20 var appsPromo = $('apps-promo');
21 var appsPromoLink = $('apps-promo-link');
21 var appsPromoPing = APP_LAUNCH_URL.PING_WEBSTORE + '+' + apps.showPromo; 22 var appsPromoPing = APP_LAUNCH_URL.PING_WEBSTORE + '+' + apps.showPromo;
22 var webStoreEntry, webStoreMiniEntry; 23 var webStoreEntry, webStoreMiniEntry;
23 24
24 // Hide menu options that are not supported on the OS or windowing system. 25 // Hide menu options that are not supported on the OS or windowing system.
25 26
26 // The "Launch as Window" menu option. 27 // The "Launch as Window" menu option.
27 $('apps-launch-type-window-menu-item').hidden = data.disableAppWindowLaunch; 28 $('apps-launch-type-window-menu-item').hidden = data.disableAppWindowLaunch;
28 29
29 // The "Create App Shortcut" menu option. 30 // The "Create App Shortcut" menu option.
30 $('apps-create-shortcut-command-menu-item').hidden = 31 $('apps-create-shortcut-command-menu-item').hidden =
(...skipping 10 matching lines...) Expand all
41 return a.app_launch_index - b.app_launch_index; 42 return a.app_launch_index - b.app_launch_index;
42 }); 43 });
43 44
44 // Determines if the web store link should be detached and place in the 45 // Determines if the web store link should be detached and place in the
45 // top right of the screen. 46 // top right of the screen.
46 apps.detachWebstoreEntry = 47 apps.detachWebstoreEntry =
47 !apps.showPromo && data.apps.length >= MAX_APPS_PER_ROW[layoutMode]; 48 !apps.showPromo && data.apps.length >= MAX_APPS_PER_ROW[layoutMode];
48 49
49 markNewApps(data.apps); 50 markNewApps(data.apps);
50 apps.data = data.apps; 51 apps.data = data.apps;
51 if (!apps.detachWebstoreEntry)
52 apps.data.push('web-store-entry');
53 52
54 clearClosedMenu(apps.menu); 53 clearClosedMenu(apps.menu);
55 54
56 // We wait for the app icons to load before displaying them, but never wait 55 // We wait for the app icons to load before displaying them, but never wait
57 // longer than 200ms. 56 // longer than 200ms.
58 apps.loadedImages = 0; 57 apps.loadedImages = 0;
59 apps.imageTimer = setTimeout(apps.showImages.bind(apps), 200); 58 apps.imageTimer = setTimeout(apps.showImages.bind(apps), 200);
60 59
61 data.apps.forEach(function(app) { 60 data.apps.forEach(function(app) {
62 appsSectionContent.appendChild(apps.createElement(app)); 61 appsSectionContent.appendChild(apps.createElement(app));
63 }); 62 });
64 63
65 webStoreEntry = apps.createWebStoreElement(); 64 if (data.showPromo) {
66 webStoreEntry.querySelector('a').setAttribute('ping', appsPromoPing); 65 // Add the promo content...
67 appsSectionContent.appendChild(webStoreEntry); 66 $('apps-promo-heading').textContent = data.promoHeader;
67 appsPromoLink.href = data.promoLink;
68 appsPromoLink.textContent = data.promoButton;
69 appsPromoLink.ping = appsPromoPing;
70 $('apps-promo-hide').textContent = data.promoExpire;
71
72 // ... then display the promo.
73 document.documentElement.classList.add('apps-promo-visible');
74 } else {
75 document.documentElement.classList.remove('apps-promo-visible');
76 }
77
78 // Only show the web store entry if there are apps installed, since the promo
79 // is sufficient otherwise.
80 if (data.apps.length > 0) {
81 webStoreEntry = apps.createWebStoreElement();
82 webStoreEntry.querySelector('a').ping = appsPromoPing;
83 appsSectionContent.appendChild(webStoreEntry);
84 if (apps.detachWebstoreEntry) {
85 webStoreEntry.classList.add('loner');
86 } else {
87 webStoreEntry.classList.remove('loner');
88 apps.data.push('web-store-entry');
89 }
90 }
68 91
69 data.apps.slice(0, MAX_MINIVIEW_ITEMS).forEach(function(app) { 92 data.apps.slice(0, MAX_MINIVIEW_ITEMS).forEach(function(app) {
70 appsMiniview.appendChild(apps.createMiniviewElement(app)); 93 appsMiniview.appendChild(apps.createMiniviewElement(app));
71 addClosedMenuEntryWithLink(apps.menu, apps.createClosedMenuElement(app)); 94 addClosedMenuEntryWithLink(apps.menu, apps.createClosedMenuElement(app));
72 }); 95 });
73 if (data.apps.length < MAX_MINIVIEW_ITEMS) { 96 if (data.apps.length < MAX_MINIVIEW_ITEMS) {
74 webStoreMiniEntry = apps.createWebStoreMiniElement(); 97 webStoreMiniEntry = apps.createWebStoreMiniElement();
75 webStoreEntry.querySelector('a').setAttribute('ping', appsPromoPing); 98 webStoreMiniEntry.querySelector('a').ping = appsPromoPing;
76 appsMiniview.appendChild(webStoreMiniEntry); 99 appsMiniview.appendChild(webStoreMiniEntry);
77 addClosedMenuEntryWithLink(apps.menu, 100 addClosedMenuEntryWithLink(apps.menu,
78 apps.createWebStoreClosedMenuElement()); 101 apps.createWebStoreClosedMenuElement());
79 } 102 }
80 103
81 if (!data.showLauncher) 104 if (!data.showLauncher)
82 hideSection(Section.APPS); 105 hideSection(Section.APPS);
83 else 106 else
84 appsSection.classList.remove('disabled'); 107 appsSection.classList.remove('disabled');
85 108
86 addClosedMenuFooter(apps.menu, 'apps', MENU_APPS, Section.APPS); 109 addClosedMenuFooter(apps.menu, 'apps', MENU_APPS, Section.APPS);
87 110
88 apps.loaded = true; 111 apps.loaded = true;
89 if (apps.showPromo)
90 document.documentElement.classList.add('apps-promo-visible');
91 else
92 document.documentElement.classList.remove('apps-promo-visible');
93 112
94 var appsPromoLink = $('apps-promo-link');
95 if (appsPromoLink) 113 if (appsPromoLink)
96 appsPromoLink.setAttribute('ping', appsPromoPing); 114 appsPromoLink.ping = appsPromoPing;
97 maybeDoneLoading(); 115 maybeDoneLoading();
98 116
99 // Disable the animations when the app launcher is being (re)initailized. 117 // Disable the animations when the app launcher is being (re)initailized.
100 apps.layout({disableAnimations:true}); 118 apps.layout({disableAnimations:true});
101 119
102 if (apps.detachWebstoreEntry)
103 webStoreEntry.classList.add('loner');
104 else
105 webStoreEntry.classList.remove('loner');
106
107 if (isDoneLoading()) { 120 if (isDoneLoading()) {
108 updateMiniviewClipping(appsMiniview); 121 updateMiniviewClipping(appsMiniview);
109 layoutSections(); 122 layoutSections();
110 } 123 }
111 } 124 }
112 125
113 function markNewApps(data) { 126 function markNewApps(data) {
114 var oldData = apps.data; 127 var oldData = apps.data;
115 data.forEach(function(app) { 128 data.forEach(function(app) {
116 if (hashParams['app-id'] == app['id']) { 129 if (hashParams['app-id'] == app['id']) {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 if (opt_mouseEvent) { 181 if (opt_mouseEvent) {
169 // Launch came from a click - add details of the click 182 // Launch came from a click - add details of the click
170 // Otherwise it came from a 'command' event from elsewhere in the UI. 183 // Otherwise it came from a 'command' event from elsewhere in the UI.
171 args.push(opt_mouseEvent.altKey, opt_mouseEvent.ctrlKey, 184 args.push(opt_mouseEvent.altKey, opt_mouseEvent.ctrlKey,
172 opt_mouseEvent.metaKey, opt_mouseEvent.shiftKey, 185 opt_mouseEvent.metaKey, opt_mouseEvent.shiftKey,
173 opt_mouseEvent.button); 186 opt_mouseEvent.button);
174 } 187 }
175 chrome.send('launchApp', args); 188 chrome.send('launchApp', args);
176 } 189 }
177 190
191 function isAppSectionMaximized() {
192 return getAppLaunchType() == APP_LAUNCH.NTP_APPS_MAXIMIZED &&
193 !$('apps').classList.contains('disabled');
194 }
195
178 function isAppsMenu(node) { 196 function isAppsMenu(node) {
179 return node.id == 'apps-menu'; 197 return node.id == 'apps-menu';
180 } 198 }
181 199
182 function getAppLaunchType() { 200 function getAppLaunchType() {
183 // We determine if the apps section is maximized, collapsed or in menu mode 201 // We determine if the apps section is maximized, collapsed or in menu mode
184 // based on the class of the apps section. 202 // based on the class of the apps section.
185 if ($('apps').classList.contains('menu')) 203 if ($('apps').classList.contains('menu'))
186 return APP_LAUNCH.NTP_APPS_MENU; 204 return APP_LAUNCH.NTP_APPS_MENU;
187 else if ($('apps').classList.contains('collapsed')) 205 else if ($('apps').classList.contains('collapsed'))
(...skipping 21 matching lines...) Expand all
209 }; 227 };
210 228
211 // Keep in sync with LaunchContainer in extension_constants.h 229 // Keep in sync with LaunchContainer in extension_constants.h
212 var LaunchContainer = { 230 var LaunchContainer = {
213 LAUNCH_WINDOW: 0, 231 LAUNCH_WINDOW: 0,
214 LAUNCH_PANEL: 1, 232 LAUNCH_PANEL: 1,
215 LAUNCH_TAB: 2 233 LAUNCH_TAB: 2
216 }; 234 };
217 235
218 var currentApp; 236 var currentApp;
237 var promoHasBeenSeen = false;
219 238
220 function addContextMenu(el, app) { 239 function addContextMenu(el, app) {
221 el.addEventListener('contextmenu', cr.ui.contextMenuHandler); 240 el.addEventListener('contextmenu', cr.ui.contextMenuHandler);
222 el.addEventListener('keydown', cr.ui.contextMenuHandler); 241 el.addEventListener('keydown', cr.ui.contextMenuHandler);
223 el.addEventListener('keyup', cr.ui.contextMenuHandler); 242 el.addEventListener('keyup', cr.ui.contextMenuHandler);
224 243
225 Object.defineProperty(el, 'contextMenu', { 244 Object.defineProperty(el, 'contextMenu', {
226 get: function() { 245 get: function() {
227 currentApp = app; 246 currentApp = app;
228 247
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 359
341 visible_: true, 360 visible_: true,
342 get visible() { 361 get visible() {
343 return this.visible_; 362 return this.visible_;
344 }, 363 },
345 set visible(visible) { 364 set visible(visible) {
346 this.visible_ = visible; 365 this.visible_ = visible;
347 this.invalidate_(); 366 this.invalidate_();
348 }, 367 },
349 368
369 maybePingPromoSeen_: function() {
370 if (promoHasBeenSeen || !this.showPromo || !isAppSectionMaximized())
371 return;
372
373 promoHasBeenSeen = true;
374 chrome.send('promoSeen', []);
375 },
376
350 // DragAndDropDelegate 377 // DragAndDropDelegate
351 378
352 dragContainer: $('apps-content'), 379 dragContainer: $('apps-content'),
353 transitionsDuration: 200, 380 transitionsDuration: 200,
354 381
355 get dragItem() { return this.dragItem_; }, 382 get dragItem() { return this.dragItem_; },
356 set dragItem(dragItem) { 383 set dragItem(dragItem) {
357 if (this.dragItem_ != dragItem) { 384 if (this.dragItem_ != dragItem) {
358 this.dragItem_ = dragItem; 385 this.dragItem_ = dragItem;
359 this.invalidate_(); 386 this.invalidate_();
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 // We need to re-enable animations asynchronously, so that the 584 // We need to re-enable animations asynchronously, so that the
558 // animations are still disabled for this layout update. 585 // animations are still disabled for this layout update.
559 setTimeout(function() { 586 setTimeout(function() {
560 container.setAttribute('launcher-animations', true); 587 container.setAttribute('launcher-animations', true);
561 }, 0); 588 }, 0);
562 } 589 }
563 } 590 }
564 }, 591 },
565 592
566 layoutImpl_: function() { 593 layoutImpl_: function() {
567 var apps = this.data; 594 var apps = this.data || [];
568 var rects = this.getLayoutRects_(apps.length); 595 var rects = this.getLayoutRects_(apps.length);
569 var appsContent = this.dragContainer; 596 var appsContent = this.dragContainer;
570 597
598 // Ping the PROMO_SEEN histogram only when the promo is maximized, and
599 // maximum once per NTP load.
600 this.maybePingPromoSeen_();
601
571 if (!this.visible) 602 if (!this.visible)
572 return; 603 return;
573 604
574 for (var i = 0; i < apps.length; i++) { 605 for (var i = 0; i < apps.length; i++) {
575 var app = appsContent.querySelector('[app-id='+apps[i]+']').parentNode; 606 var app = appsContent.querySelector('[app-id='+apps[i]+']').parentNode;
576 607
577 // If the node is being dragged, don't try to place it in the grid. 608 // If the node is being dragged, don't try to place it in the grid.
578 if (app == this.dragItem) 609 if (app == this.dragItem)
579 continue; 610 continue;
580 611
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 showImages: function() { 675 showImages: function() {
645 $('apps-content').classList.add('visible'); 676 $('apps-content').classList.add('visible');
646 clearTimeout(this.imageTimer); 677 clearTimeout(this.imageTimer);
647 }, 678 },
648 679
649 createElement: function(app) { 680 createElement: function(app) {
650 var div = createElement(app); 681 var div = createElement(app);
651 var a = div.firstChild; 682 var a = div.firstChild;
652 683
653 a.onclick = handleClick; 684 a.onclick = handleClick;
654 a.setAttribute('ping', 685 a.ping = getAppPingUrl(
655 getAppPingUrl('PING_BY_ID', this.showPromo, 'NTP_APPS_MAXIMIZED')); 686 'PING_BY_ID', this.showPromo, 'NTP_APPS_MAXIMIZED');
656 a.style.backgroundImage = url(app['icon_big']); 687 a.style.backgroundImage = url(app['icon_big']);
657 if (app.isNew) { 688 if (app.isNew) {
658 div.setAttribute('new', 'new'); 689 div.setAttribute('new', 'new');
659 // Delay changing the attribute a bit to let the page settle down a bit. 690 // Delay changing the attribute a bit to let the page settle down a bit.
660 setTimeout(function() { 691 setTimeout(function() {
661 // Make sure the new icon is scrolled into view. 692 // Make sure the new icon is scrolled into view.
662 document.body.scrollTop = document.body.scrollHeight; 693 document.body.scrollTop = document.body.scrollHeight;
663 694
664 // This will trigger the 'bounce' animation defined in apps.css. 695 // This will trigger the 'bounce' animation defined in apps.css.
665 div.setAttribute('new', 'installed'); 696 div.setAttribute('new', 'installed');
(...skipping 18 matching lines...) Expand all
684 }, 715 },
685 716
686 createMiniviewElement: function(app) { 717 createMiniviewElement: function(app) {
687 var span = document.createElement('span'); 718 var span = document.createElement('span');
688 var a = span.appendChild(document.createElement('a')); 719 var a = span.appendChild(document.createElement('a'));
689 720
690 a.setAttribute('app-id', app['id']); 721 a.setAttribute('app-id', app['id']);
691 a.textContent = app['name']; 722 a.textContent = app['name'];
692 a.href = app['launch_url']; 723 a.href = app['launch_url'];
693 a.onclick = handleClick; 724 a.onclick = handleClick;
694 a.setAttribute('ping', 725 a.ping = getAppPingUrl(
695 getAppPingUrl('PING_BY_ID', this.showPromo, 'NTP_APPS_COLLAPSED')); 726 'PING_BY_ID', this.showPromo, 'NTP_APPS_COLLAPSED');
696 a.style.backgroundImage = url(app['icon_small']); 727 a.style.backgroundImage = url(app['icon_small']);
697 a.className = 'item'; 728 a.className = 'item';
698 span.appendChild(a); 729 span.appendChild(a);
699 730
700 addContextMenu(span, app); 731 addContextMenu(span, app);
701 732
702 return span; 733 return span;
703 }, 734 },
704 735
705 createClosedMenuElement: function(app) { 736 createClosedMenuElement: function(app) {
706 var a = document.createElement('a'); 737 var a = document.createElement('a');
707 a.setAttribute('app-id', app['id']); 738 a.setAttribute('app-id', app['id']);
708 a.textContent = app['name']; 739 a.textContent = app['name'];
709 a.href = app['launch_url']; 740 a.href = app['launch_url'];
710 a.onclick = handleClick; 741 a.onclick = handleClick;
711 a.setAttribute('ping', 742 a.ping = getAppPingUrl(
712 getAppPingUrl('PING_BY_ID', this.showPromo, 'NTP_APPS_MENU')); 743 'PING_BY_ID', this.showPromo, 'NTP_APPS_MENU');
713 a.style.backgroundImage = url(app['icon_small']); 744 a.style.backgroundImage = url(app['icon_small']);
714 a.className = 'item'; 745 a.className = 'item';
715 746
716 addContextMenu(a, app); 747 addContextMenu(a, app);
717 748
718 return a; 749 return a;
719 }, 750 },
720 751
721 createWebStoreElement: function() { 752 createWebStoreElement: function() {
722 var elm = createElement({ 753 var elm = createElement({
(...skipping 17 matching lines...) Expand all
740 a.href = localStrings.getString('web_store_url'); 771 a.href = localStrings.getString('web_store_url');
741 a.style.backgroundImage = url('chrome://theme/IDR_PRODUCT_LOGO_16'); 772 a.style.backgroundImage = url('chrome://theme/IDR_PRODUCT_LOGO_16');
742 a.className = 'item'; 773 a.className = 'item';
743 return a; 774 return a;
744 } 775 }
745 }; 776 };
746 })(); 777 })();
747 778
748 // Enable drag and drop reordering of the app launcher. 779 // Enable drag and drop reordering of the app launcher.
749 var appDragAndDrop = new DragAndDropController(apps); 780 var appDragAndDrop = new DragAndDropController(apps);
OLDNEW
« no previous file with comments | « chrome/browser/resources/ntp/apps.css ('k') | chrome/browser/ui/webui/app_launcher_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698