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 Tile = ntp.Tile; | 8 var Tile = ntp.Tile; |
9 var TilePage = ntp.TilePage; | 9 var TilePage = ntp.TilePage; |
10 var APP_LAUNCH = ntp.APP_LAUNCH; | 10 var APP_LAUNCH = ntp.APP_LAUNCH; |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 } | 113 } |
114 }, | 114 }, |
115 | 115 |
116 /** | 116 /** |
117 * Does all the necessary setup to show the menu for the given app. | 117 * Does all the necessary setup to show the menu for the given app. |
118 * @param {App} app The App object that will be showing a context menu. | 118 * @param {App} app The App object that will be showing a context menu. |
119 */ | 119 */ |
120 setupForApp: function(app) { | 120 setupForApp: function(app) { |
121 this.app_ = app; | 121 this.app_ = app; |
122 | 122 |
123 this.launch_.textContent = app.appData.title; | 123 this.launch_.textContent = app.data.title; |
124 | 124 |
125 this.forAllLaunchTypes_(function(launchTypeButton, id) { | 125 this.forAllLaunchTypes_(function(launchTypeButton, id) { |
126 launchTypeButton.disabled = false; | 126 launchTypeButton.disabled = false; |
127 launchTypeButton.checked = app.appData.launch_type == id; | 127 launchTypeButton.checked = app.data.launch_type == id; |
128 }); | 128 }); |
129 | 129 |
130 this.options_.disabled = !app.appData.optionsUrl || !app.appData.enabled; | 130 this.options_.disabled = !app.data.optionsUrl || !app.data.enabled; |
131 this.details_.disabled = !app.appData.detailsUrl; | 131 this.details_.disabled = !app.data.detailsUrl; |
132 this.uninstall_.disabled = !app.appData.mayDisable; | 132 this.uninstall_.disabled = !app.data.mayDisable; |
133 | 133 |
134 this.disableNotifications_.hidden = true; | 134 this.disableNotifications_.hidden = true; |
135 var notificationsDisabled = app.appData.notifications_disabled; | 135 var notificationsDisabled = app.data.notifications_disabled; |
136 if (typeof notificationsDisabled != 'undefined') { | 136 if (typeof notificationsDisabled != 'undefined') { |
137 this.disableNotifications_.hidden = false; | 137 this.disableNotifications_.hidden = false; |
138 this.disableNotifications_.checked = notificationsDisabled; | 138 this.disableNotifications_.checked = notificationsDisabled; |
139 } | 139 } |
140 }, | 140 }, |
141 | 141 |
142 /** | 142 /** |
143 * Handlers for menu item activation. | 143 * Handlers for menu item activation. |
144 * @param {Event} e The activation event. | 144 * @param {Event} e The activation event. |
145 * @private | 145 * @private |
146 */ | 146 */ |
147 onLaunch_: function(e) { | 147 onLaunch_: function(e) { |
148 chrome.send('launchApp', [this.app_.appId, APP_LAUNCH.NTP_APPS_MENU]); | 148 chrome.send('launchApp', [this.app_.appId, APP_LAUNCH.NTP_APPS_MENU]); |
149 }, | 149 }, |
150 onLaunchTypeChanged_: function(e) { | 150 onLaunchTypeChanged_: function(e) { |
151 var pressed = e.currentTarget; | 151 var pressed = e.currentTarget; |
152 var app = this.app_; | 152 var app = this.app_; |
153 this.forAllLaunchTypes_(function(launchTypeButton, id) { | 153 this.forAllLaunchTypes_(function(launchTypeButton, id) { |
154 if (launchTypeButton == pressed) { | 154 if (launchTypeButton == pressed) { |
155 chrome.send('setLaunchType', [app.appId, id]); | 155 chrome.send('setLaunchType', [app.appId, id]); |
156 // Manually update the launch type. We will only get | 156 // Manually update the launch type. We will only get |
157 // appsPrefChangeCallback calls after changes to other NTP instances. | 157 // appsPrefChangeCallback calls after changes to other NTP instances. |
158 app.appData.launch_type = id; | 158 app.data.launch_type = id; |
159 } | 159 } |
160 }); | 160 }); |
161 }, | 161 }, |
162 onShowOptions_: function(e) { | 162 onShowOptions_: function(e) { |
163 window.location = this.app_.appData.optionsUrl; | 163 window.location = this.app_.data.optionsUrl; |
164 }, | 164 }, |
165 onShowDetails_: function(e) { | 165 onShowDetails_: function(e) { |
166 var url = this.app_.appData.detailsUrl; | 166 var url = this.app_.data.detailsUrl; |
167 url = appendParam(url, 'utm_source', 'chrome-ntp-launcher'); | 167 url = appendParam(url, 'utm_source', 'chrome-ntp-launcher'); |
168 window.location = url; | 168 window.location = url; |
169 }, | 169 }, |
170 onDisableNotifications_: function(e) { | 170 onDisableNotifications_: function(e) { |
171 var app = this.app_; | 171 var app = this.app_; |
172 app.removeBubble(); | 172 app.removeBubble(); |
173 // Toggle the current disable setting. | 173 // Toggle the current disable setting. |
174 var newSetting = !this.disableNotifications_.checked; | 174 var newSetting = !this.disableNotifications_.checked; |
175 app.appData.notifications_disabled = newSetting; | 175 app.data.notifications_disabled = newSetting; |
176 chrome.send('setNotificationsDisabled', [app.appData.id, newSetting]); | 176 chrome.send('setNotificationsDisabled', [app.data.id, newSetting]); |
177 }, | 177 }, |
178 onUninstall_: function(e) { | 178 onUninstall_: function(e) { |
179 var tileCell = this.app_.tileCell; | 179 chrome.send('uninstallApp', [this.app_.data.id]); |
180 tileCell.tilePage.setTileRepositioningState(tileCell.index, true); | |
181 chrome.send('uninstallApp', [this.app_.appData.id]); | |
182 }, | 180 }, |
183 onCreateShortcut_: function(e) { | 181 onCreateShortcut_: function(e) { |
184 chrome.send('createAppShortcut', [this.app_.appData.id]); | 182 chrome.send('createAppShortcut', [this.app_.data.id]); |
185 }, | 183 }, |
186 }; | 184 }; |
187 | 185 |
188 /** | 186 /** |
189 * Creates a new App object. | 187 * Creates a new App object. |
190 * @param {Object} appData The data object that describes the app. | |
191 * @constructor | 188 * @constructor |
192 * @extends {HTMLDivElement} | 189 * @extends {HTMLDivElement} |
193 */ | 190 */ |
194 function App(appData) { | 191 function App(data) { |
195 var el = cr.doc.createElement('div'); | 192 var el = cr.doc.createElement('div'); |
196 el.__proto__ = App.prototype; | 193 el.__proto__ = App.prototype; |
197 el.initialize(appData); | 194 el.initialize_(); |
| 195 el.data = data; |
198 | 196 |
199 return el; | 197 return el; |
200 } | 198 } |
201 | 199 |
202 App.prototype = Tile.subclass({ | 200 App.prototype = Tile.subclass({ |
203 __proto__: HTMLDivElement.prototype, | 201 __proto__: HTMLDivElement.prototype, |
204 | 202 |
205 /** | 203 /** |
206 * Initialize the app object. | 204 * Initialize the app object. |
207 * @param {Object} appData The data object that describes the app. | 205 * @private |
208 */ | 206 */ |
209 initialize: function(appData) { | 207 initialize_: function() { |
210 this.className = 'app focusable'; | |
211 | |
212 Tile.prototype.initialize.apply(this, arguments); | 208 Tile.prototype.initialize.apply(this, arguments); |
213 | 209 |
214 this.appData = appData; | 210 this.classList.add('app'); |
215 assert(this.appData_.id, 'Got an app without an ID'); | 211 this.classList.add('focusable'); |
216 this.id = this.appData_.id; | 212 }, |
| 213 |
| 214 /** |
| 215 * Formats this app according to |data|. |
| 216 * @param {Object} data The data object that describes the app. |
| 217 * @private |
| 218 */ |
| 219 formatApp_: function(data) { |
| 220 assert(this.data_.id, 'Got an app without an ID'); |
| 221 this.id = this.data_.id; |
217 this.setAttribute('role', 'menuitem'); | 222 this.setAttribute('role', 'menuitem'); |
218 | 223 |
219 if (!this.appData_.icon_big_exists && this.appData_.icon_small_exists) | 224 if (!this.data_.icon_big_exists && this.data_.icon_small_exists) |
220 this.useSmallIcon_ = true; | 225 this.useSmallIcon_ = true; |
221 | 226 |
222 this.appContents_ = this.useSmallIcon_ ? | 227 // TODO(pedrosimonetti): Fix crbug.com/165612 |
223 $('app-small-icon-template').cloneNode(true) : | 228 if (!this.appContents_) { |
224 $('app-large-icon-template').cloneNode(true); | 229 this.appContents_ = this.useSmallIcon_ ? |
225 this.appContents_.id = ''; | 230 $('app-small-icon-template').cloneNode(true) : |
226 this.appendChild(this.appContents_); | 231 $('app-large-icon-template').cloneNode(true); |
| 232 this.appContents_.id = ''; |
| 233 this.appendChild(this.appContents_); |
| 234 } |
227 | 235 |
228 this.appImgContainer_ = this.querySelector('.app-img-container'); | 236 this.appImgContainer_ = this.querySelector('.app-img-container'); |
229 this.appImg_ = this.appImgContainer_.querySelector('img'); | 237 this.appImg_ = this.appImgContainer_.querySelector('img'); |
230 this.setIcon(); | 238 this.setIcon(); |
231 | 239 |
232 if (this.useSmallIcon_) { | 240 if (this.useSmallIcon_) { |
233 this.imgDiv_ = this.querySelector('.app-icon-div'); | 241 this.imgDiv_ = this.querySelector('.app-icon-div'); |
234 this.addLaunchClickTarget_(this.imgDiv_); | 242 this.addLaunchClickTarget_(this.imgDiv_); |
235 this.imgDiv_.title = this.appData_.title; | 243 this.imgDiv_.title = this.data_.title; |
236 chrome.send('getAppIconDominantColor', [this.id]); | 244 chrome.send('getAppIconDominantColor', [this.id]); |
237 } else { | 245 } else { |
238 this.addLaunchClickTarget_(this.appImgContainer_); | 246 this.addLaunchClickTarget_(this.appImgContainer_); |
239 this.appImgContainer_.title = this.appData_.title; | 247 this.appImgContainer_.title = this.data_.title; |
240 } | 248 } |
241 | 249 |
242 var appSpan = this.appContents_.querySelector('.title'); | 250 var appSpan = this.appContents_.querySelector('.title'); |
243 appSpan.textContent = appSpan.title = this.appData_.title; | 251 appSpan.textContent = appSpan.title = this.data_.title; |
244 this.addLaunchClickTarget_(appSpan); | 252 this.addLaunchClickTarget_(appSpan); |
245 | 253 |
246 var notification = this.appData_.notification; | 254 var notification = this.data_.notification; |
247 var hasNotification = typeof notification != 'undefined' && | 255 var hasNotification = typeof notification != 'undefined' && |
248 typeof notification['title'] != 'undefined' && | 256 typeof notification['title'] != 'undefined' && |
249 typeof notification['body'] != 'undefined' && | 257 typeof notification['body'] != 'undefined' && |
250 !this.appData_.notifications_disabled; | 258 !this.data_.notifications_disabled; |
251 if (hasNotification) | 259 if (hasNotification) |
252 this.setupNotification_(notification); | 260 this.setupNotification_(notification); |
253 | 261 |
254 this.addEventListener('keydown', cr.ui.contextMenuHandler); | 262 this.addEventListener('keydown', cr.ui.contextMenuHandler); |
255 this.addEventListener('keyup', cr.ui.contextMenuHandler); | 263 this.addEventListener('keyup', cr.ui.contextMenuHandler); |
256 | 264 |
257 // This hack is here so that appContents.contextMenu will be the same as | 265 // This hack is here so that appContents.contextMenu will be the same as |
258 // this.contextMenu. | 266 // this.contextMenu. |
259 var self = this; | 267 var self = this; |
260 this.appContents_.__defineGetter__('contextMenu', function() { | 268 this.appContents_.__defineGetter__('contextMenu', function() { |
(...skipping 20 matching lines...) Expand all Loading... |
281 * been uninstalled. | 289 * been uninstalled. |
282 */ | 290 */ |
283 remove: function(opt_animate) { | 291 remove: function(opt_animate) { |
284 // Unset the ID immediately, because the app is already gone. But leave | 292 // Unset the ID immediately, because the app is already gone. But leave |
285 // the tile on the page as it animates out. | 293 // the tile on the page as it animates out. |
286 this.id = ''; | 294 this.id = ''; |
287 this.tileCell.doRemove(opt_animate); | 295 this.tileCell.doRemove(opt_animate); |
288 }, | 296 }, |
289 | 297 |
290 /** | 298 /** |
291 * Set the URL of the icon from |appData_|. This won't actually show the | 299 * Set the URL of the icon from |this.data_|. This won't actually show the |
292 * icon until loadIcon() is called (for performance reasons; we don't want | 300 * icon until loadIcon() is called (for performance reasons; we don't want |
293 * to load icons until we have to). | 301 * to load icons until we have to). |
294 */ | 302 */ |
295 setIcon: function() { | 303 setIcon: function() { |
296 var src = this.useSmallIcon_ ? this.appData_.icon_small : | 304 var src = this.useSmallIcon_ ? this.data_.icon_small : |
297 this.appData_.icon_big; | 305 this.data_.icon_big; |
298 if (!this.appData_.enabled || | 306 if (!this.data_.enabled || |
299 (!this.appData_.offlineEnabled && !navigator.onLine)) { | 307 (!this.data_.offlineEnabled && !navigator.onLine)) { |
300 src += '?grayscale=true'; | 308 src += '?grayscale=true'; |
301 } | 309 } |
302 | 310 |
303 this.appImgSrc_ = src; | 311 this.appImgSrc_ = src; |
304 this.classList.add('icon-loading'); | 312 this.classList.add('icon-loading'); |
305 }, | 313 }, |
306 | 314 |
307 /** | 315 /** |
308 * Shows the icon for the app. That is, it causes chrome to load the app | 316 * Shows the icon for the app. That is, it causes chrome to load the app |
309 * icon resource. | 317 * icon resource. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 * @param {Object} notification The notification to show in the bubble. | 360 * @param {Object} notification The notification to show in the bubble. |
353 * @private | 361 * @private |
354 */ | 362 */ |
355 setupNotification_: function(notification) { | 363 setupNotification_: function(notification) { |
356 if (notification) { | 364 if (notification) { |
357 var infoBubble; | 365 var infoBubble; |
358 if (!this.currentBubbleShowing_) { | 366 if (!this.currentBubbleShowing_) { |
359 // Create a new bubble. | 367 // Create a new bubble. |
360 infoBubble = new cr.ui.ExpandableBubble; | 368 infoBubble = new cr.ui.ExpandableBubble; |
361 infoBubble.anchorNode = this; | 369 infoBubble.anchorNode = this; |
362 infoBubble.appId = this.appData_.id; | 370 infoBubble.appId = this.data_.id; |
363 infoBubble.handleCloseEvent = function() { | 371 infoBubble.handleCloseEvent = function() { |
364 chrome.send('closeNotification', [this.appId]); | 372 chrome.send('closeNotification', [this.appId]); |
365 infoBubble.hide(); | 373 infoBubble.hide(); |
366 }; | 374 }; |
367 } else { | 375 } else { |
368 // Reuse the old bubble instead of popping up a new bubble over | 376 // Reuse the old bubble instead of popping up a new bubble over |
369 // the old one. | 377 // the old one. |
370 infoBubble = this.currentBubbleShowing_; | 378 infoBubble = this.currentBubbleShowing_; |
371 infoBubble.collapseBubble_(); | 379 infoBubble.collapseBubble_(); |
372 } | 380 } |
(...skipping 15 matching lines...) Expand all Loading... |
388 this.currentBubbleShowing_ = null; | 396 this.currentBubbleShowing_ = null; |
389 } | 397 } |
390 }, | 398 }, |
391 | 399 |
392 /** | 400 /** |
393 * Invoked when an app is clicked. | 401 * Invoked when an app is clicked. |
394 * @param {Event} e The click event. | 402 * @param {Event} e The click event. |
395 * @private | 403 * @private |
396 */ | 404 */ |
397 onClick_: function(e) { | 405 onClick_: function(e) { |
398 var url = !this.appData_.is_webstore ? '' : | 406 var url = !this.data_.is_webstore ? '' : |
399 appendParam(this.appData_.url, | 407 appendParam(this.data_.url, |
400 'utm_source', | 408 'utm_source', |
401 'chrome-ntp-icon'); | 409 'chrome-ntp-icon'); |
402 | 410 |
403 chrome.send('launchApp', | 411 chrome.send('launchApp', |
404 [this.appId, APP_LAUNCH.NTP_APPS_MAXIMIZED, url, | 412 [this.appId, APP_LAUNCH.NTP_APPS_MAXIMIZED, url, |
405 e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey]); | 413 e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey]); |
406 | 414 |
407 // Don't allow the click to trigger a link or anything | 415 // Don't allow the click to trigger a link or anything |
408 e.preventDefault(); | 416 e.preventDefault(); |
409 }, | 417 }, |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 } else { | 485 } else { |
478 this.appContents_.classList.remove('suppress-active'); | 486 this.appContents_.classList.remove('suppress-active'); |
479 } | 487 } |
480 | 488 |
481 // This class is here so we don't show the focus state for apps that | 489 // This class is here so we don't show the focus state for apps that |
482 // gain keyboard focus via mouse clicking. | 490 // gain keyboard focus via mouse clicking. |
483 this.classList.add('click-focus'); | 491 this.classList.add('click-focus'); |
484 }, | 492 }, |
485 | 493 |
486 /** | 494 /** |
487 * Change the appData and update the appearance of the app. | 495 * Change the data and update the appearance of the app. |
488 * @param {Object} appData The new data object that describes the app. | 496 * @param {Object} data The new data object that describes the app. |
489 */ | 497 */ |
490 replaceAppData: function(appData) { | 498 replaceAppData: function(data) { |
491 this.appData_ = appData; | 499 assert(data); |
| 500 this.data = data; |
492 this.setIcon(); | 501 this.setIcon(); |
493 this.loadIcon(); | 502 this.loadIcon(); |
494 }, | 503 }, |
495 | 504 |
496 /** | 505 /** |
497 * The data and preferences for this app. | 506 * The data and preferences for this app. |
498 * @type {Object} | 507 * @type {Object} |
499 */ | 508 */ |
500 set appData(data) { | 509 set data(data) { |
501 this.appData_ = data; | 510 Object.getOwnPropertyDescriptor(Tile.prototype, 'data').set.apply(this, |
| 511 arguments); |
| 512 |
| 513 this.formatApp_(data); |
502 }, | 514 }, |
503 get appData() { | 515 get data() { |
504 return this.appData_; | 516 return this.data_; |
505 }, | 517 }, |
506 | 518 |
507 get appId() { | 519 get appId() { |
508 return this.appData_.id; | 520 return this.data_.id; |
509 }, | 521 }, |
510 | 522 |
511 /** | 523 /** |
512 * Returns a pointer to the context menu for this app. All apps share the | 524 * Returns a pointer to the context menu for this app. All apps share the |
513 * singleton AppContextMenu. This function is called by the | 525 * singleton AppContextMenu. This function is called by the |
514 * ContextMenuHandler in response to the 'contextmenu' event. | 526 * ContextMenuHandler in response to the 'contextmenu' event. |
515 * @type {cr.ui.Menu} | 527 * @type {cr.ui.Menu} |
516 */ | 528 */ |
517 get contextMenu() { | 529 get contextMenu() { |
518 var menu = AppContextMenu.getInstance(); | 530 var menu = AppContextMenu.getInstance(); |
519 menu.setupForApp(this); | 531 menu.setupForApp(this); |
520 return menu.menu; | 532 return menu.menu; |
521 }, | 533 }, |
522 | 534 |
523 /** | 535 /** |
524 * Returns whether this element can be 'removed' from chrome (i.e. whether | 536 * Returns whether this element can be 'removed' from chrome (i.e. whether |
525 * the user can drag it onto the trash and expect something to happen). | 537 * the user can drag it onto the trash and expect something to happen). |
526 * @return {boolean} True if the app can be uninstalled. | 538 * @return {boolean} True if the app can be uninstalled. |
527 */ | 539 */ |
528 canBeRemoved: function() { | 540 canBeRemoved: function() { |
529 return this.appData_.mayDisable; | 541 return this.data_.mayDisable; |
530 }, | 542 }, |
531 | 543 |
532 /** | 544 /** |
533 * Uninstalls the app after it's been dropped on the trash. | 545 * Uninstalls the app after it's been dropped on the trash. |
534 */ | 546 */ |
535 removeFromChrome: function() { | 547 removeFromChrome: function() { |
536 chrome.send('uninstallApp', [this.appData_.id, true]); | 548 chrome.send('uninstallApp', [this.data_.id, true]); |
537 this.tile.tilePage.removeTile(this.tile, true); | 549 this.tile.tilePage.removeTile(this.tile, true); |
538 if (this.currentBubbleShowing_) | 550 if (this.currentBubbleShowing_) |
539 this.currentBubbleShowing_.hide(); | 551 this.currentBubbleShowing_.hide(); |
540 }, | 552 }, |
541 | |
542 /** | |
543 * Called when a drag is starting on the tile. Updates dataTransfer with | |
544 * data for this tile. | |
545 */ | |
546 setDragData: function(dataTransfer) { | |
547 dataTransfer.setData('Text', this.appData_.title); | |
548 dataTransfer.setData('URL', this.appData_.url); | |
549 }, | |
550 }); | 553 }); |
551 | 554 |
552 /** | 555 /** |
553 * Creates a new AppsPage object. | 556 * Creates a new AppsPage object. |
554 * @constructor | 557 * @constructor |
555 * @extends {TilePage} | 558 * @extends {TilePage} |
556 */ | 559 */ |
557 function AppsPage() { | 560 function AppsPage() { |
558 var el = new TilePage(); | 561 var el = new TilePage(); |
559 el.__proto__ = AppsPage.prototype; | 562 el.__proto__ = AppsPage.prototype; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 // view. | 599 // view. |
597 this.addEventListener('carddeselected', this.onCardDeselected_); | 600 this.addEventListener('carddeselected', this.onCardDeselected_); |
598 this.addEventListener('cardSlider:card_change_ended', | 601 this.addEventListener('cardSlider:card_change_ended', |
599 this.onCardChangeEnded_); | 602 this.onCardChangeEnded_); |
600 | 603 |
601 this.addEventListener('tilePage:tile_added', this.onTileAdded_); | 604 this.addEventListener('tilePage:tile_added', this.onTileAdded_); |
602 }, | 605 }, |
603 | 606 |
604 /** | 607 /** |
605 * Highlight a newly installed app as it's added to the NTP. | 608 * Highlight a newly installed app as it's added to the NTP. |
606 * @param {Object} appData The data object that describes the app. | 609 * @param {Object} data The data object that describes the app. |
607 */ | 610 */ |
608 insertAndHighlightApp: function(appData) { | 611 insertAndHighlightApp: function(data) { |
609 ntp.getCardSlider().selectCardByValue(this); | 612 ntp.getCardSlider().selectCardByValue(this); |
610 this.insertApp(appData, true); | 613 this.insertApp(data, true); |
611 }, | 614 }, |
612 | 615 |
613 /** | 616 /** |
614 * Inserts an App into the TilePage, preserving the alphabetical order. | 617 * Inserts an App into the TilePage, preserving the alphabetical order. |
615 * @param {Object} appData The data that describes the app. | 618 * @param {Object} data The data that describes the app. |
616 * @param {boolean} animate Whether to animate the insertion. | 619 * @param {boolean} animate Whether to animate the insertion. |
617 */ | 620 */ |
618 insertApp: function(appData, animate) { | 621 insertApp: function(data, animate) { |
619 var index = this.tiles_.length; | 622 var index = this.tiles_.length; |
620 for (var i = 0; i < this.tiles_.length; i++) { | 623 for (var i = 0; i < this.tiles_.length; i++) { |
621 if (appData.title.toLocaleLowerCase() < | 624 if (data.title.toLocaleLowerCase() < |
622 this.tiles_[i].appData.title.toLocaleLowerCase()) { | 625 this.tiles_[i].data.title.toLocaleLowerCase()) { |
623 index = i; | 626 index = i; |
624 break; | 627 break; |
625 } | 628 } |
626 } | 629 } |
627 | 630 |
628 var app = new App(appData); | 631 var app = new App(data); |
629 this.addTileAt(app, index); | 632 this.addTileAt(app, index); |
630 this.renderGrid_(); | 633 this.renderGrid_(); |
631 }, | 634 }, |
632 | 635 |
633 /** | 636 /** |
634 * Handler for 'cardselected' event, fired when |this| is selected. The | 637 * Handler for 'cardselected' event, fired when |this| is selected. The |
635 * first time this is called, we load all the app icons. | 638 * first time this is called, we load all the app icons. |
636 * @private | 639 * @private |
637 */ | 640 */ |
638 onCardSelected_: function(e) { | 641 onCardSelected_: function(e) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 TilePage.prototype.onScroll.apply(this, arguments); | 693 TilePage.prototype.onScroll.apply(this, arguments); |
691 | 694 |
692 for (var i = 0; i < this.tiles_.length; i++) { | 695 for (var i = 0; i < this.tiles_.length; i++) { |
693 var app = this.tiles_[i]; | 696 var app = this.tiles_[i]; |
694 assert(app instanceof App); | 697 assert(app instanceof App); |
695 if (app.currentBubbleShowing_) | 698 if (app.currentBubbleShowing_) |
696 app.currentBubbleShowing_.resizeAndReposition(); | 699 app.currentBubbleShowing_.resizeAndReposition(); |
697 } | 700 } |
698 }, | 701 }, |
699 | 702 |
700 /** @override */ | |
701 doDragOver: function(e) { | |
702 // Only animatedly re-arrange if the user is currently dragging an app. | |
703 var tile = ntp.getCurrentlyDraggingTile(); | |
704 if (tile && tile.querySelector('.app')) { | |
705 TilePage.prototype.doDragOver.call(this, e); | |
706 } else { | |
707 e.preventDefault(); | |
708 this.setDropEffect(e.dataTransfer); | |
709 } | |
710 }, | |
711 | |
712 /** @override */ | |
713 shouldAcceptDrag: function(e) { | |
714 if (ntp.getCurrentlyDraggingTile()) | |
715 return true; | |
716 if (!e.dataTransfer || !e.dataTransfer.types) | |
717 return false; | |
718 return Array.prototype.indexOf.call(e.dataTransfer.types, | |
719 'text/uri-list') != -1; | |
720 }, | |
721 | |
722 /** @override */ | |
723 addDragData: function(dataTransfer, index) { | |
724 var sourceId = -1; | |
725 var currentlyDraggingTile = ntp.getCurrentlyDraggingTile(); | |
726 if (currentlyDraggingTile) { | |
727 var tileContents = currentlyDraggingTile.firstChild; | |
728 if (tileContents.classList.contains('app')) { | |
729 var originalPage = currentlyDraggingTile.tilePage; | |
730 var samePageDrag = originalPage == this; | |
731 sourceId = samePageDrag ? DRAG_SOURCE.SAME_APPS_PANE : | |
732 DRAG_SOURCE.OTHER_APPS_PANE; | |
733 this.tileGrid_.insertBefore(currentlyDraggingTile, | |
734 this.tileElements_[index]); | |
735 this.tileMoved(currentlyDraggingTile); | |
736 if (!samePageDrag) { | |
737 originalPage.fireRemovedEvent(currentlyDraggingTile, index, true); | |
738 this.fireAddedEvent(currentlyDraggingTile, index, true); | |
739 } | |
740 } else if (currentlyDraggingTile.querySelector('.most-visited')) { | |
741 this.generateAppForLink(tileContents.data); | |
742 sourceId = DRAG_SOURCE.MOST_VISITED_PANE; | |
743 } | |
744 } else { | |
745 this.addOutsideData_(dataTransfer); | |
746 sourceId = DRAG_SOURCE.OUTSIDE_NTP; | |
747 } | |
748 | |
749 assert(sourceId != -1); | |
750 chrome.send('metricsHandler:recordInHistogram', | |
751 ['NewTabPage.AppsPageDragSource', sourceId, DRAG_SOURCE_LIMIT]); | |
752 }, | |
753 | |
754 /** | |
755 * Adds drag data that has been dropped from a source that is not a tile. | |
756 * @param {Object} dataTransfer The data transfer object that holds drop | |
757 * data. | |
758 * @private | |
759 */ | |
760 addOutsideData_: function(dataTransfer) { | |
761 var url = dataTransfer.getData('url'); | |
762 assert(url); | |
763 | |
764 // If the dataTransfer has html data, use that html's text contents as the | |
765 // title of the new link. | |
766 var html = dataTransfer.getData('text/html'); | |
767 var title; | |
768 if (html) { | |
769 // It's important that we don't attach this node to the document | |
770 // because it might contain scripts. | |
771 var node = this.ownerDocument.createElement('div'); | |
772 node.innerHTML = html; | |
773 title = node.textContent; | |
774 } | |
775 | |
776 // Make sure title is >=1 and <=45 characters for Chrome app limits. | |
777 if (!title) | |
778 title = url; | |
779 if (title.length > 45) | |
780 title = title.substring(0, 45); | |
781 var data = {url: url, title: title}; | |
782 | |
783 // Synthesize an app. | |
784 this.generateAppForLink(data); | |
785 }, | |
786 | |
787 /** | 703 /** |
788 * Creates a new crx-less app manifest and installs it. | 704 * Creates a new crx-less app manifest and installs it. |
789 * @param {Object} data The data object describing the link. Must have |url| | 705 * @param {Object} data The data object describing the link. Must have |url| |
790 * and |title| members. | 706 * and |title| members. |
791 */ | 707 */ |
792 generateAppForLink: function(data) { | 708 generateAppForLink: function(data) { |
793 assert(data.url != undefined); | 709 assert(data.url != undefined); |
794 assert(data.title != undefined); | 710 assert(data.title != undefined); |
795 chrome.send('generateAppForLink', [data.url, data.title, 0]); | 711 chrome.send('generateAppForLink', [data.url, data.title, 0]); |
796 }, | 712 }, |
797 | |
798 /** @override */ | |
799 tileMoved: function(draggedTile) { | |
800 if (!(draggedTile.firstChild instanceof App)) | |
801 return; | |
802 | |
803 chrome.send('setPageIndex', [draggedTile.firstChild.appId, 0]); | |
804 | |
805 var appIds = []; | |
806 for (var i = 0; i < this.tiles_.length; i++) { | |
807 var tileContents = this.tiles_[i]; | |
808 if (tileContents instanceof App) | |
809 appIds.push(tileContents.appId); | |
810 } | |
811 | |
812 chrome.send('reorderApps', [draggedTile.firstChild.appId, appIds]); | |
813 }, | |
814 | |
815 /** @override */ | |
816 setDropEffect: function(dataTransfer) { | |
817 var tile = ntp.getCurrentlyDraggingTile(); | |
818 if (tile && tile.querySelector('.app')) | |
819 ntp.setCurrentDropEffect(dataTransfer, 'move'); | |
820 else | |
821 ntp.setCurrentDropEffect(dataTransfer, 'copy'); | |
822 }, | |
823 }; | 713 }; |
824 | 714 |
825 /** | 715 /** |
826 * Launches the specified app using the APP_LAUNCH_NTP_APP_RE_ENABLE | 716 * Launches the specified app using the APP_LAUNCH_NTP_APP_RE_ENABLE |
827 * histogram. This should only be invoked from the AppLauncherHandler. | 717 * histogram. This should only be invoked from the AppLauncherHandler. |
828 * @param {String} appID The ID of the app. | 718 * @param {String} appID The ID of the app. |
829 */ | 719 */ |
830 function launchAppAfterEnable(appId) { | 720 function launchAppAfterEnable(appId) { |
831 chrome.send('launchApp', [appId, APP_LAUNCH.NTP_APP_RE_ENABLE]); | 721 chrome.send('launchApp', [appId, APP_LAUNCH.NTP_APP_RE_ENABLE]); |
832 } | 722 } |
833 | 723 |
834 function appNotificationChanged(id, notification) { | 724 function appNotificationChanged(id, notification) { |
835 var app = $(id); | 725 var app = $(id); |
836 // The app might have been uninstalled, or notifications might be disabled. | 726 // The app might have been uninstalled, or notifications might be disabled. |
837 if (app && !app.appData.notifications_disabled) | 727 if (app && !app.data.notifications_disabled) |
838 app.setupNotification_(notification); | 728 app.setupNotification_(notification); |
839 } | 729 } |
840 | 730 |
841 return { | 731 return { |
842 appNotificationChanged: appNotificationChanged, | 732 appNotificationChanged: appNotificationChanged, |
843 AppsPage: AppsPage, | 733 AppsPage: AppsPage, |
844 launchAppAfterEnable: launchAppAfterEnable, | 734 launchAppAfterEnable: launchAppAfterEnable, |
845 }; | 735 }; |
846 }); | 736 }); |
OLD | NEW |