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:
commit
2efa358131
67
CHANGELOG.md
67
CHANGELOG.md
@ -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.
|
||||
|
||||
2
LICENSE
2
LICENSE
@ -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
|
||||
|
||||
@ -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
@ -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>
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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": []
|
||||
}]
|
||||
|
||||
@ -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>'
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 = []
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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\/)([^#\&\?]*).*/
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user