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

View File

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

View File

@ -84,7 +84,7 @@ PostHiding =
open: (post) -> open: (post) ->
if !post.isReply or post.isClone or !post.isHidden if !post.isReply or post.isClone or !post.isHidden
return false 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 return false
PostHiding.menu.post = post PostHiding.menu.post = post
thisPost.firstChild.checked = post.isHidden thisPost.firstChild.checked = post.isHidden
@ -104,7 +104,7 @@ PostHiding =
open: (post) -> open: (post) ->
if !post.isReply or post.isClone or !post.isHidden if !post.isReply or post.isClone or !post.isHidden
return false 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 return false
PostHiding.menu.post = post PostHiding.menu.post = post

View File

@ -14,14 +14,15 @@ Recursive =
return return
add: (recursive, post, args...) -> add: (recursive, post, args...) ->
obj = Recursive.recursives[post.fullID] or= obj = Recursive.recursives[post.fullID] or= {
recursives: [] recursives: []
args: [] args: []
}
obj.recursives.push recursive obj.recursives.push recursive
obj.args.push args obj.args.push args
rm: (recursive, post) -> 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 for rec, i in obj.recursives when rec is recursive
obj.recursives.splice i, 1 obj.recursives.splice i, 1
obj.args.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 {} @hiddenThreads = JSON.parse(localStorage.getItem "4chan-hide-t-#{g.BOARD}") or {}
Main.ready -> Main.ready ->
# 4chan's catalog sets the style to "display: none;" when hiding or unhiding a thread. # 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 attributes: true
subtree: true subtree: true
attributeFilter: ['style'] attributeFilter: ['style']
}
catalogSave: -> catalogSave: ->
hiddenThreads2 = JSON.parse(localStorage.getItem "4chan-hide-t-#{g.BOARD}") or {} hiddenThreads2 = JSON.parse(localStorage.getItem "4chan-hide-t-#{g.BOARD}") or {}
@ -78,7 +79,7 @@ ThreadHiding =
return false return false
ThreadHiding.menu.thread = thread ThreadHiding.menu.thread = thread
true true
subEntries: [el: apply; el: makeStub] subEntries: [{el: apply}, {el: makeStub}]
div = $.el 'a', div = $.el 'a',
className: 'show-thread-link' className: 'show-thread-link'

View File

@ -105,7 +105,7 @@ Build.Test =
testAll: -> testAll: ->
g.posts.forEach (post) -> g.posts.forEach (post) ->
unless post.isClone or post.isFetchedQuote 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 Build.Test.testOne post
return return

View File

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

View File

