Merge tag 'beta' into archiveupdate

4chan X v1.8.8.3.

Conflicts:
	CHANGELOG.md
	LICENSE
	builds/4chan-X-beta.crx
	builds/4chan-X-beta.meta.js
	builds/4chan-X-beta.user.js
	builds/4chan-X-noupdate.crx
	builds/4chan-X-noupdate.user.js
	builds/4chan-X.crx
	builds/4chan-X.meta.js
	builds/4chan-X.user.js
	builds/4chan-X.zip
	builds/updates-beta.xml
	builds/updates.xml
	package.json
This commit is contained in:
ccd0 2014-08-04 13:03:39 -07:00
commit 9b0407754f
27 changed files with 1401 additions and 1175 deletions

View File

@ -1,3 +1,40 @@
### v1.8.8.3
*2014-08-02*
**ccd0**, **Zixaphir**
- Bug fixes.
### v1.8.8.2
*2014-07-29*
**ccd0**
- Bug fixes.
### v1.8.8.1
*2014-07-28*
**ccd0**
- Fix for image 404 redirection which was broken in v1.8.8.
### v1.8.8
*2014-07-27*
Based on v1.8.7.1.
**MayhemYDG**
- Add messages for WebM playback errors.
- Pause WebM videos off screen for better performance.
**Zixaphir**
- Code cleanup.
**ccd0**
- Improve error handling and implement WebM decoding error messages for hover and gallery features.
- Re-enable autoplay for WebM videos expanded by `Expand All Images` (disabled in [v1.7.3](#v173) due to performance issues). Videos will still only be expanded by EAI if the `Expand Videos` option is checked.
- When an image or video is expanded, scroll so that as much of the image/video is on screen as possible. This can be disabled by unchecking `Scroll into view` in the `Image Expansion` menu.
- Various image expansion related bugfixes.
- `Page Count in Stats` is now enabled by default.
### v1.8.7.2
*2014-08-04*

View File

@ -1,5 +1,5 @@
/*
* 4chan X - Version 1.8.7.2 - 2014-08-04
* 4chan X - Version 1.8.8.3 - 2014-08-02
*
* Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE

View File

@ -4,13 +4,15 @@ If you're looking for a maintained fork of OneeChan, try
https://github.com/Nebukazar/OneeChan
## [Install](https://ccd0.github.io/4chan-x/builds/4chan-X.user.js) (Firefox)
Install [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/), then click the link above to install.
Install [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/versions/2.1), then click the link above to install.
You may want to try the [Greasemonkey 2.1 beta](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/versions/2.1beta1), which fixes bugs in 2.0 that can prevent 4chan X from updating[[1]](https://github.com/greasemonkey/greasemonkey/issues/1938) or, in some versions of Firefox, break posting images from URLs and downloading with the original filename[[2]](https://github.com/greasemonkey/greasemonkey/issues/1937).
**Important**: If you are using Greasemonkey 2.0, you may be subject to a [bug](https://github.com/greasemonkey/greasemonkey/issues/1938) which prevents Greasemonkey from updating 4chan X and other userscripts to the latest version. You should update to [Greasemonkey 2.1](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/versions/2.1), in which the bug is fixed. After doing so, you may want to update 4chan X manually since it is likely to be out of date.
Greasemonkey 2.1 also fixes [another bug](https://github.com/greasemonkey/greasemonkey/issues/1937) that can break posting of images from URLs and downloading images with the original filename.
### Known issues
The combination of Firefox 29 and Greasemonkey 2.0 may cause 4chan X not to work.
Try [upgrading Firefox](http://www.mozilla.org/en-US/firefox/new/) to version 30 or higher.
The combination of Firefox 29 and Greasemonkey 2.0+ causes 4chan X not to work.
If you have this problem, you should [upgrade Firefox](http://www.mozilla.org/en-US/firefox/new/) to version 30 or higher.
Alternatively, you can downgrade to [Greasemonkey 1.15](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/versions/#version-1.15) and turn off automatic updates for Greasemonkey ([see pic](https://raw.githubusercontent.com/ccd0/4chan-x/master/img/2014-07-12_16-19-32.png)).
## [Install](https://ccd0.github.io/4chan-x/builds/4chan-X.crx) (Chromium)
@ -20,7 +22,7 @@ This should also work for non-Windows/dev/canary Chrome and Chromium-based versi
**Note**: The stable and beta releases of Chrome on Windows will disable extensions not installed from the Chrome store, so users will need to install 4chan X from [here](https://chrome.google.com/webstore/detail/4chan-x/ohnjgmpcibpbafdlkimncjhflgedgpam).
### Known issues
Some recent versions of Chromium/Chrome (starting at 38.0.2085.0) suffer from a [bug](https://crbug.com/393686) that prevents extensions from making HTTP requests in the usual way. This breaks, among other things, thread updating, quick reply, and, when `JSON Navigation` is enabled, the thread index. Until this is fixed, try another version or a different browser.
Some recent versions of Chromium/Chrome (38.0.2085 - 38.0.2103) suffer from a (now fixed) [bug](https://crbug.com/393686) that prevents extensions from making HTTP requests if more than one extension is enabled. This breaks, among other things, thread updating, quick reply, and, when `JSON Navigation` is enabled, the thread index. If you are experiencing this, try upgrading/downgrading to an unaffected version of Chromium/Chrome, disabling your other extensions, or using a different browser.
## Other browsers
This fork of 4chan X is not guaranteed to work correctly in other browsers, but you are welcome to try your luck. Pull requests to fix the bugs you will likely find are always welcome.

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
// @version 1.8.7.2
// @version 1.8.8.3
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
// @version 1.8.7.2
// @version 1.8.8.3
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.8.7.2' />
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.8.8.3' />
</app>
</gupdate>

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.8.7.2' />
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.8.8.3' />
</app>
</gupdate>

View File

@ -1,6 +1,6 @@
{
"name": "4chan-X",
"version": "1.8.7.2",
"version": "1.8.8.3",
"description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": {
"name": "4chan X",

View File

@ -276,7 +276,7 @@ Config =
'Display reply and image count.'
]
'Page Count in Stats': [
false
true
'Display the page count in the thread stats as well.'
]
'Updater and Stats in Header': [
@ -427,6 +427,10 @@ Config =
false
''
]
'Scroll into view': [
true
'Scroll down when expanding images to bring the full image into view.'
]
'Expand spoilers': [
true
'Expand all images along with spoilers.'

View File

@ -86,7 +86,7 @@ Header =
# Wait for #boardNavMobile instead of #boardNavDesktop,
# it might be incomplete otherwise.
$.asap (-> $.id('boardNavMobile') or d.readyState isnt 'loading'), Header.setBoardList
$.prepend d.body, @bar
$.prepend d.body, [@bar, @noticesRoot]
$.add d.body, Header.hover
@setBarPosition Conf['Bottom Header']
@
@ -142,7 +142,7 @@ Header =
$.rm $ '#navtopright', fullBoardList
$.add boardList, fullBoardList
$.add Header.bar, [Header.boardList, Header.shortcuts, Header.noticesRoot, Header.toggle]
$.add Header.bar, [Header.boardList, Header.shortcuts, Header.toggle]
Header.setCustomNav Conf['Custom Board Navigation']
Header.generateBoardList Conf['boardnav'].replace /(\r\n|\n|\r)/g, ' '
@ -308,18 +308,15 @@ Header =
'bottom-header'
'top-header'
'bottom'
'after'
] else [
'top-header'
'bottom-header'
'top'
'add'
]
$.addClass doc, args[0]
$.rmClass doc, args[1]
Header.bar.parentNode.className = args[2]
$[args[3]] Header.bar, Header.noticesRoot
toggleBarPosition: ->
$.cb.checked.call @
@ -406,6 +403,9 @@ Header =
headRect = Header.toggle.getBoundingClientRect()
bottom -= clientHeight - headRect.bottom + headRect.height
bottom
isNodeVisible: (node) ->
{height} = node.getBoundingClientRect()
Header.getTopOf(node) + height >= 0 and Header.getBottomOf(node) + height >= 0
isHidden: ->
{top} = Header.bar.getBoundingClientRect()
if Conf['Bottom header']

View File

@ -57,6 +57,9 @@ Main =
Redirect.navigate URL
else if Conf['Loop in New Tab'] and video = $ 'video'
video.loop = true
video.controls = false
video.play()
ImageCommon.addControls video
return
if Conf['Normalize URL'] and g.VIEW is 'thread'

View File

@ -718,6 +718,9 @@ span.hide-announcement {
:root.gecko.fit-width .full-image:not(#ihover) {
width: 100%;
}
.fileThumb > .warning {
clear: both;
}
#ihover {
-moz-box-sizing: border-box;
box-sizing: border-box;

View File

@ -58,19 +58,14 @@ class Clone extends Post
@file.text = file.firstElementChild
@file.thumb = $ 'img[data-md5]', file
@file.fullImage = $ '.full-image', file
@file.videoControls = $ '.video-controls', @file.text
# Contract thumbnails in quote preview
if contractThumb
$.rmClass root, 'expanded-image'
$.rmClass @file.thumb, 'expanding'
@file.isExpanded = $.hasClass root, 'expanded-image'
ImageExpand.contract @ if contractThumb
# Remove any #ihover ID
@file.fullImage?.removeAttribute 'id'
# Remove video controls.
($ '.video-controls', @file.text)?.remove()
@isDead = true if origin.isDead
@isClone = true
root.dataset.clone = origin.clones.push(@) - 1

View File

@ -156,9 +156,12 @@ Gallery =
file.src = name.href = @href
$.extend file.dataset, @dataset
nodes.current.pause?()
nodes.current.pause?() unless nodes.current.error
$.replace nodes.current, file
Video.configure file if elType is 'video'
if elType is 'video'
file.loop = true
file.play() if Conf['Autoplay']
ImageCommon.addControls file if Conf['Show Controls']
nodes.count.textContent = +@dataset.id + 1
nodes.current = file
nodes.frame.scrollTop = 0
@ -178,33 +181,13 @@ Gallery =
Gallery.build @
error: (file, thumb) ->
post = g.posts[file.dataset.post]
src = file.src.split '/'
if src[2] is 'i.4cdn.org'
URL = Redirect.to 'file',
boardID: src[3]
filename: src[src.length - 1]
if URL
thumb.href = URL
if URL and (/^https:\/\//.test(URL) or location.protocol is 'http:')
return unless Gallery.nodes.current is file
file.src = URL
return
if g.DEAD or post.isDead or post.file.isDead
return
# XXX CORS for i.4cdn.org WHEN?
$.ajax "//a.4cdn.org/#{post.board}/thread/#{post.thread}.json", onload: ->
return if @status isnt 200
i = 0
{posts} = @response
while postObj = posts[i++]
break if postObj.no is post.ID
unless postObj.no
return post.kill()
if postObj.filedeleted
post.kill true
if file.error?.code is MediaError.MEDIA_ERR_DECODE
return new Notice 'error', 'Corrupt or unplayable video', 30
return unless file.src.split('/')[2] is 'i.4cdn.org'
ImageCommon.error file, g.posts[file.dataset.post], null, (URL) ->
return unless URL
thumb.href = URL
file.src = URL if Gallery.nodes.current is file
prev: ->
Gallery.cb.open.call(
@ -235,7 +218,7 @@ Gallery =
Gallery.cb.cleanupTimer()
{current} = Gallery.nodes
isVideo = current.nodeName is 'VIDEO'
Video.start current if isVideo
current.play() if isVideo
if (if isVideo then current.readyState > 4 else current.complete) or current.nodeName is 'IFRAME'
Gallery.cb.startTimer()
else

View File

@ -0,0 +1,62 @@
ImageCommon =
decodeError: (file, post) ->
return false unless file.error?.code is MediaError.MEDIA_ERR_DECODE
unless message = $ '.warning', post.file.thumb.parentNode
message = $.el 'div', className: 'warning'
$.after post.file.thumb, message
message.textContent = 'Error: Corrupt or unplayable video'
return true
error: (file, post, delay, cb) ->
src = post.file.URL.split '/'
URL = Redirect.to 'file',
boardID: post.board.ID
filename: src[src.length - 1]
unless URL and (/^https:\/\//.test(URL) or location.protocol is 'http:')
URL = null
return cb URL if (post.isDead or post.file.isDead) and file.src.split('/')[2] is 'i.4cdn.org'
timeoutID = setTimeout (-> cb URL), delay if delay?
return if post.isDead or post.file.isDead
redirect = ->
if file.src.split('/')[2] is 'i.4cdn.org'
clearTimeout timeoutID if delay?
cb URL
<% if (type === 'crx') { %>
$.ajax post.file.URL,
onloadend: ->
if @status is 200
URL = post.file.URL
else
post.kill true if @status is 404
redirect()
,
type: 'head'
<% } else { %>
# XXX CORS for i.4cdn.org WHEN?
$.ajax "//a.4cdn.org/#{post.board}/thread/#{post.thread}.json", onload: ->
post.kill() if @status is 404
return redirect() if @status isnt 200
for postObj in @response.posts
break if postObj.no is post.ID
if postObj.no isnt post.ID
post.kill()
redirect()
else if postObj.filedeleted
post.kill true
redirect()
else
URL = post.file.URL
<% } %>
# Add controls, but not until the mouse is moved over the video.
addControls: (video) ->
handler = ->
$.off video, 'mouseover', handler
# Hacky workaround for Firefox forever-loading bug for very short videos
t = new Date().getTime()
$.asap (-> chrome? or (video.readyState >= 3 and video.currentTime <= Math.max 0.1, (video.duration - 0.5)) or new Date().getTime() >= t + 1000), ->
video.controls = true
$.on video, 'mouseover', handler

View File

@ -7,35 +7,37 @@ ImageExpand =
textContent: 'EAI'
title: 'Expand All Images'
href: 'javascript:;'
$.on @EAI, 'click', ImageExpand.cb.toggleAll
$.on @EAI, 'click', @cb.toggleAll
Header.addShortcut @EAI, 3
$.on d, 'scroll visibilitychange', @cb.playVideos
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
return unless @file and (@file.isImage or @file.isVideo)
$.on @file.thumb.parentNode, 'click', ImageExpand.cb.toggle
if @isClone
if @file.isExpanding
# If we clone a post where the image is still loading,
# make it loading in the clone too.
ImageExpand.contract @
ImageExpand.expand @
else if @file.isExpanded and @file.isVideo
ImageExpand.setupVideoCB @
ImageExpand.setupVideo @, !@origin.file.fullImage?.paused or @origin.file.wasPlaying, @file.fullImage.controls
else if ImageExpand.on and !@isHidden and
(Conf['Expand spoilers'] or !@file.isSpoiler) and
(Conf['Expand videos'] or !@file.isVideo)
ImageExpand.expand @, null, true
ImageExpand.expand @
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
{file} = post
return if file.isExpanded and file.isVideo and file.fullImage.controls
e.preventDefault()
ImageExpand.toggle post
@ -46,34 +48,48 @@ ImageExpand =
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)
!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
func = (post) -> ImageExpand.expand post
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
toggle post for post in [post, post.clones...]
return
playVideos: (e) ->
g.posts.forEach (post) ->
return unless post.file and post.file.isVideo and post.file.isExpanded
video = post.file.fullImage
visible = !d.hidden and Header.isNodeVisible video
if visible and post.file.wasPlaying
delete post.file.wasPlaying
video.play()
else if !visible and !video.paused
post.file.wasPlaying = true
video.pause()
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'
unless post.file.isExpanding or post.file.isExpanded
post.file.scrollIntoView = Conf['Scroll into view']
ImageExpand.expand post
return
ImageExpand.contract post
# Scroll back to the thumbnail when contracting the image
# to avoid being left miles away from the relevant post.
{root} = post.nodes
@ -96,99 +112,134 @@ ImageExpand =
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
{file} = post
expand: (post, src, disableAutoplay) ->
{bottom} = post.nodes.root.getBoundingClientRect()
oldHeight = d.body.clientHeight
$.rmClass post.nodes.root, 'expanded-image'
$.rmClass file.thumb, 'expanding'
$.rm file.videoControls if file.videoControls
file.thumb.parentNode.href = file.URL
file.thumb.parentNode.target = '_blank'
for x in ['isExpanding', 'isExpanded', 'videoControls', 'wasPlaying', 'scrollIntoView']
delete file[x]
# Scroll to keep our place in the thread when images are contracted above us.
if doc.contains(post.nodes.root) and bottom <= 0
window.scrollBy 0, d.body.clientHeight - oldHeight
if el = file.fullImage
$.off el, 'error', ImageExpand.error
if file.isVideo
el.pause()
TrashQueue.add el, post
for eventName, cb of ImageExpand.videoCB
$.off el, eventName, cb
return
expand: (post, src) ->
# 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'
{file} = post
{thumb, isVideo} = file
return if post.isHidden or file.isExpanding or file.isExpanded
$.addClass thumb, 'expanding'
if el = post.file.fullImage
file.isExpanding = true
el = file.fullImage or $.el (if isVideo then 'video' else 'img'), className: 'full-image'
$.on el, 'error', ImageExpand.error
if 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
el.src = src or file.URL
$.after thumb, el
file.fullImage = el
if isVideo
# add contract link to file info
if Conf['Show Controls'] and !file.videoControls
file.videoControls = ImageExpand.videoControls.cloneNode true
$.add file.text, file.videoControls
# disable link to file so native controls can work
thumb.parentNode.removeAttribute 'href'
thumb.parentNode.removeAttribute 'target'
el.loop = true
ImageExpand.setupVideoCB post
if !isVideo
$.asap (-> el.naturalHeight), -> ImageExpand.completeExpand post
else if el.readyState >= el.HAVE_CURRENT_DATA
ImageExpand.completeExpand post
else
$.on el, 'loadeddata', -> ImageExpand.completeExpand post
completeExpand: (post) ->
{file} = post
return unless file.isExpanding # contracted before the image loaded
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
oldHeight = d.body.clientHeight
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
$.rmClass file.thumb, 'expanding'
file.isExpanded = true
delete file.isExpanding
videoCB:
click: (e) ->
# Scroll to keep our place in the thread when images are expanded above us.
if doc.contains(post.nodes.root) and bottom <= 0
window.scrollBy 0, d.body.clientHeight - oldHeight
# Scroll to display full image.
if file.scrollIntoView
delete file.scrollIntoView
imageBottom = Header.getBottomOf(file.fullImage) - 25
if imageBottom < 0
window.scrollBy 0, Math.min(-imageBottom, Header.getTopOf file.fullImage)
if file.isVideo
ImageExpand.setupVideo post, Conf['Autoplay'], Conf['Show Controls']
setupVideo: (post, playing, controls) ->
{fullImage} = post.file
unless playing
fullImage.controls = controls
return
fullImage.controls = false
$.asap (=> doc.contains fullImage), =>
if !d.hidden and Header.isNodeVisible fullImage
fullImage.play()
else
post.file.wasPlaying = true
if controls
ImageCommon.addControls fullImage
videoControls: $.el 'span',
className: 'video-controls'
innerHTML: '\u00A0<a href="javascript:;" title="You can also contract the video by dragging it to the left.">contract</a>'
videoCB: do ->
# dragging to the left contracts the video
mousedown = false
mouseover: -> mousedown = false
mousedown: (e) -> mousedown = true if e.button is 0
mouseup: (e) -> mousedown = false if e.button is 0
mouseout: (e) -> ImageExpand.toggle(Get.postFromNode @) if mousedown and e.clientX <= @getBoundingClientRect().left
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
setupVideoCB: (post) ->
for eventName, cb of ImageExpand.videoCB
$.on post.file.fullImage, eventName, cb
if post.file.videoControls
$.on post.file.videoControls.firstElementChild, 'click', -> ImageExpand.toggle post
error: ->
post = Get.postFromNode @
@ -197,44 +248,17 @@ ImageExpand =
# 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 and (/^https:\/\//.test(URL) or location.protocol is 'http:')
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}/thread/#{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
<% } %>
# Don't try to re-expand if it was already contracted.
return unless post.file.isExpanding or post.file.isExpanded
if ImageCommon.decodeError @, post
return ImageExpand.contract post
# Don't autoretry images from the archive.
unless @src.split('/')[2] is 'i.4cdn.org'
return ImageExpand.contract post
ImageCommon.error @, post, 10 * $.SECOND, (URL) ->
if post.file.isExpanding or post.file.isExpanded
ImageExpand.contract post
ImageExpand.expand post, URL if URL
menu:
init: ->

View File

@ -12,6 +12,7 @@ ImageHover =
post = Get.postFromNode @
{file} = post
{isVideo} = file
return if post.file.isExpanding or post.file.isExpanded
if el = file.fullImage
el.id = 'ihover'
TrashQueue.remove el
@ -19,12 +20,11 @@ ImageHover =
file.fullImage = el = $.el (if isVideo then 'video' else 'img'),
className: 'full-image'
id: 'ihover'
el.dataset.fullID = post.fullID
$.on el, 'error', ImageHover.error
el.src = file.URL
$.after file.thumb, el
if isVideo
el.loop = true
el.loop = true
el.controls = false
el.play() if Conf['Autoplay']
UI.hover
@ -35,45 +35,19 @@ ImageHover =
asapTest: -> (if isVideo then el.readyState >= el.HAVE_CURRENT_DATA else el.naturalHeight)
noRemove: true
cb: ->
$.off el, 'error', ImageHover.error
if isVideo
el.pause()
TrashQueue.add el, post
el.removeAttribute 'id'
error: ->
return unless doc.contains @
post = g.posts[@dataset.fullID]
src = @src.split '/'
if src[2] is 'i.4cdn.org'
URL = Redirect.to 'file',
boardID: src[3]
filename: src[src.length - 1].replace /\?.+$/, ''
if URL and (/^https:\/\//.test(URL) or location.protocol is 'http:')
@src = URL
return
if g.DEAD or post.isDead or post.file.isDead
return
timeoutID = setTimeout (=> @src = post.file.URL + '?' + Date.now()), 3000
<% 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}/thread/#{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
<% } %>
post = Get.postFromNode @
return if post.file.isExpanding or post.file.isExpanded
if @id is 'ihover' # still hovering
return if ImageCommon.decodeError @, post
ImageCommon.error @, post, 3 * $.SECOND, (URL) =>
if URL
@src = URL + if @src is URL then '?' + Date.now() else ''
else
$.off @, 'error', ImageHover.error
$.rm @
delete post.file.fullImage

View File

@ -1,21 +0,0 @@
Video =
configure: (video, disableAutoplay) ->
video.loop = true
video.controls = Conf['Show Controls']
video.autoplay = false
if Conf['Autoplay'] and not disableAutoplay
Video.start video
else
video.pause()
start: (video) ->
return unless video.paused
{controls} = video
video.controls = false
video.play()
# Hacky workaround for Firefox forever-loading bug for very short videos
if controls
$.asap (-> (video.readyState >= 3 and video.currentTime <= Math.max 0.1, (video.duration - 0.5)) or !d.contains video), ->
video.controls = true
, 500

View File

@ -32,7 +32,8 @@ CatalogLinks =
for a in $$ """#board-list a:not(.catalog), #boardNavDesktopFoot a"""
continue if a.hostname not in ['boards.4chan.org', 'catalog.neet.tv', '4index.gropes.us'] or
!(board = a.pathname.split('/')[1]) or
board in ['f', 'status', '4chan']
board in ['f', 'status', '4chan'] or
$.hasClass a, 'external'
# Href is easier than pathname because then we don't have
# conditions where External Catalog has been disabled between switches.

View File

@ -6,6 +6,6 @@ Dice =
cb: @node
node: ->
return if @isClone or not dicestats = @info.email?.match /dice[+\s](\d+)d(\d+)/
# Use the text node directly, as the <b> has two <br>.
# Use the text node directly, as the <b> has two <br>. Count dice since 4chan imposes a maximum.
roll = $('b', @nodes.comment).firstChild
roll.data = "Rolled #{dicestats[1]}d#{dicestats[2]}: #{roll.data.slice 7}"
roll.data = "Rolled #{roll.data.split(',').length}d#{dicestats[2]}: #{roll.data.slice 7}"