From 67b7d263e25438f1abec158c431bfc4bd68c4435 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Fri, 9 Jan 2015 18:46:05 -0700 Subject: [PATCH] ImageLoader.coffee --- builds/appchan-x.user.js | 145 ++++++++++++++++++++++------------ builds/crx/script.js | 145 ++++++++++++++++++++++------------ src/Images/ImageLoader.coffee | 105 +++++++++++++----------- 3 files changed, 247 insertions(+), 148 deletions(-) diff --git a/builds/appchan-x.user.js b/builds/appchan-x.user.js index def698c86..b6948bbeb 100644 --- a/builds/appchan-x.user.js +++ b/builds/appchan-x.user.js @@ -11388,7 +11388,10 @@ ImageLoader = { init: function() { - var prefetch; + var prefetch, _ref; + if ((_ref = g.VIEW) !== 'index' && _ref !== 'thread') { + return; + } if (!(Conf["Image Prefetching"] || Conf["Replace JPG"] || Conf["Replace PNG"] || Conf["Replace GIF"] || Conf["Replace WEBM"])) { return; } @@ -11396,12 +11399,17 @@ name: 'Image Replace', cb: this.node }); - Thread.callbacks.push({ - name: 'Image Replace', - cb: this.thread + $.on(d, 'PostsInserted', function() { + return g.posts.forEach(ImageLoader.prefetch); }); + if (Conf['Replace WEBM']) { + this.processVideo(); + } + if (!Conf['Image Prefetching']) { + return; + } prefetch = $.el('label', { - innerHTML: ' Prefetch Images' + innerHTML: " Prefetch Images" }); this.el = prefetch.firstElementChild; $.on(this.el, 'change', this.toggle); @@ -11410,65 +11418,98 @@ order: 104 }); }, - thread: function() { - return ImageLoader.thread = this; - }, node: function() { - var URL, cb, file, isImage, isVideo, match, replace, style, thumb, type, _ref, _ref1; - if (!this.file) { + if (this.isClone || !this.file) { return; } - _ref = this.file, isImage = _ref.isImage, isVideo = _ref.isVideo; - if (this.isClone || this.isHidden || this.thread.isHidden || !(isImage || isVideo)) { + if (Conf['Replace WEBM'] && this.file.isVideo) { + ImageLoader.replaceVideo(this); + } + return ImageLoader.prefetch(this); + }, + replaceVideo: function(post) { + var attr, file, thumb, video, _i, _len, _ref; + file = post.file; + thumb = file.thumb; + video = $.el('video', { + preload: 'none', + loop: true, + poster: thumb.src, + textContent: thumb.alt, + className: thumb.className + }); + video.dataset.md5 = thumb.dataset.md5; + _ref = ['height', 'width', 'maxHeight', 'maxWidth']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + attr = _ref[_i]; + video.style[attr] = thumb.style[attr]; + } + video.src = file.URL; + $.replace(thumb, video); + file.thumb = video; + return file.videoThumb = true; + }, + prefetch: function(post) { + var URL, clone, el, file, isImage, isVideo, item, match, pass, replace, thumb, type, _i, _j, _len, _len1, _ref, _ref1; + file = post.file; + if (!file) { + return; + } + isImage = file.isImage, isVideo = file.isVideo, thumb = file.thumb, URL = file.URL; + if (file.isPrefetched || !(isImage || isVideo) || post.isHidden || post.thread.isHidden) { return; } - _ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL; - style = thumb.style; type = (match = URL.match(/\.([^.]+)$/)[1].toUpperCase()) === 'JPEG' ? 'JPG' : match; - replace = "Replace " + type; - if (!((Conf[replace] && !/spoiler/.test(thumb.src)) || (Conf['prefetch'] && g.VIEW === 'thread'))) { + replace = Conf["Replace " + type] && !/spoiler/.test(thumb.src); + if (!(replace || Conf['prefetch'])) { return; } - if (this.file.isSpoiler) { - style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px'; - } - file = $.el(isImage ? 'img' : 'video'); - if (Conf[replace]) { - if (isVideo) { - file.alt = thumb.alt; - file.dataset.md5 = thumb.dataset.md5; - file.style.height = style.height; - file.style.width = style.width; - file.style.maxHeight = style.maxHeight; - file.style.maxWidth = style.maxWidth; - file.loop = true; - file.autoplay = Conf['Autoplay']; - if (Conf['Image Hover']) { - $.on(file, 'mouseover', ImageHover.mouseover); - } + pass = false; + _ref = [post].concat(__slice.call(post.clones)); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + item = _ref[_i]; + if (doc.contains(item.nodes.root)) { + pass = true; + break; } - cb = (function(_this) { - return function() { - $.off(file, 'load loadedmetadata', cb); - if (isVideo) { - $.replace(thumb, file); - _this.file.thumb = file; - return; - } - return thumb.src = URL; - }; - })(this); - $.on(file, 'load loadedmetadata', cb); } - return file.src = URL; + if (!pass) { + return; + } + file.isPrefetched = true; + if (file.videoThumb) { + _ref1 = post.clones; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + clone = _ref1[_j]; + clone.file.thumb.preload = 'auto'; + } + thumb.preload = 'auto'; + if (typeof chrome === "undefined" || chrome === null) { + $.on(thumb, 'loadeddata', function() { + return this.removeAttribute('poster'); + }); + } + return; + } + el = $.el(isImage ? 'img' : 'video'); + if (replace && isImage) { + $.on(el, 'load', function() { + var _k, _len2, _ref2, _results; + _ref2 = post.clones; + _results = []; + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + clone = _ref2[_k]; + _results.push(clone.file.thumb.src = URL); + } + return _results; + }); + thumb.src = URL; + } + return el.src = URL; }, toggle: function() { - var enabled; - enabled = Conf['prefetch'] = this.checked; - if (enabled) { - g.BOARD.posts.forEach(function(post) { - return ImageLoader.node.call(post); - }); + if (Conf['prefetch'] = this.checked) { + g.BOARD.posts.forEach(ImageLoader.prefetch); } } }; diff --git a/builds/crx/script.js b/builds/crx/script.js index 84049e87f..46eff96e9 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -11410,7 +11410,10 @@ ImageLoader = { init: function() { - var prefetch; + var prefetch, _ref; + if ((_ref = g.VIEW) !== 'index' && _ref !== 'thread') { + return; + } if (!(Conf["Image Prefetching"] || Conf["Replace JPG"] || Conf["Replace PNG"] || Conf["Replace GIF"] || Conf["Replace WEBM"])) { return; } @@ -11418,12 +11421,17 @@ name: 'Image Replace', cb: this.node }); - Thread.callbacks.push({ - name: 'Image Replace', - cb: this.thread + $.on(d, 'PostsInserted', function() { + return g.posts.forEach(ImageLoader.prefetch); }); + if (Conf['Replace WEBM']) { + this.processVideo(); + } + if (!Conf['Image Prefetching']) { + return; + } prefetch = $.el('label', { - innerHTML: ' Prefetch Images' + innerHTML: " Prefetch Images" }); this.el = prefetch.firstElementChild; $.on(this.el, 'change', this.toggle); @@ -11432,65 +11440,98 @@ order: 104 }); }, - thread: function() { - return ImageLoader.thread = this; - }, node: function() { - var URL, cb, file, isImage, isVideo, match, replace, style, thumb, type, _ref, _ref1; - if (!this.file) { + if (this.isClone || !this.file) { return; } - _ref = this.file, isImage = _ref.isImage, isVideo = _ref.isVideo; - if (this.isClone || this.isHidden || this.thread.isHidden || !(isImage || isVideo)) { + if (Conf['Replace WEBM'] && this.file.isVideo) { + ImageLoader.replaceVideo(this); + } + return ImageLoader.prefetch(this); + }, + replaceVideo: function(post) { + var attr, file, thumb, video, _i, _len, _ref; + file = post.file; + thumb = file.thumb; + video = $.el('video', { + preload: 'none', + loop: true, + poster: thumb.src, + textContent: thumb.alt, + className: thumb.className + }); + video.dataset.md5 = thumb.dataset.md5; + _ref = ['height', 'width', 'maxHeight', 'maxWidth']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + attr = _ref[_i]; + video.style[attr] = thumb.style[attr]; + } + video.src = file.URL; + $.replace(thumb, video); + file.thumb = video; + return file.videoThumb = true; + }, + prefetch: function(post) { + var URL, clone, el, file, isImage, isVideo, item, match, pass, replace, thumb, type, _i, _j, _len, _len1, _ref, _ref1; + file = post.file; + if (!file) { + return; + } + isImage = file.isImage, isVideo = file.isVideo, thumb = file.thumb, URL = file.URL; + if (file.isPrefetched || !(isImage || isVideo) || post.isHidden || post.thread.isHidden) { return; } - _ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL; - style = thumb.style; type = (match = URL.match(/\.([^.]+)$/)[1].toUpperCase()) === 'JPEG' ? 'JPG' : match; - replace = "Replace " + type; - if (!((Conf[replace] && !/spoiler/.test(thumb.src)) || (Conf['prefetch'] && g.VIEW === 'thread'))) { + replace = Conf["Replace " + type] && !/spoiler/.test(thumb.src); + if (!(replace || Conf['prefetch'])) { return; } - if (this.file.isSpoiler) { - style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px'; - } - file = $.el(isImage ? 'img' : 'video'); - if (Conf[replace]) { - if (isVideo) { - file.alt = thumb.alt; - file.dataset.md5 = thumb.dataset.md5; - file.style.height = style.height; - file.style.width = style.width; - file.style.maxHeight = style.maxHeight; - file.style.maxWidth = style.maxWidth; - file.loop = true; - file.autoplay = Conf['Autoplay']; - if (Conf['Image Hover']) { - $.on(file, 'mouseover', ImageHover.mouseover); - } + pass = false; + _ref = [post].concat(__slice.call(post.clones)); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + item = _ref[_i]; + if (doc.contains(item.nodes.root)) { + pass = true; + break; } - cb = (function(_this) { - return function() { - $.off(file, 'load loadedmetadata', cb); - if (isVideo) { - $.replace(thumb, file); - _this.file.thumb = file; - return; - } - return thumb.src = URL; - }; - })(this); - $.on(file, 'load loadedmetadata', cb); } - return file.src = URL; + if (!pass) { + return; + } + file.isPrefetched = true; + if (file.videoThumb) { + _ref1 = post.clones; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + clone = _ref1[_j]; + clone.file.thumb.preload = 'auto'; + } + thumb.preload = 'auto'; + if (typeof chrome === "undefined" || chrome === null) { + $.on(thumb, 'loadeddata', function() { + return this.removeAttribute('poster'); + }); + } + return; + } + el = $.el(isImage ? 'img' : 'video'); + if (replace && isImage) { + $.on(el, 'load', function() { + var _k, _len2, _ref2, _results; + _ref2 = post.clones; + _results = []; + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + clone = _ref2[_k]; + _results.push(clone.file.thumb.src = URL); + } + return _results; + }); + thumb.src = URL; + } + return el.src = URL; }, toggle: function() { - var enabled; - enabled = Conf['prefetch'] = this.checked; - if (enabled) { - g.BOARD.posts.forEach(function(post) { - return ImageLoader.node.call(post); - }); + if (Conf['prefetch'] = this.checked) { + g.BOARD.posts.forEach(ImageLoader.prefetch); } } }; diff --git a/src/Images/ImageLoader.coffee b/src/Images/ImageLoader.coffee index 8934d8295..112866f4b 100755 --- a/src/Images/ImageLoader.coffee +++ b/src/Images/ImageLoader.coffee @@ -1,17 +1,22 @@ ImageLoader = init: -> - return unless Conf["Image Prefetching"] or Conf["Replace JPG"] or Conf["Replace PNG"] or Conf["Replace GIF"] or Conf["Replace WEBM"] + return unless g.VIEW in ['index', 'thread'] + return unless Conf["Image Prefetching"] or + Conf["Replace JPG"] or Conf["Replace PNG"] or Conf["Replace GIF"] or Conf["Replace WEBM"] Post.callbacks.push name: 'Image Replace' cb: @node - Thread.callbacks.push - name: 'Image Replace' - cb: @thread + $.on d, 'PostsInserted', -> + g.posts.forEach ImageLoader.prefetch + + @processVideo() if Conf['Replace WEBM'] + + return unless Conf['Image Prefetching'] prefetch = $.el 'label', - innerHTML: ' Prefetch Images' + <%= html(' Prefetch Images') %> @el = prefetch.firstElementChild $.on @el, 'change', @toggle @@ -20,48 +25,60 @@ ImageLoader = el: prefetch order: 104 - thread: -> - ImageLoader.thread = @ - node: -> - return unless @file - {isImage, isVideo} = @file - return if @isClone or @isHidden or @thread.isHidden or !(isImage or isVideo) - {thumb, URL} = @file - {style} = thumb - type = if (match = URL.match(/\.([^.]+)$/)[1].toUpperCase()) is 'JPEG' then 'JPG' else match - replace = "Replace #{type}" - return unless (Conf[replace] and !/spoiler/.test thumb.src) or (Conf['prefetch'] and g.VIEW is 'thread') - if @file.isSpoiler - # Revealed spoilers do not have height/width set, this fixes the image's dimensions. - style.maxHeight = style.maxWidth = if @isReply then '125px' else '250px' - file = $.el if isImage then 'img' else 'video' - if Conf[replace] - if isVideo - file.alt = thumb.alt - file.dataset.md5 = thumb.dataset.md5 - file.style.height = style.height - file.style.width = style.width - file.style.maxHeight = style.maxHeight - file.style.maxWidth = style.maxWidth - file.loop = true - file.autoplay = Conf['Autoplay'] - - $.on file, 'mouseover', ImageHover.mouseover if Conf['Image Hover'] + return if @isClone or !@file + ImageLoader.replaceVideo @ if Conf['Replace WEBM'] and @file.isVideo + ImageLoader.prefetch @ - cb = => - $.off file, 'load loadedmetadata', cb - # Replace the thumbnail once the file has finished loading. - if isVideo - $.replace thumb, file - @file.thumb = file # XXX expanding requires the post.file.thumb node. - return + replaceVideo: (post) -> + {file} = post + {thumb} = file + video = $.el 'video', + preload: 'none' + loop: true + poster: thumb.src + textContent: thumb.alt + className: thumb.className + video.dataset.md5 = thumb.dataset.md5 + video.style[attr] = thumb.style[attr] for attr in ['height', 'width', 'maxHeight', 'maxWidth'] + video.src = file.URL + $.replace thumb, video + file.thumb = video + file.videoThumb = true + + prefetch: (post) -> + {file} = post + return unless file + {isImage, isVideo, thumb, URL} = file + return if file.isPrefetched or !(isImage or isVideo) or post.isHidden or post.thread.isHidden + type = if (match = URL.match(/\.([^.]+)$/)[1].toUpperCase()) is 'JPEG' then 'JPG' else match + replace = Conf["Replace #{type}"] and !/spoiler/.test thumb.src + return unless replace or Conf['prefetch'] + + pass = false + for item in [post, post.clones...] + if doc.contains item.nodes.root + pass = true + break + return unless pass + + file.isPrefetched = true + if file.videoThumb + clone.file.thumb.preload = 'auto' for clone in post.clones + thumb.preload = 'auto' + # XXX Cloned video elements with poster in Firefox cause momentary display of image loading icon. + if !chrome? + $.on thumb, 'loadeddata', -> @removeAttribute 'poster' + return + + el = $.el if isImage then 'img' else 'video' + if replace and isImage + $.on el, 'load', -> + clone.file.thumb.src = URL for clone in post.clones thumb.src = URL - $.on file, 'load loadedmetadata', cb - file.src = URL + el.src = URL toggle: -> - enabled = Conf['prefetch'] = @checked - if enabled - g.BOARD.posts.forEach (post) -> ImageLoader.node.call post + if Conf['prefetch'] = @checked + g.BOARD.posts.forEach ImageLoader.prefetch return \ No newline at end of file