OLD | NEW |
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'); |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 function appsPrefChangeCallback(data) { | 143 function appsPrefChangeCallback(data) { |
144 // Currently the only pref that is watched is the launch type. | 144 // Currently the only pref that is watched is the launch type. |
145 data.apps.forEach(function(app) { | 145 data.apps.forEach(function(app) { |
146 var appLink = document.querySelector('.app a[app-id=' + app['id'] + ']'); | 146 var appLink = document.querySelector('.app a[app-id=' + app['id'] + ']'); |
147 if (appLink) | 147 if (appLink) |
148 appLink.setAttribute('launch-type', app['launch_type']); | 148 appLink.setAttribute('launch-type', app['launch_type']); |
149 }); | 149 }); |
150 } | 150 } |
151 | 151 |
152 function appNotificationChanged(id, lastNotification) { | 152 function appNotificationChanged(id, lastNotification) { |
153 // TODO(asargent/finnur) use this when we hook up notifications into the NTP. | 153 // TODO(asargent/finnur): Don't update all apps at once, do it in a more |
| 154 // fine grained way. |
| 155 chrome.send('getApps'); |
154 } | 156 } |
155 | 157 |
156 // Launches the specified app using the APP_LAUNCH_NTP_APP_RE_ENABLE histogram. | 158 // Launches the specified app using the APP_LAUNCH_NTP_APP_RE_ENABLE histogram. |
157 // This should only be invoked from the AppLauncherHandler. | 159 // This should only be invoked from the AppLauncherHandler. |
158 function launchAppAfterEnable(appId) { | 160 function launchAppAfterEnable(appId) { |
159 chrome.send('launchApp', [appId, APP_LAUNCH.NTP_APP_RE_ENABLE]); | 161 chrome.send('launchApp', [appId, APP_LAUNCH.NTP_APP_RE_ENABLE]); |
160 } | 162 } |
161 | 163 |
| 164 // Shows the notification bubble for a given app (the one clicked on). |
| 165 function showNotificationBubble(event) { |
| 166 var item = findAncestorByClass(event.target, 'app-anchor'); |
| 167 var title = item.getAttribute('notification-title'); |
| 168 var message = item.getAttribute('notification-message'); |
| 169 var link = item.getAttribute('notification-link'); |
| 170 var link_message = item.getAttribute('notification-link-message'); |
| 171 |
| 172 if (!title || !message) |
| 173 return; |
| 174 |
| 175 // Set the content to the right text. |
| 176 $('app-notification-title').textContent = title; |
| 177 $('app-notification-message').textContent = message; |
| 178 $('app-notification-link').href = link; |
| 179 $('app-notification-link').textContent = link_message; |
| 180 |
| 181 var target = event.target; |
| 182 while (target.parentElement && target.tagName != "A") { |
| 183 target = target.parentElement; |
| 184 } |
| 185 |
| 186 // Move the bubble to the right location. |
| 187 var bubble = $('app-notification-bubble'); |
| 188 var x = target.parentElement.offsetLeft + |
| 189 target.parentElement.offsetWidth - 20; |
| 190 var y = target.parentElement.offsetTop + 20; |
| 191 bubble.style.left = x + "px"; |
| 192 bubble.style.top = y + "px"; |
| 193 |
| 194 // Move the arrow and shadow to the right location. |
| 195 var arrow = $('arrow-contents'); |
| 196 var border = $('arrow-border'); |
| 197 var shadow = $('arrow-shadow'); |
| 198 y += 26; |
| 199 x -= arrow.style.width + 23; |
| 200 arrow.style.left = x + "px"; |
| 201 arrow.style.top = y + "px"; |
| 202 x -= 1; |
| 203 border.style.left = x + "px"; |
| 204 border.style.top = y + "px"; |
| 205 x -= 1; |
| 206 shadow.style.left = x + "px"; |
| 207 shadow.style.top = y + "px"; |
| 208 |
| 209 // Animate the bubble into view. |
| 210 bubble.classList.add("notification-bubble-opened"); |
| 211 bubble.classList.remove("notification-bubble-closed"); |
| 212 arrow.classList.add("notification-bubble-opened"); |
| 213 arrow.classList.remove("notification-bubble-closed"); |
| 214 border.classList.add("notification-bubble-opened"); |
| 215 border.classList.remove("notification-bubble-closed"); |
| 216 shadow.classList.add("notification-bubble-opened"); |
| 217 shadow.classList.remove("notification-bubble-closed"); |
| 218 |
| 219 bubble.focus(); |
| 220 } |
| 221 |
| 222 // Hide the notification bubble. |
| 223 function hideNotificationBubble(event) { |
| 224 // This will fade the bubble out of existence. |
| 225 $('app-notification-bubble').classList.add("notification-bubble-closed"); |
| 226 $('app-notification-bubble').classList.remove("notification-bubble-opened"); |
| 227 $('arrow-border').classList.add("notification-bubble-closed"); |
| 228 $('arrow-border').classList.remove("notification-bubble-opened"); |
| 229 $('arrow-shadow').classList.add("notification-bubble-closed"); |
| 230 $('arrow-shadow').classList.remove("notification-bubble-opened"); |
| 231 $('arrow-contents').classList.add("notification-bubble-closed"); |
| 232 $('arrow-contents').classList.remove("notification-bubble-opened"); |
| 233 } |
| 234 |
162 var apps = (function() { | 235 var apps = (function() { |
163 | 236 |
164 function createElement(app) { | 237 function createElement(app) { |
165 var div = document.createElement('div'); | 238 var div = document.createElement('div'); |
166 div.className = 'app'; | 239 div.className = 'app'; |
167 | 240 |
168 var a = div.appendChild(document.createElement('a')); | 241 var a = div.appendChild(document.createElement('a')); |
| 242 a.className = 'app-anchor'; |
169 a.setAttribute('app-id', app['id']); | 243 a.setAttribute('app-id', app['id']); |
170 a.setAttribute('launch-type', app['launch_type']); | 244 a.setAttribute('launch-type', app['launch_type']); |
| 245 if (typeof(app['notification']) != "undefined") { |
| 246 a.setAttribute('notification-title', app['notification']['title']); |
| 247 a.setAttribute('notification-message', app['notification']['body']); |
| 248 if (typeof(app['notification']['linkUrl']) != "undefined" && |
| 249 typeof(app['notification']['linkText']) != "undefined") { |
| 250 a.setAttribute('notification-link', app['notification']['linkUrl']); |
| 251 a.setAttribute('notification-link-message', |
| 252 app['notification']['linkText']); |
| 253 } |
| 254 } |
171 a.draggable = false; | 255 a.draggable = false; |
172 a.xtitle = a.textContent = app['name']; | |
173 a.href = app['launch_url']; | 256 a.href = app['launch_url']; |
174 | 257 |
| 258 var span = a.appendChild(document.createElement('span')); |
| 259 span.textContent = app['name']; |
| 260 |
| 261 span = a.appendChild(document.createElement('span')); |
| 262 span.className = "app_notification"; |
| 263 span.textContent = |
| 264 typeof(app['notification']) != "undefined" && |
| 265 typeof(app['notification']['title']) != "undefined" ? |
| 266 app['notification']['title'] : ""; |
| 267 span.onclick = handleClick; |
| 268 |
| 269 $("app-notification-close").onclick = hideNotificationBubble; |
| 270 $("app-notification-bubble").setAttribute("tabIndex", 0); |
| 271 $("app-notification-bubble").onblur = hideNotificationBubble; |
| 272 |
175 return div; | 273 return div; |
176 } | 274 } |
177 | 275 |
178 /** | 276 /** |
179 * Launches an application. | 277 * Launches an application. |
180 * @param {string} appId Application to launch. | 278 * @param {string} appId Application to launch. |
181 * @param {MouseEvent} opt_mouseEvent Mouse event from the click that | 279 * @param {MouseEvent} opt_mouseEvent Mouse event from the click that |
182 * triggered the launch, used to detect modifier keys that change | 280 * triggered the launch, used to detect modifier keys that change |
183 * the tab's disposition. | 281 * the tab's disposition. |
184 */ | 282 */ |
(...skipping 27 matching lines...) Expand all Loading... |
212 return APP_LAUNCH.NTP_APPS_COLLAPSED; | 310 return APP_LAUNCH.NTP_APPS_COLLAPSED; |
213 else | 311 else |
214 return APP_LAUNCH.NTP_APPS_MAXIMIZED; | 312 return APP_LAUNCH.NTP_APPS_MAXIMIZED; |
215 } | 313 } |
216 | 314 |
217 /** | 315 /** |
218 * @this {!HTMLAnchorElement} | 316 * @this {!HTMLAnchorElement} |
219 */ | 317 */ |
220 function handleClick(e) { | 318 function handleClick(e) { |
221 var appId = e.currentTarget.getAttribute('app-id'); | 319 var appId = e.currentTarget.getAttribute('app-id'); |
| 320 if (appId == null) { |
| 321 showNotificationBubble(e); |
| 322 e.stopPropagation(); |
| 323 return false; |
| 324 } |
| 325 |
222 if (!appDragAndDrop.isDragging()) | 326 if (!appDragAndDrop.isDragging()) |
223 launchApp(appId, e); | 327 launchApp(appId, e); |
224 return false; | 328 return false; |
225 } | 329 } |
226 | 330 |
227 // Keep in sync with LaunchType in extension_prefs.h | 331 // Keep in sync with LaunchType in extension_prefs.h |
228 var LaunchType = { | 332 var LaunchType = { |
229 LAUNCH_PINNED: 0, | 333 LAUNCH_PINNED: 0, |
230 LAUNCH_REGULAR: 1, | 334 LAUNCH_REGULAR: 1, |
231 LAUNCH_FULLSCREEN: 2, | 335 LAUNCH_FULLSCREEN: 2, |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 | 418 |
315 document.addEventListener('canExecute', function(e) { | 419 document.addEventListener('canExecute', function(e) { |
316 switch (e.command.id) { | 420 switch (e.command.id) { |
317 case 'apps-options-command': | 421 case 'apps-options-command': |
318 e.canExecute = currentApp && currentApp['options_url']; | 422 e.canExecute = currentApp && currentApp['options_url']; |
319 break; | 423 break; |
320 case 'apps-launch-command': | 424 case 'apps-launch-command': |
321 e.canExecute = true; | 425 e.canExecute = true; |
322 break; | 426 break; |
323 case 'apps-uninstall-command': | 427 case 'apps-uninstall-command': |
324 e.canExecute = !currentApp['can_uninstall']; | 428 e.canExecute = currentApp && !currentApp['can_uninstall']; |
325 break; | 429 break; |
326 } | 430 } |
327 }); | 431 }); |
328 | 432 |
329 // Moves the element at position |from| in array |arr| to position |to|. | 433 // Moves the element at position |from| in array |arr| to position |to|. |
330 function arrayMove(arr, from, to) { | 434 function arrayMove(arr, from, to) { |
331 var element = arr.splice(from, 1); | 435 var element = arr.splice(from, 1); |
332 arr.splice(to, 0, element[0]); | 436 arr.splice(to, 0, element[0]); |
333 } | 437 } |
334 | 438 |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 return; | 781 return; |
678 } | 782 } |
679 }, | 783 }, |
680 | 784 |
681 showImages: function() { | 785 showImages: function() { |
682 $('apps-content').classList.add('visible'); | 786 $('apps-content').classList.add('visible'); |
683 clearTimeout(this.imageTimer); | 787 clearTimeout(this.imageTimer); |
684 }, | 788 }, |
685 | 789 |
686 createElement: function(app) { | 790 createElement: function(app) { |
| 791 var container = document.createElement('div'); |
687 var div = createElement(app); | 792 var div = createElement(app); |
| 793 container.appendChild(div); |
688 var a = div.firstChild; | 794 var a = div.firstChild; |
689 | 795 |
690 a.onclick = handleClick; | 796 a.onclick = handleClick; |
691 a.ping = getAppPingUrl( | 797 a.ping = getAppPingUrl( |
692 'PING_BY_ID', this.showPromo, 'NTP_APPS_MAXIMIZED'); | 798 'PING_BY_ID', this.showPromo, 'NTP_APPS_MAXIMIZED'); |
693 a.style.backgroundImage = url(app['icon_big']); | 799 a.style.backgroundImage = url(app['icon_big']); |
694 if (app.isNew) { | 800 if (app.isNew) { |
695 div.setAttribute('new', 'new'); | 801 div.setAttribute('new', 'new'); |
696 // Delay changing the attribute a bit to let the page settle down a bit. | 802 // Delay changing the attribute a bit to let the page settle down a bit. |
697 setTimeout(function() { | 803 setTimeout(function() { |
(...skipping 14 matching lines...) Expand all Loading... |
712 img.src = app['icon_big']; | 818 img.src = app['icon_big']; |
713 | 819 |
714 // User cannot change launch options or uninstall component extension. | 820 // User cannot change launch options or uninstall component extension. |
715 if (!app['is_component']) { | 821 if (!app['is_component']) { |
716 var settingsButton = div.appendChild(new cr.ui.ContextMenuButton); | 822 var settingsButton = div.appendChild(new cr.ui.ContextMenuButton); |
717 settingsButton.className = 'app-settings'; | 823 settingsButton.className = 'app-settings'; |
718 settingsButton.title = localStrings.getString('appsettings'); | 824 settingsButton.title = localStrings.getString('appsettings'); |
719 addContextMenu(div, app); | 825 addContextMenu(div, app); |
720 } | 826 } |
721 | 827 |
722 return div; | 828 if (app.notifications && app.notifications.length > 0) { |
| 829 // Create the notification div below the app icon that is used to |
| 830 // trigger the hidden notification bubble to appear. |
| 831 var notification = document.createElement('div') |
| 832 container.appendChild(notification); |
| 833 var title = document.createElement('span'); |
| 834 title.innerText = app.notifications[0].title; |
| 835 notification.appendChild(title); |
| 836 notification.appendChild(document.createElement('br')); |
| 837 |
| 838 var body = document.createElement('span'); |
| 839 container.appendChild(body); |
| 840 body.innerText = app.notifications[0].body; |
| 841 notification.appendChild(body); |
| 842 if (app.notifications[0].linkUrl) { |
| 843 notification.appendChild(document.createElement('br')); |
| 844 var link = document.createElement('a'); |
| 845 link.href = app.notifications[0].linkUrl; |
| 846 link.innerText = app.notifications[0].linkText ? |
| 847 app.notifications[0].linkText : "link"; |
| 848 notification.appendChild(link); |
| 849 } |
| 850 } |
| 851 |
| 852 return container; |
723 }, | 853 }, |
724 | 854 |
725 createMiniviewElement: function(app) { | 855 createMiniviewElement: function(app) { |
726 var span = document.createElement('span'); | 856 var span = document.createElement('span'); |
727 var a = span.appendChild(document.createElement('a')); | 857 var a = span.appendChild(document.createElement('a')); |
728 | 858 |
729 a.setAttribute('app-id', app['id']); | 859 a.setAttribute('app-id', app['id']); |
730 a.textContent = app['name']; | 860 a.textContent = app['name']; |
731 a.href = app['launch_url']; | 861 a.href = app['launch_url']; |
732 a.onclick = handleClick; | 862 a.onclick = handleClick; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
785 a.href = localStrings.getString('web_store_url'); | 915 a.href = localStrings.getString('web_store_url'); |
786 a.style.backgroundImage = url('chrome://theme/IDR_WEBSTORE_ICON_16'); | 916 a.style.backgroundImage = url('chrome://theme/IDR_WEBSTORE_ICON_16'); |
787 a.className = 'item'; | 917 a.className = 'item'; |
788 return a; | 918 return a; |
789 } | 919 } |
790 }; | 920 }; |
791 })(); | 921 })(); |
792 | 922 |
793 // Enable drag and drop reordering of the app launcher. | 923 // Enable drag and drop reordering of the app launcher. |
794 var appDragAndDrop = new DragAndDropController(apps); | 924 var appDragAndDrop = new DragAndDropController(apps); |
OLD | NEW |