Merge branch 'master' into catalog

This commit is contained in:
ccd0 2014-09-13 01:56:37 -07:00
commit 1285b3aeff
35 changed files with 769 additions and 528 deletions

View File

@ -1,3 +1,82 @@
### v1.9.2.8
*2014-09-11*
**ccd0**
- Simplify and improve thumbnail replacement / preloading. Remove the download queue (didn't work well). Drop support for non-autoplaying replaced WebM thumbnails.
### v1.9.2.7
*2014-09-10*
**ccd0**
- Quote fetching bugfix.
### v1.9.2.6
*2014-09-09*
**ccd0**
- Small bugfixes.
### v1.9.2.5
*2014-09-09*
**Worer**
- Remove mawa.re from archive list (as in v1.9.1.10).
### v1.9.2.4
*2014-09-08*
**ccd0**
- Fix thumbnail replacement / preloading loading images which are not actually on the page.
### v1.9.2.3
*2014-09-07*
**ccd0**
- Thumbnail replacement / preloading / WebM bugfixes.
- Embedded videos from mediacru.sh are no longer autoplayed and have controls.
### v1.9.2.2
*2014-09-07*
**ccd0**
- Fix bug causing missing pages from index search (as in v1.9.1.9).
- Also fix bug from v1.9.2.0 causing threads to be missing from infinite scroll.
### v1.9.2.1
*2014-09-07*
**ccd0**
- Improve reliability of thumbnail replacement / preloading by queueing downloads.
### v1.9.2.0
*2014-09-06*
Based on v1.9.1.8.
**Zixaphir**
- Implement WebM thumbnail replacement / preloading.
**ccd0**
- Pause offscreen WebM thumbnails, fix some bugs.
### v1.9.1.10
*2014-09-09*
**Worer**
- Remove mawa.re from archive list.
### v1.9.1.9
*2014-09-07*
**ccd0**
- Fix bug causing missing pages from index search.
### v1.9.1.8
*2014-09-06*
**ccd0**
- Fix bug in WebM hover/expand.
### v1.9.1.7
*2014-09-05*

View File

@ -1,5 +1,5 @@
/*
* 4chan X - Version 1.9.1.7
* 4chan X - Version 1.9.2.8
*
* Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
// @version 1.9.1.7
// @version 1.9.2.8
// @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.9.1.7
// @version 1.9.2.8
// @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.9.1.7' />
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.9.2.8' />
</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.9.1.7' />
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.9.2.8' />
</app>
</gupdate>

View File

@ -3,7 +3,7 @@
"description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": {
"name": "4chan X",
"version": "1.9.1.7",
"version": "1.9.2.8",
"repo": "https://github.com/ccd0/4chan-x/",
"page": "https://github.com/ccd0/4chan-x",
"downloads": "https://ccd0.github.io/4chan-x/builds/",

View File

@ -70,14 +70,4 @@
"software": "foolfuuka",
"boards": ["asp", "cm", "h", "hc", "hm", "n", "p", "r", "s", "soc", "y"],
"files": ["asp", "cm", "h", "hc", "hm", "n", "p", "r", "s", "soc", "y"]
}, {
"uid": 16,
"name": "maware",
"domain": "archive.mawa.re",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": ["t"],
"files": ["t"],
"imagehosts": ["http://archive.mawa.re/"]
}]

View File

@ -151,8 +151,9 @@ Filter =
return post.file.name
false
dimensions: (post) ->
if post.file and post.file.isImage
return post.file.dimensions
{file} = post
if file and (file.isImage or file.isVideo)
return file.dimensions
false
filesize: (post) ->
if post.file

View File

@ -173,15 +173,19 @@ Config =
]
'Replace GIF': [
false
'Replace thumbnail of gifs with its actual image.'
]
'Replace PNG': [
false
'Replace pngs.'
'Replace gif thumbnails with the actual image.'
]
'Replace JPG': [
false
'Replace jpgs.'
'Replace jpg thumbnails with the actual image.'
]
'Replace PNG': [
false
'Replace png thumbnails with the actual image.'
]
'Replace WEBM': [
false
'Replace webm thumbnails with the actual webm video. Probably will degrade browser performance ;)'
]
'Image Prefetching': [
false
@ -644,7 +648,7 @@ vp-replace
]
'Toggle sage': [
'Alt+s'
'Toggle sage in email field'
'Toggle sage in options field.'
]
'Submit QR': [
'Ctrl+Enter'

View File

@ -91,6 +91,7 @@ Get =
$.rmAll root
$.add root, nodes.root
$.event 'PostsInserted'
fetchedPost: (req, boardID, threadID, postID, root, context) ->
# In case of multiple callbacks for the same request,
# don't parse the same original post more than once.
@ -116,6 +117,13 @@ Get =
break if post.no is postID # we found it!
if post.no isnt postID
# Cached requests can be stale and must be rechecked.
if req.cached
api = "//a.4cdn.org/#{boardID}/thread/#{threadID}.json"
$.cleanCache (url) -> url is api
$.cache api, ->
Get.fetchedPost @, boardID, threadID, postID, root, context
return
# The post can be deleted by the time we check a quote.
unless Get.archivedPost boardID, postID, root, context
$.addClass root, 'warning'

View File

@ -407,6 +407,7 @@ Header =
bottom -= clientHeight - headRect.bottom + headRect.height
bottom
isNodeVisible: (node) ->
return false if d.hidden or !doc.contains node
{height} = node.getBoundingClientRect()
Header.getTopOf(node) + height >= 0 and Header.getBottomOf(node) + height >= 0
isHidden: ->

View File

@ -98,6 +98,7 @@ Index =
$.asap (-> $('.board', doc) or d.readyState isnt 'loading'), ->
board = $ '.board'
$.replace board, Index.root
$.event 'PostsInserted'
# Hacks:
# - When removing an element from the document during page load,
# its ancestors will still be correctly created inside of it.
@ -128,7 +129,6 @@ Index =
return Index.endNotice() if pageNum > Index.pagesNum
nodes = Index.buildSinglePage pageNum
nodes.shift() # Remove thread common with previous page
Index.buildReplies nodes if Conf['Show Replies']
Index.buildStructure nodes
Index.setPage pageNum
@ -281,7 +281,7 @@ Index =
getPagesNum: ->
if Index.isSearching
Math.ceil (Index.sortedNodes.length / 2) / Index.threadsNumPerPage
Math.ceil Index.sortedNodes.length / Index.threadsNumPerPage
else
Index.pagesNum
getMaxPageNum: ->
@ -553,6 +553,7 @@ Index =
buildStructure: (nodes) ->
for node in nodes
$.add Index.root, [node, $.el 'hr']
$.event 'PostsInserted' if doc.contains Index.root
ThreadHiding.onIndexBuild nodes
isSearching: false

View File

@ -170,28 +170,31 @@ Settings =
data.Conf[newKey] = data.Conf[prevKey] if newKey
delete data.Conf[prevKey]
data
data = Settings.convertSettings data,
data = convertSettings data,
# General confs
'Disable 4chan\'s extension': ''
'Catalog Links': ''
'Reply Navigation': ''
'Remove Slug': ''
'Check for Updates': ''
'Recursive Filtering': 'Recursive Hiding'
'Reply Hiding': 'Reply Hiding Buttons'
'Thread Hiding': 'Thread Hiding Buttons'
'Show Stubs': 'Stubs'
'Image Auto-Gif': 'Auto-GIF'
'Expand From Current': ''
'Unread Tab Icon': 'Unread Favicon'
'Image Auto-Gif': 'Replace GIF'
'Reveal Spoilers': 'Reveal Spoiler Thumbnails'
'Expand From Current': 'Expand from here'
'Post in Title': 'Thread Excerpt'
'Auto Hide QR': ''
'Open Reply in New Tab': ''
'Remember QR size': ''
'Open Reply in New Tab': 'Open Post in New Tab'
'Remember QR size': 'Remember QR Size'
'Remember Subject': ''
'Quote Inline': 'Quote Inlining'
'Quote Preview': 'Quote Previewing'
'Indicate OP quote': 'Mark OP Quotes'
'Indicate You quote': 'Mark Quotes of You'
'Indicate Cross-thread Quotes': 'Mark Cross-thread Quotes'
'Reply Hiding': 'Reply Hiding Buttons'
'Thread Hiding': 'Thread Hiding Buttons'
# filter
'uniqueid': 'uniqueID'
'mod': 'capcode'
'email': ''
'country': 'flag'
'md5': 'MD5'
# keybinds
@ -200,6 +203,7 @@ Settings =
'openOptions': 'Open settings'
'close': 'Close'
'spoiler': 'Spoiler tags'
'sageru': 'Toggle sage'
'code': 'Code tags'
'submit': 'Submit QR'
'watch': 'Watch'

View File

@ -89,7 +89,7 @@ a {
[hidden] {
display: none !important;
}
hr ~ div.center:not(.ad-cnt) {
hr + div.center:not(.ad-cnt):not(.topad):not(.middlead):not(.bottomad) {
display: none !important;
}
.page-num {
@ -795,6 +795,7 @@ span.hide-announcement {
/* File */
.fnswitch:hover > .fntrunc,
.fnswitch:not(:hover) > .fnfull,
.expanded-image > .post > .file > .fileThumb > video[data-md5],
.expanded-image > .post > .file > .fileThumb > img[data-md5] {
display: none;
}

View File

@ -89,6 +89,7 @@ do ->
$.on req, 'load', (e) ->
cb.call @, e for cb in @callbacks
@evt = e
@cached = true
delete @callbacks
$.on req, 'abort error', rm
req.callbacks = [cb]

View File

@ -56,7 +56,7 @@ class Clone extends Post
@file[key] = val
file = $ '.file', post
@file.text = file.firstElementChild
@file.thumb = $ 'img[data-md5]', file
@file.thumb = $ '.fileThumb > [data-md5]', file
@file.fullImage = $ '.full-image', file
@file.videoControls = $ '.video-controls', @file.text
@ -72,7 +72,7 @@ class Clone extends Post
root.dataset.clone = origin.clones.push(@) - 1
cloneWithoutVideo: (node) ->
if node.tagName is 'VIDEO'
if node.tagName is 'VIDEO' and !node.dataset.md5 # (exception for WebM thumbnails)
[]
else if node.nodeType is Node.ELEMENT_NODE and $ 'video', node
clone = node.cloneNode false

View File

@ -74,7 +74,7 @@ class DataBoard
ajaxClean: (boardID) ->
$.cache "//a.4cdn.org/#{boardID}/threads.json", (e) =>
if e.target.status isnt 200
@delete boardID if e.target.status is 404
@delete {boardID} if e.target.status is 404
return
board = @data.boards[boardID]
threads = {}

View File

@ -1,20 +0,0 @@
AutoGIF =
init: ->
return if g.VIEW is 'catalog' or !Conf['Auto-GIF'] or g.BOARD.ID in ['gif', 'wsg']
Post.callbacks.push
name: 'Auto-GIF'
cb: @node
node: ->
return if @isClone or @isHidden or @thread.isHidden or !@file?.isImage
{thumb, URL} = @file
return unless /gif$/.test(URL) and !/spoiler/.test thumb.src
if @file.isSpoiler
# Revealed spoilers do not have height/width set, this fixes auto-gifs dimensions.
{style} = thumb
style.maxHeight = style.maxWidth = if @isReply then '125px' else '250px'
gif = $.el 'img'
$.on gif, 'load', ->
# Replace the thumbnail once the GIF has finished loading.
thumb.src = URL
gif.src = URL

View File

@ -29,7 +29,7 @@ ImageExpand =
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
else if ImageExpand.on and !@isHidden and !@isFetchedQuote and
(Conf['Expand spoilers'] or !@file.isSpoiler) and
(Conf['Expand videos'] or !@file.isVideo)
ImageExpand.expand @
@ -70,15 +70,15 @@ ImageExpand =
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()
for post in [post, post.clones...] when post.file and post.file.isVideo and post.file.isExpanded
video = post.file.fullImage
visible = 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: ->
@ -158,7 +158,7 @@ ImageExpand =
TrashQueue.remove el
unless file.isHovered
$.queueTask(-> el.src = el.src) if /\.gif$/.test el.src
el.currentTime = 0 if isVideo
el.currentTime = 0 if isVideo and el.readyState >= el.HAVE_METADATA
else
el.src = src or file.URL
$.after thumb, el

View File

@ -18,7 +18,7 @@ ImageHover =
el.id = 'ihover'
TrashQueue.remove el
$.queueTask(-> el.src = el.src) if /\.gif$/.test el.src
el.currentTime = 0 if isVideo
el.currentTime = 0 if isVideo and el.readyState >= el.HAVE_METADATA
else
file.fullImage = el = $.el (if isVideo then 'video' else 'img'),
className: 'full-image'

View File

@ -1,48 +1,81 @@
ImageLoader =
init: ->
return if g.VIEW is 'catalog'
return unless Conf["Image Prefetching"] or Conf["Replace JPG"] or Conf["Replace PNG"] or Conf["Replace GIF"]
return unless Conf['Image Prefetching'] or Conf['Replace JPG'] or Conf['Replace PNG'] or Conf['Replace GIF'] or Conf['Replace WEBM']
Post.callbacks.push
name: 'Image Replace'
cb: @node
Thread.callbacks.push
name: 'Image Replace'
cb: @thread
return unless Conf['Image Prefetching'] and g.VIEW is 'thread'
$.on d, 'PostsInserted', ->
g.posts.forEach ImageLoader.prefetch
if Conf['Replace WEBM']
$.on d, 'scroll visibilitychange 4chanXInitFinished PostsInserted', ->
# Special case: Quote previews are off screen when inserted into document, but quickly moved on screen.
qpClone = $.id('qp')?.firstElementChild
g.posts.forEach (post) ->
for post in [post, post.clones...] when post.file?.videoThumb
{thumb} = post.file
if Header.isNodeVisible(thumb) or post.nodes.root is qpClone then thumb.play() else thumb.pause()
return
return unless Conf['Image Prefetching']
prefetch = $.el 'label',
<%= html('<input type="checkbox" name="prefetch"> Prefetch Images') %>
@el = prefetch.firstElementChild
$.on @el, 'change', @toggle
$.on @el, 'change', ->
if Conf['prefetch'] = @checked
g.posts.forEach ImageLoader.prefetch
Header.menu.addEntry
el: prefetch
order: 104
thread: ->
ImageLoader.thread = @
node: ->
return if @isClone or @isHidden or @thread.isHidden or !@file?.isImage
{thumb, URL} = @file
return unless (Conf[string = "Replace #{if (type = (URL.match /\w{3}$/)[0].toUpperCase()) is 'PEG' then 'JPG' else type}"] and !/spoiler/.test thumb.src) or Conf['prefetch']
if @file.isSpoiler
# Revealed spoilers do not have height/width set, this fixes the image's dimensions.
{style} = thumb
style.maxHeight = style.maxWidth = if @isReply then '125px' else '250px'
img = $.el 'img'
if Conf[string]
$.on img, 'load', ->
# Replace the thumbnail once the GIF has finished loading.
thumb.src = URL
img.src = URL
return if @isClone or !@file
ImageLoader.replaceVideo @ if Conf['Replace WEBM'] and @file.isVideo
ImageLoader.prefetch @
toggle: ->
enabled = Conf['prefetch'] = @checked
if enabled
ImageLoader.thread.posts.forEach (post) -> ImageLoader.node.call post
return
replaceVideo: (post) ->
{file} = post
{thumb} = file
video = $.el 'video',
preload: 'none'
loop: true
poster: thumb.src
textContent: thumb.alt
className: thumb.className
video.dataset.md5 = thumb.dataset.md5
video.style[attr] = thumb.style[attr] for attr in ['height', 'width', 'maxHeight', 'maxWidth']
video.src = file.URL
$.on video, 'mouseover', ImageHover.mouseover if Conf['Image Hover']
$.replace thumb, video
file.thumb = video
file.videoThumb = true
prefetch: (post) ->
{file} = post
return unless file
{isImage, isVideo, thumb, URL} = file
return if file.isPrefetched or !(isImage or isVideo) or post.isHidden or post.thread.isHidden
type = if (match = URL.match(/\.([^.]+)$/)[1].toUpperCase()) is 'JPEG' then 'JPG' else match
replace = Conf["Replace #{type}"] and !/spoiler/.test thumb.src
return unless replace or Conf['prefetch']
return unless [post, post.clones...].some (clone) -> doc.contains clone.nodes.root
file.isPrefetched = true
if file.videoThumb
clone.file.thumb.preload = 'auto' for clone in post.clones
thumb.preload = 'auto'
# XXX Cloned video elements with poster in Firefox cause momentary display of image loading icon.
if !chrome?
$.on thumb, 'loadeddata', -> @removeAttribute 'poster'
return
el = $.el if isImage then 'img' else 'video'
if replace and isImage
$.on el, 'load', ->
clone.file.thumb.src = URL for clone in post.clones
thumb.src = URL
el.src = URL

View File

@ -8,5 +8,8 @@ RevealSpoilers =
node: ->
return if @isClone or !@file?.isSpoiler
{thumb} = @file
# Remove old width and height.
thumb.removeAttribute 'style'
# Enforce thumbnail size if thumbnail is replaced.
thumb.style.maxHeight = thumb.style.maxWidth = if @isReply then '125px' else '250px'
thumb.src = @file.thumbURL

View File

@ -295,7 +295,7 @@ Linkify =
return div.textContent = "ERROR: Not a valid filetype" unless embed
switch embed.type
when 'video/mp4', 'video/webm', 'video/ogv'
$.extend el, <%= html('<video autoplay loop><source type="video/mp4"><source type="video/webm"></video>') %>
$.extend el, <%= html('<video controls loop><source type="video/mp4"><source type="video/webm"></video>') %>
for ext, i in ['mp4', 'webm']
el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}"
when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg'

