Commit 3d3eacfa authored by Randall Leeds's avatar Randall Leeds

Rewrite infinite scroll against the window

Rather than having a fixed body that scrolls, let the body take a
natural height and rewrite the infinite scroll handler to watch the
global scroll.

The infinite scroll directive is now smarter and has tests.
parent 9cfad021
......@@ -101,12 +101,12 @@ module.exports = angular.module('h', [
.directive('statusButton', require('./directive/status-button'))
.directive('thread', require('./directive/thread'))
.directive('threadFilter', require('./directive/thread-filter'))
.directive('whenscrolled', require('./directive/whenscrolled'))
.directive('match', require('./directive/match'))
.directive('spinner', require('./directive/spinner'))
.directive('tabbable', require('./directive/tabbable'))
.directive('tabReveal', require('./directive/tab-reveal'))
.directive('shareDialog', require('./directive/share-dialog'))
.directive('windowScroll', require('./directive/window-scroll'))
.filter('converter', require('./filter/converter'))
.filter('moment', require('./filter/moment'))
......
var module = angular.mock.module;
var inject = angular.mock.inject;
var windowScroll = require('../window-scroll');
describe('windowScroll', function () {
var directive = null;
var doc = null;
var html = null;
var view = null;
var scope = null;
var elem = null;
var attr = null;
before(function () {
angular.module('h', []);
});
beforeEach(module('h'));
beforeEach(inject(function ($injector) {
directive = $injector.invoke(windowScroll);
html = {};
view = {
addEventListener: sinon.spy(),
removeEventListener: sinon.spy()
};
doc = {documentElement: html, defaultView: view};
scope = {$apply: sinon.stub().yields(), $on: sinon.stub()};
elem = {prop: sinon.stub().withArgs('ownerDocument').returns(doc)};
attr = {windowScroll: sinon.stub()};
directive.link(scope, elem, attr);
}));
it('installs a scroll handler on the window', function () {
assert.calledOnce(view.addEventListener);
assert.calledWith(view.addEventListener, 'scroll', sinon.match.func);
assert.calledOnce(scope.$on);
assert.calledWith(scope.$on, '$destroy', sinon.match.func);
scope.$on.firstCall.args[1]();
var handler = view.addEventListener.firstCall.args[1];
assert.calledOnce(view.removeEventListener);
assert.calledWith(view.removeEventListener, 'scroll', handler);
});
describe('attribute argument', function () {
var callback = null;
var handler = null;
beforeEach(function () {
callback = attr.windowScroll;
handler = view.addEventListener.firstCall.args[1];
html.clientHeight = 100;
html.scrollHeight = 1000;
view.scrollY = 0;
});
it('is not called when scrolling near the top of the view', function () {
handler();
assert.notCalled(callback);
});
it('is not called when scrolling near the middle of the view', function () {
handler();
view.scrollY = 500;
handler();
assert.notCalled(callback);
});
it('is called when one screen remains', function () {
handler();
view.scrollY = 800;
handler();
assert.calledOnce(callback);
});
describe ('throttle', function () {
it('prevents extraneous calls', function () {
view.scrollY = 800;
handler();
handler();
assert.calledOnce(callback);
});
it('allows calls after the view grows', function () {
view.scrollY = 800;
handler();
assert.calledOnce(callback);
html.scrollHeight = 2000;
handler();
assert.calledOnce(callback);
view.scrollY = 1800;
handler()
assert.calledTwice(callback);
});
});
});
});
module.exports = ->
link: (scope, elem, attr) ->
elem.bind 'scroll', ->
{clientHeight, scrollHeight, scrollTop} = elem[0]
if scrollHeight - scrollTop <= clientHeight + 40
scope.$apply attr.whenscrolled
......@@ -9,10 +9,7 @@ body {
font-family: $sans-font-family;
font-weight: 300;
font-size: .8em;
height: 100%;
width: 100%;
padding-top: 30px;
position: fixed;
}
#{nest("hgroup", "#{headings()}")} {
......@@ -27,12 +24,7 @@ ol {
}
#wrapper {
height: 100%;
padding: .72em;
text-align: center;
overflow-y: auto;
position: relative;
-webkit-overflow-scrolling: touch;
@include respond-to(tablets desktops) {
padding-bottom: 4em;
......@@ -50,7 +42,6 @@ ol {
.content {
margin-left: auto;
margin-right: auto;
text-align: left;
@include respond-to(tablets desktops) {
margin: auto;
......
<!-- Thread view -->
<ul class="stream-list"
deep-count="count"
thread-filter="search.query">
thread-filter="search.query"
window-scroll="loadMore(10)">
<li ng-show="threadFilter.active()"
><span ng-pluralize
count="count('match')"
......
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