parent
2b8f808b6b
commit
7326caf438
285
4chan_x.user.js
285
4chan_x.user.js
File diff suppressed because one or more lines are too long
@ -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.
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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'
|
|
||||||
|
|||||||
@ -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 =
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user