| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 // Text content needed for range intersection checks in _updateSelectionMode
l. | 47 // Text content needed for range intersection checks in _updateSelectionMode
l. |
| 48 // Use Unicode ZERO WIDTH NO-BREAK SPACE, which avoids contributing any heig
ht to the element's layout overflow. | 48 // Use Unicode ZERO WIDTH NO-BREAK SPACE, which avoids contributing any heig
ht to the element's layout overflow. |
| 49 this._topGapElement.textContent = "\uFEFF"; | 49 this._topGapElement.textContent = "\uFEFF"; |
| 50 this._bottomGapElement.textContent = "\uFEFF"; | 50 this._bottomGapElement.textContent = "\uFEFF"; |
| 51 | 51 |
| 52 this._provider = provider; | 52 this._provider = provider; |
| 53 this.element.addEventListener("scroll", this._onScroll.bind(this), false); | 53 this.element.addEventListener("scroll", this._onScroll.bind(this), false); |
| 54 this.element.addEventListener("copy", this._onCopy.bind(this), false); | 54 this.element.addEventListener("copy", this._onCopy.bind(this), false); |
| 55 this.element.addEventListener("dragstart", this._onDragStart.bind(this), fal
se); | 55 this.element.addEventListener("dragstart", this._onDragStart.bind(this), fal
se); |
| 56 | 56 |
| 57 this._firstVisibleIndex = 0; | 57 this._firstActiveIndex = 0; |
| 58 this._lastVisibleIndex = -1; | 58 this._lastActiveIndex = -1; |
| 59 this._renderedItems = []; | 59 this._renderedItems = []; |
| 60 this._anchorSelection = null; | 60 this._anchorSelection = null; |
| 61 this._headSelection = null; | 61 this._headSelection = null; |
| 62 this._itemCount = 0; | 62 this._itemCount = 0; |
| 63 | 63 |
| 64 // Listen for any changes to descendants and trigger a refresh. This ensures | 64 // Listen for any changes to descendants and trigger a refresh. This ensures |
| 65 // that items updated asynchronously will not break stick-to-bottom behavior | 65 // that items updated asynchronously will not break stick-to-bottom behavior |
| 66 // if they change the scroll height. | 66 // if they change the scroll height. |
| 67 this._observer = new MutationObserver(this.refresh.bind(this)); | 67 this._observer = new MutationObserver(this.refresh.bind(this)); |
| 68 this._observerConfig = { childList: true, subtree: true }; | 68 this._observerConfig = { childList: true, subtree: true }; |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 } | 223 } |
| 224 return element; | 224 return element; |
| 225 }, | 225 }, |
| 226 | 226 |
| 227 _rebuildCumulativeHeightsIfNeeded: function() | 227 _rebuildCumulativeHeightsIfNeeded: function() |
| 228 { | 228 { |
| 229 if (this._cumulativeHeights) | 229 if (this._cumulativeHeights) |
| 230 return; | 230 return; |
| 231 if (!this._itemCount) | 231 if (!this._itemCount) |
| 232 return; | 232 return; |
| 233 var firstVisibleIndex = this._firstVisibleIndex; | 233 var firstActiveIndex = this._firstActiveIndex; |
| 234 var lastVisibleIndex = this._lastVisibleIndex; | 234 var lastActiveIndex = this._lastActiveIndex; |
| 235 var height = 0; | 235 var height = 0; |
| 236 this._cumulativeHeights = new Int32Array(this._itemCount); | 236 this._cumulativeHeights = new Int32Array(this._itemCount); |
| 237 for (var i = 0; i < this._itemCount; ++i) { | 237 for (var i = 0; i < this._itemCount; ++i) { |
| 238 if (firstVisibleIndex <= i && i <= lastVisibleIndex) | 238 if (firstActiveIndex <= i && i <= lastActiveIndex) |
| 239 height += this._renderedItems[i - firstVisibleIndex].element().o
ffsetHeight; | 239 height += this._renderedItems[i - firstActiveIndex].element().of
fsetHeight; |
| 240 else | 240 else |
| 241 height += this._provider.fastHeight(i); | 241 height += this._provider.fastHeight(i); |
| 242 this._cumulativeHeights[i] = height; | 242 this._cumulativeHeights[i] = height; |
| 243 } | 243 } |
| 244 }, | 244 }, |
| 245 | 245 |
| 246 /** | 246 /** |
| 247 * @param {number} index | 247 * @param {number} index |
| 248 * @return {number} | 248 * @return {number} |
| 249 */ | 249 */ |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 this._anchorSelection = null; | 292 this._anchorSelection = null; |
| 293 return false; | 293 return false; |
| 294 } | 294 } |
| 295 | 295 |
| 296 var firstSelected = Number.MAX_VALUE; | 296 var firstSelected = Number.MAX_VALUE; |
| 297 var lastSelected = -1; | 297 var lastSelected = -1; |
| 298 | 298 |
| 299 var hasVisibleSelection = false; | 299 var hasVisibleSelection = false; |
| 300 for (var i = 0; i < this._renderedItems.length; ++i) { | 300 for (var i = 0; i < this._renderedItems.length; ++i) { |
| 301 if (range.intersectsNode(this._renderedItems[i].element())) { | 301 if (range.intersectsNode(this._renderedItems[i].element())) { |
| 302 var index = i + this._firstVisibleIndex; | 302 var index = i + this._firstActiveIndex; |
| 303 firstSelected = Math.min(firstSelected, index); | 303 firstSelected = Math.min(firstSelected, index); |
| 304 lastSelected = Math.max(lastSelected, index); | 304 lastSelected = Math.max(lastSelected, index); |
| 305 hasVisibleSelection = true; | 305 hasVisibleSelection = true; |
| 306 } | 306 } |
| 307 } | 307 } |
| 308 if (hasVisibleSelection) { | 308 if (hasVisibleSelection) { |
| 309 firstSelected = this._createSelectionModel(firstSelected, /** @type
{!Node} */(range.startContainer), range.startOffset); | 309 firstSelected = this._createSelectionModel(firstSelected, /** @type
{!Node} */(range.startContainer), range.startOffset); |
| 310 lastSelected = this._createSelectionModel(lastSelected, /** @type {!
Node} */(range.endContainer), range.endOffset); | 310 lastSelected = this._createSelectionModel(lastSelected, /** @type {!
Node} */(range.endContainer), range.endOffset); |
| 311 } | 311 } |
| 312 var topOverlap = range.intersectsNode(this._topGapElement) && this._topG
apElement._active; | 312 var topOverlap = range.intersectsNode(this._topGapElement) && this._topG
apElement._active; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 return true; | 348 return true; |
| 349 }, | 349 }, |
| 350 | 350 |
| 351 /** | 351 /** |
| 352 * @param {?Selection} selection | 352 * @param {?Selection} selection |
| 353 */ | 353 */ |
| 354 _restoreSelection: function(selection) | 354 _restoreSelection: function(selection) |
| 355 { | 355 { |
| 356 var anchorElement = null; | 356 var anchorElement = null; |
| 357 var anchorOffset; | 357 var anchorOffset; |
| 358 if (this._firstVisibleIndex <= this._anchorSelection.item && this._ancho
rSelection.item <= this._lastVisibleIndex) { | 358 if (this._firstActiveIndex <= this._anchorSelection.item && this._anchor
Selection.item <= this._lastActiveIndex) { |
| 359 anchorElement = this._anchorSelection.node; | 359 anchorElement = this._anchorSelection.node; |
| 360 anchorOffset = this._anchorSelection.offset; | 360 anchorOffset = this._anchorSelection.offset; |
| 361 } else { | 361 } else { |
| 362 if (this._anchorSelection.item < this._firstVisibleIndex) | 362 if (this._anchorSelection.item < this._firstActiveIndex) |
| 363 anchorElement = this._topGapElement; | 363 anchorElement = this._topGapElement; |
| 364 else if (this._anchorSelection.item > this._lastVisibleIndex) | 364 else if (this._anchorSelection.item > this._lastActiveIndex) |
| 365 anchorElement = this._bottomGapElement; | 365 anchorElement = this._bottomGapElement; |
| 366 anchorOffset = this._selectionIsBackward ? 1 : 0; | 366 anchorOffset = this._selectionIsBackward ? 1 : 0; |
| 367 } | 367 } |
| 368 | 368 |
| 369 var headElement = null; | 369 var headElement = null; |
| 370 var headOffset; | 370 var headOffset; |
| 371 if (this._firstVisibleIndex <= this._headSelection.item && this._headSel
ection.item <= this._lastVisibleIndex) { | 371 if (this._firstActiveIndex <= this._headSelection.item && this._headSele
ction.item <= this._lastActiveIndex) { |
| 372 headElement = this._headSelection.node; | 372 headElement = this._headSelection.node; |
| 373 headOffset = this._headSelection.offset; | 373 headOffset = this._headSelection.offset; |
| 374 } else { | 374 } else { |
| 375 if (this._headSelection.item < this._firstVisibleIndex) | 375 if (this._headSelection.item < this._firstActiveIndex) |
| 376 headElement = this._topGapElement; | 376 headElement = this._topGapElement; |
| 377 else if (this._headSelection.item > this._lastVisibleIndex) | 377 else if (this._headSelection.item > this._lastActiveIndex) |
| 378 headElement = this._bottomGapElement; | 378 headElement = this._bottomGapElement; |
| 379 headOffset = this._selectionIsBackward ? 0 : 1; | 379 headOffset = this._selectionIsBackward ? 0 : 1; |
| 380 } | 380 } |
| 381 | 381 |
| 382 selection.setBaseAndExtent(anchorElement, anchorOffset, headElement, hea
dOffset); | 382 selection.setBaseAndExtent(anchorElement, anchorOffset, headElement, hea
dOffset); |
| 383 }, | 383 }, |
| 384 | 384 |
| 385 refresh: function() | 385 refresh: function() |
| 386 { | 386 { |
| 387 this._observer.disconnect(); | 387 this._observer.disconnect(); |
| 388 this._innerRefresh(); | 388 this._innerRefresh(); |
| 389 if (this._stickToBottom) | 389 if (this._stickToBottom) |
| 390 this._observer.observe(this._contentElement, this._observerConfig); | 390 this._observer.observe(this._contentElement, this._observerConfig); |
| 391 }, | 391 }, |
| 392 | 392 |
| 393 _innerRefresh: function() | 393 _innerRefresh: function() |
| 394 { | 394 { |
| 395 if (!this._visibleHeight()) | 395 if (!this._visibleHeight()) |
| 396 return; // Do nothing for invisible controls. | 396 return; // Do nothing for invisible controls. |
| 397 | 397 |
| 398 if (!this._itemCount) { | 398 if (!this._itemCount) { |
| 399 for (var i = 0; i < this._renderedItems.length; ++i) | 399 for (var i = 0; i < this._renderedItems.length; ++i) |
| 400 this._renderedItems[i].willHide(); | 400 this._renderedItems[i].willHide(); |
| 401 this._renderedItems = []; | 401 this._renderedItems = []; |
| 402 this._contentElement.removeChildren(); | 402 this._contentElement.removeChildren(); |
| 403 this._topGapElement.style.height = "0px"; | 403 this._topGapElement.style.height = "0px"; |
| 404 this._bottomGapElement.style.height = "0px"; | 404 this._bottomGapElement.style.height = "0px"; |
| 405 this._firstVisibleIndex = -1; | 405 this._firstActiveIndex = -1; |
| 406 this._lastVisibleIndex = -1; | 406 this._lastActiveIndex = -1; |
| 407 return; | 407 return; |
| 408 } | 408 } |
| 409 | 409 |
| 410 var selection = this.element.getComponentSelection(); | 410 var selection = this.element.getComponentSelection(); |
| 411 var shouldRestoreSelection = this._updateSelectionModel(selection); | 411 var shouldRestoreSelection = this._updateSelectionModel(selection); |
| 412 | 412 |
| 413 var visibleFrom = this.element.scrollTop; | 413 var visibleFrom = this.element.scrollTop; |
| 414 var visibleHeight = this._visibleHeight(); | 414 var visibleHeight = this._visibleHeight(); |
| 415 var isInvalidating = !this._cumulativeHeights; | 415 var isInvalidating = !this._cumulativeHeights; |
| 416 | 416 |
| 417 for (var i = 0; i < this._renderedItems.length; ++i) { | 417 for (var i = 0; i < this._renderedItems.length; ++i) { |
| 418 // Tolerate 1-pixel error due to double-to-integer rounding errors. | 418 // Tolerate 1-pixel error due to double-to-integer rounding errors. |
| 419 if (this._cumulativeHeights && Math.abs(this._cachedItemHeight(this.
_firstVisibleIndex + i) - this._renderedItems[i].element().offsetHeight) > 1) | 419 if (this._cumulativeHeights && Math.abs(this._cachedItemHeight(this.
_firstActiveIndex + i) - this._renderedItems[i].element().offsetHeight) > 1) |
| 420 delete this._cumulativeHeights; | 420 delete this._cumulativeHeights; |
| 421 } | 421 } |
| 422 this._rebuildCumulativeHeightsIfNeeded(); | 422 this._rebuildCumulativeHeightsIfNeeded(); |
| 423 var oldFirstVisibleIndex = this._firstVisibleIndex; | 423 var oldFirstActiveIndex = this._firstActiveIndex; |
| 424 var oldLastVisibleIndex = this._lastVisibleIndex; | 424 var oldLastActiveIndex = this._lastActiveIndex; |
| 425 | 425 var activeHeight = visibleHeight * 2; |
| 426 // When the viewport is scrolled to the bottom, using the cumulative hei
ghts estimate is not | 426 // When the viewport is scrolled to the bottom, using the cumulative hei
ghts estimate is not |
| 427 // precise enough to determine next visible indices. This stickToBottom
check avoids extra | 427 // precise enough to determine next visible indices. This stickToBottom
check avoids extra |
| 428 // calls to refresh in those cases. | 428 // calls to refresh in those cases. |
| 429 if (this._stickToBottom) { | 429 if (this._stickToBottom) { |
| 430 this._firstVisibleIndex = Math.max(this._itemCount - Math.ceil(visib
leHeight / this._provider.minimumRowHeight()), 0); | 430 this._firstActiveIndex = Math.max(this._itemCount - Math.ceil(active
Height / this._provider.minimumRowHeight()), 0); |
| 431 this._lastVisibleIndex = this._itemCount - 1; | 431 this._lastActiveIndex = this._itemCount - 1; |
| 432 } else { | 432 } else { |
| 433 this._firstVisibleIndex = Math.max(Array.prototype.lowerBound.call(t
his._cumulativeHeights, visibleFrom + 1), 0); | 433 this._firstActiveIndex = Math.max(Array.prototype.lowerBound.call(th
is._cumulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2), 0)
; |
| 434 // Proactively render more rows in case some of them will be collaps
ed without triggering refresh. @see crbug.com/390169 | 434 // Proactively render more rows in case some of them will be collaps
ed without triggering refresh. @see crbug.com/390169 |
| 435 this._lastVisibleIndex = this._firstVisibleIndex + Math.ceil(visible
Height / this._provider.minimumRowHeight()) - 1; | 435 this._lastActiveIndex = this._firstActiveIndex + Math.ceil(activeHei
ght / this._provider.minimumRowHeight()) - 1; |
| 436 this._lastVisibleIndex = Math.min(this._lastVisibleIndex, this._item
Count - 1); | 436 this._lastActiveIndex = Math.min(this._lastActiveIndex, this._itemCo
unt - 1); |
| 437 } | 437 } |
| 438 | 438 |
| 439 var topGapHeight = this._cumulativeHeights[this._firstVisibleIndex - 1]
|| 0; | 439 var topGapHeight = this._cumulativeHeights[this._firstActiveIndex - 1] |
| 0; |
| 440 var bottomGapHeight = this._cumulativeHeights[this._cumulativeHeights.le
ngth - 1] - this._cumulativeHeights[this._lastVisibleIndex]; | 440 var bottomGapHeight = this._cumulativeHeights[this._cumulativeHeights.le
ngth - 1] - this._cumulativeHeights[this._lastActiveIndex]; |
| 441 | 441 |
| 442 /** | 442 /** |
| 443 * @this {WebInspector.ViewportControl} | 443 * @this {WebInspector.ViewportControl} |
| 444 */ | 444 */ |
| 445 function prepare() | 445 function prepare() |
| 446 { | 446 { |
| 447 this._topGapElement.style.height = topGapHeight + "px"; | 447 this._topGapElement.style.height = topGapHeight + "px"; |
| 448 this._bottomGapElement.style.height = bottomGapHeight + "px"; | 448 this._bottomGapElement.style.height = bottomGapHeight + "px"; |
| 449 this._topGapElement._active = !!topGapHeight; | 449 this._topGapElement._active = !!topGapHeight; |
| 450 this._bottomGapElement._active = !!bottomGapHeight; | 450 this._bottomGapElement._active = !!bottomGapHeight; |
| 451 this._contentElement.style.setProperty("height", "10000000px"); | 451 this._contentElement.style.setProperty("height", "10000000px"); |
| 452 } | 452 } |
| 453 | 453 |
| 454 if (isInvalidating) | 454 if (isInvalidating) |
| 455 this._fullViewportUpdate(prepare.bind(this)); | 455 this._fullViewportUpdate(prepare.bind(this)); |
| 456 else | 456 else |
| 457 this._partialViewportUpdate(oldFirstVisibleIndex, oldLastVisibleInde
x, prepare.bind(this)); | 457 this._partialViewportUpdate(oldFirstActiveIndex, oldLastActiveIndex,
prepare.bind(this)); |
| 458 this._contentElement.style.removeProperty("height"); | 458 this._contentElement.style.removeProperty("height"); |
| 459 // Should be the last call in the method as it might force layout. | 459 // Should be the last call in the method as it might force layout. |
| 460 if (shouldRestoreSelection) | 460 if (shouldRestoreSelection) |
| 461 this._restoreSelection(selection); | 461 this._restoreSelection(selection); |
| 462 if (this._stickToBottom) | 462 if (this._stickToBottom) |
| 463 this.element.scrollTop = 10000000; | 463 this.element.scrollTop = 10000000; |
| 464 }, | 464 }, |
| 465 | 465 |
| 466 /** | 466 /** |
| 467 * @param {function()} prepare | 467 * @param {function()} prepare |
| 468 */ | 468 */ |
| 469 _fullViewportUpdate: function(prepare) | 469 _fullViewportUpdate: function(prepare) |
| 470 { | 470 { |
| 471 for (var i = 0; i < this._renderedItems.length; ++i) | 471 for (var i = 0; i < this._renderedItems.length; ++i) |
| 472 this._renderedItems[i].willHide(); | 472 this._renderedItems[i].willHide(); |
| 473 prepare(); | 473 prepare(); |
| 474 this._renderedItems = []; | 474 this._renderedItems = []; |
| 475 this._contentElement.removeChildren(); | 475 this._contentElement.removeChildren(); |
| 476 for (var i = this._firstVisibleIndex; i <= this._lastVisibleIndex; ++i)
{ | 476 for (var i = this._firstActiveIndex; i <= this._lastActiveIndex; ++i) { |
| 477 var viewportElement = this._providerElement(i); | 477 var viewportElement = this._providerElement(i); |
| 478 this._contentElement.appendChild(viewportElement.element()); | 478 this._contentElement.appendChild(viewportElement.element()); |
| 479 this._renderedItems.push(viewportElement); | 479 this._renderedItems.push(viewportElement); |
| 480 } | 480 } |
| 481 for (var i = 0; i < this._renderedItems.length; ++i) | 481 for (var i = 0; i < this._renderedItems.length; ++i) |
| 482 this._renderedItems[i].wasShown(); | 482 this._renderedItems[i].wasShown(); |
| 483 }, | 483 }, |
| 484 | 484 |
| 485 /** | 485 /** |
| 486 * @param {number} oldFirstVisibleIndex | 486 * @param {number} oldFirstActiveIndex |
| 487 * @param {number} oldLastVisibleIndex | 487 * @param {number} oldLastActiveIndex |
| 488 * @param {function()} prepare | 488 * @param {function()} prepare |
| 489 */ | 489 */ |
| 490 _partialViewportUpdate: function(oldFirstVisibleIndex, oldLastVisibleIndex,
prepare) | 490 _partialViewportUpdate: function(oldFirstActiveIndex, oldLastActiveIndex, pr
epare) |
| 491 { | 491 { |
| 492 var willBeHidden = []; | 492 var willBeHidden = []; |
| 493 for (var i = 0; i < this._renderedItems.length; ++i) { | 493 for (var i = 0; i < this._renderedItems.length; ++i) { |
| 494 var index = oldFirstVisibleIndex + i; | 494 var index = oldFirstActiveIndex + i; |
| 495 if (index < this._firstVisibleIndex || this._lastVisibleIndex < inde
x) | 495 if (index < this._firstActiveIndex || this._lastActiveIndex < index) |
| 496 willBeHidden.push(this._renderedItems[i]); | 496 willBeHidden.push(this._renderedItems[i]); |
| 497 } | 497 } |
| 498 for (var i = 0; i < willBeHidden.length; ++i) | 498 for (var i = 0; i < willBeHidden.length; ++i) |
| 499 willBeHidden[i].willHide(); | 499 willBeHidden[i].willHide(); |
| 500 prepare(); | 500 prepare(); |
| 501 for (var i = 0; i < willBeHidden.length; ++i) | 501 for (var i = 0; i < willBeHidden.length; ++i) |
| 502 willBeHidden[i].element().remove(); | 502 willBeHidden[i].element().remove(); |
| 503 | 503 |
| 504 this._renderedItems = []; | 504 this._renderedItems = []; |
| 505 var anchor = this._contentElement.firstChild; | 505 var anchor = this._contentElement.firstChild; |
| 506 var wasShown = []; | 506 var wasShown = []; |
| 507 for (var i = this._firstVisibleIndex; i <= this._lastVisibleIndex; ++i)
{ | 507 for (var i = this._firstActiveIndex; i <= this._lastActiveIndex; ++i) { |
| 508 var viewportElement = this._providerElement(i); | 508 var viewportElement = this._providerElement(i); |
| 509 var element = viewportElement.element(); | 509 var element = viewportElement.element(); |
| 510 if (element !== anchor) { | 510 if (element !== anchor) { |
| 511 this._contentElement.insertBefore(element, anchor); | 511 this._contentElement.insertBefore(element, anchor); |
| 512 wasShown.push(viewportElement); | 512 wasShown.push(viewportElement); |
| 513 } else { | 513 } else { |
| 514 anchor = anchor.nextSibling; | 514 anchor = anchor.nextSibling; |
| 515 } | 515 } |
| 516 this._renderedItems.push(viewportElement); | 516 this._renderedItems.push(viewportElement); |
| 517 } | 517 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 _onScroll: function(event) | 578 _onScroll: function(event) |
| 579 { | 579 { |
| 580 this.refresh(); | 580 this.refresh(); |
| 581 }, | 581 }, |
| 582 | 582 |
| 583 /** | 583 /** |
| 584 * @return {number} | 584 * @return {number} |
| 585 */ | 585 */ |
| 586 firstVisibleIndex: function() | 586 firstVisibleIndex: function() |
| 587 { | 587 { |
| 588 return this._firstVisibleIndex; | 588 var firstVisibleIndex; |
| 589 if (this._stickToBottom) |
| 590 firstVisibleIndex = Math.max(this._itemCount - Math.ceil(this._visib
leHeight() / this._provider.minimumRowHeight()), 0); |
| 591 else |
| 592 firstVisibleIndex = Math.max(Array.prototype.lowerBound.call(this._c
umulativeHeights, this.element.scrollTop + 1), 0); |
| 593 return Math.max(firstVisibleIndex, this._firstActiveIndex); |
| 589 }, | 594 }, |
| 590 | 595 |
| 591 /** | 596 /** |
| 592 * @return {number} | 597 * @return {number} |
| 593 */ | 598 */ |
| 594 lastVisibleIndex: function() | 599 lastVisibleIndex: function() |
| 595 { | 600 { |
| 596 return this._lastVisibleIndex; | 601 var lastVisibleIndex; |
| 602 if (this._stickToBottom) |
| 603 lastVisibleIndex = this._itemCount - 1; |
| 604 else |
| 605 lastVisibleIndex = this.firstVisibleIndex() + Math.ceil(this._visibl
eHeight() / this._provider.minimumRowHeight()) - 1; |
| 606 return Math.min(lastVisibleIndex, this._lastActiveIndex); |
| 597 }, | 607 }, |
| 598 | 608 |
| 599 /** | 609 /** |
| 600 * @return {?Element} | 610 * @return {?Element} |
| 601 */ | 611 */ |
| 602 renderedElementAt: function(index) | 612 renderedElementAt: function(index) |
| 603 { | 613 { |
| 604 if (index < this._firstVisibleIndex) | 614 if (index < this._firstActiveIndex) |
| 605 return null; | 615 return null; |
| 606 if (index > this._lastVisibleIndex) | 616 if (index > this._lastActiveIndex) |
| 607 return null; | 617 return null; |
| 608 return this._renderedItems[index - this._firstVisibleIndex].element(); | 618 return this._renderedItems[index - this._firstActiveIndex].element(); |
| 609 }, | 619 }, |
| 610 | 620 |
| 611 /** | 621 /** |
| 612 * @param {number} index | 622 * @param {number} index |
| 613 * @param {boolean=} makeLast | 623 * @param {boolean=} makeLast |
| 614 */ | 624 */ |
| 615 scrollItemIntoView: function(index, makeLast) | 625 scrollItemIntoView: function(index, makeLast) |
| 616 { | 626 { |
| 617 if (index > this._firstVisibleIndex && index < this._lastVisibleIndex) | 627 if (index > this._firstActiveIndex && index < this._lastActiveIndex) |
| 618 return; | 628 return; |
| 619 if (makeLast) | 629 if (makeLast) |
| 620 this.forceScrollItemToBeLast(index); | 630 this.forceScrollItemToBeLast(index); |
| 621 else if (index <= this._firstVisibleIndex) | 631 else if (index <= this._firstActiveIndex) |
| 622 this.forceScrollItemToBeFirst(index); | 632 this.forceScrollItemToBeFirst(index); |
| 623 else if (index >= this._lastVisibleIndex) | 633 else if (index >= this._lastActiveIndex) |
| 624 this.forceScrollItemToBeLast(index); | 634 this.forceScrollItemToBeLast(index); |
| 625 }, | 635 }, |
| 626 | 636 |
| 627 /** | 637 /** |
| 628 * @param {number} index | 638 * @param {number} index |
| 629 */ | 639 */ |
| 630 forceScrollItemToBeFirst: function(index) | 640 forceScrollItemToBeFirst: function(index) |
| 631 { | 641 { |
| 632 this.setStickToBottom(false); | 642 this.setStickToBottom(false); |
| 633 this._rebuildCumulativeHeightsIfNeeded(); | 643 this._rebuildCumulativeHeightsIfNeeded(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 652 | 662 |
| 653 /** | 663 /** |
| 654 * @return {number} | 664 * @return {number} |
| 655 */ | 665 */ |
| 656 _visibleHeight: function() | 666 _visibleHeight: function() |
| 657 { | 667 { |
| 658 // Use offsetHeight instead of clientHeight to avoid being affected by h
orizontal scroll. | 668 // Use offsetHeight instead of clientHeight to avoid being affected by h
orizontal scroll. |
| 659 return this.element.offsetHeight; | 669 return this.element.offsetHeight; |
| 660 } | 670 } |
| 661 } | 671 } |
| OLD | NEW |