| 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 | 
|---|