Commit 1d5669fd authored by Sean Roberts's avatar Sean Roberts

Fix mobile scrolling

parent 4b3c1325
......@@ -19,6 +19,7 @@ describe('VirtualThreadList', function () {
};
var fakeScope;
var fakeScrollRoot;
var fakeWindow;
function idRange(start, end) {
......@@ -45,6 +46,26 @@ describe('VirtualThreadList', function () {
beforeEach(function () {
fakeScope = {$digest: sinon.stub()};
fakeScrollRoot = {
className: 'app-content-wrapper',
scrollTop: 0,
listeners: {},
addEventListener: function (event, listener) {
this.listeners[event] = this.listeners[event] || [];
this.listeners[event].push(listener);
},
removeEventListener: function (event, listener) {
this.listeners[event] = this.listeners[event].filter(function (fn) {
return fn !== listener;
});
},
trigger: function (event) {
(this.listeners[event] || []).forEach(function (cb) {
cb();
});
},
};
fakeWindow = {
listeners: {},
addEventListener: function (event, listener) {
......@@ -57,12 +78,19 @@ describe('VirtualThreadList', function () {
});
},
trigger: function (event) {
this.listeners[event].forEach(function (cb) {
(this.listeners[event] || []).forEach(function (cb) {
cb();
});
},
innerHeight: 100,
pageYOffset: 0,
document: {
querySelector: function(selector){
if(selector === '.' + fakeScrollRoot.className){
return fakeScrollRoot;
}
return null;
},
},
};
threadOptions.invisibleThreadFilter = sinon.stub().returns(false);
......@@ -77,7 +105,7 @@ describe('VirtualThreadList', function () {
unroll('generates expected state when #when', function (testCase) {
var thread = generateRootThread(testCase.threads);
fakeWindow.pageYOffset = testCase.scrollOffset;
fakeScrollRoot.scrollTop = testCase.scrollOffset;
fakeWindow.innerHeight = testCase.windowHeight;
// make sure for everything that is not being presented in the
......@@ -93,7 +121,7 @@ describe('VirtualThreadList', function () {
assert.equal(lastState.offscreenUpperHeight, testCase.expectedHeightAbove);
assert.equal(lastState.offscreenLowerHeight, testCase.expectedHeightBelow);
},[{
when: 'window is scrolled to top of list',
when: 'scrollRoot is scrolled to top of list',
threads: 100,
scrollOffset: 0,
windowHeight: 300,
......@@ -101,7 +129,7 @@ describe('VirtualThreadList', function () {
expectedHeightAbove: 0,
expectedHeightBelow: 18800,
},{
when: 'window is scrolled to middle of list',
when: 'scrollRoot is scrolled to middle of list',
threads: 100,
scrollOffset: 2000,
windowHeight: 300,
......@@ -109,7 +137,7 @@ describe('VirtualThreadList', function () {
expectedHeightAbove: 1000,
expectedHeightBelow: 16800,
},{
when: 'window is scrolled to bottom of list',
when: 'scrollRoot is scrolled to bottom of list',
threads: 100,
scrollOffset: 18800,
windowHeight: 300,
......@@ -118,15 +146,17 @@ describe('VirtualThreadList', function () {
expectedHeightBelow: 0,
}]);
unroll('recalculates when a window.#event occurs', function (testCase) {
it('recalculates when a window.resize occurs', function () {
lastState = null;
fakeWindow.trigger(testCase.event);
fakeWindow.trigger('resize');
assert.ok(lastState);
},[{
event: 'resize',
},{
event: 'scroll',
}]);
});
it('recalculates when a scrollRoot.scroll occurs', function () {
lastState = null;
fakeScrollRoot.trigger('scroll');
assert.ok(lastState);
});
it('recalculates when root thread changes', function () {
threadList.setRootThread({annotation: undefined, children: []});
......@@ -137,7 +167,7 @@ describe('VirtualThreadList', function () {
unroll('affects visible threads', function (testCase) {
var thread = generateRootThread(10);
fakeWindow.innerHeight = 500;
fakeWindow.pageYOffset = 0;
fakeScrollRoot.scrollTop = 0;
idRange(0,10).forEach(function (id) {
threadList.setThreadHeight(id, testCase.threadHeight);
});
......@@ -154,16 +184,18 @@ describe('VirtualThreadList', function () {
});
describe('#detach', function () {
unroll('stops listening to window.#event events', function (testCase) {
it('stops listening to window.resize events', function () {
threadList.detach();
lastState = null;
fakeWindow.trigger(testCase.event);
fakeWindow.trigger('resize');
assert.isNull(lastState);
},[{
event: 'resize',
},{
event: 'scroll',
}]);
});
it('stops listening to scrollRoot.scroll events', function () {
threadList.detach();
lastState = null;
fakeScrollRoot.trigger('scroll');
assert.isNull(lastState);
});
});
describe('#yOffsetOf', function () {
......
......@@ -36,16 +36,17 @@ function VirtualThreadList($scope, window_, rootThread, options) {
this._heights = {};
this.window = window_;
this.scrollRoot = this.window.document.querySelector('.app-content-wrapper');
var debouncedUpdate = debounce(function () {
self._updateVisibleThreads();
$scope.$digest();
}, 20);
this.window.addEventListener('scroll', debouncedUpdate);
this.scrollRoot.addEventListener('scroll', debouncedUpdate);
this.window.addEventListener('resize', debouncedUpdate);
this._detach = function () {
this.window.removeEventListener('scroll', debouncedUpdate);
this.scrollRoot.removeEventListener('scroll', debouncedUpdate);
this.window.removeEventListener('resize', debouncedUpdate);
};
}
......@@ -153,17 +154,20 @@ VirtualThreadList.prototype._updateVisibleThreads = function () {
for (var i = 0; i < allThreads.length; i++) {
thread = allThreads[i];
var threadHeight = this._height(thread.id);
var added = false;
if (usedHeight + threadHeight < this.window.pageYOffset - MARGIN_ABOVE) {
if (usedHeight + threadHeight < this.scrollRoot.scrollTop - MARGIN_ABOVE) {
// Thread is above viewport
offscreenUpperHeight += threadHeight;
} else if (usedHeight <
this.window.pageYOffset + visibleHeight + MARGIN_BELOW) {
this.scrollRoot.scrollTop + visibleHeight + MARGIN_BELOW) {
// Thread is either in or close to the viewport
visibleThreads.push(thread);
added = true;
} else {
// Thread is below viewport
offscreenLowerHeight += threadHeight;
}
......
......@@ -57,6 +57,9 @@ hypothesis-app {
@include grey-background;
min-height: 100%;
height: 100%;
overflow: scroll;
-webkit-overflow-scrolling: touch;
padding: $sidebar-h-padding;
padding-top: $sidebar-h-padding + $top-bar-height;
......
......@@ -6,7 +6,7 @@
border-bottom: solid 1px $gray-lighter;
height: $top-bar-height;
font-size: 15px;
position: fixed;
position: absolute;
left: 0;
right: 0;
top: 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment