Merge branch 'v3'

Conflicts:
	CHANGELOG.md
	LICENSE
	builds/appchan-x.user.js
	builds/crx/manifest.json
	builds/crx/script.js
	package.json
	src/General/Navigate.coffee
	src/Miscellaneous/CatalogLinks.coffee
	src/Posting/QR.coffee
This commit is contained in:
Zixaphir 2014-05-27 12:39:01 -07:00
commit 2efa358131
21 changed files with 622 additions and 566 deletions

View File

@ -1,5 +1,72 @@
<<<<<<< HEAD
### v2.9.26
*2014-05-07*
=======
**MayhemYDG**:
- [Security fix](https://github.com/MayhemYDG/4chan-x/issues/1634).
### v1.7.33
*2014-05-10*
**DamonGant**
- Add Innovandalism Archive.
**ccd0**
- Update archive list.
- Add "disabled" option when Foolz Beta is the only choice.
### v1.7.32
*2014-05-10*
**Zixaphir, ccd0**
- Bug fixes in linkification/embedding.
**ccd0**
- Begin refactoring code to reduce potential for introducing Javascript injection bugs.
### v1.7.31
*2014-05-08*
**Zixaphir**
- Refactoring, bug fixes.
**ccd0**
- Fix some potential Javascript injection issues.
- Bug fixes.
### v1.7.30
*2014-05-05*
**thebladeee**
- Update archives.
### v1.7.29
*2014-05-03*
**ccd0**:
- If the original post form not hidden, it is expanded (except on the catalog page).
- 4chan's horizontal rules are no longer hidden. If you want to hide them as before, add the old code to your custom CSS:
```
body > hr,
#blotter hr,
.desktop > hr,
#delform > hr,
#content > hr {
display: none;
}
:root.index .board > hr:last-of-type,
:root.thread .board > hr {
border: 0px;
margin: 0px;
}
```
### v1.7.28
*2014-05-03*
**ccd0**:
- Copy Mayhem's fix for 4chan post form changes.
>>>>>>> v3
**zixaphir**
- Fixed (maybe?) a vulnerability in the post parser that allowed playful users to inject scripts or elements into posts, which could be used maliciously.

View File

@ -1,5 +1,5 @@
/*
* appchan x - Version 2.9.26 - 2014-05-11
* appchan x - Version 2.9.26 - 2014-05-27
*
* Licensed under the MIT license.
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
// @version 1.7.27
// @version 1.7.33
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/crx.crx' version='1.7.27' />
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/crx.crx' version='1.7.33' />
</app>
</gupdate>

View File

@ -18,9 +18,9 @@
outline: none;
transition: color .25s, border-color .25s, flex .25s;
}
.field::-moz-placeholder,
.field:hover::-moz-placeholder {
color: #AAA !important;
.field::-moz-placeholder {
color: #AAA;
opacity: 1;
}
.field:hover {
border-color: #999;

View File

@ -7,9 +7,9 @@ Redirect =
archives = {}
for data in Redirect.archives
{name, boards, files, software} = data
{name, boards, files, software, withCredentials} = data
archives[name] = data
for boardID in boards
for boardID in boards when !withCredentials
o.thread[boardID] = data unless boardID of o.thread
o.post[boardID] = data unless boardID of o.post or software isnt 'foolfuuka'
o.file[boardID] = data unless boardID of o.file or boardID not in files

View File

@ -6,7 +6,7 @@
"https": true,
"software": "foolfuuka",
"boards": ["a", "biz", "co", "diy", "gd", "jp", "m", "sci", "sp", "tg", "tv", "vg", "vp", "vr", "wsg"],
"files": ["a", "biz", "gd", "diy", "jp", "m", "sci", "tg", "vg", "vp", "vr", "wsg"]
"files": ["a", "biz", "diy", "gd", "jp", "m", "sci", "tg", "vg", "vp", "vr", "wsg"]
}, {
"uid": 1,
"name": "NSFW Foolz",
@ -65,7 +65,7 @@
"uid": 8,
"name": "Rebecca Black Tech",
"domain": "rbt.asia",
"http": true,
"http": false,
"https": true,
"software": "fuuka",
"boards": ["cgl", "g", "mu", "w"],
@ -78,7 +78,7 @@
"https": false,
"software": "fuuka",
"boards": ["an", "fit", "k", "mlp", "r9k", "toy"],
"files": ["an", "fit", "k", "r9k", "toy"]
"files": ["an", "fit", "k", "mlp", "r9k", "toy"]
}, {
"uid": 10,
"name": "warosu",
@ -115,6 +115,15 @@
"software": "foolfuuka",
"boards": ["g", "t"],
"files": ["g", "t"]
}, {
"uid": 19,
"name": "Innovandalism Archive",
"domain": "boards.innovandalism.eu",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": ["v"],
"files": []
}, {
"uid": 13,
"name": "Foolz Beta",
@ -125,4 +134,13 @@
"software": "foolfuuka",
"boards": ["a", "biz", "co", "d", "diy", "gd", "jp", "m", "s4s", "sci", "sp", "tg", "tv", "u", "vg", "vp", "vr", "wsg"],
"files": ["a", "biz", "d", "diy", "gd", "jp", "m", "s4s", "sci", "tg", "u", "vg", "vp", "vr", "wsg"]
}, {
"uid": 19,
"name": "Innovandalism Archive",
"domain": "boards.innovandalism.eu",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": ["v"],
"files": []
}]

View File

@ -47,7 +47,7 @@ Build =
name: data.filename + data.ext
timestamp: "#{data.tim}#{data.ext}"
url: if boardID is 'f'
"//i.4cdn.org/#{boardID}/#{data.filename}#{data.ext}"
"//i.4cdn.org/#{boardID}/#{encodeURIComponent data.filename}#{data.ext}"
else
"//i.4cdn.org/#{boardID}/#{data.tim}#{data.ext}"
height: data.h
@ -150,7 +150,7 @@ Build =
imgSrc = if boardID is 'f'
''
else
"<a class='fileThumb#{if file.isSpoiler then ' imgspoiler' else ''}' href='#{file.url}' target=_blank>" +
"<a class='fileThumb#{if file.isSpoiler then ' imgspoiler' else ''}' href=\"#{file.url}\" target=_blank>" +
"<img src='#{fileThumb}' alt='#{fileSize}' data-md5=#{file.MD5} style='height: #{file.theight}px; width: #{file.twidth}px;'>" +
"</a>"
@ -166,7 +166,7 @@ Build =
fileDims = if file.name[-3..] is 'pdf' then 'PDF' else "#{file.width}x#{file.height}"
fileInfo = "<div class=fileText #{if file.isSpoiler then "title='#{filename}'" else ''}>File: " +
"<a href='#{file.url}' #{if filename isnt shortFilename and !file.isSpoiler then " title='#{filename}'" else ''} target=_blank>#{if file.isSpoiler then 'Spoiler Image' else shortFilename}</a>" +
"<a href=\"#{file.url}\" #{if filename isnt shortFilename and !file.isSpoiler then " title='#{filename}'" else ''} target=_blank>#{if file.isSpoiler then 'Spoiler Image' else shortFilename}</a>" +
" (#{fileSize}, #{fileDims})</div>"
fileHTML = "<div class=file>#{fileInfo}#{imgSrc}</div>"
@ -284,7 +284,7 @@ Build =
pageCount = Index.liveThreadData.keys.indexOf("#{thread.ID}") // Index.threadsNumPerPage + 1
subject = if thread.OP.info.subject
"<div class='subject'>#{thread.OP.info.subject}</div>"
"<div class='subject'>#{thread.OP.nodes.subject.innerHTML}</div>"
else
''
comment = thread.OP.nodes.comment.innerHTML.replace /(<br>\s*){2,}/g, '<br>'

View File

@ -91,6 +91,7 @@ Index =
@navLinks = $.el 'div',
className: 'navLinks'
innerHTML: <%= importHTML('Features/Index-navlinks') %>
@timeEl = $ 'time#index-last-refresh', @navLinks
@searchInput = $ '#index-search', @navLinks
@ -114,7 +115,8 @@ Index =
@currentPage = @getCurrentPage()
$.on d, 'scroll', Index.scroll
$.on d, 'scroll', @scroll
$.on window, 'focus', @updateIfNeeded
$.on @pagelist, 'click', @cb.pageNav
returnLink = $.el 'a',
@ -221,11 +223,12 @@ Index =
thread = g.threads[@parentNode.dataset.fullID]
if e.shiftKey
PostHiding.toggle thread.OP
e.preventDefault()
else if e.altKey
Index.togglePin thread
e.preventDefault()
else
Navigate.navigate.call @
e.preventDefault()
Navigate.navigate.call @, e
onOver: (e) ->
# 4chan's less than stellar CSS forces us to include a .post and .postInfo
@ -297,7 +300,7 @@ Index =
setupNavLinks: ->
for el in $$ '.navLinks.desktop > a'
if el.getAttribute('href') is '.././catalog'
if /\/catalog$/.test el.pathname
el.href = '.././'
$.on el, 'click', ->
switch @textContent
@ -508,6 +511,18 @@ Index =
else
"#{hiddenCount} hidden threads"
updateIfNeeded: ->
{timeEl} = Index
needed =
# we're on the index,
g.VIEW is 'index' and
# not currently refreshing
!Index.req and
timeEl.dataset.utc and
# more than 10 minutes have elapsed since the last refresh.
timeEl.dataset.utc < Date.now() - (10 * $.MINUTE)
Index.update() if needed
update: (pageNum) ->
return unless navigator.onLine
if g.VIEW is 'thread'
@ -585,7 +600,7 @@ Index =
new Notice 'error', 'Index refresh failed.', 1
return
timeEl = $ 'time#index-last-refresh', Index.navLinks
{timeEl} = Index
timeEl.dataset.utc = Date.parse req.getResponseHeader 'Last-Modified'
RelativeDates.update timeEl
Index.scrollToIndex()

View File

@ -87,11 +87,6 @@ Main =
Report.init()
return
when 'i.4cdn.org'
if Conf['Loop in New Tab'] and video = $ 'video'
Video.configure video
$.on video, 'click', ->
if !video.controls
if video.paused then video.play() else video.pause()
$.ready ->
if Conf['404 Redirect'] and d.title in ['4chan - Temporarily Offline', '4chan - 404 Not Found']
Redirect.init()
@ -100,6 +95,11 @@ Main =
boardID: g.BOARD.ID
filename: pathname[pathname.length - 1]
location.replace URL if URL
else if Conf['Loop in New Tab'] and video = $ 'video'
Video.configure video
if !video.controls
$.on video, 'click', ->
if video.paused then video.play() else video.pause()
return
# c.time 'All initializations'

View File

@ -196,7 +196,7 @@ Navigate =
return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org'
if e
if e.shiftKey or e.ctrlKey or (e.type is 'click' and e.button isnt 0) # Not simply a left click
Navigate.setMode @ unless e?.button is 2 # Right Click
Navigate.setMode @ unless e.button is 2 # Right Click
return
if @pathname is Navigate.path

View File

@ -266,15 +266,21 @@ Settings =
$.on $.id('apply-css'), 'click', Settings.usercss
archBoards = {}
for {name, boards, files, software} in Redirect.archives
for {name, boards, files, software, withCredentials} in Redirect.archives
for boardID in boards
o = archBoards[boardID] or=
thread: []
post: []
file: []
o.thread.push name
o.post.push name if software is 'foolfuuka'
o.file.push name if boardID in files
thread: [[], []]
post: [[], []]
file: [[], []]
i = +!!withCredentials
o.thread[i].push name
o.post[i].push name if software is 'foolfuuka'
o.file[i].push name if boardID in files
for boardID, o of archBoards
for item in ['thread', 'post', 'file']
if o[item][0].length is 0 and o[item][1].length isnt 0
o[item][0].push 'disabled'
o[item] = o[item][0].concat(o[item][1])
rows = []
boardOptions = []

View File

@ -69,24 +69,9 @@ a {
border-radius: 3px;
padding: 0px 2px;
}
body > hr,
#blotter hr,
.desktop > hr,
#delform > hr,
#content > hr {
display: none;
}
:root.index .board > hr:last-of-type,
:root.thread .board > hr {
border: 0px;
margin: 0px;
}
.ad-plea {
display: none;
}
.ad-cnt {
margin: 10px !important;
}
/* 4chan style fixes */
.opContainer, .op {
@ -904,13 +889,16 @@ span.hide-announcement {
/* QR */
:root.hide-original-post-form #postForm,
:root.hide-original-post-form .postingMode,
:root.hide-original-post-form #togglePostForm,
:root.hide-original-post-form #togglePostFormLink,
:root:not(.catalog) #togglePostFormLink,
#qr.autohide:not(.focus):not(:hover):not(:active) > form,
.thread #qr select[data-name=thread],
#file-n-submit:not(.has-file) #qr-filerm {
display: none;
}
:root:not(.hide-original-post-form):not(.catalog) #postForm {
display: table;
}
#qr select,
#dump-button,
#url-button,

View File

@ -24,7 +24,7 @@
"javascript:quote(#{postID})"
else
"/#{boardID}/thread/#{threadID}#q#{postID}"
}' title='Quote this post'>#{postID}</a>
}' title='Reply to this post'>#{postID}</a>
#{pageIcon + sticky + closed + replyLink}
</span>
</div>

