ImageExpand = init: -> return if g.VIEW is 'catalog' or !Conf['Image Expansion'] @EAI = $.el 'a', className: 'expand-all-shortcut fa fa-expand' textContent: 'EAI' title: 'Expand All Images' href: 'javascript:;' $.on @EAI, 'click', ImageExpand.cb.toggleAll Header.addShortcut @EAI, 3 Post.callbacks.push name: 'Image Expansion' cb: @node node: -> return unless @file?.isImage or @file?.isVideo {thumb} = @file $.on thumb.parentNode, 'click', ImageExpand.cb.toggle if @isClone and $.hasClass thumb, 'expanding' # If we clone a post where the image is still loading, # make it loading in the clone too. ImageExpand.contract @ ImageExpand.expand @ else if @isClone and @file.isExpanded and @file.isVideo clone = @ ImageExpand.setupVideoControls clone unless clone.origin.file.fullImage.paused $.queueTask -> Video.start clone.file.fullImage else if ImageExpand.on and !@isHidden and (Conf['Expand spoilers'] or !@file.isSpoiler) and (Conf['Expand videos'] or !@file.isVideo) ImageExpand.expand @, null, true cb: toggle: (e) -> return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0 post = Get.postFromNode @ return if post.file.isExpanded and post.file.fullImage?.controls e.preventDefault() ImageExpand.toggle post toggleAll: -> $.event 'CloseMenu' toggle = (post) -> {file} = post return unless file and (file.isImage or file.isVideo) and doc.contains post.nodes.root if ImageExpand.on and (!Conf['Expand spoilers'] and file.isSpoiler or !Conf['Expand videos'] and file.isVideo or Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0) return $.queueTask func, post if ImageExpand.on = $.hasClass ImageExpand.EAI, 'expand-all-shortcut' ImageExpand.EAI.className = 'contract-all-shortcut fa fa-compress' ImageExpand.EAI.title = 'Contract All Images' func = (post) -> ImageExpand.expand post, null, true else ImageExpand.EAI.className = 'expand-all-shortcut fa fa-expand' ImageExpand.EAI.title = 'Expand All Images' func = ImageExpand.contract g.posts.forEach (post) -> toggle post toggle post for post in post.clones return setFitness: -> (if @checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-' toggle: (post) -> {thumb} = post.file unless post.file.isExpanded or $.hasClass thumb, 'expanding' ImageExpand.expand post return # Scroll back to the thumbnail when contracting the image # to avoid being left miles away from the relevant post. {root} = post.nodes {top, left} = (if Conf['Advance on contract'] then do -> next = root while next = $.x "following::div[contains(@class,'postContainer')][1]", next continue if $('.stub', next) or next.offsetHeight is 0 return next root else root ).getBoundingClientRect() if top < 0 y = top if Conf['Fixed Header'] and not Conf['Bottom Header'] headRect = Header.bar.getBoundingClientRect() y -= headRect.top + headRect.height if left < 0 x = -window.scrollX window.scrollBy x, y if x or y ImageExpand.contract post contract: (post) -> if post.file.isVideo and video = post.file.fullImage video.pause() TrashQueue.add video, post post.file.thumb.parentNode.href = video.src post.file.thumb.parentNode.target = '_blank' for eventName, cb of ImageExpand.videoCB $.off video, eventName, cb $.rm post.file.videoControls delete post.file.videoControls $.rmClass post.nodes.root, 'expanded-image' $.rmClass post.file.thumb, 'expanding' post.file.isExpanded = false expand: (post, src, disableAutoplay) -> # Do not expand images of hidden/filtered replies, or already expanded pictures. {thumb, isVideo} = post.file return if post.isHidden or post.file.isExpanded or $.hasClass thumb, 'expanding' $.addClass thumb, 'expanding' if el = post.file.fullImage # Expand already-loaded/ing picture. TrashQueue.remove el else el = post.file.fullImage = $.el (if isVideo then 'video' else 'img'), className: 'full-image' $.on el, 'error', ImageExpand.error el.src = src or post.file.URL $.after thumb, el unless el is thumb.nextSibling $.asap (-> if isVideo then el.videoHeight else el.naturalHeight), -> ImageExpand.completeExpand post, disableAutoplay completeExpand: (post, disableAutoplay) -> {thumb} = post.file return unless $.hasClass thumb, 'expanding' # contracted before the image loaded unless post.nodes.root.parentNode # Image might start/finish loading before the post is inserted. # Don't scroll when it's expanded in a QP for example. ImageExpand.completeExpand2 post return {bottom} = post.nodes.root.getBoundingClientRect() $.queueTask -> ImageExpand.completeExpand2 post, disableAutoplay return unless bottom <= 0 window.scrollBy 0, post.nodes.root.getBoundingClientRect().bottom - bottom completeExpand2: (post, disableAutoplay) -> {thumb} = post.file $.addClass post.nodes.root, 'expanded-image' $.rmClass post.file.thumb, 'expanding' post.file.isExpanded = true if post.file.isVideo ImageExpand.setupVideoControls post Video.configure post.file.fullImage, disableAutoplay videoCB: click: (e) -> if @paused and not @controls @play() e.stopPropagation() # dragging to the left contracts the video mousedown: (e) -> @dataset.mousedown = 'true' if e.button is 0 mouseup: (e) -> @dataset.mousedown = 'false' if e.button is 0 mouseover: (e) -> @dataset.mousedown = 'false' mouseout: (e) -> if @dataset.mousedown is 'true' and e.clientX <= @getBoundingClientRect().left ImageExpand.contract (Get.postFromNode @) setupVideoControls: (post) -> {file} = post video = file.fullImage # disable link to file so native controls can work file.thumb.parentNode.removeAttribute 'href' file.thumb.parentNode.removeAttribute 'target' # setup callbacks on video element video.dataset.mousedown = 'false' $.on video, eventName, cb for eventName, cb of ImageExpand.videoCB # setup controls in file info file.videoControls = $.el 'span', className: 'video-controls' if Conf['Show Controls'] contract = $.el 'a', textContent: 'contract' href: 'javascript:;' title: 'You can also contract the video by dragging it to the left.' $.on contract, 'click', (e) -> ImageExpand.contract post $.add file.videoControls, [$.tn('\u00A0'), contract] $.add file.text, file.videoControls error: -> post = Get.postFromNode @ $.rm @ delete post.file.fullImage # Images can error: # - before the image started loading. # - after the image started loading. unless $.hasClass(post.file.thumb, 'expanding') or $.hasClass post.nodes.root, 'expanded-image' # Don't try to re-expend if it was already contracted. return ImageExpand.contract post src = @src.split '/' if src[2] is 'i.4cdn.org' URL = Redirect.to 'file', boardID: src[3] filename: src[src.length - 1] if URL setTimeout ImageExpand.expand, 10000, post, URL return if g.DEAD or post.isDead or post.file.isDead return timeoutID = setTimeout ImageExpand.expand, 10000, post <% if (type === 'crx') { %> $.ajax @src, onloadend: -> return if @status isnt 404 clearTimeout timeoutID post.kill true , type: 'head' <% } else { %> # XXX CORS for i.4cdn.org WHEN? $.ajax "//a.4cdn.org/#{post.board}/res/#{post.thread}.json", onload: -> return if @status isnt 200 for postObj in @response.posts break if postObj.no is post.ID if postObj.no isnt post.ID clearTimeout timeoutID post.kill() else if postObj.filedeleted clearTimeout timeoutID post.kill true <% } %> menu: init: -> return if g.VIEW is 'catalog' or !Conf['Image Expansion'] el = $.el 'span', textContent: 'Image Expansion' className: 'image-expansion-link' {createSubEntry} = ImageExpand.menu subEntries = [] for name, conf of Config.imageExpansion subEntries.push createSubEntry name, conf[1] $.event 'AddMenuEntry', type: 'header' el: el order: 105 subEntries: subEntries createSubEntry: (name, desc) -> label = $.el 'label', innerHTML: " #{name}" title: desc input = label.firstElementChild if name in ['Fit width', 'Fit height'] $.on input, 'change', ImageExpand.cb.setFitness input.checked = Conf[name] $.event 'change', null, input $.on input, 'change', $.cb.checked el: label