From 1385d19f64ec03f9e08d4621e609cd6dbfa72ac9 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 30 Mar 2016 18:10:03 -0400 Subject: [PATCH] Further tweaks to viewport shuffling and dynamic image loading @BenLubar --- public/less/global.less | 2 +- public/src/client/topic/posts.js | 119 ++++++++++++++++--------------- public/src/modules/navigator.js | 18 +++-- 3 files changed, 73 insertions(+), 66 deletions(-) diff --git a/public/less/global.less b/public/less/global.less index d9f16c74e8..d606b8221c 100644 --- a/public/less/global.less +++ b/public/less/global.less @@ -14,7 +14,7 @@ &[data-state="unloaded"], &[data-state="loading"] { display: inherit; - height: 1rem; + height: 0; opacity: 0; } diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 5823d81b65..2cbe2a0d2a 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -10,7 +10,9 @@ define('forum/topic/posts', [ 'components' ], function(pagination, infinitescroll, postTools, navigator, components) { - var Posts = {}; + var Posts = { + _imageLoaderTimeout: undefined + }; Posts.onNewPost = function(data) { if (!data || !data.posts || !data.posts.length) { @@ -240,70 +242,74 @@ define('forum/topic/posts', [ images.each(function() { $(this).attr('data-src', $(this).attr('src')); $(this).attr('data-state', 'unloaded'); - $(this).attr('src', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'); + $(this).attr('src', 'about:blank'); }); - - $(window).scrollTop(scrollTop + $(document).height() - height); }; Posts.loadImages = function(threshold) { - /* - If threshold is defined, images loaded above this threshold will modify - the user's scroll position so they are not scrolled away from content - they were reading. Images loaded below this threshold will push down content. + if (Posts._imageLoaderTimeout) { + clearTimeout(Posts._imageLoaderTimeout); + } - If no threshold is defined, loaded images will push down content, as per - default - */ + Posts._imageLoaderTimeout = setTimeout(function() { + /* + If threshold is defined, images loaded above this threshold will modify + the user's scroll position so they are not scrolled away from content + they were reading. Images loaded below this threshold will push down content. - var images = components.get('post/content').find('img[data-state="unloaded"]'), - visible = images.filter(function() { - return utils.isElementInViewport(this); - }), - scrollTop = $(window).scrollTop(), - adjusting = false, - adjustQueue = [], - adjustPosition = function() { - adjusting = true; - oldHeight = document.body.clientHeight; + If no threshold is defined, loaded images will push down content, as per + default + */ - // Display the image - $(this).attr('data-state', 'loaded'); - newHeight = document.body.clientHeight; + var images = components.get('post/content').find('img[data-state="unloaded"]'), + visible = images.filter(function() { + return utils.isElementInViewport(this); + }), + scrollTop = $(window).scrollTop(), + adjusting = false, + adjustQueue = [], + adjustPosition = function() { + adjusting = true; + oldHeight = document.body.clientHeight; - var imageRect = this.getBoundingClientRect(); - if (imageRect.top < threshold) { - scrollTop = scrollTop + (newHeight - oldHeight); - $(window).scrollTop(scrollTop); - } - - if (adjustQueue.length) { - adjustQueue.pop()(); - } else { - adjusting = false; - } - }, - oldHeight, newHeight; - - // For each image, reset the source and adjust scrollTop when loaded - visible.attr('data-state', 'loading'); - visible.each(function(index, image) { - image = $(image); - - image.on('load', function() { - if (!adjusting) { - adjustPosition.call(this); - } else { - adjustQueue.push(adjustPosition.bind(this)); + // Display the image + $(this).attr('data-state', 'loaded'); + newHeight = document.body.clientHeight; + + var imageRect = this.getBoundingClientRect(); + if (imageRect.top < threshold) { + scrollTop = scrollTop + (newHeight - oldHeight); + $(window).scrollTop(scrollTop); + } + + if (adjustQueue.length) { + adjustQueue.pop()(); + } else { + adjusting = false; + } + }, + oldHeight, newHeight; + + // For each image, reset the source and adjust scrollTop when loaded + visible.attr('data-state', 'loading'); + visible.each(function(index, image) { + image = $(image); + + image.on('load', function() { + if (!adjusting) { + adjustPosition.call(this); + } else { + adjustQueue.push(adjustPosition.bind(this)); + } + }); + + image.attr('src', image.attr('data-src')); + if (image.parent().attr('href')) { + image.parent().attr('href', image.attr('data-src')); } + image.removeAttr('data-src'); }); - - image.attr('src', image.attr('data-src')); - if (image.parent().attr('href')) { - image.parent().attr('href', image.attr('data-src')); - } - image.removeAttr('data-src'); - }); + }, 250); }; Posts.wrapImagesInLinks = function(posts) { @@ -318,13 +324,10 @@ define('forum/topic/posts', [ Posts.showBottomPostBar = function() { var mainPost = components.get('post', 'index', 0); var posts = $('[component="post"]'); - var height = $(document).height(); if (!!mainPost.length && posts.length > 1 && $('.post-bar').length < 2) { $('.post-bar').clone().appendTo(mainPost); - $(window).scrollTop($(window).scrollTop() + $(document).height() - height); } else if (mainPost.length && posts.length < 2) { mainPost.find('.post-bar').remove(); - $(window).scrollTop($(window).scrollTop() - $(document).height() - height); } }; diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index 6877abe8db..3d65f6b8a0 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -121,20 +121,24 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com } }); + var atTop = scrollTop === 0 && parseInt(els.first().attr('data-index'), 10) === 0, + nearBottom = scrollTop + windowHeight > documentHeight - 100 && parseInt(els.last().attr('data-index'), 10) === count - 1; - // check if we are at the top - if (scrollTop === 0 && parseInt(els.first().attr('data-index'), 10) === 0) { + if (atTop) { index = 1; - // check if we are near the bottom - } else if (scrollTop + windowHeight > documentHeight - 100 && parseInt(els.last().attr('data-index'), 10) === count - 1) { + } else if (nearBottom) { index = count; } // If a threshold is undefined, try to determine one based on new index if (threshold === undefined) { - var anchorEl = components.get('post/anchor', index - 1); - var anchorRect = anchorEl.get(0).getBoundingClientRect(); - threshold = anchorRect.top; + if (atTop) { + threshold = 0; + } else { + var anchorEl = components.get('post/anchor', index - 1); + var anchorRect = anchorEl.get(0).getBoundingClientRect(); + threshold = anchorRect.top; + } } if (typeof navigator.callback === 'function') {