Merge branch 'mayhem' into v3

Conflicts:
	CHANGELOG.md
	CONTRIBUTING.md
	css/style.css
	html/General/Settings-section-Main.html
	json/archives.json
	package.json
	src/Archive/Redirect.coffee
	src/General/Header.coffee
	src/General/Main.coffee
	src/General/Settings.coffee
	src/General/lib/$.coffee
	src/General/lib/thread.class
	src/Linkification/Linkify.coffee
	src/Miscellaneous/AnnouncementHiding.coffee
	src/Monitoring/ThreadStats.coffee
This commit is contained in:
Zixaphir 2014-01-22 12:08:37 -07:00
commit b6749b91a5
28 changed files with 761 additions and 489 deletions

View File

@ -1,5 +1,7 @@
### v1.3.2
*2014-01-12*
**MayhemYDG**:
- Added a `Reset Settings` button in the settings.
- More stability update.
- Stability update.
**seaweedchan**:
- Fix Menu errors on older Firefox versions, such as the ESR

48
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,48 @@
## Reporting bugs and suggestions
Reporting bugs:
1. Make sure both your **browser** and **4chan X** are up to date.<br>
Only **Chrome**, **Firefox** and **Opera** are supported.<br>
**SRWare Iron**, **Firefox ESR**, **Pale Moon**, **Waterfox**, and other derivatives are not supported, use them at your own risk.
2. Look at the list of [known problems and solutions](https://github.com/MayhemYDG/4chan-x/wiki/FAQ#known-problems).
3. Disable your other extensions & scripts to identify conflicts.
4. If your issue persists, open a [new issue](https://github.com/MayhemYDG/4chan-x/issues) with the following information:
1. Precise steps to reproduce the problem, with the expected and actual results.
2. [Console errors](https://github.com/MayhemYDG/4chan-x/wiki/FAQ#console-errors), if any.
3. 4chan X version, browser variant, browser version, and Greasemonkey version if you are using it.
4. Your exported settings. If your settings contains sensible information (e.g. personas), edit the text file manually.
Respect these guidelines:
- Describe the issue clearly, put some effort into it. A one-liner isn't a good enough description.
- If you want to get your suggestion implemented sooner, make it convincing.
- If you want to criticize, make it convincing and constructive.
- Be mature. Act like an idiot and you will be blocked without warning.
## Development & Contribution
### Get started
- Install [node.js](http://nodejs.org/).
- Install [Grunt's CLI](http://gruntjs.com/) with `npm install -g grunt-cli`.
- Clone 4chan X.
- `cd` into it.
- Install/Update 4chan X dependencies with `npm install`.
### Build
- Build with `grunt`.
- Continuously build with `grunt watch`.
### Release
- Update the version with `grunt patch`, `grunt minor` or `grunt major`.
- Release with `grunt release`.
Note: this is only used to release new 4chan X versions, and is **not** needed or wanted in pull requests.
### Contribute
- Edit the sources.
- If the edits affect regular users, edit the changelog.
- Open a pull request.

View File

@ -1,5 +1,5 @@
/*
* 4chan X - Version 1.3.2 - 2014-01-21
* 4chan X - Version 1.3.2 - 2014-01-22
*
* Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @name 4chan X
// @version 1.3.2
// @minGMVer 1.13
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
// @description Cross-browser userscript for maximum lurking on 4chan.
@ -13,6 +13,7 @@
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM_openInTab
// @run-at document-start
// @updateURL https://github.com/seaweedchan/4chan-x/raw/stable/builds/4chan-X.meta.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -21,22 +21,22 @@
"min": {
"chrome": "31",
"firefox": "26",
"greasemonkey": "1.13"
"greasemonkey": "1.14"
}
},
"devDependencies": {
"font-awesome": "https://github.com/FortAwesome/Font-Awesome/archive/v4.0.3.tar.gz",
"grunt": "~0.4.1",
"grunt-bump": "~0.0.11",
"grunt-concurrent": "~0.4.0",
"font-awesome": "~4.0.3",
"grunt": "~0.4.2",
"grunt-bump": "~0.0.13",
"grunt-concurrent": "~0.4.3",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-coffee": "~0.8.0",
"grunt-contrib-compress": "~0.5.2",
"grunt-contrib-coffee": "~0.8.2",
"grunt-contrib-compress": "~0.6.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-copy": "~0.5.0",
"grunt-contrib-watch": "~0.5.3",
"grunt-shell": "~0.6.0",
"load-grunt-tasks": "~0.2.0"
"grunt-shell": "~0.6.3",
"load-grunt-tasks": "~0.2.1"
},
"repository": {
"type": "git",

View File

@ -1,5 +1,4 @@
Redirect =
init: ->
o =
thread: {}
@ -52,8 +51,8 @@ Redirect =
software: "foolfuuka"
,
name: "4plebs"
boards: ["hr", "o", "pol", "s4s", "tg", "tv", "x"]
files: ["hr", "o", "pol", "s4s", "tg", "tv", "x"]
boards: ["adv", "hr", "o", "pol", "s4s", "tg", "tv", "x"]
files: ["adv", "hr", "o", "pol", "s4s", "tg", "tv", "x"]
data:
domain: "archive.4plebs.org"
http: true
@ -68,6 +67,15 @@ Redirect =
http: true
https: true
software: "foolfuuka"
,
name: "Love is Over"
boards: ["d", "i"],
files: ["d", "i"]
data:
domain: "loveisover.me"
http: true
https: true
software: "foolfuuka"
,
name: "Install Gentoo"
boards: ["diy", "g", "sci"]
@ -82,7 +90,7 @@ Redirect =
boards: ["cgl", "g", "mu", "w"]
files: ["cgl", "g", "mu", "w"]
data:
domain: "rbt.asia"
domain: "archive.rebeccablacktech.com"
http: true
https: true
software: "fuuka"
@ -100,9 +108,33 @@ Redirect =
files: ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "tg", "vr"]
data:
domain: "fuuka.warosu.org"
http: true
https: true
software: "fuuka"
,
name: "fgts"
boards: ["soc"]
files: ["soc"]
data:
domain: "fgts.eu"
http: true
https: true
software: "foolfuuka"
,
name: "maware"
boards: ["t"]
files: ["t"]
data:
domain: "archive.mawa.re"
http: true
software: "foolfuuka"
,
name: "installgentoo.com"
boards: ["g", "t"]
files: ["g", "t"]
data:
domain: "chan.installgentoo.com"
http: true
software: "foolfuuka"
,
name: "Foolz Beta"
boards: ["a", "co", "d", "gd", "h", "jp", "m", "mlp", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"],
@ -113,15 +145,6 @@ Redirect =
https: true
withCredentials: true
software: "foolfuuka"
,
name: "Love is Over"
boards: ["d", "i"],
files: ["d", "i"]
data:
domain: "loveisover.me"
http: true
https: true
software: "foolfuuka"
]
to: (dest, data) ->

View File

@ -58,7 +58,7 @@ ThreadHiding =
$.cache "//a.4cdn.org/#{g.BOARD}/threads.json", ->
return unless @status is 200
threads = {}
for page in JSON.parse @response
for page in @response
for thread in page.threads
if thread.no of hiddenThreadsOnCatalog
threads[thread.no] = hiddenThreadsOnCatalog[thread.no]

View File

@ -80,6 +80,7 @@ Get =
$.cache url,
-> Get.archivedPost @, boardID, postID, root, context
,
responseType: 'json'
withCredentials: url.archive.withCredentials
insert: (post, root, context) ->
# Stop here if the container has been removed while loading.
@ -118,7 +119,7 @@ Get =
"Error #{req.statusText} (#{req.status})."
return
posts = JSON.parse(req.response).posts
{posts} = req.response
Build.spoilerRange[boardID] = posts[0].custom_spoiler
for post in posts
break if post.no is postID # we found it!
@ -149,7 +150,7 @@ Get =
Get.insert post, root, context
return
data = JSON.parse req.response
data = req.response
if data.error
$.addClass root, 'warning'
root.textContent = data.error
@ -227,4 +228,4 @@ Get =
'[/moot]': '</div>'
'[banned]': '<strong style="color: red;">'
'[/banned]': '</strong>'
}[text] or text.replace ':lit', ''
}[text] or text.replace ':lit', ''

View File

@ -305,17 +305,15 @@ Header =
toggleHideBarOnScroll: (e) ->
hide = @checked
$.set 'Header auto-hide on scroll', hide
$.cb.checked.call @
Header.setHideBarOnScroll hide
hideBarOnScroll: ->
offsetY = window.pageYOffset
if offsetY > (Header.previousOffset or 0)
$.addClass Header.bar, 'autohide'
$.addClass Header.bar, 'scroll'
$.addClass Header.bar, 'autohide', 'scroll'
else
$.rmClass Header.bar, 'autohide'
$.rmClass Header.bar, 'scroll'
$.rmClass Header.bar, 'autohide', 'scroll'
Header.previousOffset = offsetY
setBarPosition: (bottom) ->
@ -389,9 +387,21 @@ Header =
scrollTo: (root, down, needed) ->
if down
x = Header.getBottomOf root
if Conf['Header auto-hide on scroll'] and Conf['Bottom header']
{height} = Header.bar.getBoundingClientRect()
if x <= 0
x += height if !Header.isHidden()
else
x -= height if Header.isHidden()
window.scrollBy 0, -x unless needed and x >= 0
else
x = Header.getTopOf root
if Conf['Header auto-hide on scroll'] and !Conf['Bottom header']
{height} = Header.bar.getBoundingClientRect()
if x >= 0
x += height if !Header.isHidden()
else
x -= height if Header.isHidden()
window.scrollBy 0, x unless needed and x >= 0
scrollToIfNeeded: (root, down) ->
@ -411,6 +421,12 @@ Header =
headRect = Header.toggle.getBoundingClientRect()
bottom -= clientHeight - headRect.bottom + headRect.height
bottom
isHidden: ->
{top} = Header.bar.getBoundingClientRect()
if Conf['Bottom header']
top is doc.clientHeight
else
top < 0
addShortcut: (el) ->
shortcut = $.el 'span',

View File

@ -279,7 +279,7 @@ Index =
try
if req.status is 200
Index.parse JSON.parse(req.response), pageNum
Index.parse req.response, pageNum
else if req.status is 304 and pageNum?
Index.pageNav pageNum
catch err
@ -475,6 +475,7 @@ Index =
else
pageNum = Index.getCurrentPage()
else
return unless Index.searchInput.dataset.searching
pageNum = Index.pageBeforeSearch
delete Index.pageBeforeSearch
<% if (type === 'userscript') { %>

View File

@ -78,16 +78,9 @@ Main =
return if !Main.isThisPageLegit() or $.hasClass doc, 'fourchan-x'
# disable the mobile layout
$('link[href*=mobile]', d.head)?.disabled = true
<% if (type === 'crx') { %>
$.addClass doc, 'blink'
<% } else { %>
$.addClass doc, 'gecko'
<% } %>
$.addClass doc, 'fourchan-x'
$.addClass doc, 'seaweedchan'
$.addClass doc, g.VIEW
$.addClass doc, 'fourchan-x', 'seaweedchan', g.VIEW, '<% if (type === 'crx') { %>blink<% } else { %>gecko<% } %>'
$.addStyle Main.css
Main.setClass()
setClass: ->
@ -124,6 +117,7 @@ Main =
# Something might have gone wrong!
Main.initStyle()
# 4chan Pass Link
if styleSelector = $.id 'styleSelector'
passLink = $.el 'a',
textContent: '4chan Pass'
@ -134,12 +128,18 @@ Main =
'left=0,top=0,width=500,height=255,toolbar=0,resizable=0'
$.before styleSelector.previousSibling, [$.tn '['; passLink, $.tn ']\u00A0\u00A0']
# Parse HTML or skip it and start building from JSON.
unless Conf['JSON Navigation'] and g.VIEW is 'index'
Main.initThread()
else
$.event '4chanXInitFinished'
<% if (type === 'userscript') { %>
test = $.el 'span'
test.classList.add 'a', 'b'
if test.className isnt 'a b'
new Notice 'warning', "Your version of Firefox is outdated (v<%= meta.min.firefox %> minimum) and <%= meta.name %> may not operate correctly.", 30
GMver = GM_info.version.split '.'
for v, i in "<%= meta.min.greasemonkey %>".split '.'
continue if v is GMver[i]
@ -176,6 +176,17 @@ Main =
Main.callbackNodesDB Post, posts, ->
$.event '4chanXInitFinished'
$.get 'previousversion', null, ({previousversion}) ->
return if previousversion is g.VERSION
if previousversion
changelog = '<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md'
el = $.el 'span',
innerHTML: "<%= meta.name %> has been updated to <a href='#{changelog}' target=_blank>version #{g.VERSION}</a>."
new Notice 'info', el, 15
else
Settings.open()
$.set 'previousversion', g.VERSION
callbackNodes: (klass, nodes) ->
i = 0
cb = klass.callbacks

View File

@ -249,7 +249,7 @@ Navigate =
Navigate.title()
try
Navigate.parse JSON.parse(req.response).posts
Navigate.parse req.response.posts
catch err
console.error 'Navigate failure:'
console.log err

View File

@ -9,19 +9,6 @@ Settings =
Header.addShortcut link
$.get 'previousversion', null, (item) ->
if previous = item['previousversion']
return if previous is g.VERSION
changelog = '<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md'
el = $.el 'span',
innerHTML: "<%= meta.name %> has been updated to <a href='#{changelog}' target=_blank>version #{g.VERSION}</a>."
if Conf['Show Updated Notifications']
new Notice 'info', el, 30
else
$.on d, '4chanXInitFinished', Settings.open
$.set 'previousversion', g.VERSION
Settings.addSection 'Main', Settings.main
Settings.addSection 'Filter', Settings.filter
Settings.addSection 'Sauce', Settings.sauce
@ -37,7 +24,6 @@ Settings =
localStorage.setItem '4chan-settings', JSON.stringify settings
open: (openSection) ->
$.off d, '4chanXInitFinished', Settings.open
return if Settings.dialog
$.event 'CloseMenu'
@ -53,6 +39,7 @@ Settings =
$.on $('.export', Settings.dialog), 'click', Settings.export
$.on $('.import', Settings.dialog), 'click', Settings.import
$.on $('.reset', Settings.dialog), 'click', Settings.reset
$.on $('input', Settings.dialog), 'change', Settings.onImport
links = []
@ -124,56 +111,39 @@ Settings =
div = $.el 'div',
innerHTML: "<button></button><span class=description>: Clear manually-hidden threads and posts on all boards. Reload the page to apply."
button = $ 'button', div
hiddenNum = 0
$.get 'hiddenThreads', boards: {}, (item) ->
for ID, board of item.hiddenThreads.boards
$.get {hiddenThreads: {}, hiddenPosts: {}}, ({hiddenThreads, hiddenPosts}) ->
hiddenNum = 0
for ID, board of hiddenThreads.boards
hiddenNum += Object.keys(board).length
for ID, board of hiddenPosts.boards
for ID, thread of board
hiddenNum++
button.textContent = "Hidden: #{hiddenNum}"
$.get 'hiddenPosts', boards: {}, (item) ->
for ID, board of item.hiddenPosts.boards
for ID, thread of board
for ID, post of thread
hiddenNum++
hiddenNum += Object.keys(thread).length
button.textContent = "Hidden: #{hiddenNum}"
$.on button, 'click', ->
@textContent = 'Hidden: 0'
$.get 'hiddenThreads', boards: {}, (item) ->
for boardID of item.hiddenThreads.boards
$.get 'hiddenThreads', {}, ({hiddenThreads}) ->
for boardID of hiddenThreads.boards
localStorage.removeItem "4chan-hide-t-#{boardID}"
$.delete ['hiddenThreads', 'hiddenPosts']
$.after $('input[name="Stubs"]', section).parentNode.parentNode, div
export: (now, data) ->
unless typeof now is 'number'
now = Date.now()
data =
version: g.VERSION
date: now
for db in DataBoard.keys
Conf[db] = boards: {}
# Make sure to export the most recent data.
$.get Conf, (Conf) ->
# XXX don't export archives.
delete Conf['archives']
data.Conf = Conf
Settings.export now, data
return
export: ->
# Make sure to export the most recent data.
$.get Conf, (Conf) ->
# XXX don't export archives.
delete Conf['archives']
Settings.downloadExport {version: g.VERSION, date: Date.now(), Conf}
downloadExport: (data) ->
a = $.el 'a',
className: 'warning'
textContent: 'Save me!'
download: "<%= meta.name %> v#{g.VERSION}-#{now}.json"
download: "<%= meta.name %> v#{g.VERSION}-#{data.date}.json"
href: "data:application/json;base64,#{btoa unescape encodeURIComponent JSON.stringify data, null, 2}"
target: '_blank'
<% if (type === 'userscript') { %>
# XXX Firefox won't let us download automatically.
p = $ '.imp-exp-result', Settings.dialog
$.rmAll p
$.add p, a
<% } else { %>
a.click()
<% } %>
a.click()
import: ->
@nextElementSibling.click()
$('input', @parentNode).click()
onImport: ->
return unless file = @files[0]
output = $('.imp-exp-result')
@ -183,8 +153,7 @@ Settings =
reader = new FileReader()
reader.onload = (e) ->
try
data = JSON.parse e.target.result
Settings.loadSettings data
Settings.loadSettings JSON.parse e.target.result
if confirm 'Import successful. Reload now?'
window.location.reload()
catch err
@ -194,6 +163,11 @@ Settings =
loadSettings: (data) ->
version = data.version.split '.'
if version[0] is '2'
convertSettings = (data, map) ->
for prevKey, newKey of map
data.Conf[newKey] = data.Conf[prevKey] if newKey
delete data.Conf[prevKey]
data
data = Settings.convertSettings data,
# General confs
'Disable 4chan\'s extension': ''
@ -265,11 +239,9 @@ Settings =
data.Conf['watchedThreads'] = boards: ThreadWatcher.convert data.Conf['WatchedThreads']
delete data.Conf['WatchedThreads']
$.set data.Conf
convertSettings: (data, map) ->
for prevKey, newKey of map
data.Conf[newKey] = data.Conf[prevKey] if newKey
delete data.Conf[prevKey]
data
reset: ->
if confirm 'Your current settings will be entirely wiped, are you sure?'
$.clear -> window.location.reload() if confirm 'Reset successful. Reload now?'
filter: (section) ->
section.innerHTML = <%= importHTML('Settings/Filter-select') %>

View File

@ -157,6 +157,9 @@ UI = do ->
e.preventDefault()
e.stopPropagation()
onFocus: (e) =>
e.stopPropagation()
@focus e.target
focus: (entry) ->
while focused = $.x 'parent::*/child::*[contains(@class,"focused")]', entry
$.rmClass focused, 'focused'
@ -199,10 +202,7 @@ UI = do ->
parseEntry: (entry) ->
{el, subEntries} = entry
$.addClass el, 'entry'
$.on el, 'focus mouseover', ((e) ->
e.stopPropagation()
@focus el
).bind @
$.on el, 'focus mouseover', @onFocus
el.style.order = entry.order or 100
return unless subEntries
$.addClass el, 'has-submenu'

View File

@ -653,6 +653,15 @@ span.hide-announcement {
text-decoration: none;
border-bottom: 1px dashed;
}
@supports (text-decoration-style: dashed) or (-moz-text-decoration-style: dashed) {
.quotelink.forwardlink,
.backlink.forwardlink {
text-decoration: underline;
-moz-text-decoration-style: dashed;
text-decoration-style: dashed;
border-bottom: none;
}
}
.filtered {
text-decoration: underline line-through;
}

View File

@ -4,11 +4,12 @@
<div class=credits>
<a class=export>Export</a> |
<a class=import>Import</a> |
<input type=file style='display: none;'>
<button class="reset">Reset Settings</button> |
<input type=file hidden>
<a href='<%= meta.page %>' target=_blank><%= meta.name %></a> |
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md' target=_blank>#{g.VERSION}</a> |
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/README.md#reporting-bugs-and-suggestions' target=_blank>Issues</a> |
<a href=javascript:; class=close title=Close>×</a>
<a href=javascript:; class='fa fa-times' title=Close></a>
</div>
</nav>
<div class=section-container><section></section></div>

View File

@ -54,6 +54,8 @@ $.ajax = do ->
if whenModified
r.setRequestHeader 'If-Modified-Since', lastModified[url] if url of lastModified
$.on r, 'load', -> lastModified[url] = r.getResponseHeader 'Last-Modified'
if /\.json$/.test url
r.responseType = 'json'
$.extend r, options
$.extend r.upload, upCallbacks
r.send form
@ -113,11 +115,11 @@ $.X = (path, root) ->
# XPathResult.ORDERED_NODE_SNAPSHOT_TYPE === 7
d.evaluate path, root, null, 7, null
$.addClass = (el, className) ->
el.classList.add className
$.addClass = (el, className...) ->
el.classList.add className...
$.rmClass = (el, className) ->
el.classList.remove className
$.rmClass = (el, className...) ->
el.classList.remove className...
$.toggleClass = (el, className) ->
el.classList.toggle className
@ -332,29 +334,50 @@ $.get = (key, val, cb) ->
chrome.storage.sync.get syncItems, done
$.set = do ->
items = {}
localItems = {}
items =
sync: {}
local: {}
timeout = {}
set = $.debounce $.SECOND, ->
setArea = (area) ->
data = items[area]
return if !Object.keys(data).length or timeout[area]
items[area] = {}
chrome.storage[area].set data, ->
if chrome.runtime.lastError
c.error chrome.runtime.lastError.message
for key, val of data when key not of items[area]
items[area][key] = val
timeout[area] = setTimeout setArea, $.MINUTE, area
return
delete timeout[area]
setAll = $.debounce $.SECOND, ->
for key in $.localKeys
if key of items
(localItems or= {})[key] = items[key]
delete items[key]
if key of items.sync
items.local[key] = items.sync[key]
delete items.sync[key]
try
chrome.storage.local.set localItems
chrome.storage.sync.set items
items = {}
localItems = {}
setArea 'local'
setArea 'sync'
catch err
c.error err.stack
(key, val) ->
if typeof key is 'string'
items[key] = val
items.sync[key] = val
else
$.extend items, key
set()
$.extend items.sync, key
setAll()
$.clear = (cb) ->
count = 2
done = ->
if chrome.runtime.lastError
c.error chrome.runtime.lastError.message
return
cb?() unless --count
chrome.storage.local.clear done
chrome.storage.sync.clear done
<% } else { %>
# http://wiki.greasespot.net/Main_Page
@ -402,6 +425,9 @@ $.set = do ->
for key, val of keys
set key, val
return
$.clear = (cb) ->
$.delete GM_listValues().map (key) -> key.replace g.NAMESPACE, ''
cb?()
<% } %>
$$ = (selector, root=d.body) ->

View File

@ -78,7 +78,7 @@ class DataBoard
return
board = @data.boards[boardID]
threads = {}
for page in JSON.parse e.target.response
for page in e.target.response
for thread in page.threads
if thread.no of board
threads[thread.no] = board[thread.no]
@ -93,4 +93,4 @@ class DataBoard
disconnect: ->
$.desync @key
delete @sync
delete @data
delete @data

View File

@ -14,6 +14,7 @@
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM_openInTab
// @run-at document-start
// @updateURL <%= meta.repo %>raw/stable/builds/<%= meta.files.metajs %>

View File

@ -153,10 +153,19 @@ ImageExpand =
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}/res/#{post.thread}.json", onload: ->
return if @status isnt 200
for postObj in JSON.parse(@response).posts
for postObj in @response.posts
break if postObj.no is post.ID
if postObj.no isnt post.ID
clearTimeout timeoutID
@ -164,6 +173,7 @@ ImageExpand =
else if postObj.filedeleted
clearTimeout timeoutID
post.kill true
<% } %>
menu:
init: ->

View File

@ -38,10 +38,19 @@ ImageHover =
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}/res/#{post.thread}.json", onload: ->
return if @status isnt 200
for postObj in JSON.parse(@response).posts
for postObj in @response.posts
break if postObj.no is post.ID
if postObj.no isnt post.ID
clearTimeout timeoutID
@ -49,3 +58,4 @@ ImageHover =
else if postObj.filedeleted
clearTimeout timeoutID
post.kill true
<% } %>

