Add Image Expansion.

Close #314.
Close #481.
This commit is contained in:
Nicolas Stepien 2013-02-14 02:32:22 +01:00
parent 2b8f808b6b
commit 7326caf438
8 changed files with 462 additions and 34 deletions

File diff suppressed because one or more lines are too long

View File

@ -6,11 +6,15 @@ alpha
From the Header's menu, access to: From the Header's menu, access to:
Settings Settings
Quick Reply shortcut Quick Reply shortcut
Image Expansion
Can be auto-hidden. Can be auto-hidden.
QR changes: QR changes:
Creating threads outside of the index is now possible. Creating threads outside of the index is now possible.
Selection-to-quote also applies to selected text inside the post, not just inside the comment. Selection-to-quote also applies to selected text inside the post, not just inside the comment.
Quoting the OP will not insert the >>opnumber anymore unless the QR was already opened. Quoting the OP will not insert the >>opnumber anymore unless the QR was already opened.
Image Expansion changes:
Expanding OP images won't squish replies anymore.
There is now a setting to allow expanding spoilers.
Added touch and multi-touch support for dragging windows. Added touch and multi-touch support for dragging windows.
The Thread Updater will pause when offline, and resume when online. The Thread Updater will pause when offline, and resume when online.
Added Thread & Post Hiding in the Menu, with individual settings. Added Thread & Post Hiding in the Menu, with individual settings.

View File