View File

@ -101,6 +101,7 @@ ExpandThread =
postsRoot.push root
Main.callbackNodes Post, posts
$.after a, postsRoot
$.event 'PostsInserted'
postsCount = postsRoot.length
a.textContent = ExpandThread.text '-', postsCount, filesCount

View File

@ -326,6 +326,7 @@ ThreadUpdater =
$.add ThreadUpdater.root, root
else
$.add ThreadUpdater.root, root
$.event 'PostsInserted'
if scroll
if Conf['Bottom Scroll']

View File

@ -29,12 +29,6 @@ QR =
$.on d, '4chanXInitFinished', @initReady
if Conf['Persistent QR']
unless g.BOARD.ID is 'f' and g.VIEW is 'index'
$.on d, '4chanXInitFinished', @persist
else
$.ready @persist
Post.callbacks.push
name: 'Quick Reply'
cb: @node
@ -94,11 +88,6 @@ QR =
node: ->
$.on $('a[title="Reply to this post"]', @nodes.info), 'click', QR.quote
persist: ->
return unless QR.postingIsEnabled
QR.open()
QR.hide() if Conf['Auto Hide QR'] or g.VIEW is 'catalog'
open: ->
if QR.nodes
QR.nodes.el.hidden = false

View File

@ -160,7 +160,10 @@ QR.post = class
@filesize = $.bytesToString file.size
@nodes.label.hidden = false if QR.spoiler
URL.revokeObjectURL @URL
@showFileData() if @ is QR.selected
if @ is QR.selected
@showFileData()
else
@updateFilename()
if el
@setThumbnail el
else