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() { |
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_(); |
198 | 195 |
199 return el; | 196 return el; |
200 } | 197 } |
201 | 198 |
202 App.prototype = Tile.subclass({ | 199 App.prototype = Tile.subclass({ |
203 __proto__: HTMLDivElement.prototype, | 200 __proto__: HTMLDivElement.prototype, |
204 | 201 |
205 /** | 202 /** |
206 * Initialize the app object. | 203 * Initialize the app object. |
207 * @param {Object} appData The data object that describes the app. | 204 * @param {Object} data The data object that describes the app. |
205 * @private | |
208 */ | 206 */ |
209 initialize: function(appData) { | 207 initialize_: function(data) { |
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 * Initialize the app object. | |
Dan Beam
2012/12/11 01:49:24
give a new description highlighting how it's diffe
pedro (no code reviews)
2012/12/11 07:20:53
Done.
| |
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 if (!this.appContents_) { |
Dan Beam
2012/12/11 01:49:24
what happens if you want to re-use apps - does thi
pedro (no code reviews)
2012/12/11 07:20:53
This change does not break the ability to do that.
Dan Beam
2012/12/11 22:47:23
this.useSmallIcon_ is based on this.data, so if yo
pedro (no code reviews)
2012/12/11 23:23:15
No, that's not entirely correct. If an already 'pa
| |
223 $('app-small-icon-template').cloneNode(true) : | 228 this.appContents_ = this.useSmallIcon_ ? |
224 $('app-large-icon-template').cloneNode(true); | 229 $('app-small-icon-template').cloneNode(true) : |
225 this.appContents_.id = ''; | 230 $('app-large-icon-template').cloneNode(true); |
226 this.appendChild(this.appContents_); | 231 this.appContents_.id = ''; |
232 this.appendChild(this.appContents_); | |
233 } | |
227 | 234 |
228 this.appImgContainer_ = this.querySelector('.app-img-container'); | 235 this.appImgContainer_ = this.querySelector('.app-img-container'); |
229 this.appImg_ = this.appImgContainer_.querySelector('img'); | 236 this.appImg_ = this.appImgContainer_.querySelector('img'); |
230 this.setIcon(); | 237 this.setIcon(); |
231 | 238 |
232 if (this.useSmallIcon_) { | 239 if (this.useSmallIcon_) { |
233 this.imgDiv_ = this.querySelector('.app-icon-div'); | 240 this.imgDiv_ = this.querySelector('.app-icon-div'); |
234 this.addLaunchClickTarget_(this.imgDiv_); | 241 this.addLaunchClickTarget_(this.imgDiv_); |
235 this.imgDiv_.title = this.appData_.title; | 242 this.imgDiv_.title = this.data_.title; |
236 chrome.send('getAppIconDominantColor', [this.id]); | 243 chrome.send('getAppIconDominantColor', [this.id]); |
237 } else { | 244 } else { |
238 this.addLaunchClickTarget_(this.appImgContainer_); | 245 this.addLaunchClickTarget_(this.appImgContainer_); |
239 this.appImgContainer_.title = this.appData_.title; | 246 this.appImgContainer_.title = this.data_.title; |
240 } | 247 } |
241 | 248 |
242 var appSpan = this.appContents_.querySelector('.title'); | 249 var appSpan = this.appContents_.querySelector('.title'); |
243 appSpan.textContent = appSpan.title = this.appData_.title; | 250 appSpan.textContent = appSpan.title = this.data_.title; |
244 this.addLaunchClickTarget_(appSpan); | 251 this.addLaunchClickTarget_(appSpan); |
245 | 252 |
246 var notification = this.appData_.notification; | 253 var notification = this.data_.notification; |
247 var hasNotification = typeof notification != 'undefined' && | 254 var hasNotification = typeof notification != 'undefined' && |
248 typeof notification['title'] != 'undefined' && | 255 typeof notification['title'] != 'undefined' && |
249 typeof notification['body'] != 'undefined' && | 256 typeof notification['body'] != 'undefined' && |
250 !this.appData_.notifications_disabled; | 257 !this.data_.notifications_disabled; |
251 if (hasNotification) | 258 if (hasNotification) |
252 this.setupNotification_(notification); | 259 this.setupNotification_(notification); |
253 | 260 |
254 this.addEventListener('keydown', cr.ui.contextMenuHandler); | 261 this.addEventListener('keydown', cr.ui.contextMenuHandler); |
255 this.addEventListener('keyup', cr.ui.contextMenuHandler); | 262 this.addEventListener('keyup', cr.ui.contextMenuHandler); |
256 | 263 |
257 // This hack is here so that appContents.contextMenu will be the same as | 264 // This hack is here so that appContents.contextMenu will be the same as |
258 // this.contextMenu. | 265 // this.contextMenu. |
259 var self = this; | 266 var self = this; |
260 this.appContents_.__defineGetter__('contextMenu', function() { | 267 this.appContents_.__defineGetter__('contextMenu', function() { |
(...skipping 20 matching lines...) Expand all Loading... | |
281 * been uninstalled. | 288 * been uninstalled. |
282 */ | 289 */ |
283 remove: function(opt_animate) { | 290 remove: function(opt_animate) { |
284 // Unset the ID immediately, because the app is already gone. But leave | 291 // Unset the ID immediately, because the app is already gone. But leave |
285 // the tile on the page as it animates out. | 292 // the tile on the page as it animates out. |
286 this.id = ''; | 293 this.id = ''; |
287 this.tileCell.doRemove(opt_animate); | 294 this.tileCell.doRemove(opt_animate); |
288 }, | 295 }, |
289 | 296 |
290 /** | 297 /** |
291 * Set the URL of the icon from |appData_|. This won't actually show the | 298 * 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 | 299 * icon until loadIcon() is called (for performance reasons; we don't want |
293 * to load icons until we have to). | 300 * to load icons until we have to). |
294 */ | 301 */ |
295 setIcon: function() { | 302 setIcon: function() { |
296 var src = this.useSmallIcon_ ? this.appData_.icon_small : | 303 var src = this.useSmallIcon_ ? this.data_.icon_small : |
297 this.appData_.icon_big; | 304 this.data_.icon_big; |
298 if (!this.appData_.enabled || | 305 if (!this.data_.enabled || |
299 (!this.appData_.offlineEnabled && !navigator.onLine)) { | 306 (!this.data_.offlineEnabled && !navigator.onLine)) { |
300 src += '?grayscale=true'; | 307 src += '?grayscale=true'; |
301 } | 308 } |
302 | 309 |
303 this.appImgSrc_ = src; | 310 this.appImgSrc_ = src; |
304 this.classList.add('icon-loading'); | 311 this.classList.add('icon-loading'); |
305 }, | 312 }, |
306 | 313 |
307 /** | 314 /** |
308 * Shows the icon for the app. That is, it causes chrome to load the app | 315 * Shows the icon for the app. That is, it causes chrome to load the app |
309 * icon resource. | 316 * 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. | 359 * @param {Object} notification The notification to show in the bubble. |
353 * @private | 360 * @private |
354 */ | 361 */ |
355 setupNotification_: function(notification) { | 362 setupNotification_: function(notification) { |
356 if (notification) { | 363 if (notification) { |
357 var infoBubble; | 364 var infoBubble; |
358 if (!this.currentBubbleShowing_) { | 365 if (!this.currentBubbleShowing_) { |
359 // Create a new bubble. | 366 // Create a new bubble. |
360 infoBubble = new cr.ui.ExpandableBubble; | 367 infoBubble = new cr.ui.ExpandableBubble; |
361 infoBubble.anchorNode = this; | 368 infoBubble.anchorNode = this; |
362 infoBubble.appId = this.appData_.id; | 369 infoBubble.appId = this.data_.id; |
363 infoBubble.handleCloseEvent = function() { | 370 infoBubble.handleCloseEvent = function() { |
364 chrome.send('closeNotification', [this.appId]); | 371 chrome.send('closeNotification', [this.appId]); |
365 infoBubble.hide(); | 372 infoBubble.hide(); |
366 }; | 373 }; |
367 } else { | 374 } else { |
368 // Reuse the old bubble instead of popping up a new bubble over | 375 // Reuse the old bubble instead of popping up a new bubble over |
369 // the old one. | 376 // the old one. |
370 infoBubble = this.currentBubbleShowing_; | 377 infoBubble = this.currentBubbleShowing_; |
371 infoBubble.collapseBubble_(); | 378 infoBubble.collapseBubble_(); |
372 } | 379 } |
(...skipping 15 matching lines...) Expand all Loading... | |
388 this.currentBubbleShowing_ = null; | 395 this.currentBubbleShowing_ = null; |
389 } | 396 } |
390 }, | 397 }, |
391 | 398 |
392 /** | 399 /** |
393 * Invoked when an app is clicked. | 400 * Invoked when an app is clicked. |
394 * @param {Event} e The click event. | 401 * @param {Event} e The click event. |
395 * @private | 402 * @private |
396 */ | 403 */ |
397 onClick_: function(e) { | 404 onClick_: function(e) { |
398 var url = !this.appData_.is_webstore ? '' : | 405 var url = !this.data_.is_webstore ? '' : |
399 appendParam(this.appData_.url, | 406 appendParam(this.data_.url, |
400 'utm_source', | 407 'utm_source', |
401 'chrome-ntp-icon'); | 408 'chrome-ntp-icon'); |
402 | 409 |
403 chrome.send('launchApp', | 410 chrome.send('launchApp', |
404 [this.appId, APP_LAUNCH.NTP_APPS_MAXIMIZED, url, | 411 [this.appId, APP_LAUNCH.NTP_APPS_MAXIMIZED, url, |
405 e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey]); | 412 e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey]); |
406 | 413 |
407 // Don't allow the click to trigger a link or anything | 414 // Don't allow the click to trigger a link or anything |
408 e.preventDefault(); | 415 e.preventDefault(); |
409 }, | 416 }, |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
477 } else { | 484 } else { |
478 this.appContents_.classList.remove('suppress-active'); | 485 this.appContents_.classList.remove('suppress-active'); |
479 } | 486 } |
480 | 487 |
481 // This class is here so we don't show the focus state for apps that | 488 // This class is here so we don't show the focus state for apps that |
482 // gain keyboard focus via mouse clicking. | 489 // gain keyboard focus via mouse clicking. |
483 this.classList.add('click-focus'); | 490 this.classList.add('click-focus'); |
484 }, | 491 }, |
485 | 492 |
486 /** | 493 /** |
487 * Change the appData and update the appearance of the app. | 494 * Change the data and update the appearance of the app. |
488 * @param {Object} appData The new data object that describes the app. | 495 * @param {Object} data The new data object that describes the app. |
489 */ | 496 */ |
490 replaceAppData: function(appData) { | 497 replaceAppData: function(data) { |
491 this.appData_ = appData; | 498 assert(data); |
499 this.data = data; | |
492 this.setIcon(); | 500 this.setIcon(); |
493 this.loadIcon(); | 501 this.loadIcon(); |
494 }, | 502 }, |
495 | 503 |
496 /** | 504 /** |
497 * The data and preferences for this app. | 505 * The data and preferences for this app. |
498 * @type {Object} | 506 * @type {Object} |
499 */ | 507 */ |
500 set appData(data) { | 508 set data(data) { |
501 this.appData_ = data; | 509 Object.getOwnPropertyDescriptor(Tile.prototype, 'data').set.apply(this, |
510 arguments); | |
511 | |
512 this.formatApp_(data); | |
Dan Beam
2012/12/11 01:49:24
what is the difference between formatApp_, replace
pedro (no code reviews)
2012/12/11 07:20:53
'set data' is the setter of, well, data. When that
| |
502 }, | 513 }, |
503 get appData() { | 514 get data() { |
504 return this.appData_; | 515 return this.data_; |
505 }, | 516 }, |
506 | 517 |
507 get appId() { | 518 get appId() { |
508 return this.appData_.id; | 519 return this.data_.id; |
509 }, | 520 }, |
510 | 521 |
511 /** | 522 /** |
512 * Returns a pointer to the context menu for this app. All apps share the | 523 * Returns a pointer to the context menu for this app. All apps share the |
513 * singleton AppContextMenu. This function is called by the | 524 * singleton AppContextMenu. This function is called by the |
514 * ContextMenuHandler in response to the 'contextmenu' event. | 525 * ContextMenuHandler in response to the 'contextmenu' event. |
515 * @type {cr.ui.Menu} | 526 * @type {cr.ui.Menu} |
516 */ | 527 */ |
517 get contextMenu() { | 528 get contextMenu() { |
518 var menu = AppContextMenu.getInstance(); | 529 var menu = AppContextMenu.getInstance(); |
519 menu.setupForApp(this); | 530 menu.setupForApp(this); |
520 return menu.menu; | 531 return menu.menu; |
521 }, | 532 }, |
522 | 533 |
523 /** | 534 /** |
524 * Returns whether this element can be 'removed' from chrome (i.e. whether | 535 * 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). | 536 * the user can drag it onto the trash and expect something to happen). |
526 * @return {boolean} True if the app can be uninstalled. | 537 * @return {boolean} True if the app can be uninstalled. |
527 */ | 538 */ |
528 canBeRemoved: function() { | 539 canBeRemoved: function() { |
529 return this.appData_.mayDisable; | 540 return this.data_.mayDisable; |
530 }, | 541 }, |
531 | 542 |
532 /** | 543 /** |
533 * Uninstalls the app after it's been dropped on the trash. | 544 * Uninstalls the app after it's been dropped on the trash. |
534 */ | 545 */ |
535 removeFromChrome: function() { | 546 removeFromChrome: function() { |
536 chrome.send('uninstallApp', [this.appData_.id, true]); | 547 chrome.send('uninstallApp', [this.data_.id, true]); |
537 this.tile.tilePage.removeTile(this.tile, true); | 548 this.tile.tilePage.removeTile(this.tile, true); |
538 if (this.currentBubbleShowing_) | 549 if (this.currentBubbleShowing_) |
539 this.currentBubbleShowing_.hide(); | 550 this.currentBubbleShowing_.hide(); |
540 }, | 551 }, |
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 }); | 552 }); |
551 | 553 |
552 /** | 554 /** |
553 * Creates a new AppsPage object. | 555 * Creates a new AppsPage object. |
554 * @constructor | 556 * @constructor |
555 * @extends {TilePage} | 557 * @extends {TilePage} |
556 */ | 558 */ |
557 function AppsPage() { | 559 function AppsPage() { |
558 var el = new TilePage(); | 560 var el = new TilePage(); |
559 el.__proto__ = AppsPage.prototype; | 561 el.__proto__ = AppsPage.prototype; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
596 // view. | 598 // view. |
597 this.addEventListener('carddeselected', this.onCardDeselected_); | 599 this.addEventListener('carddeselected', this.onCardDeselected_); |
598 this.addEventListener('cardSlider:card_change_ended', | 600 this.addEventListener('cardSlider:card_change_ended', |
599 this.onCardChangeEnded_); | 601 this.onCardChangeEnded_); |
600 | 602 |
601 this.addEventListener('tilePage:tile_added', this.onTileAdded_); | 603 this.addEventListener('tilePage:tile_added', this.onTileAdded_); |
602 }, | 604 }, |
603 | 605 |
604 /** | 606 /** |
605 * Highlight a newly installed app as it's added to the NTP. | 607 * Highlight a newly installed app as it's added to the NTP. |
606 * @param {Object} appData The data object that describes the app. | 608 * @param {Object} data The data object that describes the app. |
607 */ | 609 */ |
608 insertAndHighlightApp: function(appData) { | 610 insertAndHighlightApp: function(data) { |
609 ntp.getCardSlider().selectCardByValue(this); | 611 ntp.getCardSlider().selectCardByValue(this); |
610 this.insertApp(appData, true); | 612 this.insertApp(data, true); |
611 }, | 613 }, |
612 | 614 |
613 /** | 615 /** |
614 * Inserts an App into the TilePage, preserving the alphabetical order. | 616 * Inserts an App into the TilePage, preserving the alphabetical order. |
615 * @param {Object} appData The data that describes the app. | 617 * @param {Object} data The data that describes the app. |
616 * @param {boolean} animate Whether to animate the insertion. | 618 * @param {boolean} animate Whether to animate the insertion. |
617 */ | 619 */ |
618 insertApp: function(appData, animate) { | 620 insertApp: function(data, animate) { |
619 var index = this.tiles_.length; | 621 var index = this.tiles_.length; |
620 for (var i = 0; i < this.tiles_.length; i++) { | 622 for (var i = 0; i < this.tiles_.length; i++) { |
621 if (appData.title.toLocaleLowerCase() < | 623 if (data.title.toLocaleLowerCase() < |
622 this.tiles_[i].appData.title.toLocaleLowerCase()) { | 624 this.tiles_[i].data.title.toLocaleLowerCase()) { |
623 index = i; | 625 index = i; |
624 break; | 626 break; |
625 } | 627 } |
626 } | 628 } |
627 | 629 |
628 var app = new App(appData); | 630 // TODO(pedrosimonetti): Refactor code so instantiation is new App(data). |
Dan Beam
2012/12/11 01:49:24
why TODO() when you could just do?
pedro (no code reviews)
2012/12/11 07:20:53
Because not having to do this would've made this C
| |
631 var app = new App(); | |
632 app.data = data; | |
629 this.addTileAt(app, index); | 633 this.addTileAt(app, index); |
630 this.renderGrid_(); | 634 this.renderGrid_(); |
631 }, | 635 }, |
632 | 636 |
633 /** | 637 /** |
634 * Handler for 'cardselected' event, fired when |this| is selected. The | 638 * Handler for 'cardselected' event, fired when |this| is selected. The |
635 * first time this is called, we load all the app icons. | 639 * first time this is called, we load all the app icons. |
636 * @private | 640 * @private |
637 */ | 641 */ |
638 onCardSelected_: function(e) { | 642 onCardSelected_: function(e) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
690 TilePage.prototype.onScroll.apply(this, arguments); | 694 TilePage.prototype.onScroll.apply(this, arguments); |
691 | 695 |
692 for (var i = 0; i < this.tiles_.length; i++) { | 696 for (var i = 0; i < this.tiles_.length; i++) { |
693 var app = this.tiles_[i]; | 697 var app = this.tiles_[i]; |
694 assert(app instanceof App); | 698 assert(app instanceof App); |
695 if (app.currentBubbleShowing_) | 699 if (app.currentBubbleShowing_) |
696 app.currentBubbleShowing_.resizeAndReposition(); | 700 app.currentBubbleShowing_.resizeAndReposition(); |
697 } | 701 } |
698 }, | 702 }, |
699 | 703 |
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 /** | 704 /** |
788 * Creates a new crx-less app manifest and installs it. | 705 * Creates a new crx-less app manifest and installs it. |
789 * @param {Object} data The data object describing the link. Must have |url| | 706 * @param {Object} data The data object describing the link. Must have |url| |
790 * and |title| members. | 707 * and |title| members. |
791 */ | 708 */ |
792 generateAppForLink: function(data) { | 709 generateAppForLink: function(data) { |
793 assert(data.url != undefined); | 710 assert(data.url != undefined); |
794 assert(data.title != undefined); | 711 assert(data.title != undefined); |
795 chrome.send('generateAppForLink', [data.url, data.title, 0]); | 712 chrome.send('generateAppForLink', [data.url, data.title, 0]); |
796 }, | 713 }, |
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 }; | 714 }; |
824 | 715 |
825 /** | 716 /** |
826 * Launches the specified app using the APP_LAUNCH_NTP_APP_RE_ENABLE | 717 * Launches the specified app using the APP_LAUNCH_NTP_APP_RE_ENABLE |
827 * histogram. This should only be invoked from the AppLauncherHandler. | 718 * histogram. This should only be invoked from the AppLauncherHandler. |
828 * @param {String} appID The ID of the app. | 719 * @param {String} appID The ID of the app. |
829 */ | 720 */ |
830 function launchAppAfterEnable(appId) { | 721 function launchAppAfterEnable(appId) { |
831 chrome.send('launchApp', [appId, APP_LAUNCH.NTP_APP_RE_ENABLE]); | 722 chrome.send('launchApp', [appId, APP_LAUNCH.NTP_APP_RE_ENABLE]); |
832 } | 723 } |
833 | 724 |
834 function appNotificationChanged(id, notification) { | 725 function appNotificationChanged(id, notification) { |
835 var app = $(id); | 726 var app = $(id); |
836 // The app might have been uninstalled, or notifications might be disabled. | 727 // The app might have been uninstalled, or notifications might be disabled. |
837 if (app && !app.appData.notifications_disabled) | 728 if (app && !app.data.notifications_disabled) |
838 app.setupNotification_(notification); | 729 app.setupNotification_(notification); |
839 } | 730 } |
840 | 731 |
841 return { | 732 return { |
842 appNotificationChanged: appNotificationChanged, | 733 appNotificationChanged: appNotificationChanged, |
843 AppsPage: AppsPage, | 734 AppsPage: AppsPage, |
844 launchAppAfterEnable: launchAppAfterEnable, | 735 launchAppAfterEnable: launchAppAfterEnable, |
845 }; | 736 }; |
846 }); | 737 }); |
OLD | NEW |