@ -249,6 +249,17 @@ a[href="javascript:;"] {
.fileText:not(:hover) .fnfull { .fileText:not(:hover) .fnfull {
display: none; display: none;
} }
:root.fit-width .full-image {
max-width: 100%;
}
:root.gecko.fit-width .full-image,
:root.presto.fit-width .full-image {
width: 100%;
}
.expanded-image > .op > .file > .fileThumb,
.expanded-image > .op > .file > .fileThumb > .full-image {
float: none;
}
#ihover { #ihover {
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;

View File

@ -86,7 +86,8 @@ $.extend $,
addStyle: (css) -> addStyle: (css) ->
style = $.el 'style', style = $.el 'style',
textContent: css textContent: css
$.add d.head, style $.asap (-> d.head), ->
$.add d.head, style
style style
x: (path, root=d.body) -> x: (path, root=d.body) ->
# XPathResult.ANY_UNORDERED_NODE_TYPE === 8 # XPathResult.ANY_UNORDERED_NODE_TYPE === 8

View File

@ -22,7 +22,6 @@ Config =
Imaging: Imaging:
'Auto-GIF': [false, 'Animate GIF thumbnails.'] 'Auto-GIF': [false, 'Animate GIF thumbnails.']
'Image Expansion': [true, 'Expand images.'] 'Image Expansion': [true, 'Expand images.']
'Expand From Position': [true, 'Expand all images only from current position to thread end.']
'Image Hover': [false, 'Show full image on mouseover.'] 'Image Hover': [false, 'Show full image on mouseover.']
'Sauce': [true, 'Add sauce links to images.'] 'Sauce': [true, 'Add sauce links to images.']
'Reveal Spoilers': [false, 'Reveal spoiler thumbnails.'] 'Reveal Spoilers': [false, 'Reveal spoiler thumbnails.']
@ -161,4 +160,3 @@ Config =
'Scroll BG': [false, 'Auto-scroll background tabs.'] 'Scroll BG': [false, 'Auto-scroll background tabs.']
'Auto Update': [true, 'Automatically fetch new posts.'] 'Auto Update': [true, 'Automatically fetch new posts.']
'Interval': 30 'Interval': 30
imageFit: 'fit width'

View File

@ -38,7 +38,7 @@ Header =
$.prepend headerBar, [menuButton, boardListButton, $.tn(' '), boardTitle, boardList, toggleBar] $.prepend headerBar, [menuButton, boardListButton, $.tn(' '), boardTitle, boardList, toggleBar]
catalogToggler = $.el 'label', catalogToggler = $.el 'label',
innerHTML: "<input type=checkbox#{if g.VIEW is 'catalog' then ' checked' else ''}> Use catalog links" innerHTML: "<input type=checkbox #{if g.VIEW is 'catalog' then 'checked' else ''}> Use catalog links"
$.on catalogToggler.firstElementChild, 'change', @toggleCatalogLinks $.on catalogToggler.firstElementChild, 'change', @toggleCatalogLinks
$.event 'AddMenuEntry', $.event 'AddMenuEntry',
type: 'header' type: 'header'
@ -811,7 +811,7 @@ Menu =
toggle: (e) -> toggle: (e) ->
post = post =
if @dataset.clone if @dataset.clone
Get.postFromRoot $.x 'ancestor::div[contains(@class,"postContainer")][1]', @ Get.postFromNode @
else else
g.posts[@dataset.postid] g.posts[@dataset.postid]
Menu.menu.toggle e, @, post Menu.menu.toggle e, @, post
@ -1377,6 +1377,10 @@ Get =
index = root.dataset.clone index = root.dataset.clone
post = g.posts["#{board}.#{postID}"] post = g.posts["#{board}.#{postID}"]
if index then post.clones[index] else post if index then post.clones[index] else post
postFromNode: (root) ->
Get.postFromRoot $.x 'ancestor::div[contains(@class,"postContainer")][1]', root
contextFromLink: (quotelink) ->
Get.postFromRoot $.x 'ancestor::div[parent::div[@class="thread"]][1]', quotelink
postDataFromLink: (link) -> postDataFromLink: (link) ->
if link.hostname is 'boards.4chan.org' if link.hostname is 'boards.4chan.org'
path = link.pathname.split '/' path = link.pathname.split '/'
@ -1418,8 +1422,6 @@ Get =
quotelinks.filter (quotelink) -> quotelinks.filter (quotelink) ->
{board, postID} = Get.postDataFromLink quotelink {board, postID} = Get.postDataFromLink quotelink
board is post.board.ID and postID is post.ID board is post.board.ID and postID is post.ID
contextFromLink: (quotelink) ->
Get.postFromRoot $.x 'ancestor::div[parent::div[@class="thread"]][1]', quotelink
postClone: (board, threadID, postID, root, context) -> postClone: (board, threadID, postID, root, context) ->
if post = g.posts["#{board}.#{postID}"] if post = g.posts["#{board}.#{postID}"]
Get.insert post, root, context Get.insert post, root, context
@ -2085,6 +2087,171 @@ Sauce =
nodes.push $.tn('\u00A0'), link @, Sauce.link.cloneNode true nodes.push $.tn('\u00A0'), link @, Sauce.link.cloneNode true
$.add @file.info, nodes $.add @file.info, nodes
ImageExpand =
init: ->
return if g.VIEW is 'catalog' or !Conf['Image Expansion']
Post::callbacks.push
name: 'Image Expansion'
cb: @node
node: ->
return unless @file and @file.isImage
$.on @file.thumb.parentNode, 'click', ImageExpand.cb.toggle
if ImageExpand.on and !@isHidden
ImageExpand.expand @
cb:
toggle: (e) ->
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0
e.preventDefault()
ImageExpand.toggle Get.postFromNode @
all: ->
$.event 'CloseMenu'
ImageExpand.on = @checked
for ID, post of g.posts
for post in [post].concat post.clones
{file} = post
continue unless file and file.isImage
{thumb} = file
continue unless doc.contains thumb
if ImageExpand.on
if !ImageExpand.spoilers and file.isSpoiler or
ImageExpand.fromPosition and thumb.getBoundingClientRect().top < 0
continue
ImageExpand.expand post
else
ImageExpand.contract post
return
updateFitness: ->
{checked} = @
(if checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-'
return unless @name is 'Fit height'
if checked
$.on window, 'resize', ImageExpand.resize
unless ImageExpand.style
ImageExpand.style = $.addStyle ''
ImageExpand.resize()
else
$.off window, 'resize', ImageExpand.resize
spoilers: ->
ImageExpand.spoilers = @checked
position: ->
ImageExpand.fromPosition = @checked
toggle: (post) ->
{thumb} = post.file
unless thumb.hidden
ImageExpand.expand post
return
rect = thumb.parentNode.getBoundingClientRect()
if rect.bottom > 0 # Should be at least partially visible.
# Scroll back to the thumbnail when contracting the image
# to avoid being left miles away from the relevant post.
postRect = post.nodes.root.getBoundingClientRect()
headRect = $.id('header-bar').getBoundingClientRect()
top = postRect.top - headRect.top - headRect.height - 2
if $.engine is 'webkit'
d.body.scrollTop += top if rect.top < 0
d.body.scrollLeft = 0 if rect.left < 0
else
d.documentElement.scrollTop += top if rect.top < 0
d.documentElement.scrollLeft = 0 if rect.left < 0
ImageExpand.contract post
contract: (post) ->
{thumb} = post.file
thumb.hidden = false
if img = $ '.full-image', thumb.parentNode
img.hidden = true
$.rmClass post.nodes.root, 'expanded-image'
expand: (post) ->
# Do not expand images of hidden/filtered replies, or already expanded pictures.
{thumb} = post.file
return if post.isHidden or thumb.hidden
thumb.hidden = true
$.addClass post.nodes.root, 'expanded-image'
if img = $ '.full-image', thumb.parentNode
# Expand already loaded picture
img.hidden = false
return
img = $.el 'img',
className: 'full-image'
src: post.file.URL
$.on img, 'error', ImageExpand.error
$.after thumb, img
error: ->
post = Get.postFromNode @
ImageExpand.contract post
$.rm @
src = @src.split '/'
unless src[2] is 'images.4chan.org' and URL = Redirect.image src[3], src[5]
return if g.DEAD
{URL} = post.file
return if $.engine isnt 'webkit' and URL.split('/')[2] is 'images.4chan.org'
timeoutID = setTimeout ImageExpand.expand, 10000, post
# Only Chrome let userscripts do cross domain requests.
# Don't check for 404'd status in the archivers.
return if $.engine isnt 'webkit' or URL.split('/')[2] isnt 'images.4chan.org'
$.ajax URL, onreadystatechange: (-> clearTimeout timeoutID if @status is 404),
type: 'head'
menu:
init: ->
return if g.VIEW is 'catalog' or !Conf['Image Expansion']
el = $.el 'span',
textContent: 'Image expansion'
ImageExpand.menu.config = $.get 'ImageExpansionConfig',
'Fit width': true
'Fit height': false
'Expand spoilers': false
'Expand from here': true
{createSubEntry} = ImageExpand.menu
subEntries = []
subEntries.push createSubEntry 'Expand all'
subEntries.push createSubEntry 'Fit width', true
subEntries.push createSubEntry 'Fit height', true
subEntries.push createSubEntry 'Expand spoilers', true
subEntries.push createSubEntry 'Expand from here', true
$.event 'AddMenuEntry',
type: 'header'
el: el
order: 20
subEntries: subEntries
createSubEntry: (type, hasConfig) ->
label = $.el 'label',
innerHTML: "<input type=checkbox name='#{type}'> #{type}"
input = label.firstElementChild
switch type
when 'Expand all'
$.on input, 'change', ImageExpand.cb.all
when 'Expand spoilers'
label.title = 'Expand all images along with spoilers.'
$.on input, 'change', ImageExpand.cb.spoilers
when 'Expand from here'
label.title = 'Expand all images only from current position to thread end.'
$.on input, 'change', ImageExpand.cb.position
else
$.on input, 'change', ImageExpand.cb.updateFitness
if hasConfig
input.checked = ImageExpand.menu.config[type]
$.event 'change', null, input
$.on input, 'change', ImageExpand.menu.saveConfig
el: label
saveConfig: ->
{config} = ImageExpand.menu
config[@name] = @checked
$.set 'ImageExpansionConfig', config
resize: ->
ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:#{doc.clientHeight}px}"
RevealSpoilers = RevealSpoilers =
init: -> init: ->
return if g.VIEW is 'catalog' or !Conf['Reveal Spoilers'] return if g.VIEW is 'catalog' or !Conf['Reveal Spoilers']
@ -2148,15 +2315,15 @@ ImageHover =
error: -> error: ->
return unless @parentNode return unless @parentNode
src = @src.split '/' src = @src.split '/'
unless src[2] is 'images.4chan.org' and url = Redirect.image src[3], src[5] unless src[2] is 'images.4chan.org' and URL = Redirect.image src[3], src[5]
return if g.DEAD return if g.DEAD
url = "//images.4chan.org/#{src[3]}/src/#{src[5]}" {URL} = post.file
return if $.engine isnt 'webkit' and url.split('/')[2] is 'images.4chan.org' return if $.engine isnt 'webkit' and URL.split('/')[2] is 'images.4chan.org'
timeoutID = setTimeout (=> @src = url), 3000 timeoutID = setTimeout (=> @src = URL), 3000
# Only Chrome let userscripts do cross domain requests. # Only Chrome let userscripts do cross domain requests.
# Don't check for 404'd status in the archivers. # Don't check for 404'd status in the archivers.
return if $.engine isnt 'webkit' or url.split('/')[2] isnt 'images.4chan.org' return if $.engine isnt 'webkit' or URL.split('/')[2] isnt 'images.4chan.org'
$.ajax url, onreadystatechange: (-> clearTimeout timeoutID if @status is 404), $.ajax URL, onreadystatechange: (-> clearTimeout timeoutID if @status is 404),
type: 'head' type: 'head'
ThreadUpdater = ThreadUpdater =

View File

@ -316,6 +316,8 @@ Main =
initFeature 'Time Formatting', Time initFeature 'Time Formatting', Time
initFeature 'File Info Formatting', FileInfo initFeature 'File Info Formatting', FileInfo
initFeature 'Sauce', Sauce initFeature 'Sauce', Sauce
initFeature 'Image Expansion', ImageExpand
initFeature 'Image Expansion (Menu)', ImageExpand.menu
initFeature 'Reveal Spoilers', RevealSpoilers initFeature 'Reveal Spoilers', RevealSpoilers
initFeature 'Auto-GIF', AutoGIF initFeature 'Auto-GIF', AutoGIF
initFeature 'Image Hover', ImageHover initFeature 'Image Hover', ImageHover

View File

@ -96,7 +96,7 @@ QR =
status: (data={}) -> status: (data={}) ->
return unless QR.el return unless QR.el
if g.dead # XXX if g.DEAD
value = 404 value = 404
disabled = true disabled = true
QR.cooldown.auto = false QR.cooldown.auto = false