View File

@ -1,10 +1,9 @@
PSAHiding =
init: ->
return if !Conf['Announcement Hiding']
$.addClass doc, 'hide-announcement'
$.on d, '4chanXInitFinished', @setup
setup: ->
$.off d, '4chanXInitFinished', PSAHiding.setup

View File

@ -77,13 +77,13 @@ ExpandThread =
a.textContent = "Error #{req.statusText} (#{req.status})"
return
data = JSON.parse(req.response).posts
Build.spoilerRange[thread.board] = data.shift().custom_spoiler
Build.spoilerRange[thread.board] = req.response.posts[0].custom_spoiler
posts = []
postsRoot = []
filesCount = 0
for postData in data
for postData in req.response.posts
continue if postData.no is thread.ID
if post = thread.posts[postData.no]
filesCount++ if 'file' of post
postsRoot.push post.nodes.root

View File

@ -77,9 +77,8 @@ ThreadStats =
onThreadsLoad: ->
return unless Conf["Page Count in Stats"] and @status is 200
pages = JSON.parse @response
for page in pages
for page in @response
for thread in page.threads when thread.no is ThreadStats.thread.ID
ThreadStats.pageCountEl.textContent = page.page
(if page.page is pages.length - 1 then $.addClass else $.rmClass) ThreadStats.pageCountEl, 'warning'
return
(if page.page is @response.length - 1 then $.addClass else $.rmClass) ThreadStats.pageCountEl, 'warning'
return

View File

@ -158,7 +158,7 @@ ThreadUpdater =
switch req.status
when 200
g.DEAD = false
ThreadUpdater.parse JSON.parse(req.response).posts
ThreadUpdater.parse req.response.posts
ThreadUpdater.setInterval()
when 404
g.DEAD = true

View File

@ -670,7 +670,7 @@ QR =
# Too many frequent mistyped captchas will auto-ban you!
# On connection error, the post most likely didn't go through.
QR.cooldown.set delay: 2
else if err.textContent and m = err.textContent.match /wait\s(\d+)\ssecond/i
else if err.textContent and m = err.textContent.match /wait\s+(\d+)\s+second/i
QR.cooldown.auto = if QR.captcha.isEnabled
!!QR.captcha.captchas.length
else