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:
commit
9b0407754f
37
CHANGELOG.md
37
CHANGELOG.md
@ -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
|
### v1.8.7.2
|
||||||
*2014-08-04*
|
*2014-08-04*
|
||||||
|
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@ -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.
|
* Licensed under the MIT license.
|
||||||
* https://github.com/ccd0/4chan-x/blob/master/LICENSE
|
* https://github.com/ccd0/4chan-x/blob/master/LICENSE
|
||||||
|
|||||||
12
README.md
12
README.md
@ -4,13 +4,15 @@ If you're looking for a maintained fork of OneeChan, try
|
|||||||
https://github.com/Nebukazar/OneeChan
|
https://github.com/Nebukazar/OneeChan
|
||||||
|
|
||||||
## [Install](https://ccd0.github.io/4chan-x/builds/4chan-X.user.js) (Firefox)
|
## [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
|
### Known issues
|
||||||
The combination of Firefox 29 and Greasemonkey 2.0 may cause 4chan X not to work.
|
The combination of Firefox 29 and Greasemonkey 2.0+ causes 4chan X not to work.
|
||||||
Try [upgrading Firefox](http://www.mozilla.org/en-US/firefox/new/) to version 30 or higher.
|
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)).
|
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)
|
## [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).
|
**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
|
### 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
|
## 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.
|
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.
@ -1,6 +1,6 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name 4chan X
|
// @name 4chan X
|
||||||
// @version 1.8.7.2
|
// @version 1.8.8.3
|
||||||
// @minGMVer 1.14
|
// @minGMVer 1.14
|
||||||
// @minFFVer 26
|
// @minFFVer 26
|
||||||
// @namespace 4chan-X
|
// @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.
@ -1,6 +1,6 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name 4chan X
|
// @name 4chan X
|
||||||
// @version 1.8.7.2
|
// @version 1.8.8.3
|
||||||
// @minGMVer 1.14
|
// @minGMVer 1.14
|
||||||
// @minFFVer 26
|
// @minFFVer 26
|
||||||
// @namespace 4chan-X
|
// @namespace 4chan-X
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1,7 +1,7 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
|
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
|
||||||
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
|
<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>
|
</app>
|
||||||
</gupdate>
|
</gupdate>
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
|
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
|
||||||
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
|
<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>
|
</app>
|
||||||
</gupdate>
|
</gupdate>
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "4chan-X",
|
"name": "4chan-X",
|
||||||
"version": "1.8.7.2",
|
"version": "1.8.8.3",
|
||||||
"description": "Cross-browser userscript for maximum lurking on 4chan.",
|
"description": "Cross-browser userscript for maximum lurking on 4chan.",
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "4chan X",
|
"name": "4chan X",
|
||||||
|
|||||||
@ -276,7 +276,7 @@ Config =
|
|||||||
'Display reply and image count.'
|
'Display reply and image count.'
|
||||||
]
|
]
|
||||||
'Page Count in Stats': [
|
'Page Count in Stats': [
|
||||||
false
|
true
|
||||||
'Display the page count in the thread stats as well.'
|
'Display the page count in the thread stats as well.'
|
||||||
]
|
]
|
||||||
'Updater and Stats in Header': [
|
'Updater and Stats in Header': [
|
||||||
@ -427,6 +427,10 @@ Config =
|
|||||||
false
|
false
|
||||||
''
|
''
|
||||||
]
|
]
|
||||||
|
'Scroll into view': [
|
||||||
|
true
|
||||||
|
'Scroll down when expanding images to bring the full image into view.'
|
||||||
|
]
|
||||||
'Expand spoilers': [
|
'Expand spoilers': [
|
||||||
true
|
true
|
||||||
'Expand all images along with spoilers.'
|
'Expand all images along with spoilers.'
|
||||||
|
|||||||
@ -86,7 +86,7 @@ Header =
|
|||||||
# Wait for #boardNavMobile instead of #boardNavDesktop,
|
# Wait for #boardNavMobile instead of #boardNavDesktop,
|
||||||
# it might be incomplete otherwise.
|
# it might be incomplete otherwise.
|
||||||
$.asap (-> $.id('boardNavMobile') or d.readyState isnt 'loading'), Header.setBoardList
|
$.asap (-> $.id('boardNavMobile') or d.readyState isnt 'loading'), Header.setBoardList
|
||||||
$.prepend d.body, @bar
|
$.prepend d.body, [@bar, @noticesRoot]
|
||||||
$.add d.body, Header.hover
|
$.add d.body, Header.hover
|
||||||
@setBarPosition Conf['Bottom Header']
|
@setBarPosition Conf['Bottom Header']
|
||||||
@
|
@
|
||||||
@ -142,7 +142,7 @@ Header =
|
|||||||
|
|
||||||
$.rm $ '#navtopright', fullBoardList
|
$.rm $ '#navtopright', fullBoardList
|
||||||
$.add boardList, 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.setCustomNav Conf['Custom Board Navigation']
|
||||||
Header.generateBoardList Conf['boardnav'].replace /(\r\n|\n|\r)/g, ' '
|
Header.generateBoardList Conf['boardnav'].replace /(\r\n|\n|\r)/g, ' '
|
||||||
@ -308,18 +308,15 @@ Header =
|
|||||||
'bottom-header'
|
'bottom-header'
|
||||||
'top-header'
|
'top-header'
|
||||||
'bottom'
|
'bottom'
|
||||||
'after'
|
|
||||||
] else [
|
] else [
|
||||||
'top-header'
|
'top-header'
|
||||||
'bottom-header'
|
'bottom-header'
|
||||||
'top'
|
'top'
|
||||||
'add'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
$.addClass doc, args[0]
|
$.addClass doc, args[0]
|
||||||
$.rmClass doc, args[1]
|
$.rmClass doc, args[1]
|
||||||
Header.bar.parentNode.className = args[2]
|
Header.bar.parentNode.className = args[2]
|
||||||
$[args[3]] Header.bar, Header.noticesRoot
|
|
||||||
|
|
||||||
toggleBarPosition: ->
|
toggleBarPosition: ->
|
||||||
$.cb.checked.call @
|
$.cb.checked.call @
|
||||||
@ -406,6 +403,9 @@ Header =
|
|||||||
headRect = Header.toggle.getBoundingClientRect()
|
headRect = Header.toggle.getBoundingClientRect()
|
||||||
bottom -= clientHeight - headRect.bottom + headRect.height
|
bottom -= clientHeight - headRect.bottom + headRect.height
|
||||||
bottom
|
bottom
|
||||||
|
isNodeVisible: (node) ->
|
||||||
|
{height} = node.getBoundingClientRect()
|
||||||
|
Header.getTopOf(node) + height >= 0 and Header.getBottomOf(node) + height >= 0
|
||||||
isHidden: ->
|
isHidden: ->
|
||||||
{top} = Header.bar.getBoundingClientRect()
|
{top} = Header.bar.getBoundingClientRect()
|
||||||
if Conf['Bottom header']
|
if Conf['Bottom header']
|
||||||
|
|||||||
@ -57,6 +57,9 @@ Main =
|
|||||||
Redirect.navigate URL
|
Redirect.navigate URL
|
||||||
else if Conf['Loop in New Tab'] and video = $ 'video'
|
else if Conf['Loop in New Tab'] and video = $ 'video'
|
||||||
video.loop = true
|
video.loop = true
|
||||||
|
video.controls = false
|
||||||
|
video.play()
|
||||||
|
ImageCommon.addControls video
|
||||||
return
|
return
|
||||||
|
|
||||||
if Conf['Normalize URL'] and g.VIEW is 'thread'
|
if Conf['Normalize URL'] and g.VIEW is 'thread'
|
||||||
|
|||||||
@ -718,6 +718,9 @@ span.hide-announcement {
|
|||||||
:root.gecko.fit-width .full-image:not(#ihover) {
|
:root.gecko.fit-width .full-image:not(#ihover) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.fileThumb > .warning {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
#ihover {
|
#ihover {
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
@ -58,19 +58,14 @@ class Clone extends Post
|
|||||||
@file.text = file.firstElementChild
|
@file.text = file.firstElementChild
|
||||||
@file.thumb = $ 'img[data-md5]', file
|
@file.thumb = $ 'img[data-md5]', file
|
||||||
@file.fullImage = $ '.full-image', file
|
@file.fullImage = $ '.full-image', file
|
||||||
|
@file.videoControls = $ '.video-controls', @file.text
|
||||||
|
|
||||||
# Contract thumbnails in quote preview
|
# Contract thumbnails in quote preview
|
||||||
if contractThumb
|
ImageExpand.contract @ if contractThumb
|
||||||
$.rmClass root, 'expanded-image'
|
|
||||||
$.rmClass @file.thumb, 'expanding'
|
|
||||||
@file.isExpanded = $.hasClass root, 'expanded-image'
|
|
||||||
|
|
||||||
# Remove any #ihover ID
|
# Remove any #ihover ID
|
||||||
@file.fullImage?.removeAttribute 'id'
|
@file.fullImage?.removeAttribute 'id'
|
||||||
|
|
||||||
# Remove video controls.
|
|
||||||
($ '.video-controls', @file.text)?.remove()
|
|
||||||
|
|
||||||
@isDead = true if origin.isDead
|
@isDead = true if origin.isDead
|
||||||
@isClone = true
|
@isClone = true
|
||||||
root.dataset.clone = origin.clones.push(@) - 1
|
root.dataset.clone = origin.clones.push(@) - 1
|
||||||
|
|||||||
@ -156,9 +156,12 @@ Gallery =
|
|||||||
file.src = name.href = @href
|
file.src = name.href = @href
|
||||||
|
|
||||||
$.extend file.dataset, @dataset
|
$.extend file.dataset, @dataset
|
||||||
nodes.current.pause?()
|
nodes.current.pause?() unless nodes.current.error
|
||||||
$.replace nodes.current, file
|
$.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.count.textContent = +@dataset.id + 1
|
||||||
nodes.current = file
|
nodes.current = file
|
||||||
nodes.frame.scrollTop = 0
|
nodes.frame.scrollTop = 0
|
||||||
@ -178,33 +181,13 @@ Gallery =
|
|||||||
Gallery.build @
|
Gallery.build @
|
||||||
|
|
||||||
error: (file, thumb) ->
|
error: (file, thumb) ->
|
||||||
post = g.posts[file.dataset.post]
|
if file.error?.code is MediaError.MEDIA_ERR_DECODE
|
||||||
|
return new Notice 'error', 'Corrupt or unplayable video', 30
|
||||||
src = file.src.split '/'
|
return unless file.src.split('/')[2] is 'i.4cdn.org'
|
||||||
if src[2] is 'i.4cdn.org'
|
ImageCommon.error file, g.posts[file.dataset.post], null, (URL) ->
|
||||||
URL = Redirect.to 'file',
|
return unless URL
|
||||||
boardID: src[3]
|
thumb.href = URL
|
||||||
filename: src[src.length - 1]
|
file.src = URL if Gallery.nodes.current is file
|
||||||
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
|
|
||||||
|
|
||||||
prev: ->
|
prev: ->
|
||||||
Gallery.cb.open.call(
|
Gallery.cb.open.call(
|
||||||
@ -235,7 +218,7 @@ Gallery =
|
|||||||
Gallery.cb.cleanupTimer()
|
Gallery.cb.cleanupTimer()
|
||||||
{current} = Gallery.nodes
|
{current} = Gallery.nodes
|
||||||
isVideo = current.nodeName is 'VIDEO'
|
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'
|
if (if isVideo then current.readyState > 4 else current.complete) or current.nodeName is 'IFRAME'
|
||||||
Gallery.cb.startTimer()
|
Gallery.cb.startTimer()
|
||||||
else
|
else
|
||||||
|
|||||||
62
src/Images/ImageCommon.coffee
Normal file
62
src/Images/ImageCommon.coffee
Normal 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
|
||||||
@ -7,35 +7,37 @@ ImageExpand =
|
|||||||
textContent: 'EAI'
|
textContent: 'EAI'
|
||||||
title: 'Expand All Images'
|
title: 'Expand All Images'
|
||||||
href: 'javascript:;'
|
href: 'javascript:;'
|
||||||
$.on @EAI, 'click', ImageExpand.cb.toggleAll
|
$.on @EAI, 'click', @cb.toggleAll
|
||||||
Header.addShortcut @EAI, 3
|
Header.addShortcut @EAI, 3
|
||||||
|
$.on d, 'scroll visibilitychange', @cb.playVideos
|
||||||
|
|
||||||
Post.callbacks.push
|
Post.callbacks.push
|
||||||
name: 'Image Expansion'
|
name: 'Image Expansion'
|
||||||
cb: @node
|
cb: @node
|
||||||
|
|
||||||
node: ->
|
node: ->
|
||||||
return unless @file?.isImage or @file?.isVideo
|
return unless @file and (@file.isImage or @file.isVideo)
|
||||||
{thumb} = @file
|
$.on @file.thumb.parentNode, 'click', ImageExpand.cb.toggle
|
||||||
$.on thumb.parentNode, 'click', ImageExpand.cb.toggle
|
if @isClone
|
||||||
if @isClone and $.hasClass thumb, 'expanding'
|
if @file.isExpanding
|
||||||
# If we clone a post where the image is still loading,
|
# If we clone a post where the image is still loading,
|
||||||
# make it loading in the clone too.
|
# make it loading in the clone too.
|
||||||
ImageExpand.contract @
|
ImageExpand.contract @
|
||||||
ImageExpand.expand @
|
ImageExpand.expand @
|
||||||
else if @isClone and @file.isExpanded and @file.isVideo
|
else if @file.isExpanded and @file.isVideo
|
||||||
clone = @
|
ImageExpand.setupVideoCB @
|
||||||
ImageExpand.setupVideoControls clone
|
ImageExpand.setupVideo @, !@origin.file.fullImage?.paused or @origin.file.wasPlaying, @file.fullImage.controls
|
||||||
unless clone.origin.file.fullImage.paused
|
|
||||||
$.queueTask -> Video.start clone.file.fullImage
|
|
||||||
else if ImageExpand.on and !@isHidden and
|
else if ImageExpand.on and !@isHidden and
|
||||||
(Conf['Expand spoilers'] or !@file.isSpoiler) and
|
(Conf['Expand spoilers'] or !@file.isSpoiler) and
|
||||||
(Conf['Expand videos'] or !@file.isVideo)
|
(Conf['Expand videos'] or !@file.isVideo)
|
||||||
ImageExpand.expand @, null, true
|
ImageExpand.expand @
|
||||||
|
|
||||||
cb:
|
cb:
|
||||||
toggle: (e) ->
|
toggle: (e) ->
|
||||||
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0
|
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0
|
||||||
post = Get.postFromNode @
|
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()
|
e.preventDefault()
|
||||||
ImageExpand.toggle post
|
ImageExpand.toggle post
|
||||||
|
|
||||||
@ -46,34 +48,48 @@ ImageExpand =
|
|||||||
return unless file and (file.isImage or file.isVideo) and doc.contains post.nodes.root
|
return unless file and (file.isImage or file.isVideo) and doc.contains post.nodes.root
|
||||||
if ImageExpand.on and
|
if ImageExpand.on and
|
||||||
(!Conf['Expand spoilers'] and file.isSpoiler or
|
(!Conf['Expand spoilers'] and file.isSpoiler or
|
||||||
!Conf['Expand videos'] and file.isVideo or
|
!Conf['Expand videos'] and file.isVideo or
|
||||||
Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0)
|
Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0)
|
||||||
return
|
return
|
||||||
$.queueTask func, post
|
$.queueTask func, post
|
||||||
|
|
||||||
if ImageExpand.on = $.hasClass ImageExpand.EAI, 'expand-all-shortcut'
|
if ImageExpand.on = $.hasClass ImageExpand.EAI, 'expand-all-shortcut'
|
||||||
ImageExpand.EAI.className = 'contract-all-shortcut fa fa-compress'
|
ImageExpand.EAI.className = 'contract-all-shortcut fa fa-compress'
|
||||||
ImageExpand.EAI.title = 'Contract All Images'
|
ImageExpand.EAI.title = 'Contract All Images'
|
||||||
func = (post) -> ImageExpand.expand post, null, true
|
func = (post) -> ImageExpand.expand post
|
||||||
else
|
else
|
||||||
ImageExpand.EAI.className = 'expand-all-shortcut fa fa-expand'
|
ImageExpand.EAI.className = 'expand-all-shortcut fa fa-expand'
|
||||||
ImageExpand.EAI.title = 'Expand All Images'
|
ImageExpand.EAI.title = 'Expand All Images'
|
||||||
func = ImageExpand.contract
|
func = ImageExpand.contract
|
||||||
|
|
||||||
g.posts.forEach (post) ->
|
g.posts.forEach (post) ->
|
||||||
toggle post
|
toggle post for post in [post, post.clones...]
|
||||||
toggle post for post in 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
|
return
|
||||||
|
|
||||||
setFitness: ->
|
setFitness: ->
|
||||||
(if @checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-'
|
(if @checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-'
|
||||||
|
|
||||||
toggle: (post) ->
|
toggle: (post) ->
|
||||||
{thumb} = post.file
|
unless post.file.isExpanding or post.file.isExpanded
|
||||||
unless post.file.isExpanded or $.hasClass thumb, 'expanding'
|
post.file.scrollIntoView = Conf['Scroll into view']
|
||||||
ImageExpand.expand post
|
ImageExpand.expand post
|
||||||
return
|
return
|
||||||
|
|
||||||
|
ImageExpand.contract post
|
||||||
|
|
||||||
# Scroll back to the thumbnail when contracting the image
|
# Scroll back to the thumbnail when contracting the image
|
||||||
# to avoid being left miles away from the relevant post.
|
# to avoid being left miles away from the relevant post.
|
||||||
{root} = post.nodes
|
{root} = post.nodes
|
||||||
@ -96,99 +112,134 @@ ImageExpand =
|
|||||||
if left < 0
|
if left < 0
|
||||||
x = -window.scrollX
|
x = -window.scrollX
|
||||||
window.scrollBy x, y if x or y
|
window.scrollBy x, y if x or y
|
||||||
ImageExpand.contract post
|
|
||||||
|
|
||||||
contract: (post) ->
|
contract: (post) ->
|
||||||
if post.file.isVideo and video = post.file.fullImage
|
{file} = post
|
||||||
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) ->
|
{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.
|
# Do not expand images of hidden/filtered replies, or already expanded pictures.
|
||||||
{thumb, isVideo} = post.file
|
{file} = post
|
||||||
return if post.isHidden or post.file.isExpanded or $.hasClass thumb, 'expanding'
|
{thumb, isVideo} = file
|
||||||
|
return if post.isHidden or file.isExpanding or file.isExpanded
|
||||||
|
|
||||||
$.addClass thumb, 'expanding'
|
$.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.
|
# Expand already-loaded/ing picture.
|
||||||
TrashQueue.remove el
|
TrashQueue.remove el
|
||||||
else
|
else
|
||||||
el = post.file.fullImage = $.el (if isVideo then 'video' else 'img'),
|
el.src = src or file.URL
|
||||||
className: 'full-image'
|
$.after thumb, el
|
||||||
$.on el, 'error', ImageExpand.error
|
file.fullImage = el
|
||||||
el.src = src or post.file.URL
|
|
||||||
$.after thumb, el unless el is thumb.nextSibling
|
if isVideo
|
||||||
$.asap (-> if isVideo then el.videoHeight else el.naturalHeight), ->
|
# add contract link to file info
|
||||||
ImageExpand.completeExpand post, disableAutoplay
|
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()
|
{bottom} = post.nodes.root.getBoundingClientRect()
|
||||||
$.queueTask ->
|
oldHeight = d.body.clientHeight
|
||||||
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'
|
$.addClass post.nodes.root, 'expanded-image'
|
||||||
$.rmClass post.file.thumb, 'expanding'
|
$.rmClass file.thumb, 'expanding'
|
||||||
post.file.isExpanded = true
|
file.isExpanded = true
|
||||||
if post.file.isVideo
|
delete file.isExpanding
|
||||||
ImageExpand.setupVideoControls post
|
|
||||||
Video.configure post.file.fullImage, disableAutoplay
|
|
||||||
|
|
||||||
videoCB:
|
# Scroll to keep our place in the thread when images are expanded above us.
|
||||||
click: (e) ->
|
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
|
if @paused and not @controls
|
||||||
@play()
|
@play()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
# dragging to the left contracts the video
|
setupVideoCB: (post) ->
|
||||||
mousedown: (e) -> @dataset.mousedown = 'true' if e.button is 0
|
for eventName, cb of ImageExpand.videoCB
|
||||||
mouseup: (e) -> @dataset.mousedown = 'false' if e.button is 0
|
$.on post.file.fullImage, eventName, cb
|
||||||
mouseover: (e) -> @dataset.mousedown = 'false'
|
if post.file.videoControls
|
||||||
mouseout: (e) ->
|
$.on post.file.videoControls.firstElementChild, 'click', -> ImageExpand.toggle post
|
||||||
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: ->
|
error: ->
|
||||||
post = Get.postFromNode @
|
post = Get.postFromNode @
|
||||||
@ -197,44 +248,17 @@ ImageExpand =
|
|||||||
# Images can error:
|
# Images can error:
|
||||||
# - before the image started loading.
|
# - before the image started loading.
|
||||||
# - after 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-expand if it was already contracted.
|
||||||
# Don't try to re-expend if it was already contracted.
|
return unless post.file.isExpanding or post.file.isExpanded
|
||||||
return
|
if ImageCommon.decodeError @, post
|
||||||
ImageExpand.contract post
|
return ImageExpand.contract post
|
||||||
|
# Don't autoretry images from the archive.
|
||||||
src = @src.split '/'
|
unless @src.split('/')[2] is 'i.4cdn.org'
|
||||||
if src[2] is 'i.4cdn.org'
|
return ImageExpand.contract post
|
||||||
URL = Redirect.to 'file',
|
ImageCommon.error @, post, 10 * $.SECOND, (URL) ->
|
||||||
boardID: src[3]
|
if post.file.isExpanding or post.file.isExpanded
|
||||||
filename: src[src.length - 1]
|
ImageExpand.contract post
|
||||||
if URL and (/^https:\/\//.test(URL) or location.protocol is 'http:')
|
ImageExpand.expand post, URL 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}/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
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
menu:
|
menu:
|
||||||
init: ->
|
init: ->
|
||||||
|
|||||||
@ -12,6 +12,7 @@ ImageHover =
|
|||||||
post = Get.postFromNode @
|
post = Get.postFromNode @
|
||||||
{file} = post
|
{file} = post
|
||||||
{isVideo} = file
|
{isVideo} = file
|
||||||
|
return if post.file.isExpanding or post.file.isExpanded
|
||||||
if el = file.fullImage
|
if el = file.fullImage
|
||||||
el.id = 'ihover'
|
el.id = 'ihover'
|
||||||
TrashQueue.remove el
|
TrashQueue.remove el
|
||||||
@ -19,12 +20,11 @@ ImageHover =
|
|||||||
file.fullImage = el = $.el (if isVideo then 'video' else 'img'),
|
file.fullImage = el = $.el (if isVideo then 'video' else 'img'),
|
||||||
className: 'full-image'
|
className: 'full-image'
|
||||||
id: 'ihover'
|
id: 'ihover'
|
||||||
el.dataset.fullID = post.fullID
|
|
||||||
$.on el, 'error', ImageHover.error
|
$.on el, 'error', ImageHover.error
|
||||||
el.src = file.URL
|
el.src = file.URL
|
||||||
$.after file.thumb, el
|
$.after file.thumb, el
|
||||||
if isVideo
|
if isVideo
|
||||||
el.loop = true
|
el.loop = true
|
||||||
el.controls = false
|
el.controls = false
|
||||||
el.play() if Conf['Autoplay']
|
el.play() if Conf['Autoplay']
|
||||||
UI.hover
|
UI.hover
|
||||||
@ -35,45 +35,19 @@ ImageHover =
|
|||||||
asapTest: -> (if isVideo then el.readyState >= el.HAVE_CURRENT_DATA else el.naturalHeight)
|
asapTest: -> (if isVideo then el.readyState >= el.HAVE_CURRENT_DATA else el.naturalHeight)
|
||||||
noRemove: true
|
noRemove: true
|
||||||
cb: ->
|
cb: ->
|
||||||
$.off el, 'error', ImageHover.error
|
|
||||||
if isVideo
|
if isVideo
|
||||||
el.pause()
|
el.pause()
|
||||||
TrashQueue.add el, post
|
TrashQueue.add el, post
|
||||||
el.removeAttribute 'id'
|
el.removeAttribute 'id'
|
||||||
error: ->
|
error: ->
|
||||||
return unless doc.contains @
|
post = Get.postFromNode @
|
||||||
post = g.posts[@dataset.fullID]
|
return if post.file.isExpanding or post.file.isExpanded
|
||||||
|
if @id is 'ihover' # still hovering
|
||||||
src = @src.split '/'
|
return if ImageCommon.decodeError @, post
|
||||||
if src[2] is 'i.4cdn.org'
|
ImageCommon.error @, post, 3 * $.SECOND, (URL) =>
|
||||||
URL = Redirect.to 'file',
|
if URL
|
||||||
boardID: src[3]
|
@src = URL + if @src is URL then '?' + Date.now() else ''
|
||||||
filename: src[src.length - 1].replace /\?.+$/, ''
|
else
|
||||||
if URL and (/^https:\/\//.test(URL) or location.protocol is 'http:')
|
$.off @, 'error', ImageHover.error
|
||||||
@src = URL
|
$.rm @
|
||||||
return
|
delete post.file.fullImage
|
||||||
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
|
|
||||||
<% } %>
|
|
||||||
|
|||||||
@ -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
|
|
||||||
|
|
||||||
@ -32,7 +32,8 @@ CatalogLinks =
|
|||||||
for a in $$ """#board-list a:not(.catalog), #boardNavDesktopFoot a"""
|
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
|
continue if a.hostname not in ['boards.4chan.org', 'catalog.neet.tv', '4index.gropes.us'] or
|
||||||
!(board = a.pathname.split('/')[1]) 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
|
# Href is easier than pathname because then we don't have
|
||||||
# conditions where External Catalog has been disabled between switches.
|
# conditions where External Catalog has been disabled between switches.
|
||||||
|
|||||||
@ -6,6 +6,6 @@ Dice =
|
|||||||
cb: @node
|
cb: @node
|
||||||
node: ->
|
node: ->
|
||||||
return if @isClone or not dicestats = @info.email?.match /dice[+\s](\d+)d(\d+)/
|
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 = $('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}"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user