View File

@ -10,14 +10,13 @@ Linkify =
if Conf['Embedding'] or Conf['Link Title']
@embedProcess = Function 'link',
"var data = this.services(link);
if (data) {
#{
(if Conf['Embedding'] then 'this.embed(data);\n' else '') +
if Conf['Link Title'] then 'this.title(data);' else ''
}
}
"
"""
var data = this.services(link);
if (data) {#{
(if Conf['Embedding'] then 'this.embed(data); ' else '') +
if Conf['Link Title'] then 'data.push(post); this.title(data);' else ''
}}
"""
Post.callbacks.push
name: 'Linkify'
@ -156,7 +155,7 @@ Linkify =
return
embed: (data) ->
[key, uid, options, link] = data
[key, uid, options, link, post] = data
href = link.href
embed = $.el 'a',
className: 'embedder'
@ -164,7 +163,6 @@ Linkify =
textContent: '(embed)'
embed.dataset[name] = value for name, value of {key, href, uid, options}
embed.dataset.nodedata = link.innerHTML
$.addClass link, "#{embed.dataset.key}"
@ -173,33 +171,30 @@ Linkify =
Linkify.cb.toggle.call embed if Conf['Auto-embed']
data.push embed
title: (data) ->
[key, uid, options, link, embed] = data
[key, uid, options, link, post] = data
return unless service = Linkify.types[key].title
titles = Conf['CachedTitles']
if title = titles[uid]
# Auto-embed may destroy our links.
if link
link.textContent = title[0]
if Conf['Embedding']
embed.dataset.title = title[0]
link.textContent = title[0]
else
try
$.cache service.api(uid), (-> Linkify.cb.title @, data), responseType: 'json'
catch err
if link
link.innerHTML = "[#{key}] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>"
link.innerHTML = '<span class="warning">Title Link Blocked</span> (are you using NoScript?)</a>'
$.prepend link, $.tn "[#{key}] "
return
cb:
toggle: ->
[string, @textContent] = if $.hasClass @, "embedded"
['unembed', '(embed)']
if $.hasClass @, "embedded"
$.rm @previousElementSibling
@previousElementSibling.hidden = false
@textContent = '(embed)'
else
['embed', '(unembed)']
$.replace @previousElementSibling, Linkify.cb[string] @
@previousElementSibling.hidden = true
$.before @, Linkify.cb.embed @
@textContent = '(unembed)'
$.toggleClass @, 'embedded'
embed: (a) ->
@ -214,21 +209,8 @@ Linkify =
return el
unembed: (a) ->
# Recreate the original link.
el = $.el 'a',
rel: 'nofollow noreferrer'
target: 'blank'
className: 'linkify'
href: a.dataset.href
innerHTML: a.dataset.title or a.dataset.nodedata
$.addClass el, a.dataset.key
return el
title: (req, data) ->
[key, uid, options, link, embed] = data
[key, uid, options, link, post] = data
{status} = req
service = Linkify.types[key].title
@ -243,8 +225,11 @@ Linkify =
"#{status}'d"
}"
embed.dataset.title = text if Conf['Embedding'] and status in [200, 304]
link.textContent = text if link
link.textContent = text
for post2 in post.clones
for link2 in $$ 'a', post2.nodes.comment when link2.href is link.href
link2.textContent = text
return
ordered_types: [
key: 'audio'
@ -271,8 +256,10 @@ Linkify =
regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/
style: 'border: 0; width: auto; height: auto;'
el: (a) ->
$.el 'div',
innerHTML: "<a target=_blank href='#{a.dataset.href}'><img src='#{a.dataset.href}'></a>"
el = $.el 'div'
el.innerHTML = '<a target="_blank"><img></a>'
el.firstChild.href = el.firstChild.firstChild.src = a.dataset.href
el
,
key: 'InstallGentoo'
regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/
@ -298,35 +285,36 @@ Linkify =
el
,
key: 'MediaCrush'
regExp: /.*(?:mediacru.sh\/)([0-9a-z_]+)/i
regExp: /.*(?:mediacru.sh\/)([0-9a-z_-]+)/i
style: 'border: 0;'
el: (a) ->
el = $.el 'div'
$.cache "https://mediacru.sh/#{a.dataset.uid}.json", ->
{status} = @
return div.innerHTML = "ERROR #{status}" unless status in [200, 304]
return el.textContent = "ERROR #{status}" unless status in [200, 304]
{files} = @response
for type in ['video/mp4', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'image/svg', 'audio/mpeg']
for type in ['video/mp4', 'video/webm', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'audio/mpeg', 'audio/ogg']
for file in files
if file.type is type
embed = file
break
break if embed
return div.innerHTML = "ERROR: Not a valid filetype" unless embed
el.innerHTML = switch embed.type
when 'video/mp4', 'video/ogv' then """
<video autoplay loop>
<source src="https://mediacru.sh/#{a.dataset.uid}.mp4" type="video/mp4;">
<source src="https://mediacru.sh/#{a.dataset.uid}.ogv" type="video/ogg; codecs='theora, vorbis'">
</video>"""
when 'image/png', 'image/gif', 'image/jpeg'
"<a target=_blank href='#{a.dataset.href}'><img src='https://mediacru.sh/#{file.file}'></a>"
when 'image/svg', 'image/svg+xml'
"<embed src='https://mediacru.sh/#{file.file}' type='image/svg+xml' />"
when 'audio/mpeg'
"<audio controls><source src='https://mediacru.sh/#{file.file}'></audio>"
return div.textContent = "ERROR: Not a valid filetype" unless embed
switch embed.type
when 'video/mp4', 'video/webm', 'video/ogv'
el.innerHTML = '<video autoplay loop><source type="video/mp4"><source type="video/webm"><source type="video/ogg"></video>'
for ext, i in ['mp4', 'webm', 'ogv']
el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}"
when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg'
el.innerHTML = '<a target="_blank"><img></a>'
el.firstChild.href = a.dataset.href
el.firstChild.firstChild.src = "https://mediacru.sh/#{file.file}"
when 'audio/mpeg', 'audio/ogg'
el.innerHTML = '<audio controls><source type="audio/ogg"><source type="audio/mpeg"></audio>'
for ext, i in ['ogg', 'mp3']
el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}"
else
"ERROR: No valid filetype."
el.textContent = "ERROR: No valid filetype."
el
,
key: 'pastebin'
@ -343,19 +331,12 @@ Linkify =
,
key: 'SoundCloud'
regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/
style: 'height: auto; width: 500px; display: inline-block;'
style: 'border: 0; width: 500px; height: 400px;'
el: (a) ->
div = $.el 'div',
className: "soundcloud"
name: "soundcloud"
$.ajax(
"//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/#{a.dataset.uid}"
onloadend: ->
div.innerHTML = JSON.parse(@responseText).html
false)
div
$.el 'iframe',
src: "//w.soundcloud.com/player/?visual=true&show_comments=false&url=https%3A%2F%2Fsoundcloud.com%2F#{encodeURIComponent a.dataset.uid}"
title:
api: (uid) -> "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/#{uid}"
api: (uid) -> "//soundcloud.com/oembed?format=json&url=https%3A%2F%2Fsoundcloud.com%2F#{encodeURIComponent uid}"
text: (_) -> _.title
,
key: 'StrawPoll'
@ -369,26 +350,21 @@ Linkify =
regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/
style: "border: none; width: 640px; height: 360px;"
el: (a) ->
if result = /(\w+)\/(?:[a-z]\/)?(\d+)/i.exec a.dataset.uid
[_, channel, chapter] = result
$.el 'object',
if result = /(\w+)\/([bc])\/(\d+)/i.exec a.dataset.uid
[_, channel, type, id] = result
idparam = {'b': 'archive_id', 'c': 'chapter_id'}
obj = $.el 'object',
data: 'http://www.twitch.tv/widgets/archive_embed_player.swf'
innerHTML: """
<param name='allowFullScreen' value='true' />
<param name='flashvars' value='channel=#{channel}&start_volume=25&auto_play=false#{if chapter then "&chapter_id=" + chapter else ""}' />
"""
obj.innerHTML = '<param name="allowFullScreen" value="true"><param name="flashvars">'
obj.children[1].value = "channel=#{channel}&start_volume=25&auto_play=false&#{idparam[type]}=#{id}"
obj
else
channel = (/(\w+)/.exec a.dataset.uid)[0]
$.el 'object',
obj = $.el 'object',
data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=#{channel}"
innerHTML: """
<param name="allowFullScreen" value="true" />
<param name="movie" value="http://www.twitch.tv/widgets/live_embed_player.swf" />
<param name="flashvars" value="hostname=www.twitch.tv&channel=#{channel}&auto_play=true&start_volume=25" />
"""
obj.innerHTML = '<param name="allowFullScreen" value="true"><param name="flashvars">'
obj.children[1].value = "hostname=www.twitch.tv&channel=#{channel}&auto_play=true&start_volume=25"
obj
,
key: 'Vocaroo'
regExp: /.*(?:vocaroo.com\/)([^#\&\?]*).*/

View File

@ -44,10 +44,7 @@ CatalogLinks =
CatalogLinks.el.title = "Turn catalog links #{if useCatalog then 'off' else 'on'}."
external: (board) ->
switch board
when 'a', 'c', 'g', 'co', 'k', 'm', 'o', 'p', 'v', 'vg', 'w', 'cm', '3', 'adv', 'an', 'cgl', 'ck', 'diy', 'fa', 'fit', 'int', 'jp', 'mlp', 'lit', 'mu', 'n', 'po', 'sci', 'toy', 'trv', 'tv', 'vp', 'x', 'q'
"http://catalog.neet.tv/#{board}"
when 'd', 'e', 'gif', 'h', 'hr', 'hc', 'r9k', 's', 'pol', 'soc', 'u', 'i', 'ic', 'hm', 'r', 'w', 'wg', 'wsg', 't', 'y'
"http://4index.gropes.us/#{board}"
else
"/#{board}/catalog"
if board in ['a', 'c', 'g', 'co', 'k', 'm', 'o', 'p', 'v', 'vg', 'w', 'cm', '3', 'adv', 'an', 'cgl', 'ck', 'diy', 'fa', 'fit', 'int', 'jp', 'mlp', 'lit', 'mu', 'n', 'po', 'sci', 'toy', 'trv', 'tv', 'vp', 'x', 'q']
"http://catalog.neet.tv/#{board}"
else
"/#{board}/catalog"

View File

@ -19,6 +19,7 @@ Keybinds =
keydown: (e) ->
return unless key = Keybinds.keyCode e
{target} = e
return if target.nodeName is 'EMBED' # Prevent keybinds from firing on /f/ embeds.
if target.nodeName in ['INPUT', 'TEXTAREA']
return unless /(Esc|Alt|Ctrl|Meta|Shift\+\w{2,})/.test key
unless g.VIEW is 'catalog'

View File

@ -43,8 +43,7 @@ QR =
initReady: ->
$.off d, '4chanXInitFinished', @initReady
QR.postingIsEnabled = !!$.id 'postForm'
unless QR.postingIsEnabled
return
return unless QR.postingIsEnabled
$.on d, 'QRGetSelectedPost', ({detail: cb}) ->
cb QR.selected
@ -359,26 +358,23 @@ QR =
if /^text\//.test file.type
if isSingle
post = QR.selected
else if index isnt 0 or (post = QR.posts[QR.posts.length - 1]).com
else if (post = QR.posts[QR.posts.length - 1]).com
post = new QR.post()
post.pasteText file
return
unless file.type in QR.mimeTypes
QR.error "#{file.name}: Unsupported file type."
return unless isSingle
return
max = QR.nodes.fileInput.max
max = Math.min(max, QR.max_size_video) if /^video\//.test file.type
if file.size > max
QR.error "#{file.name}: File too large (file: #{$.bytesToString file.size}, max: #{$.bytesToString max})."
return unless isSingle
return
if isSingle
post = QR.selected
else if index isnt 0 or (post = QR.posts[QR.posts.length - 1]).file
else if (post = QR.posts[QR.posts.length - 1]).file
post = new QR.post()
if /^text/.test file.type
return post.pasteText file
else
post.setFile file
post.setFile file
openFileInput: (e) ->
e.stopPropagation()
@ -436,7 +432,6 @@ QR =
setNode 'addPost', '#add-post'
setNode 'charCount', '#char-count'
setNode 'fileSubmit', '#file-n-submit'
setNode 'filesize', '#qr-filesize'
setNode 'filename', '#qr-filename'
setNode 'fileContainer', '#qr-filename-container'
setNode 'fileRM', '#qr-filerm'

View File

@ -82,6 +82,7 @@ QR.post = class
(QR.posts[index-1] or QR.posts[index+1]).select()
QR.posts.splice index, 1
QR.status()
delete: ->
$.rm @nodes.el
URL.revokeObjectURL @URL
@ -185,7 +186,7 @@ QR.post = class
if errors.length
QR.error error for error in errors
@URL = fileURL # this.removeFile will revoke this proper.
return @rmFile()
return if (QR.posts.length is 1) or (@com and @com.length) then @rmFile() else @rm() # I wrote this while listening to MCR
# Generate thumbnails only if they're really big.
# Resized pictures through canvases look like ass,