diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 9088830554..d620da1e70 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -7,11 +7,12 @@ define('forum/topic', [ 'forum/topic/postTools', 'forum/topic/events', 'forum/topic/posts', + 'forum/topic/images', 'forum/topic/replies', 'navigator', 'sort', 'components', -], function (infinitescroll, threadTools, postTools, events, posts, replies, navigator, sort, components) { +], function (infinitescroll, threadTools, postTools, events, posts, images, replies, navigator, sort, components) { var Topic = {}; var currentUrl = ''; @@ -238,7 +239,7 @@ define('forum/topic', [ return; } - posts.loadImages(threshold); + images.loadImages(threshold); var newUrl = 'topic/' + ajaxify.data.slug + (index > 1 ? ('/' + index) : ''); diff --git a/public/src/client/topic/events.js b/public/src/client/topic/events.js index f3e2d925c6..22a6c69d6c 100644 --- a/public/src/client/topic/events.js +++ b/public/src/client/topic/events.js @@ -6,9 +6,10 @@ define('forum/topic/events', [ 'forum/topic/postTools', 'forum/topic/threadTools', 'forum/topic/posts', + 'forum/topic/images', 'components', 'translator', -], function (postTools, threadTools, posts, components, translator) { +], function (postTools, threadTools, posts, images, components, translator) { var Events = {}; var events = { @@ -128,9 +129,9 @@ define('forum/topic/events', [ editedPostEl.html(translator.unescape(data.post.content)); editedPostEl.find('img:not(.not-responsive)').addClass('img-responsive'); app.replaceSelfLinks(editedPostEl.find('a')); - posts.wrapImagesInLinks(editedPostEl.parent()); - posts.unloadImages(editedPostEl.parent()); - posts.loadImages(); + images.wrapImagesInLinks(editedPostEl.parent()); + images.unloadImages(editedPostEl.parent()); + images.loadImages(); editedPostEl.fadeIn(250); var editData = { diff --git a/public/src/client/topic/images.js b/public/src/client/topic/images.js new file mode 100644 index 0000000000..cd44dd0914 --- /dev/null +++ b/public/src/client/topic/images.js @@ -0,0 +1,119 @@ +'use strict'; + + +define('forum/topic/images', [ + 'forum/topic/postTools', + 'navigator', + 'components', +], function (postTools, navigator, components) { + var Images = { + _imageLoaderTimeout: undefined, + }; + + Images.unloadImages = function (posts) { + var images = posts.find('[component="post/content"] img:not(.not-responsive)'); + + if (config.delayImageLoading) { + images.each(function () { + $(this).attr('data-src', $(this).attr('src')); + }).attr('data-state', 'unloaded').attr('src', 'about:blank'); + } else { + images.attr('data-state', 'loaded'); + Images.wrapImagesInLinks(posts); + } + }; + + Images.loadImages = function (threshold) { + if (Images._imageLoaderTimeout) { + clearTimeout(Images._imageLoaderTimeout); + } + + Images._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. + + If no threshold is defined, loaded images will push down content, as per + default + */ + + var images = components.get('post/content').find('img[data-state="unloaded"]'); + var visible = images.filter(function () { + return utils.isElementInViewport(this); + }); + var posts = $.unique(visible.map(function () { + return $(this).parents('[component="post"]').get(0); + })); + var scrollTop = $(window).scrollTop(); + var adjusting = false; + var adjustQueue = []; + var oldHeight; + var newHeight; + + function adjustPosition() { + adjusting = true; + oldHeight = document.body.clientHeight; + + // Display the image + $(this).attr('data-state', 'loaded'); + newHeight = document.body.clientHeight; + + var imageRect = this.getBoundingClientRect(); + if (imageRect.top < threshold) { + scrollTop += newHeight - oldHeight; + $(window).scrollTop(scrollTop); + } + + if (adjustQueue.length) { + adjustQueue.pop()(); + } else { + adjusting = false; + + Images.wrapImagesInLinks(posts); + posts.length = 0; + } + } + + // 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')); + image.removeAttr('data-src'); + }); + }, 250); + }; + + Images.wrapImagesInLinks = function (posts) { + posts.find('[component="post/content"] img:not(.emoji)').each(function () { + var $this = $(this); + var src = $this.attr('src'); + var suffixRegex = /-resized(\.[\w]+)?$/; + + if (src === 'about:blank') { + return; + } + + if (utils.isRelativeUrl(src) && suffixRegex.test(src)) { + src = src.replace(suffixRegex, '$1'); + } + + if (!$this.parent().is('a')) { + $this.wrap(''); + } + }); + }; + + + return Images; +}); diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 689d443ad3..86c387e39d 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -5,12 +5,11 @@ define('forum/topic/posts', [ 'forum/pagination', 'forum/infinitescroll', 'forum/topic/postTools', + 'forum/topic/images', 'navigator', 'components', -], function (pagination, infinitescroll, postTools, navigator, components) { - var Posts = { - _imageLoaderTimeout: undefined, - }; +], function (pagination, infinitescroll, postTools, images, navigator, components) { + var Posts = { }; Posts.onNewPost = function (data) { if (!data || !data.posts || !data.posts.length) { @@ -63,7 +62,7 @@ define('forum/topic/posts', [ function onNewPostPagination(data) { function scrollToPost() { scrollToPostIfSelf(data.posts[0]); - Posts.loadImages(); + images.loadImages(); } var posts = data.posts; @@ -107,7 +106,7 @@ define('forum/topic/posts', [ html.addClass('new'); } scrollToPostIfSelf(data.posts[0]); - Posts.loadImages(); + images.loadImages(); }); } @@ -247,7 +246,7 @@ define('forum/topic/posts', [ }; Posts.processPage = function (posts) { - Posts.unloadImages(posts); + images.unloadImages(posts); Posts.showBottomPostBar(); posts.find('[component="post/content"] img:not(.not-responsive)').addClass('img-responsive'); app.createUserTooltips(posts); @@ -260,110 +259,6 @@ define('forum/topic/posts', [ hidePostToolsForDeletedPosts(posts); }; - Posts.unloadImages = function (posts) { - var images = posts.find('[component="post/content"] img:not(.not-responsive)'); - - if (config.delayImageLoading) { - images.each(function () { - $(this).attr('data-src', $(this).attr('src')); - }).attr('data-state', 'unloaded').attr('src', 'about:blank'); - } else { - images.attr('data-state', 'loaded'); - Posts.wrapImagesInLinks(posts); - } - }; - - Posts.loadImages = function (threshold) { - if (Posts._imageLoaderTimeout) { - clearTimeout(Posts._imageLoaderTimeout); - } - - 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. - - If no threshold is defined, loaded images will push down content, as per - default - */ - - var images = components.get('post/content').find('img[data-state="unloaded"]'); - var visible = images.filter(function () { - return utils.isElementInViewport(this); - }); - var posts = $.unique(visible.map(function () { - return $(this).parents('[component="post"]').get(0); - })); - var scrollTop = $(window).scrollTop(); - var adjusting = false; - var adjustQueue = []; - var oldHeight; - var newHeight; - - function adjustPosition() { - adjusting = true; - oldHeight = document.body.clientHeight; - - // Display the image - $(this).attr('data-state', 'loaded'); - newHeight = document.body.clientHeight; - - var imageRect = this.getBoundingClientRect(); - if (imageRect.top < threshold) { - scrollTop += newHeight - oldHeight; - $(window).scrollTop(scrollTop); - } - - if (adjustQueue.length) { - adjustQueue.pop()(); - } else { - adjusting = false; - - Posts.wrapImagesInLinks(posts); - posts.length = 0; - } - } - - // 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')); - image.removeAttr('data-src'); - }); - }, 250); - }; - - Posts.wrapImagesInLinks = function (posts) { - posts.find('[component="post/content"] img:not(.emoji)').each(function () { - var $this = $(this); - var src = $this.attr('src'); - var suffixRegex = /-resized(\.[\w]+)?$/; - - if (src === 'about:blank') { - return; - } - - if (utils.isRelativeUrl(src) && suffixRegex.test(src)) { - src = src.replace(suffixRegex, '$1'); - } - - if (!$this.parent().is('a')) { - $this.wrap(''); - } - }); - }; - Posts.showBottomPostBar = function () { var mainPost = components.get('post', 'index', 0); var placeHolder = $('.post-bar-placeholder'); diff --git a/test/controllers.js b/test/controllers.js index 2ddbd6d914..b745004d59 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -507,7 +507,7 @@ describe('Controllers', function () { cid: cid, }, function (err) { assert.ifError(err); - request(nconf.get('url') + '/api/groups/group-details', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/groups/group-details', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body);