Help out decaffeinate. #829

This commit is contained in:
ccd0 2016-10-01 03:18:22 -07:00
parent 6a16010cfb
commit ad9c3df4dc
52 changed files with 152 additions and 131 deletions

View File

@ -139,7 +139,7 @@ Redirect =
if type is 'capcode'
value = {'Developer': 'dev'}[value] or value.toLowerCase()
else if type is 'image'
value = value.replace /[+/=]/g, (c) -> {'+': '-', '/': '_', '=': ''}[c]
value = value.replace /[+/=]/g, (c) -> ({'+': '-', '/': '_', '=': ''})[c]
value = encodeURIComponent value
path = if archive.software is 'foolfuuka'
"#{boardID}/search/#{type}/#{value}/"

View File

@ -11,7 +11,7 @@ Filter =
for line in Conf[key].split '\n'
continue if line[0] is '#'
unless regexp = line.match /\/(.+)\/(\w*)/
if not (regexp = line.match /\/(.+)\/(\w*)/)
continue
# Don't mix up filter flags with the regular expression.

View File

@ -84,7 +84,7 @@ PostHiding =
open: (post) ->
if !post.isReply or post.isClone or !post.isHidden
return false
unless data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
if not (data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID})
return false
PostHiding.menu.post = post
thisPost.firstChild.checked = post.isHidden
@ -104,7 +104,7 @@ PostHiding =
open: (post) ->
if !post.isReply or post.isClone or !post.isHidden
return false
unless data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
if not (data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID})
return false
PostHiding.menu.post = post

View File

@ -14,14 +14,15 @@ Recursive =
return
add: (recursive, post, args...) ->
obj = Recursive.recursives[post.fullID] or=
obj = Recursive.recursives[post.fullID] or= {
recursives: []
args: []
}
obj.recursives.push recursive
obj.args.push args
rm: (recursive, post) ->
return unless obj = Recursive.recursives[post.fullID]
return if not (obj = Recursive.recursives[post.fullID])
for rec, i in obj.recursives when rec is recursive
obj.recursives.splice i, 1
obj.args.splice i, 1

View File

@ -22,10 +22,11 @@ ThreadHiding =
@hiddenThreads = JSON.parse(localStorage.getItem "4chan-hide-t-#{g.BOARD}") or {}
Main.ready ->
# 4chan's catalog sets the style to "display: none;" when hiding or unhiding a thread.
new MutationObserver(ThreadHiding.catalogSave).observe $.id('threads'),
new MutationObserver(ThreadHiding.catalogSave).observe $.id('threads'), {
attributes: true
subtree: true
attributeFilter: ['style']
}
catalogSave: ->
hiddenThreads2 = JSON.parse(localStorage.getItem "4chan-hide-t-#{g.BOARD}") or {}
@ -78,7 +79,7 @@ ThreadHiding =
return false
ThreadHiding.menu.thread = thread
true
subEntries: [el: apply; el: makeStub]
subEntries: [{el: apply}, {el: makeStub}]
div = $.el 'a',
className: 'show-thread-link'

View File

@ -105,7 +105,7 @@ Build.Test =
testAll: ->
g.posts.forEach (post) ->
unless post.isClone or post.isFetchedQuote
unless (abbr = $ '.abbr', post.nodes.comment) and /Comment too long\./.test(abbr.textContent)
if not ((abbr = $ '.abbr', post.nodes.comment) and /Comment too long\./.test(abbr.textContent))
Build.Test.testOne post
return

View File