@ -1,7 +1,7 @@
Get = Get =
threadExcerpt: (thread) -> threadExcerpt: (thread) ->
{OP} = thread {OP} = thread
excerpt = "/#{thread.board}/ - " + ( excerpt = ("/#{thread.board}/ - ") + (
OP.info.subject?.trim() or OP.info.subject?.trim() or
OP.info.commentDisplay.replace(/\n+/g, ' // ') or OP.info.commentDisplay.replace(/\n+/g, ' // ') or
OP.file?.name 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.textContent = if /-title/.test(t) or /-replace/.test(t) and boardID is g.BOARD.ID
a.title or a.textContent a.title or a.textContent
else if /-full/.test t else if /-full/.test t
"/#{boardID}/" + (if a.title then " - #{a.title}" else '') ("/#{boardID}/") + (if a.title then " - #{a.title}" else '')
else else
text or boardID text or boardID

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
Gallery = Gallery =
init: -> 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'] @delay = Conf['Slide Delay']
@ -202,7 +202,7 @@ Gallery =
ImageCommon.error @, g.posts[@dataset.post], null, (url) => ImageCommon.error @, g.posts[@dataset.post], null, (url) =>
return unless url return unless url
Gallery.images[@dataset.id].href = url Gallery.images[@dataset.id].href = url
@src = url if Gallery.nodes.current is @ (@src = url if Gallery.nodes.current is @)
cacheError: -> cacheError: ->
delete Gallery.cache delete Gallery.cache
@ -236,7 +236,7 @@ Gallery =
cb: cb:
keybinds: (e) -> keybinds: (e) ->
return unless key = Keybinds.keyCode e return if not (key = Keybinds.keyCode e)
cb = switch key cb = switch key
when Conf['Close'], Conf['Open Gallery'] when Conf['Close'], Conf['Open Gallery']

View File

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

View File

@ -1,6 +1,6 @@
ImageExpand = ImageExpand =
init: -> 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', @EAI = $.el 'a',
className: 'expand-all-shortcut fa fa-expand' className: 'expand-all-shortcut fa fa-expand'
@ -273,7 +273,7 @@ ImageExpand =
ImageCommon.error @, post, 10 * $.SECOND, (URL) -> ImageCommon.error @, post, 10 * $.SECOND, (URL) ->
if post.file.isExpanding or post.file.isExpanded if post.file.isExpanding or post.file.isExpanded
ImageExpand.contract post ImageExpand.contract post
ImageExpand.expand post, URL if URL (ImageExpand.expand post, URL if URL)
menu: menu:
init: -> init: ->

View File

@ -19,7 +19,7 @@ Sauce =
cb: @node cb: @node
createSauceLink: (link, post) -> createSauceLink: (link, post) ->
return null unless link = link.trim() return null if not (link = link.trim())
parts = {} parts = {}
for part, i in link.split /;(?=(?:text|boards|types|sandbox):?)/ for part, i in link.split /;(?=(?:text|boards|types|sandbox):?)/
@ -60,7 +60,7 @@ Sauce =
nodes = [] nodes = []
skipped = [] skipped = []
for link in Sauce.links for link in Sauce.links
unless (node = Sauce.createSauceLink link, @) if not (node = Sauce.createSauceLink link, @)
node = Sauce.link.cloneNode false node = Sauce.link.cloneNode false
skipped.push [link, node] skipped.push [link, node]
nodes.push $.tn(' '), node nodes.push $.tn(' '), node
@ -79,7 +79,7 @@ Sauce =
URL: (post) -> post.file.url URL: (post) -> post.file.url
IMG: (post, ext) -> if ext in ['gif', 'jpg', 'png'] then post.file.url else post.file.thumbURL IMG: (post, ext) -> if ext in ['gif', 'jpg', 'png'] then post.file.url else post.file.thumbURL
MD5: (post) -> post.file.MD5 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('') 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 board: (post) -> post.board.ID
name: (post) -> post.file.name name: (post) -> post.file.name

View File

@ -71,7 +71,7 @@ Volume =
wheel: (e) -> wheel: (e) ->
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey 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 return if el.muted or not $.hasAudio el
volume = el.volume + 0.1 volume = el.volume + 0.1
volume *= 1.1 if e.deltaY < 0 volume *= 1.1 if e.deltaY < 0

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@ Flash =
initReady: -> initReady: ->
if $.hasStorage 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 else
if g.VIEW is 'thread' if g.VIEW is 'thread'
$.global -> window.Main.tid = location.pathname.split(/\/+/)[3] $.global -> window.Main.tid = location.pathname.split(/\/+/)[3]

View File

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

View File

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

View File

@ -17,7 +17,7 @@ Keybinds =
Conf[hotkey] = key Conf[hotkey] = key
keydown: (e) -> keydown: (e) ->
return unless key = Keybinds.keyCode e return if not (key = Keybinds.keyCode e)
{target} = e {target} = e
if target.nodeName in ['INPUT', 'TEXTAREA'] 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) 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 'code' then !!config.code_tags
when 'math', 'eqn' then !!config.math_tags when 'math', 'eqn' then !!config.math_tags
when 'sjis' then !!config.sjis_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 value = ta.value
selStart = ta.selectionStart selStart = ta.selectionStart
@ -272,7 +272,7 @@ Keybinds =
value[selEnd..] value[selEnd..]
# Move the caret to the end of the selection. # Move the caret to the end of the selection.
range = "[#{tag}]".length + selEnd range = ("[#{tag}]").length + selEnd
ta.setSelectionRange range, range ta.setSelectionRange range, range
# Fire the 'input' event # Fire the 'input' event
@ -314,7 +314,7 @@ Keybinds =
'following' 'following'
else else
'preceding' '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 Header.scrollToIfNeeded next, delta is +1
@focus next @focus next
$.rmClass postEl, 'highlight' $.rmClass postEl, 'highlight'

View File

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

View File

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

View File

@ -1,6 +1,6 @@
Favicon = Favicon =
init: -> 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: -> initAsap: ->
Favicon.el.type = 'image/x-icon' Favicon.el.type = 'image/x-icon'

View File

@ -60,7 +60,7 @@ ReplyPruning =
@posts.forEach (post) -> @posts.forEach (post) ->
if post.isReply if post.isReply
ReplyPruning.total++ 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. # 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. # 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) -> @posts.forEach (post) ->
postCount++ postCount++
fileCount++ if post.file fileCount++ if post.file
ThreadStats.lastPost = post.info.date if ThreadStats.pageCountEl (ThreadStats.lastPost = post.info.date if ThreadStats.pageCountEl)
ThreadStats.thread = @ ThreadStats.thread = @
ThreadStats.fetchPage() ThreadStats.fetchPage()
ThreadStats.update postCount, fileCount, @ipCount ThreadStats.update postCount, fileCount, @ipCount

View File

@ -32,7 +32,7 @@ ThreadUpdater =
className: 'brackets-wrap updatelink' className: 'brackets-wrap updatelink'
$.extend updateLink, <%= html('<a href="javascript:;">Update</a>') %> $.extend updateLink, <%= html('<a href="javascript:;">Update</a>') %>
Main.ready -> Main.ready ->
$.add navLinksBot, [$.tn(' '), updateLink] if (navLinksBot = $ '.navLinksBot') ($.add navLinksBot, [$.tn(' '), updateLink] if (navLinksBot = $ '.navLinksBot'))
$.on updateLink.firstElementChild, 'click', @update $.on updateLink.firstElementChild, 'click', @update
subEntries = [] subEntries = []
@ -77,7 +77,7 @@ ThreadUpdater =
ThreadUpdater.fileIDs = [] ThreadUpdater.fileIDs = []
@posts.forEach (post) -> @posts.forEach (post) ->
ThreadUpdater.postIDs.push post.ID 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'] ThreadUpdater.cb.interval.call $.el 'input', value: Conf['Interval']
@ -238,7 +238,7 @@ ThreadUpdater =
whenModified: 'ThreadUpdater' whenModified: 'ThreadUpdater'
updateThreadStatus: (type, status) -> 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 ThreadUpdater.thread.setStatus type, status
return if type is 'Closed' and ThreadUpdater.thread.isArchived return if type is 'Closed' and ThreadUpdater.thread.isArchived
change = if type is 'Sticky' change = if type is 'Sticky'
@ -346,7 +346,7 @@ ThreadUpdater =
Header.scrollTo firstPost if firstPost Header.scrollTo firstPost if firstPost
# Update IP count in original post form. # 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.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.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') 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 = ThreadWatcher =
init: -> init: ->
return unless (@enabled = Conf['Thread Watcher']) return if not (@enabled = Conf['Thread Watcher'])
@shortcut = sc = $.el 'a', @shortcut = sc = $.el 'a',
id: 'watcher-link' id: 'watcher-link'
@ -335,7 +335,7 @@ ThreadWatcher =
for post in [thread.OP, thread.OP.clones...] for post in [thread.OP, thread.OP.clones...]
toggler = $ '.watch-thread-link', post.nodes.info toggler = $ '.watch-thread-link', post.nodes.info
ThreadWatcher.setToggler toggler, isWatched 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'] if Conf['Pin Watched Threads']
$.event 'SortIndex', {deferred: Conf['Index Mode'] isnt 'catalog'} $.event 'SortIndex', {deferred: Conf['Index Mode'] isnt 'catalog'}
@ -346,7 +346,7 @@ ThreadWatcher =
return return
update: (boardID, threadID, newData) -> 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'] if newData.isDead and Conf['Auto Prune']
ThreadWatcher.db.delete {boardID, threadID} ThreadWatcher.db.delete {boardID, threadID}
ThreadWatcher.refresh() ThreadWatcher.refresh()
@ -354,7 +354,7 @@ ThreadWatcher =
n = 0 n = 0
n++ for key, val of newData when data[key] isnt val n++ for key, val of newData when data[key] isnt val
return unless n 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} ThreadWatcher.db.extend {boardID, threadID, val: newData}
if line = $ "#watched-threads > [data-full-i-d='#{boardID}.#{threadID}']", ThreadWatcher.dialog if line = $ "#watched-threads > [data-full-i-d='#{boardID}.#{threadID}']", ThreadWatcher.dialog
newLine = ThreadWatcher.makeLine boardID, threadID, data newLine = ThreadWatcher.makeLine boardID, threadID, data
@ -364,7 +364,7 @@ ThreadWatcher =
ThreadWatcher.refresh() ThreadWatcher.refresh()
set404: (boardID, threadID, cb) -> 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'] if Conf['Auto Prune']
ThreadWatcher.db.delete {boardID, threadID} ThreadWatcher.db.delete {boardID, threadID}
return cb() return cb()

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@ Captcha.v2 =
init: -> init: ->
return if d.cookie.indexOf('pass_enabled=1') >= 0 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) if (@noscript = Conf['Force Noscript Captcha'] or not Main.jsEnabled)
$.addClass QR.nodes.el, 'noscript-captcha' $.addClass QR.nodes.el, 'noscript-captcha'

View File

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

View File

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

View File

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

View File

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

View File

@ -26,7 +26,7 @@ QuoteBacklink =
a = $.el 'a', a = $.el 'a',
href: Build.postURL @board.ID, @thread.ID, @ID href: Build.postURL @board.ID, @thread.ID, @ID
className: if @isHidden then 'filtered backlink' else 'backlink' 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 $.add a, QuoteYou.mark.cloneNode(true) if markYours
for quote in @quotes for quote in @quotes
containers = [QuoteBacklink.getContainer quote] containers = [QuoteBacklink.getContainer quote]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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