Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 // The URL prefix used in the app link 'ping' attributes. | 9 // The URL prefix used in the app link 'ping' attributes. |
| 10 var PING_APP_LAUNCH_PREFIX = 'record-app-launch'; | 10 var PING_APP_LAUNCH_PREFIX = 'record-app-launch'; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 38 $('apps-create-shortcut-command-separator').style.display = | 38 $('apps-create-shortcut-command-separator').style.display = |
| 39 (data.disableCreateAppShortcut ? 'none' : ''); | 39 (data.disableCreateAppShortcut ? 'none' : ''); |
| 40 | 40 |
| 41 appsMiniview.textContent = ''; | 41 appsMiniview.textContent = ''; |
| 42 appsSectionContent.textContent = ''; | 42 appsSectionContent.textContent = ''; |
| 43 | 43 |
| 44 data.apps.sort(function(a,b) { | 44 data.apps.sort(function(a,b) { |
| 45 return a.app_launch_index - b.app_launch_index; | 45 return a.app_launch_index - b.app_launch_index; |
| 46 }); | 46 }); |
| 47 | 47 |
| 48 // Determines if the web store link should be detached and place in the | |
| 49 // top right of the screen. | |
| 50 apps.detachWebstoreEntry = | |
| 51 !apps.showPromo && data.apps.length >= MAX_APPS_PER_ROW[layoutMode]; | |
| 52 | |
| 53 apps.data = data.apps; | |
| 54 if (!apps.detachWebstoreEntry) | |
| 55 apps.data.push('web-store-entry'); | |
| 56 | |
| 48 clearClosedMenu(apps.menu); | 57 clearClosedMenu(apps.menu); |
| 49 data.apps.forEach(function(app) { | 58 data.apps.forEach(function(app) { |
| 50 appsSectionContent.appendChild(apps.createElement(app)); | 59 appsSectionContent.appendChild(apps.createElement(app)); |
| 51 }); | 60 }); |
| 52 | 61 |
| 53 webStoreEntry = apps.createWebStoreElement(); | 62 webStoreEntry = apps.createWebStoreElement(); |
| 54 webStoreEntry.querySelector('a').setAttribute('ping', appsPromoPing); | 63 webStoreEntry.querySelector('a').setAttribute('ping', appsPromoPing); |
| 55 appsSectionContent.appendChild(webStoreEntry); | 64 appsSectionContent.appendChild(webStoreEntry); |
| 56 | 65 |
| 57 data.apps.slice(0, MAX_MINIVIEW_ITEMS).forEach(function(app) { | 66 data.apps.slice(0, MAX_MINIVIEW_ITEMS).forEach(function(app) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 77 if (apps.showPromo) | 86 if (apps.showPromo) |
| 78 document.documentElement.classList.add('apps-promo-visible'); | 87 document.documentElement.classList.add('apps-promo-visible'); |
| 79 else | 88 else |
| 80 document.documentElement.classList.remove('apps-promo-visible'); | 89 document.documentElement.classList.remove('apps-promo-visible'); |
| 81 | 90 |
| 82 var appsPromoLink = $('apps-promo-link'); | 91 var appsPromoLink = $('apps-promo-link'); |
| 83 if (appsPromoLink) | 92 if (appsPromoLink) |
| 84 appsPromoLink.setAttribute('ping', appsPromoPing); | 93 appsPromoLink.setAttribute('ping', appsPromoPing); |
| 85 maybeDoneLoading(); | 94 maybeDoneLoading(); |
| 86 | 95 |
| 96 // Disable the animations when the app launcher is being (re)initailized. | |
| 97 apps.layout(true); | |
| 98 | |
| 99 if (apps.detachWebstoreEntry) | |
| 100 webStoreEntry.classList.add('loner'); | |
| 101 else | |
| 102 webStoreEntry.classList.remove('loner'); | |
| 103 | |
| 87 if (isDoneLoading()) { | 104 if (isDoneLoading()) { |
| 88 if (!apps.showPromo && data.apps.length >= MAX_APPS_PER_ROW[layoutMode]) | |
| 89 webStoreEntry.classList.add('loner'); | |
| 90 else | |
| 91 webStoreEntry.classList.remove('loner'); | |
| 92 | |
| 93 updateMiniviewClipping(appsMiniview); | 105 updateMiniviewClipping(appsMiniview); |
| 94 layoutSections(); | 106 layoutSections(); |
| 95 } | 107 } |
| 96 } | 108 } |
| 97 | 109 |
| 98 function appsPrefChangeCallback(data) { | 110 function appsPrefChangeCallback(data) { |
| 99 // Currently the only pref that is watched is the launch type. | 111 // Currently the only pref that is watched is the launch type. |
| 100 data.apps.forEach(function(app) { | 112 data.apps.forEach(function(app) { |
| 101 var appLink = document.querySelector('.app a[app-id=' + app['id'] + ']'); | 113 var appLink = document.querySelector('.app a[app-id=' + app['id'] + ']'); |
| 102 if (appLink) | 114 if (appLink) |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 254 case 'apps-options-command': | 266 case 'apps-options-command': |
| 255 e.canExecute = currentApp && currentApp['options_url']; | 267 e.canExecute = currentApp && currentApp['options_url']; |
| 256 break; | 268 break; |
| 257 case 'apps-launch-command': | 269 case 'apps-launch-command': |
| 258 case 'apps-uninstall-command': | 270 case 'apps-uninstall-command': |
| 259 e.canExecute = true; | 271 e.canExecute = true; |
| 260 break; | 272 break; |
| 261 } | 273 } |
| 262 }); | 274 }); |
| 263 | 275 |
| 276 // Moves the element at position |from| in array |arr| to position |to|. | |
| 277 function arrayMove(arr, from, to) { | |
| 278 var element = arr.splice(from, 1); | |
| 279 arr.splice(to, 0, element[0]); | |
| 280 } | |
| 281 | |
| 264 return { | 282 return { |
| 265 loaded: false, | 283 loaded: false, |
| 266 | 284 |
| 267 menu: $('apps-menu'), | 285 menu: $('apps-menu'), |
| 268 | 286 |
| 269 showPromo: false, | 287 showPromo: false, |
| 270 | 288 |
| 289 detachWebstoreEntry: false, | |
| 290 | |
| 291 // The list of app ids, in order, of each app in the launcher. | |
| 292 data_: null, | |
| 293 get data() { return this.data_; }, | |
| 294 set data(data) { | |
| 295 var ids = []; | |
|
arv (Not doing code reviews)
2011/01/22 00:52:14
this.data_ = data.map(function(app) {
return app
jstritar
2011/01/24 01:00:42
Done.
| |
| 296 data.forEach(function(app) { | |
| 297 ids.push(app.id); | |
| 298 }); | |
| 299 this.data_ = ids; | |
| 300 this.invalidate(); | |
| 301 }, | |
| 302 | |
| 303 dirty_: true, | |
| 304 invalidate: function() { | |
| 305 this.dirty_ = true; | |
| 306 }, | |
| 307 | |
| 308 visible_: true, | |
| 309 get visible() { | |
| 310 return this.visible_; | |
| 311 }, | |
| 312 set visible(visible) { | |
| 313 this.visible_ = visible; | |
| 314 this.invalidate(); | |
| 315 }, | |
| 316 | |
| 317 // DragAndDropDelegate | |
| 318 | |
| 319 dragContainer: $('apps-content'), | |
| 320 transitionsDuration: 200, | |
| 321 | |
| 322 get dragItem() { return this.dragItem_; }, | |
| 323 set dragItem(dragItem) { | |
| 324 if (this.dragItem_ != dragItem) { | |
| 325 this.dragItem_ = dragItem; | |
| 326 this.invalidate(); | |
| 327 } | |
| 328 }, | |
| 329 | |
| 330 // These are the dimensions of each item in the app launcher. These need | |
| 331 // to be in sync with the rules in apps.css. | |
|
Aaron Boodman
2011/01/22 23:42:57
Is it possible to get them via offsetHeight/offset
jstritar
2011/01/24 01:00:42
Done.
| |
| 332 get dimensions() { | |
| 333 return { | |
| 334 itemHeight: 136, | |
| 335 itemWidth: 124, | |
| 336 marginWidth: 3, | |
| 337 marginHeight: 5, | |
| 338 borderWidth: 0 | |
| 339 }; | |
| 340 }, | |
| 341 | |
| 342 // Gets the item under the mouse event |e|. Returns null if there is no | |
| 343 // item or if the item is not draggable. | |
| 344 getItem: function(e) { | |
| 345 var item = findAncestorByClass(e.target, 'app'); | |
| 346 | |
| 347 // You can't drag the web store launcher. | |
| 348 if (item.classList.contains('web-store-entry')) | |
| 349 return null; | |
| 350 | |
| 351 return item; | |
| 352 }, | |
| 353 | |
| 354 // Returns true if |position| is a valid place to drop an app. | |
| 355 canDropOn: function(position) { | |
| 356 var appCount = this.data.length; | |
| 357 if (!this.detachWebstoreEntry) | |
| 358 appCount--; | |
| 359 return position >= 0 && position < appCount; | |
| 360 }, | |
| 361 | |
| 362 setDragPlaceholder: function(position) { | |
| 363 var appId = this.dragItem.querySelector('a').getAttribute('app-id'); | |
| 364 var current = this.data.indexOf(appId); | |
| 365 | |
| 366 if (current == position || current < 0) | |
| 367 return; | |
| 368 | |
| 369 arrayMove(this.data, current, position); | |
| 370 this.invalidate(); | |
| 371 this.layout(); | |
| 372 }, | |
| 373 | |
| 374 saveDrag: function() { | |
|
Aaron Boodman
2011/01/22 23:42:57
Method isn't called from dragdrop.js ?
jstritar
2011/01/24 01:00:42
Oops.... that could be a problem! Done.
| |
| 375 this.invalidate(); | |
| 376 this.layout(); | |
| 377 | |
| 378 // Wait until the transitions are complete before notifying the browser. | |
| 379 // Otherwise, the apps will be re-rendered while still transitioning. | |
| 380 setTimeout(function() { | |
| 381 chrome.send('reorderApps', this.data.filter(function(id) { | |
| 382 return id != 'web-store-entry'; | |
| 383 })); | |
| 384 }, this.transitionsDuration + 10); | |
| 385 }, | |
| 386 | |
| 387 layout: function(disable_animations) { | |
|
Aaron Boodman
2011/01/22 23:42:57
It sucks that it is different, but naming in JavaS
Aaron Boodman
2011/01/22 23:42:57
Style nit: I don't much care for the boolean flags
jstritar
2011/01/24 01:00:42
Done. Went with layout({disableAnimation:true}) in
jstritar
2011/01/24 01:00:42
Done.
| |
| 388 if (!this.dirty_) | |
| 389 return; | |
| 390 | |
| 391 try { | |
| 392 if (disable_animations) | |
| 393 this.dragContainer.setAttribute('launcher-animations', false); | |
| 394 var d0 = Date.now(); | |
| 395 this.applyAppRects(); | |
| 396 this.dirty_ = false; | |
| 397 logEvent('apps.layout: ' + (Date.now() - d0)); | |
| 398 | |
| 399 } finally { | |
| 400 if (disable_animations) { | |
| 401 // We need to re-enable animations asynchronously, so that the | |
| 402 // animations are still disabled for this layout update. | |
| 403 setTimeout(function() { | |
| 404 this.dragContainer.setAttribute('launcher-animations', true); | |
|
arv (Not doing code reviews)
2011/01/22 00:52:14
How about introducing a variable to dragContainer.
jstritar
2011/01/24 01:00:42
Done.
| |
| 405 }.bind(this), 0); | |
| 406 } | |
| 407 } | |
| 408 }, | |
| 409 | |
| 410 applyAppRects: function() { | |
|
Aaron Boodman
2011/01/22 23:42:57
Kind of an odd name for this method. What about la
jstritar
2011/01/24 01:00:42
Done.
| |
| 411 var apps = this.data; | |
| 412 var rects = this.getAppLayoutRects(apps.length); | |
| 413 var appsContent = $('apps-content'); | |
| 414 var d = this.dimensions; | |
| 415 var h = d.itemHeight + 2 * d.marginHeight + 2 * d.borderWidth; | |
| 416 var maxRows = 0; | |
| 417 | |
| 418 for (var i = 0; i < apps.length; i++) { | |
| 419 var t = appsContent.querySelector('[app-id='+apps[i]+']').parentNode; | |
|
Aaron Boodman
2011/01/22 23:42:57
Avoid single variable letter names unless they are
jstritar
2011/01/24 01:00:42
Done.
| |
| 420 | |
| 421 // If the node is being dragged, don't try to place it in the grid. | |
| 422 if (t == this.dragItem) | |
| 423 continue; | |
| 424 | |
| 425 maxRows = Math.max(maxRows, rects[i].row); | |
| 426 | |
| 427 t.style.left = rects[i].left + 'px'; | |
| 428 t.style.top = rects[i].top + 'px'; | |
| 429 t.style.right = ''; | |
|
Aaron Boodman
2011/01/22 23:42:57
It looks like maybe you were going to use 'right',
jstritar
2011/01/24 01:00:42
Done.
| |
| 430 t.style.display = this.visible ? '' : 'none'; | |
|
Aaron Boodman
2011/01/22 23:42:57
If this.visible is false, does it mean that the se
jstritar
2011/01/24 01:00:42
Done.
| |
| 431 | |
| 432 var innerStyle = t.firstElementChild.style; | |
| 433 innerStyle.left = innerStyle.top = ''; | |
|
Aaron Boodman
2011/01/22 23:42:57
This seems odd, when are these ever used?
jstritar
2011/01/24 01:00:42
Oops... must have brought this in from the most vi
| |
| 434 } | |
| 435 | |
| 436 // Set the container's height manually now that we use absolute | |
| 437 // positioning. | |
| 438 var lastRect = rects[rects.length - 1]; | |
| 439 appsContent.style.height = (++maxRows * h) + 'px'; | |
| 440 }, | |
| 441 | |
| 442 getAppLayoutRects: function(appCount) { | |
| 443 var d = this.dimensions; | |
|
Aaron Boodman
2011/01/22 23:42:57
I don't think it's obvious what d stands for. How
jstritar
2011/01/24 01:00:42
Done.
| |
| 444 var availableWidth = this.dragContainer.offsetWidth; | |
| 445 var rtl = isRtl(); | |
| 446 var rects = []; | |
| 447 var w = d.itemWidth + 2 * d.borderWidth + 2 * d.marginWidth; | |
| 448 var h = d.itemHeight + 2 * d.borderWidth + 2 * d.marginHeight; | |
| 449 | |
| 450 for (var i = 0; i < appCount; i++) { | |
| 451 var row = Math.floor((w * i) / availableWidth); | |
| 452 var top = row * h; | |
| 453 var left = (w * i) % availableWidth; | |
| 454 | |
| 455 // Reflect the X axis if an RTL language is active. | |
| 456 if (rtl) left = availableWidth - left - w; | |
|
arv (Not doing code reviews)
2011/01/22 00:52:14
line break?
jstritar
2011/01/24 01:00:42
Done.
| |
| 457 rects[i] = {left: left, top: top, row: row}; | |
| 458 } | |
| 459 return rects; | |
| 460 }, | |
| 461 | |
| 271 createElement: function(app) { | 462 createElement: function(app) { |
| 272 var div = createElement(app); | 463 var div = createElement(app); |
| 273 var a = div.firstChild; | 464 var a = div.firstChild; |
| 274 | 465 |
| 275 a.onclick = handleClick; | 466 a.onclick = handleClick; |
| 276 a.setAttribute('ping', PING_APP_LAUNCH_PREFIX + '+' + this.showPromo); | 467 a.setAttribute('ping', PING_APP_LAUNCH_PREFIX + '+' + this.showPromo); |
| 277 a.style.backgroundImage = url(app['icon_big']); | 468 a.style.backgroundImage = url(app['icon_big']); |
| 278 if (hashParams['app-id'] == app['id']) { | 469 if (hashParams['app-id'] == app['id']) { |
| 279 div.setAttribute('new', 'new'); | 470 div.setAttribute('new', 'new'); |
| 280 // Delay changing the attribute a bit to let the page settle down a bit. | 471 // Delay changing the attribute a bit to let the page settle down a bit. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 | 528 |
| 338 return a; | 529 return a; |
| 339 }, | 530 }, |
| 340 | 531 |
| 341 createWebStoreElement: function() { | 532 createWebStoreElement: function() { |
| 342 var elm = createElement({ | 533 var elm = createElement({ |
| 343 'id': 'web-store-entry', | 534 'id': 'web-store-entry', |
| 344 'name': localStrings.getString('web_store_title'), | 535 'name': localStrings.getString('web_store_title'), |
| 345 'launch_url': localStrings.getString('web_store_url') | 536 'launch_url': localStrings.getString('web_store_url') |
| 346 }); | 537 }); |
| 347 elm.setAttribute('app-id', 'web-store-entry'); | 538 elm.classList.add('web-store-entry'); |
| 348 return elm; | 539 return elm; |
| 349 }, | 540 }, |
| 350 | 541 |
| 351 createWebStoreMiniElement: function() { | 542 createWebStoreMiniElement: function() { |
| 352 var span = document.createElement('span'); | 543 var span = document.createElement('span'); |
| 353 span.appendChild(this.createWebStoreClosedMenuElement()); | 544 span.appendChild(this.createWebStoreClosedMenuElement()); |
| 354 return span; | 545 return span; |
| 355 }, | 546 }, |
| 356 | 547 |
| 357 createWebStoreClosedMenuElement: function() { | 548 createWebStoreClosedMenuElement: function() { |
| 358 var a = document.createElement('a'); | 549 var a = document.createElement('a'); |
| 359 a.textContent = localStrings.getString('web_store_title'); | 550 a.textContent = localStrings.getString('web_store_title'); |
| 360 a.href = localStrings.getString('web_store_url'); | 551 a.href = localStrings.getString('web_store_url'); |
| 361 a.style.backgroundImage = url('chrome://theme/IDR_PRODUCT_LOGO_16'); | 552 a.style.backgroundImage = url('chrome://theme/IDR_PRODUCT_LOGO_16'); |
| 362 a.className = 'item'; | 553 a.className = 'item'; |
| 363 return a; | 554 return a; |
| 364 } | 555 } |
| 365 }; | 556 }; |
| 366 })(); | 557 })(); |
| 558 | |
| 559 // Enable drag and drop reordering of the app launcher. | |
| 560 var appDragAndDrop = new DragAndDropController(apps); | |
| OLD | NEW |