@ -6,7 +6,7 @@ Build =
unescape: (text) ->
return text unless text?
text.replace(/<[^>]*>/g, '').replace /&(amp|#039|quot|lt|gt|#44);/g, (c) ->
{'&amp;': '&', '&#039;': "'", '&quot;': '"', '&lt;': '<', '&gt;': '>', '&#44;': ','}[c]
(({'&amp;': '&', '&#039;': "'", '&quot;': '"', '&lt;': '<', '&gt;': '>', '&#44;': ','})[c])
shortFilename: (filename) ->
ext = filename.match(/\.?[^\.]*$/)[0]
@ -149,7 +149,7 @@ Build =
for quote in $$ '.quotelink', container
href = quote.getAttribute 'href'
if (href[0] is '#') and !(Build.sameThread boardID, threadID)
quote.href = "/#{boardID}/thread/#{threadID}" + href
quote.href = ("/#{boardID}/thread/#{threadID}") + href
else if (match = href.match /^\/([^\/]+)\/thread\/(\d+)/) and (Build.sameThread match[1], match[2])
quote.href = href.match(/(#[^#]*)?$/)[0] or '#'
else if /^\d+(#|$)/.test(href) and not (g.VIEW is 'thread' and g.BOARD.ID is boardID) # used on /f/
@ -199,7 +199,7 @@ Build =
src = "#{staticPath}spoiler"
if spoilerRange = Build.spoilerRange[thread.board]
# Randomize the spoiler image.
src += "-#{thread.board}" + Math.floor 1 + spoilerRange * Math.random()
src += ("-#{thread.board}") + Math.floor 1 + spoilerRange * Math.random()
src += '.png'
imgClass = 'spoiler-file'
else if data.filedeleted

View File

@ -1,7 +1,7 @@
Get =
threadExcerpt: (thread) ->
{OP} = thread
excerpt = "/#{thread.board}/ - " + (
excerpt = ("/#{thread.board}/ - ") + (
OP.info.subject?.trim() or
OP.info.commentDisplay.replace(/\n+/g, ' // ') or
OP.file?.name or

View File

@ -246,7 +246,7 @@ Header =
a.textContent = if /-title/.test(t) or /-replace/.test(t) and boardID is g.BOARD.ID
a.title or a.textContent
else if /-full/.test t
"/#{boardID}/" + (if a.title then " - #{a.title}" else '')
("/#{boardID}/") + (if a.title then " - #{a.title}" else '')
else
text or boardID

View File

@ -20,10 +20,11 @@ Index =
Conf['Index Mode'] = history.state?.mode
@currentSort = history.state?.sort
@currentSort or=
if typeof Conf['Index Sort'] is 'object'
if typeof Conf['Index Sort'] is 'object' then (
Conf['Index Sort'][g.BOARD.ID] or 'bump'
else
) else (
Conf['Index Sort']
)
@currentPage = @getCurrentPage()
@processHash()
@ -594,7 +595,7 @@ Index =
if Index.liveThreadData[0]
Build.spoilerRange[g.BOARD.ID] = Index.liveThreadData[0].custom_spoiler
g.BOARD.threads.forEach (thread) ->
thread.collect() unless thread.ID in Index.liveThreadIDs
(thread.collect() unless thread.ID in Index.liveThreadIDs)
return
buildThreads: ->
@ -616,7 +617,7 @@ Index =
thread = new Thread threadData.no, g.BOARD
threads.push thread
unless (OP = thread.OP) and not OP.isFetchedQuote
if not ((OP = thread.OP) and not OP.isFetchedQuote)
OP = new Post Build.postFromObject(threadData, g.BOARD.ID, true), thread, g.BOARD
posts.push OP
thread.setPage i // Index.threadsNumPerPage + 1
@ -638,7 +639,7 @@ Index =
buildReplies: (threads) ->
posts = []
for thread in threads
continue unless (lastReplies = Index.liveThreadDict[thread.ID].last_replies)
continue if not (lastReplies = Index.liveThreadDict[thread.ID].last_replies)
nodes = []
for data in lastReplies
if (post = thread.posts[data.no]) and not post.isFetchedQuote
@ -681,7 +682,7 @@ Index =
buildCatalogReplies: (threads) ->
for thread in threads
{nodes} = thread.catalogView
continue unless (lastReplies = Index.liveThreadDict[thread.ID].last_replies)
continue if not (lastReplies = Index.liveThreadDict[thread.ID].last_replies)
if nodes.replies
# RelativeDates will stop updating elements if they go out of document.
@ -816,7 +817,7 @@ Index =
Index.pageLoad false
querySearch: (query) ->
return unless keywords = query.toLowerCase().match /\S+/g
return if not (keywords = query.toLowerCase().match /\S+/g)
Index.sortedThreads.filter (thread) ->
Index.searchMatch thread, keywords

View File

@ -183,7 +183,7 @@ Settings =
if $.hasStorage
for boardID of hiddenThreads.boards
localStorage.removeItem "4chan-hide-t-#{boardID}"
$.delete ['hiddenThreads', 'hiddenPosts']
($.delete ['hiddenThreads', 'hiddenPosts'])
$.after $('input[name="Stubs"]', section).parentNode.parentNode, div
export: ->
@ -191,7 +191,7 @@ Settings =
$.get Conf, (Conf) ->
# Don't export cached JSON data.
delete Conf['boardConfig']
Settings.downloadExport {version: g.VERSION, date: Date.now(), Conf}
(Settings.downloadExport {version: g.VERSION, date: Date.now(), Conf})
downloadExport: (data) ->
a = $.el 'a',
@ -206,7 +206,7 @@ Settings =
$('input[type=file]', @parentNode).click()
onImport: ->
return unless file = @files[0]
return if not (file = @files[0])
@value = null
output = $('.imp-exp-result')
unless confirm 'Your current settings will be entirely overwritten, are you sure?'
@ -437,7 +437,7 @@ Settings =
className: 'field'
spellcheck: false
$.get name, Conf[name], (item) ->
ta.value = item[name]
(ta.value = item[name])
$.on ta, 'change', $.cb.value
$.add div, ta
return
@ -449,7 +449,7 @@ Settings =
$('.warning', section).hidden = Conf['Sauce']
ta = $ 'textarea', section
$.get 'sauces', Conf['sauces'], (item) ->
ta.value = item['sauces']
(ta.value = item['sauces'])
$.on ta, 'change', $.cb.value
advanced: (section) ->
@ -530,10 +530,11 @@ Settings =
for {uid, name, boards, files, software} in Conf['archives']
continue unless software in ['fuuka', 'foolfuuka']
for boardID in boards
o = archBoards[boardID] or=
o = archBoards[boardID] or= {
thread: []
post: []
file: []
}
archive = [uid ? name, name]
o.thread.push archive
o.post.push archive if software is 'foolfuuka'
@ -546,10 +547,11 @@ Settings =
className: "board-#{boardID}"
row.hidden = boardID isnt g.BOARD.ID
boardOptions.push $.el 'option',
boardOptions.push $.el 'option', {
textContent: "/#{boardID}/"
value: "board-#{boardID}"
selected: boardID is g.BOARD.ID
}
o = archBoards[boardID]
$.add row, Settings.addArchiveCell boardID, o, item for item in ['thread', 'post', 'file']
@ -587,13 +589,14 @@ Settings =
i = 0
while i < length
archive = data[type][i++]
options.push $.el 'option',
options.push $.el 'option', {
value: JSON.stringify archive[0]
textContent: archive[1]
}
$.extend td, <%= html('<select></select>') %>
select = td.firstElementChild
unless select.disabled = length is 1
if not (select.disabled = length is 1)
# XXX GM can't into datasets
select.setAttribute 'data-boardid', boardID
select.setAttribute 'data-type', type
@ -616,7 +619,7 @@ Settings =
@nextElementSibling.textContent = Time.format @value, new Date()
backlink: ->
@nextElementSibling.textContent = @value.replace /%(?:id|%)/g, (x) -> {'%id': '123456789', '%%': '%'}[x]
@nextElementSibling.textContent = @value.replace /%(?:id|%)/g, (x) -> ({'%id': '123456789', '%%': '%'})[x]
fileInfo: ->
data =

View File

@ -5,7 +5,7 @@ dialog = (id, position, properties) ->
$.extend el, properties
el.style.cssText = position
$.get "#{id}.position", position, (item) ->
el.style.cssText = item["#{id}.position"]
(el.style.cssText = item["#{id}.position"])
move = $ '.move', el
$.on move, 'touchstart mousedown', dragstart
@ -153,7 +153,7 @@ class Menu
if next = @findNextEntry entry, +1
@focus next
when 39 # Right
if (submenu = $ '.submenu', entry) and next = submenu.firstElementChild
if (submenu = $ '.submenu', entry) and (next = submenu.firstElementChild)
while nextPrev = @findNextEntry next, -1
next = nextPrev
@focus next
@ -178,7 +178,7 @@ class Menu
$.addClass entry, 'focused'
# Submenu positioning.
return unless submenu = $ '.submenu', entry
return if not (submenu = $ '.submenu', entry)
sRect = submenu.getBoundingClientRect()
eRect = entry.getBoundingClientRect()
cHeight = doc.clientHeight

View File

@ -1,6 +1,6 @@
Gallery =
init: ->
return unless @enabled = Conf['Gallery'] and g.VIEW in ['index', 'thread'] and g.BOARD.ID isnt 'f'
return if not (@enabled = Conf['Gallery'] and g.VIEW in ['index', 'thread'] and g.BOARD.ID isnt 'f')
@delay = Conf['Slide Delay']
@ -202,7 +202,7 @@ Gallery =
ImageCommon.error @, g.posts[@dataset.post], null, (url) =>
return unless url
Gallery.images[@dataset.id].href = url
@src = url if Gallery.nodes.current is @
(@src = url if Gallery.nodes.current is @)
cacheError: ->
delete Gallery.cache
@ -236,7 +236,7 @@ Gallery =
cb:
keybinds: (e) ->
return unless key = Keybinds.keyCode e
return if not (key = Keybinds.keyCode e)
cb = switch key
when Conf['Close'], Conf['Open Gallery']

View File

@ -27,7 +27,7 @@ ImageCommon =
decodeError: (file, post) ->
return false unless file.error?.code is MediaError.MEDIA_ERR_DECODE
unless message = $ '.warning', post.file.thumb.parentNode
if not (message = $ '.warning', post.file.thumb.parentNode)
message = $.el 'div', className: 'warning'
$.after post.file.thumb, message
message.textContent = 'Error: Corrupt or unplayable video'
@ -35,9 +35,10 @@ ImageCommon =
error: (file, post, delay, cb) ->
src = post.file.url.split '/'
URL = Redirect.to 'file',
URL = Redirect.to 'file', {
boardID: post.board.ID
filename: src[src.length - 1]
}
unless Conf['404 Redirect'] and URL and Redirect.securityCheck URL
URL = null

View File

@ -1,6 +1,6 @@
ImageExpand =
init: ->
return unless @enabled = Conf['Image Expansion'] and g.VIEW in ['index', 'thread'] and g.BOARD.ID isnt 'f'
return if not (@enabled = Conf['Image Expansion'] and g.VIEW in ['index', 'thread'] and g.BOARD.ID isnt 'f')
@EAI = $.el 'a',
className: 'expand-all-shortcut fa fa-expand'
@ -273,7 +273,7 @@ ImageExpand =
ImageCommon.error @, post, 10 * $.SECOND, (URL) ->
if post.file.isExpanding or post.file.isExpanded
ImageExpand.contract post
ImageExpand.expand post, URL if URL
(ImageExpand.expand post, URL if URL)
menu:
init: ->

View File

@ -19,7 +19,7 @@ Sauce =
cb: @node
createSauceLink: (link, post) ->
return null unless link = link.trim()
return null if not (link = link.trim())
parts = {}
for part, i in link.split /;(?=(?:text|boards|types|sandbox):?)/
@ -60,7 +60,7 @@ Sauce =
nodes = []
skipped = []
for link in Sauce.links
unless (node = Sauce.createSauceLink link, @)
if not (node = Sauce.createSauceLink link, @)
node = Sauce.link.cloneNode false
skipped.push [link, node]
nodes.push $.tn(' '), node
@ -79,7 +79,7 @@ Sauce =
URL: (post) -> post.file.url
IMG: (post, ext) -> if ext in ['gif', 'jpg', 'png'] then post.file.url else post.file.thumbURL
MD5: (post) -> post.file.MD5
sMD5: (post) -> post.file.MD5?.replace /[+/=]/g, (c) -> {'+': '-', '/': '_', '=': ''}[c]
sMD5: (post) -> post.file.MD5?.replace /[+/=]/g, (c) -> ({'+': '-', '/': '_', '=': ''})[c]
hMD5: (post) -> if post.file.MD5 then ("0#{c.charCodeAt(0).toString(16)}"[-2..] for c in atob post.file.MD5).join('')
board: (post) -> post.board.ID
name: (post) -> post.file.name

View File

@ -71,7 +71,7 @@ Volume =
wheel: (e) ->
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey
return unless el = $ 'video:not([data-md5])', @
return if not (el = $ 'video:not([data-md5])', @)
return if el.muted or not $.hasAudio el
volume = el.volume + 0.1
volume *= 1.1 if e.deltaY < 0

View File

@ -69,7 +69,7 @@ Embedding =
$.on $('.close', Embedding.dialog), 'click', Embedding.closeFloat
$.on $('.move', Embedding.dialog), 'mousedown', Embedding.dragEmbed
$.on $('.jump', Embedding.dialog), 'click', ->
Header.scrollTo Embedding.lastEmbed if doc.contains Embedding.lastEmbed
(Header.scrollTo Embedding.lastEmbed if doc.contains Embedding.lastEmbed)
$.add d.body, Embedding.dialog
closeFloat: ->
@ -91,7 +91,7 @@ Embedding =
title: (data) ->
{key, uid, options, link, post} = data
return unless service = Embedding.types[key].title
return if not (service = Embedding.types[key].title)
$.addClass link, key.toLowerCase()
if service.batchSize
(service.queue or= []).push data
@ -117,7 +117,7 @@ Embedding =
click: (e) ->
e.preventDefault()
if Conf['Floating Embeds'] or $.hasClass(doc, 'catalog-mode')
return unless div = Embedding.media.firstChild
return if not (div = Embedding.media.firstChild)
$.replace div, Embedding.cb.embed @
Embedding.lastEmbed = Get.postFromNode(@).nodes.root
$.rmClass Embedding.dialog, 'empty'

View File

@ -24,7 +24,7 @@ ExpandComment =
$.replace post.nodes.shortComment, post.nodes.longComment
post.nodes.comment = post.nodes.longComment
return
return unless a = $ '.abbr > a', post.nodes.comment
return if not (a = $ '.abbr > a', post.nodes.comment)
a.textContent = "Post No.#{post} Loading..."
$.cache "//a.4cdn.org#{a.pathname.split(/\/+/).splice(0,4).join('/')}.json", -> ExpandComment.parse @, a, post

View File

@ -1,7 +1,7 @@
ExpandThread =
statuses: {}
init: ->
return unless g.VIEW is 'index' and Conf['Thread Expansion']
return if not (g.VIEW is 'index' and Conf['Thread Expansion'])
if Conf['JSON Index']
$.on d, 'IndexRefreshInternal', @onIndexRefresh
else
@ -10,7 +10,7 @@ ExpandThread =
cb: -> ExpandThread.setButton @
setButton: (thread) ->
return unless thread.nodes.root and (a = $ '.summary', thread.nodes.root)
return if not (thread.nodes.root and (a = $ '.summary', thread.nodes.root))
a.textContent = Build.summaryText '+', a.textContent.match(/\d+/g)...
a.style.cursor = 'pointer'
$.on a, 'click', ExpandThread.cbToggle
@ -35,7 +35,7 @@ ExpandThread =
toggle: (thread) ->
threadRoot = thread.nodes.root
return unless a = $ '.summary', threadRoot
return if not (a = $ '.summary', threadRoot)
if thread.ID of ExpandThread.statuses
ExpandThread.contract thread, a, threadRoot
else

View File

@ -5,7 +5,7 @@ Flash =
initReady: ->
if $.hasStorage
$.global -> window.SWFEmbed.init() if JSON.parse(localStorage['4chan-settings'] or '{}').disableAll
$.global -> (window.SWFEmbed.init() if JSON.parse(localStorage['4chan-settings'] or '{}').disableAll)
else
if g.VIEW is 'thread'
$.global -> window.Main.tid = location.pathname.split(/\/+/)[3]

View File

@ -4,8 +4,8 @@ Fourchan =
if g.BOARD.ID is 'g'
$.on window, 'prettyprint:cb', (e) ->
return unless post = g.posts[e.detail.ID]
return unless pre = $$('.prettyprint', post.nodes.comment)[e.detail.i]
return if not (post = g.posts[e.detail.ID])
return if not (pre = $$('.prettyprint', post.nodes.comment)[e.detail.i])
unless $.hasClass pre, 'prettyprinted'
pre.innerHTML = e.detail.html
$.addClass pre, 'prettyprinted'

View File

@ -16,5 +16,5 @@ IDPostCount =
{uniqueID} = Get.postFromNode(@).info
n = 0
IDPostCount.thread.posts.forEach (post) ->
n++ if post.info.uniqueID is uniqueID
(n++ if post.info.uniqueID is uniqueID)
@title = "#{n} post#{if n is 1 then '' else 's'} by this ID"

View File

@ -17,7 +17,7 @@ Keybinds =
Conf[hotkey] = key
keydown: (e) ->
return unless key = Keybinds.keyCode e
return if not (key = Keybinds.keyCode e)
{target} = e
if target.nodeName in ['INPUT', 'TEXTAREA']
return unless /(Esc|Alt|Ctrl|Meta|Shift\+\w{2,})/.test(key) and not /^Alt\+(\d|Up|Down|Left|Right)$/.test(key)
@ -260,7 +260,7 @@ Keybinds =
when 'code' then !!config.code_tags
when 'math', 'eqn' then !!config.math_tags
when 'sjis' then !!config.sjis_tags
new Notice 'warning', "[#{tag}] tags are not supported on /#{g.BOARD}/.", 20 unless supported
(new Notice 'warning', "[#{tag}] tags are not supported on /#{g.BOARD}/.", 20 unless supported)
value = ta.value
selStart = ta.selectionStart
@ -272,7 +272,7 @@ Keybinds =
value[selEnd..]
# Move the caret to the end of the selection.
range = "[#{tag}]".length + selEnd
range = ("[#{tag}]").length + selEnd
ta.setSelectionRange range, range
# Fire the 'input' event
@ -314,7 +314,7 @@ Keybinds =
'following'
else
'preceding'
return unless next = $.x "#{axis}-sibling::div[contains(@class,'replyContainer') and not(@hidden) and not(child::div[@class='stub'])][1]/child::div[contains(@class,'reply')]", root
return if not (next = $.x "#{axis}-sibling::div[contains(@class,'replyContainer') and not(@hidden) and not(child::div[@class='stub'])][1]/child::div[contains(@class,'reply')]", root)
Header.scrollToIfNeeded next, delta is +1
@focus next
$.rmClass postEl, 'highlight'

View File

@ -5,7 +5,7 @@ PSAHiding =
$.one d, '4chanXInitFinished', @setup
setup: ->
unless psa = PSAHiding.psa = $.id 'globalMessage'
if not (psa = PSAHiding.psa = $.id 'globalMessage')
$.rmClass doc, 'hide-announcement'
return
if (hr = $.id('globalToggle')?.previousElementSibling) and hr.nodeName is 'HR'

View File

@ -1,6 +1,6 @@
Report =
init: ->
return unless (match = location.search.match /\bno=(\d+)/)
return if not (match = location.search.match /\bno=(\d+)/)
Captcha.replace.init()
@postID = +match[1]
$.ready @ready
@ -20,6 +20,6 @@ Report =
Report.fit 'body'
fit: (selector) ->
return unless (el = $ selector, doc) and getComputedStyle(el).visibility isnt 'hidden'
return if not ((el = $ selector, doc) and getComputedStyle(el).visibility isnt 'hidden')
dy = el.getBoundingClientRect().bottom - doc.clientHeight + 8
window.resizeBy 0, dy if dy > 0

View File

@ -1,6 +1,6 @@
Favicon =
init: ->
$.asap (-> d.head and Favicon.el = $ 'link[rel="shortcut icon"]', d.head), Favicon.initAsap
$.asap (-> d.head and (Favicon.el = $ 'link[rel="shortcut icon"]', d.head)), Favicon.initAsap
initAsap: ->
Favicon.el.type = 'image/x-icon'

View File

@ -60,7 +60,7 @@ ReplyPruning =
@posts.forEach (post) ->
if post.isReply
ReplyPruning.total++
ReplyPruning.totalFiles++ if post.file
(ReplyPruning.totalFiles++ if post.file)
# If we're linked to a post that we would hide, don't hide the posts in the first place.
# Also don't hide posts if we open the thread by a link to the OP.

View File

@ -42,7 +42,7 @@ ThreadStats =
@posts.forEach (post) ->
postCount++
fileCount++ if post.file
ThreadStats.lastPost = post.info.date if ThreadStats.pageCountEl
(ThreadStats.lastPost = post.info.date if ThreadStats.pageCountEl)
ThreadStats.thread = @
ThreadStats.fetchPage()
ThreadStats.update postCount, fileCount, @ipCount

View File

@ -32,7 +32,7 @@ ThreadUpdater =
className: 'brackets-wrap updatelink'
$.extend updateLink, <%= html('<a href="javascript:;">Update</a>') %>
Main.ready ->
$.add navLinksBot, [$.tn(' '), updateLink] if (navLinksBot = $ '.navLinksBot')
($.add navLinksBot, [$.tn(' '), updateLink] if (navLinksBot = $ '.navLinksBot'))
$.on updateLink.firstElementChild, 'click', @update
subEntries = []
@ -77,7 +77,7 @@ ThreadUpdater =
ThreadUpdater.fileIDs = []
@posts.forEach (post) ->
ThreadUpdater.postIDs.push post.ID
ThreadUpdater.fileIDs.push post.ID if post.file
(ThreadUpdater.fileIDs.push post.ID if post.file)
ThreadUpdater.cb.interval.call $.el 'input', value: Conf['Interval']
@ -238,7 +238,7 @@ ThreadUpdater =
whenModified: 'ThreadUpdater'
updateThreadStatus: (type, status) ->
return unless hasChanged = ThreadUpdater.thread["is#{type}"] isnt status
return if not (hasChanged = ThreadUpdater.thread["is#{type}"] isnt status)
ThreadUpdater.thread.setStatus type, status
return if type is 'Closed' and ThreadUpdater.thread.isArchived
change = if type is 'Sticky'
@ -346,7 +346,7 @@ ThreadUpdater =
Header.scrollTo firstPost if firstPost
# Update IP count in original post form.
if OP.unique_ips? and ipCountEl = $.id('unique-ips')
if OP.unique_ips? and (ipCountEl = $.id('unique-ips'))
ipCountEl.textContent = OP.unique_ips
ipCountEl.previousSibling.textContent = ipCountEl.previousSibling.textContent.replace(/\b(?:is|are)\b/, if OP.unique_ips is 1 then 'is' else 'are')
ipCountEl.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, if OP.unique_ips is 1 then 'poster' else 'posters')

View File

@ -1,6 +1,6 @@
ThreadWatcher =
init: ->
return unless (@enabled = Conf['Thread Watcher'])
return if not (@enabled = Conf['Thread Watcher'])
@shortcut = sc = $.el 'a',
id: 'watcher-link'
@ -335,7 +335,7 @@ ThreadWatcher =
for post in [thread.OP, thread.OP.clones...]
toggler = $ '.watch-thread-link', post.nodes.info
ThreadWatcher.setToggler toggler, isWatched
thread.catalogView.nodes.root.classList.toggle 'watched', isWatched if thread.catalogView
(thread.catalogView.nodes.root.classList.toggle 'watched', isWatched if thread.catalogView)
if Conf['Pin Watched Threads']
$.event 'SortIndex', {deferred: Conf['Index Mode'] isnt 'catalog'}
@ -346,7 +346,7 @@ ThreadWatcher =
return
update: (boardID, threadID, newData) ->
return unless data = ThreadWatcher.db?.get {boardID, threadID}
return if not (data = ThreadWatcher.db?.get {boardID, threadID})
if newData.isDead and Conf['Auto Prune']
ThreadWatcher.db.delete {boardID, threadID}
ThreadWatcher.refresh()
@ -354,7 +354,7 @@ ThreadWatcher =
n = 0
n++ for key, val of newData when data[key] isnt val
return unless n
return unless (data = ThreadWatcher.db.get {boardID, threadID})
return if not (data = ThreadWatcher.db.get {boardID, threadID})
ThreadWatcher.db.extend {boardID, threadID, val: newData}
if line = $ "#watched-threads > [data-full-i-d='#{boardID}.#{threadID}']", ThreadWatcher.dialog
newLine = ThreadWatcher.makeLine boardID, threadID, data
@ -364,7 +364,7 @@ ThreadWatcher =
ThreadWatcher.refresh()
set404: (boardID, threadID, cb) ->
return cb() unless data = ThreadWatcher.db?.get {boardID, threadID}
return cb() if not (data = ThreadWatcher.db?.get {boardID, threadID})
if Conf['Auto Prune']
ThreadWatcher.db.delete {boardID, threadID}
return cb()

View File

@ -185,7 +185,7 @@ Unread =
return unless count
Unread.updatePosition()
Unread.saveLastReadPost()
Unread.update() if e
(Unread.update() if e)
updatePosition: ->
while Unread.position and !Unread.posts.has Unread.position.ID

View File

@ -26,7 +26,7 @@ Captcha.replace =
$.onExists doc, 'iframe', Captcha.replace.iframe
noscript: ->
return unless (original = $ '#g-recaptcha, #captchaContainerAlt') and (noscript = $ 'noscript')
return if not ((original = $ '#g-recaptcha, #captchaContainerAlt') and (noscript = $ 'noscript'))
span = $.el 'span',
id: 'captcha-forced-noscript'
$.replace noscript, span

View File

@ -3,7 +3,7 @@ Captcha.v1 =
init: ->
return if d.cookie.indexOf('pass_enabled=1') >= 0
return unless @isEnabled = !!$ '#g-recaptcha, #captchaContainerAlt'
return if not (@isEnabled = !!$ '#g-recaptcha, #captchaContainerAlt')
imgContainer = $.el 'div',
className: 'captcha-img'
@ -40,7 +40,7 @@ Captcha.v1 =
replace: ->
return if @script
unless @script = $ 'script[src="//www.google.com/recaptcha/api/js/recaptcha_ajax.js"]', d.head
if not (@script = $ 'script[src="//www.google.com/recaptcha/api/js/recaptcha_ajax.js"]', d.head)
@script = $.el 'script',
src: '//www.google.com/recaptcha/api/js/recaptcha_ajax.js'
$.add d.head, @script
@ -66,7 +66,7 @@ Captcha.v1 =
$.on field, 'keydown', (e) ->
if e.keyCode is 8 and not field.value
$.global -> window.Recaptcha.reload()
field.focus() if location.hostname is 'sys.4chan.org'
(field.focus() if location.hostname is 'sys.4chan.org')
$.global ->
container = document.getElementById 'captchaContainerAlt'
@ -113,7 +113,7 @@ Captcha.v1 =
@nodes.input.focus()
afterSetup: ->
return unless challenge = $.id 'recaptcha_challenge_field_holder'
return if not (challenge = $.id 'recaptcha_challenge_field_holder')
return if challenge is QR.captcha.nodes.challenge
setLifetime = (e) -> QR.captcha.lifetime = e.detail
@ -192,7 +192,7 @@ Captcha.v1 =
@nodes.img.src = @blank
return
return unless @nodes.challenge.firstChild
return unless challenge_image = $.id 'recaptcha_challenge_image'
return if not (challenge_image = $.id 'recaptcha_challenge_image')
# -1 minute to give upload some time.
@timeout = Date.now() + @lifetime * $.SECOND - $.MINUTE
challenge = @nodes.challenge.firstChild.value

View File

@ -3,7 +3,7 @@ Captcha.v2 =
init: ->
return if d.cookie.indexOf('pass_enabled=1') >= 0
return unless (@isEnabled = !!$ '#g-recaptcha, #captchaContainerAlt, #captcha-forced-noscript')
return if not (@isEnabled = !!$ '#g-recaptcha, #captchaContainerAlt, #captcha-forced-noscript')
if (@noscript = Conf['Force Noscript Captcha'] or not Main.jsEnabled)
$.addClass QR.nodes.el, 'noscript-captcha'

View File

@ -4,7 +4,7 @@ PassLink =
Main.ready @ready
ready: ->
return unless (styleSelector = $.id 'styleSelector')
return if not (styleSelector = $.id 'styleSelector')
passLink = $.el 'span',
className: 'brackets-wrap pass-link-container'

View File

@ -536,14 +536,14 @@ QR =
i = 0
save = -> QR.selected.save @
while name = items[i++]
continue unless node = nodes[name]
continue if not (node = nodes[name])
event = if node.nodeName is 'SELECT' then 'change' else 'input'
$.on nodes[name], event, save
# XXX Blink and WebKit treat width and height of <textarea>s as min-width and min-height
if $.engine is 'gecko' and Conf['Remember QR Size']
$.get 'QR Size', '', (item) ->
nodes.com.style.cssText = item['QR Size']
(nodes.com.style.cssText = item['QR Size'])
$.on nodes.com, 'mouseup', (e) ->
return if e.button isnt 0
$.set 'QR Size', @style.cssText
@ -777,10 +777,11 @@ QR =
QR.cooldown.add threadID, postID
URL = if threadID is postID # new thread
URL = if threadID is postID then ( # new thread
"#{window.location.origin}/#{g.BOARD}/thread/#{threadID}"
else if threadID isnt g.THREADID and lastPostToThread and Conf['Open Post in New Tab'] # replying from the index or a different thread
) else if threadID isnt g.THREADID and lastPostToThread and Conf['Open Post in New Tab'] then ( # replying from the index or a different thread
"#{window.location.origin}/#{g.BOARD}/thread/#{threadID}#p#{postID}"
) else undefined
if URL
open = if Conf['Open Post in New Tab'] or postsCount

View File

@ -51,9 +51,10 @@ QR.oekaki =
window.Tegaki.flatten().toBlob (file) ->
source = "oekaki-#{Date.now()}"
FCX.oekakiLatest = source
document.dispatchEvent new CustomEvent 'QRSetFile',
document.dispatchEvent new CustomEvent 'QRSetFile', {
bubbles: true
detail: {file, name: FCX.oekakiName, source}
}
if window.Tegaki
document.querySelector('#qr .oekaki').hidden = false
@ -101,9 +102,10 @@ QR.oekaki =
name = document.getElementById('qr-filename').value.replace(/\.\w+$/, '') + '.png'
{source} = document.getElementById('file-n-submit').dataset
error = (content) ->
document.dispatchEvent new CustomEvent 'CreateNotification',
document.dispatchEvent new CustomEvent 'CreateNotification', {
bubbles: true
detail: {type: 'warning', content, lifetime: 20}
}
cb = (e) ->
document.removeEventListener 'QRFile', cb, false
return error 'No file to edit.' unless e.detail

View File

@ -13,7 +13,7 @@ QR.persona =
parseItem: (item) ->
return if item[0] is '#'
return unless match = item.match /(name|options|email|subject|password):"(.*)"/i
return if not (match = item.match /(name|options|email|subject|password):"(.*)"/i)
[match, type, val] = match
# Don't mix up item settings with val.

View File

@ -16,7 +16,7 @@ QR.post = class
$.on @nodes.rm, 'click', (e) => e.stopPropagation(); @rm()
$.on @nodes.spoiler, 'change', (e) =>
@spoiler = e.target.checked
QR.nodes.spoiler.checked = @spoiler if @ is QR.selected
(QR.nodes.spoiler.checked = @spoiler if @ is QR.selected)
for label in $$ 'label', el
$.on label, 'click', (e) -> e.stopPropagation()
$.add QR.nodes.dumpList, el
@ -53,7 +53,7 @@ QR.post = class
else
''
@load() if QR.selected is @ # load persona
(@load() if QR.selected is @) # load persona
@select() if select
@unlock()
# Post count temporarily off by 1 when called from QR.post.rm or QR.close
@ -104,7 +104,7 @@ QR.post = class
# Load this post's values.
for name in ['thread', 'name', 'email', 'sub', 'com', 'filename']
continue unless node = QR.nodes[name]
continue if not (node = QR.nodes[name])
node.value = @[name] or node.dataset.default or ''
(if @thread isnt 'new' then $.addClass else $.rmClass) QR.nodes.el, 'reply-to-thread'
@ -140,7 +140,7 @@ QR.post = class
# Do this in case people use extensions
# that do not trigger the `input` event.
for name in ['thread', 'name', 'email', 'sub', 'com', 'filename', 'spoiler']
continue unless node = QR.nodes[name]
continue if not (node = QR.nodes[name])
@save node
return
@ -171,10 +171,10 @@ QR.post = class
(@errors or= []).push div
[rm, rmAll] = $$ 'a', div
$.on div, 'click', =>
@select() if @ in QR.posts
(@select() if @ in QR.posts)
$.on rm, 'click', (e) =>
e.stopPropagation()
@rm() if @ in QR.posts
(@rm() if @ in QR.posts)
$.on rmAll, 'click', QR.post.rmErrored
QR.error div, true

View File

@ -26,7 +26,7 @@ QuoteBacklink =
a = $.el 'a',
href: Build.postURL @board.ID, @thread.ID, @ID
className: if @isHidden then 'filtered backlink' else 'backlink'
textContent: Conf['backlink'].replace(/%(?:id|%)/g, (x) => {'%id': @ID, '%%': '%'}[x])
textContent: Conf['backlink'].replace(/%(?:id|%)/g, (x) => ({'%id': @ID, '%%': '%'})[x])
$.add a, QuoteYou.mark.cloneNode(true) if markYours
for quote in @quotes
containers = [QuoteBacklink.getContainer quote]

View File

@ -65,14 +65,16 @@ QuoteInline =
$.addClass qroot, 'hasInline'
new Fetcher boardID, threadID, postID, inline, quoter
return unless (post = g.posts["#{boardID}.#{postID}"]) and
return if not (
(post = g.posts["#{boardID}.#{postID}"]) and
context.thread is post.thread
)
# Hide forward post if it's a backlink of a post in this thread.
# Will only unhide if there's no inlined backlinks of it anymore.
if isBacklink and Conf['Forward Hiding']
$.addClass post.nodes.root, 'forwarded'
post.forwarded++ or post.forwarded = 1
post.forwarded++ or (post.forwarded = 1)
# Decrease the unread count if this post
# is in the array of unread posts.
@ -91,7 +93,7 @@ QuoteInline =
$.rmClass qroot, 'hasInline'
# Stop if it only contains text.
return unless el = root.firstElementChild
return if not (el = root.firstElementChild)
# Dereference clone.
post = g.posts["#{boardID}.#{postID}"]

View File

@ -43,7 +43,7 @@ QuotePreview =
mouseout: ->
# Stop if it only contains text.
return unless root = @el.firstElementChild
return if not (root = @el.firstElementChild)
clone = Get.postFromRoot root
post = clone.origin

View File

@ -48,7 +48,7 @@ QuoteThreading =
setThread: ->
QuoteThreading.thread = @
$.asap (-> !Conf['Thread Updater'] or $ '.navLinksBot > .updatelink'), ->
$.add navLinksBot, [$.tn(' '), QuoteThreading.threadNewLink] if (navLinksBot = $ '.navLinksBot')
($.add navLinksBot, [$.tn(' '), QuoteThreading.threadNewLink] if (navLinksBot = $ '.navLinksBot'))
node: ->
return if @isFetchedQuote or @isClone or !@isReply
@ -77,9 +77,11 @@ QuoteThreading =
posts
insert: (post) ->
return false unless Conf['Thread Quotes'] and
return false if not (
Conf['Thread Quotes'] and
(parent = QuoteThreading.parent[post.fullID]) and
!QuoteThreading.inserted[post.fullID]
)
descendants = QuoteThreading.descendants post
if !Unread.posts.has(parent.ID)

View File

@ -8,7 +8,7 @@ QuoteYou =
$.forceSync 'Remember Your Posts'
if Conf['Remember Your Posts']
{boardID, threadID, postID} = e.detail
QuoteYou.db.set {boardID, threadID, postID, val: true}
(QuoteYou.db.set {boardID, threadID, postID, val: true})
return unless g.VIEW in ['index', 'thread']
@ -49,7 +49,7 @@ QuoteYou =
$.rmClass highlight, 'highlight' if highlight = $ '.highlight'
unless QuoteYou.lastRead and doc.contains(QuoteYou.lastRead) and $.hasClass(QuoteYou.lastRead, 'quotesYou')
unless (post = QuoteYou.lastRead = $ '.quotesYou')
if not (post = QuoteYou.lastRead = $ '.quotesYou')
new Notice 'warning', 'No posts are currently quoting you, loser.', 20
return
return if QuoteYou.cb.scroll post

View File

@ -22,7 +22,7 @@ Quotify =
return
parseArchivelink: (link) ->
return unless (m = link.pathname.match /^\/([^/]+)\/thread\/S?(\d+)\/?$/)
return if not (m = link.pathname.match /^\/([^/]+)\/thread\/S?(\d+)\/?$/)
return if link.hostname is 'boards.4chan.org'
boardID = m[1]
threadID = m[2]
@ -43,7 +43,7 @@ Quotify =
return
quote = deadlink.textContent
return unless postID = quote.match(/\d+$/)?[0]
return if not (postID = quote.match(/\d+$/)?[0])
if postID[0] is '0'
# Fix quotelinks that start with a `0`.
Quotify.fixDeadlink deadlink

View File

@ -98,7 +98,7 @@ class DataBoard
@ajaxCleanParse boardID, e1.target.response, e2.target.response
ajaxCleanParse: (boardID, response1, response2) ->
return unless (board = @data.boards[boardID])
return if not (board = @data.boards[boardID])
threads = {}
if response1
for page in response1

View File

@ -92,7 +92,7 @@ class Fetcher
archivedPost: ->
return false unless Conf['Resurrect Quotes']
return false unless url = Redirect.to 'post', {@boardID, @postID}
return false if not (url = Redirect.to 'post', {@boardID, @postID})
archive = Redirect.data.post[@boardID]
if /^https:\/\//.test(url) or location.protocol is 'http:'
$.cache url, (e) =>

View File

@ -14,7 +14,7 @@ class Post
@nodes = @parseNodes root
unless (@isReply = $.hasClass @nodes.post, 'reply')
if not (@isReply = $.hasClass @nodes.post, 'reply')
@thread.OP = @
@thread.isArchived = !!$ '.archivedIcon', @nodes.info
@thread.isSticky = !!$ '.stickyIcon', @nodes.info
@ -164,8 +164,8 @@ class Post
parseFile: ->
{fileRoot} = @nodes
return unless fileRoot
return unless (link = $ '.fileText > a, .fileText-original > a', fileRoot)
return unless (info = link.nextSibling?.textContent.match /\(([\d.]+ [KMG]?B).*\)/)
return if not (link = $ '.fileText > a, .fileText-original > a', fileRoot)
return if not (info = link.nextSibling?.textContent.match /\(([\d.]+ [KMG]?B).*\)/)
fileText = fileRoot.firstElementChild
@file =
text: fileText
@ -206,7 +206,7 @@ class Post
$.rmClass @nodes.root, 'deleted-file'
$.addClass @nodes.root, 'deleted-post'
unless (strong = $ 'strong.warning', @nodes.info)
if not (strong = $ 'strong.warning', @nodes.info)
strong = $.el 'strong',
className: 'warning'
$.after $('input', @nodes.info), strong

View File

@ -26,7 +26,7 @@ class Thread
setPage: (pageNum) ->
{info, reply} = @OP.nodes
unless (icon = $ '.page-num', info)
if not (icon = $ '.page-num', info)
icon = $.el 'span', className: 'page-num'
$.replace reply.parentNode.previousSibling, [$.tn(' '), icon, $.tn(' ')]
icon.title = "This thread is on page #{pageNum} in the original index."

View File

@ -122,9 +122,10 @@ Main =
else if (match = search.match /\bres=(\d+)/)
$.ready ->
if Conf['404 Redirect'] and $.id('errmsg')?.textContent is 'Error: Specified thread does not exist.'
Redirect.navigate 'thread',
Redirect.navigate 'thread', {
boardID: g.BOARD.ID
postID: +match[1]
}
else if pathname[2] is 'post'
PostSuccessful.init()
return
@ -132,9 +133,10 @@ Main =
return unless pathname[2] and not /s\.jpg$/.test(pathname[2])
$.asap (-> d.readyState isnt 'loading'), ->
if Conf['404 Redirect'] and d.title in ['4chan - Temporarily Offline', '4chan - 404 Not Found']
Redirect.navigate 'file',
Redirect.navigate 'file', {
boardID: g.BOARD.ID
filename: pathname[pathname.length - 1]
}
else if video = $ 'video'
if Conf['Volume in New Tab']
Volume.setup video
@ -197,7 +199,7 @@ Main =
keyboard = false
$.on d, 'mousedown', -> keyboard = false
$.on d, 'keydown', (e) -> keyboard = true if e.keyCode is 9 # tab
$.on d, 'keydown', (e) -> (keyboard = true if e.keyCode is 9) # tab
window.addEventListener 'focus', (-> doc.classList.toggle 'keyboard-focus', keyboard), true
Main.setClass()
@ -236,9 +238,10 @@ Main =
$.after $.id('fourchanx-css'), Main.bgColorStyle
setStyle()
return unless mainStyleSheet
new MutationObserver(setStyle).observe mainStyleSheet,
new MutationObserver(setStyle).observe mainStyleSheet, {
attributes: true
attributeFilter: ['href']
}
initReady: ->
# XXX Sometimes threads don't 404 but are left over as stubs containing one garbage reply post.
@ -322,7 +325,7 @@ Main =
i = 0
cbs = Callbacks[klass]
fn = ->
return false unless node = nodes[i]
return false if not (node = nodes[i])
cbs.execute node
++i % 25
@ -330,7 +333,7 @@ Main =
while fn()
continue
unless nodes[i]
cb() if cb
(cb() if cb)
return
setTimeout softTask, 0
@ -353,10 +356,11 @@ Main =
div = $.el 'div',
<%= html('${errors.length} errors occurred.&{Main.reportLink(errors)} [<a href="javascript:;">show</a>]') %>
$.on div.lastElementChild, 'click', ->
[@textContent, logs.hidden] = if @textContent is 'show'
[@textContent, logs.hidden] = if @textContent is 'show' then (
['hide', false]
else
) else (
['show', true]
)
logs = $.el 'div',
hidden: true
@ -408,7 +412,7 @@ Main =
ready: (cb) ->
$.ready ->
cb() if Main.isThisPageLegit()
(cb() if Main.isThisPageLegit())
features: [
['Polyfill', Polyfill]

View File

@ -4,10 +4,13 @@
$ = (selector, root=d.body) ->
root.querySelector selector
$.DAY = 24 *
$.HOUR = 60 *
$.MINUTE = 60 *
$.DAY = 24 * (
$.HOUR = 60 * (
$.MINUTE = 60 * (
$.SECOND = 1000
)
)
)
$.id = (id) ->
d.getElementById id
@ -60,7 +63,7 @@ $.ajax = do ->
$.extend r, options
$.extend r.upload, upCallbacks
# connection error or content blocker
$.on r, 'error', -> c.error "4chan X failed to load: #{url}" unless r.status
$.on r, 'error', -> (c.error "4chan X failed to load: #{url}" unless r.status)
r.send form
catch err
# XXX Some content blockers in Firefox (e.g. Adblock Plus and NoScript) throw an exception instead of simulating a connection error.
@ -81,7 +84,7 @@ do ->
return req
rm = -> delete reqs[url]
try
return unless req = $.ajax url, options
return if not (req = $.ajax url, options)
catch err
return
$.on req, 'load', (e) ->
@ -456,7 +459,7 @@ do ->
items.sync[key] = val for key, val of data when not exceedsQuota(key, val)
setSync()
else
chrome.storage.local.remove (key for key of data when key not of items.local)
chrome.storage.local.remove (key for key of data when not (key of items.local))
cb?()
setSync = $.debounce $.SECOND, ->
@ -544,7 +547,7 @@ else if GM_deleteValue? or $.hasStorage
do ->
onChange = ({key, newValue}) ->
return unless cb = $.syncing[key]
return if not (cb = $.syncing[key])
if newValue?
return if newValue is $.oldValue[key]
$.oldValue[key] = newValue