Merge branch 'v3'
Conflicts: CHANGELOG.md LICENSE builds/4chan-X.js builds/4chan-X.meta.js builds/4chan-X.user.js builds/crx/manifest.json builds/crx/script.js latest.js package.json src/General/Header.coffee src/General/Main.coffee src/General/Settings.coffee src/General/css/burichan.css src/General/css/futaba.css src/General/css/photon.css src/General/css/style.css src/General/css/tomorrow.css src/General/css/yotsuba-b.css src/General/css/yotsuba.css src/General/html/Settings/Advanced.html src/Monitoring/Favicon.coffee src/Monitoring/ThreadWatcher.coffee
This commit is contained in:
commit
1debf61f2e
16
CHANGELOG.md
16
CHANGELOG.md
@ -1,5 +1,19 @@
|
|||||||
|
**MayhemYDG**:
|
||||||
|
- Add new archive selection
|
||||||
|
|
||||||
|
**seaweedchan**:
|
||||||
|
- Change watcher favicon to a heart. Change class name from `.favicon` to `.watch-thread-link`. Add `.watched` if thread is watched.
|
||||||
|
- Remove new archive selection back into Advanced
|
||||||
|
- Some styling fixes
|
||||||
|
|
||||||
|
**zixaphir**:
|
||||||
|
- Make new archive selection not depend on a JSON file
|
||||||
|
- Remove some code that sends user errors back to us (we didn't have a working link anyway)
|
||||||
|
|
||||||
### v2.0.3
|
### v2.0.3
|
||||||
*2013-05-10*
|
*2013-05-10*
|
||||||
|
**seaweedchan**:
|
||||||
|
- bug fixes
|
||||||
|
|
||||||
**zixaphir**:
|
**zixaphir**:
|
||||||
- Change Custom Board Navigation input into textarea, new lines will convert to spaces
|
- Change Custom Board Navigation input into textarea, new lines will convert to spaces
|
||||||
@ -60,4 +74,4 @@ Completely rebased off https://github.com/seaweedchan/4chan-x/ 1.1.16
|
|||||||
I hate changelogs so I'd rather not talk about it, but rest assured it
|
I hate changelogs so I'd rather not talk about it, but rest assured it
|
||||||
comes with various performance improvements, layout changes, and the
|
comes with various performance improvements, layout changes, and the
|
||||||
like. If you don't like it, I'm sorry, but change comes with sacrifice,
|
like. If you don't like it, I'm sorry, but change comes with sacrifice,
|
||||||
and we've certainly gained more than we've lost
|
and we've certainly gained more than we've lost
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* appchan x - Version 2.0.3 - 2013-05-13
|
* appchan x - Version 2.0.3 - 2013-05-14
|
||||||
*
|
*
|
||||||
* Licensed under the MIT license.
|
* Licensed under the MIT license.
|
||||||
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
|
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,159 +1,170 @@
|
|||||||
Redirect =
|
Redirect =
|
||||||
|
thread: {}
|
||||||
|
post: {}
|
||||||
|
file: {}
|
||||||
|
|
||||||
init: ->
|
init: ->
|
||||||
$.sync 'archivers', @updateArchives
|
for boardID, data of Conf['selectedArchives']
|
||||||
|
for type, id of data
|
||||||
|
for name, archive of Redirect.archives
|
||||||
|
continue if name isnt id or type is 'post' and archive.software isnt 'foolfuuka'
|
||||||
|
arr = if type is 'file'
|
||||||
|
archive.files
|
||||||
|
else
|
||||||
|
archive.boards
|
||||||
|
Redirect[type][boardID] = archive if arr.contains boardID
|
||||||
|
for name, archive of Redirect.archives
|
||||||
|
for boardID in archive.boards
|
||||||
|
unless boardID of Redirect.thread
|
||||||
|
Redirect.thread[boardID] = archive
|
||||||
|
unless boardID of Redirect.post or archive.software isnt 'foolfuuka'
|
||||||
|
Redirect.post[boardID] = archive
|
||||||
|
unless boardID of Redirect.file or !archive.files.contains boardID
|
||||||
|
Redirect.file[boardID] = archive
|
||||||
|
return
|
||||||
|
|
||||||
updateArchives: ->
|
archives:
|
||||||
$.get 'archivers', {}, ({archivers}) ->
|
|
||||||
Conf['archivers'] = archivers
|
|
||||||
|
|
||||||
imageArchives: do ->
|
|
||||||
o =
|
|
||||||
a: "//archive.foolz.us/"
|
|
||||||
ck: "//fuuka.warosu.org/"
|
|
||||||
an: "http://archive.heinessen.com/"
|
|
||||||
cgl: "//rbt.asia/"
|
|
||||||
c: "//archive.nyafuu.org/"
|
|
||||||
d: "//loveisover.me/"
|
|
||||||
e: "http://archive.foolzashit.com"
|
|
||||||
hr: "http://archive.4plebs.org/"
|
|
||||||
u: "//nsfw.foolz.us/"
|
|
||||||
po: "//archive.thedarkcave.org/"
|
|
||||||
vg: "http://nth.pensivenonsen.se/"
|
|
||||||
c: "//archive.nyafuu.org/"
|
|
||||||
|
|
||||||
o.adv = o.asp = o.cm = o.i = o.n = o.o = o.p = o.s = o.t = o.trv = o.y = o.lgbt = o.s4s = o.e
|
|
||||||
o.gd = o.jp = o.m = o.q = o.tg = o.vp = o.vr = o.wsg = o.a
|
|
||||||
o.fa = o.lit = o.ck
|
|
||||||
o.k = o.toy = o.x = o.an
|
|
||||||
o.g = o.mu = o.cgl
|
|
||||||
o.w = o.wg = o.c
|
|
||||||
o.h = o.v = o.d
|
|
||||||
o.tv = o.hr
|
|
||||||
|
|
||||||
return o
|
|
||||||
|
|
||||||
image: (boardID, filename) ->
|
|
||||||
# Do not use g.BOARD, the image url can originate from a cross-quote.
|
|
||||||
# Fuck. Your. Shit.
|
|
||||||
"#{Redirect.imageArchives[boardID]}#{boardID}/full_image/#{filename}"
|
|
||||||
|
|
||||||
post: (boardID, postID) ->
|
|
||||||
unless Redirect.post[boardID]?
|
|
||||||
for name, archive of @archiver
|
|
||||||
if archive.type is 'foolfuuka' and archive.boards.contains boardID
|
|
||||||
Redirect.post[boardID] = archive.base
|
|
||||||
break
|
|
||||||
Redirect.post[boardID] or= false
|
|
||||||
|
|
||||||
return if Redirect.post[boardID]
|
|
||||||
"#{Redirect.post[boardID]}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
|
|
||||||
else
|
|
||||||
null
|
|
||||||
|
|
||||||
select: (board) ->
|
|
||||||
for name, archive of @archiver
|
|
||||||
continue unless archive.boards.contains board
|
|
||||||
name
|
|
||||||
|
|
||||||
to: (data) ->
|
|
||||||
{boardID} = data
|
|
||||||
|
|
||||||
unless (arch = Conf.archivers[boardID])?
|
|
||||||
Conf.archivers[boardID] = arch = @select(boardID)[0]
|
|
||||||
$.set 'archivers', Conf.archivers
|
|
||||||
|
|
||||||
return (if arch and archive = @archiver[arch]
|
|
||||||
Redirect.path archive.base, archive.type, data
|
|
||||||
else if data.threadID
|
|
||||||
"//boards.4chan.org/#{boardID}/"
|
|
||||||
else
|
|
||||||
null)
|
|
||||||
|
|
||||||
unless archive.boards.contains g.BOARD.ID
|
|
||||||
Conf['archivers'] = archive
|
|
||||||
|
|
||||||
archiver:
|
|
||||||
'Foolz':
|
'Foolz':
|
||||||
base: 'https://archive.foolz.us'
|
'domain': 'archive.foolz.us'
|
||||||
boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg']
|
'http': true
|
||||||
type: 'foolfuuka'
|
'https': true
|
||||||
'NSFWFoolz':
|
'software': 'foolfuuka'
|
||||||
base: 'https://nsfw.foolz.us'
|
'boards': ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg']
|
||||||
boards: ['u']
|
'files': ['a', 'gd', 'jp', 'm', 'q', 'tg', 'vp', 'vr', 'wsg']
|
||||||
type: 'foolfuuka'
|
|
||||||
'TheDarkCave':
|
'NSFW Foolz':
|
||||||
base: 'http://archive.thedarkcave.org'
|
'domain': 'nsfw.foolz.us'
|
||||||
boards: ['c', 'int', 'out', 'po']
|
'http': true
|
||||||
type: 'foolfuuka'
|
'https': true
|
||||||
|
'software': 'foolfuuka'
|
||||||
|
'boards': ['u']
|
||||||
|
'files': ['u']
|
||||||
|
|
||||||
|
'The Dark Cave':
|
||||||
|
'domain': 'archive.thedarkcave.org'
|
||||||
|
'http': true
|
||||||
|
'https': true
|
||||||
|
'software': 'foolfuuka'
|
||||||
|
'boards': ['c', 'int', 'out', 'po']
|
||||||
|
'files': ['c', 'po']
|
||||||
|
|
||||||
'4plebs':
|
'4plebs':
|
||||||
base: 'http://archive.4plebs.org'
|
'domain': 'archive.4plebs.org'
|
||||||
boards: ['hr', 'tg', 'tv', 'x']
|
'http': true
|
||||||
base: 'foolfuuka'
|
'software': 'foolfuuka'
|
||||||
'NyaFuu':
|
'boards': ['hr', 'tg', 'tv', 'x']
|
||||||
base: '//archive.nyafuu.org'
|
'files': ['hr', 'tg', 'tv', 'x']
|
||||||
boards: ['c', 'w', 'wg']
|
|
||||||
type: 'foolfuuka'
|
'Nyafuu':
|
||||||
'LoveIsOver':
|
'http': true
|
||||||
base: '//loveisover.me'
|
'https': true
|
||||||
boards: ['d', 'h', 'v']
|
'software': 'foolfuuka'
|
||||||
type: 'foolfuuka'
|
'boards': ['c', 'w', 'wg']
|
||||||
'PensiveNonsen':
|
'files': ['c', 'w', 'wg']
|
||||||
base: 'http://nth.pensivenonsen.se'
|
|
||||||
boards: ['vg']
|
'Love is Over':
|
||||||
type: 'foolfuuka'
|
'domain': 'loveisover.me'
|
||||||
'FoolzaShit':
|
'http': true
|
||||||
base: 'http://archive.foolzashit.com'
|
'https': true
|
||||||
boards: ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"]
|
'software': 'foolfuuka'
|
||||||
type: 'foolfuuka'
|
'boards': ['d', 'h', 'v']
|
||||||
'Warosu':
|
'files': ['d', 'h', 'v']
|
||||||
base: '//fuuka.warosu.org'
|
|
||||||
boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg', 'vr']
|
'nth-chan':
|
||||||
type: 'fuuka'
|
'domain': 'nth.pensivenonsen.se'
|
||||||
'InstallGentoo':
|
'http': true
|
||||||
base: '//archive.installgentoo.net'
|
'software': 'foolfuuka'
|
||||||
boards: ['diy', 'g', 'sci']
|
'boards': ['vg']
|
||||||
type: 'fuuka'
|
'files': ['vg']
|
||||||
'RebeccaBlackTech':
|
|
||||||
base: '//rbt.asia'
|
'Foolz a Shit':
|
||||||
boards: ['cgl', 'g', 'mu', 'w']
|
'domain': 'archive.foolzashit.com'
|
||||||
type: 'fuuka_mail'
|
'http': true
|
||||||
|
'https': true
|
||||||
|
'software': 'foolfuuka'
|
||||||
|
'boards': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y']
|
||||||
|
'files': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y']
|
||||||
|
|
||||||
|
'Install Gentoo':
|
||||||
|
'domain': 'archive.installgentoo.net'
|
||||||
|
'http': true
|
||||||
|
'https': true
|
||||||
|
'software': 'fuuka'
|
||||||
|
'boards': ['diy', 'g', 'sci']
|
||||||
|
'files': []
|
||||||
|
|
||||||
|
'Rebecca Black Tech':
|
||||||
|
'domain': 'rbt.asia'
|
||||||
|
'http': true
|
||||||
|
'https': true
|
||||||
|
'software': 'fuuka'
|
||||||
|
'boards': ['cgl', 'g', 'mu', 'w']
|
||||||
|
'files': ['cgl', 'g', 'mu', 'w']
|
||||||
|
|
||||||
'Heinessen':
|
'Heinessen':
|
||||||
base: 'http://archive.heinessen.com'
|
'domain': 'archive.heinessen.com'
|
||||||
boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x']
|
'http': true
|
||||||
type: 'fuuka'
|
'software': 'fuuka'
|
||||||
'Cliche':
|
'boards': ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x']
|
||||||
base: '//www.cliché.net/4chan/cgi-board.pl'
|
'files': ['an', 'k', 'toy', 'x']
|
||||||
boards: ['e']
|
|
||||||
type: 'fuuka'
|
|
||||||
|
|
||||||
path: (base, archiver, data) ->
|
'warosu':
|
||||||
if data.isSearch
|
'domain': 'fuuka.warosu.org'
|
||||||
{boardID, type, value} = data
|
'http': true
|
||||||
type = if type is 'name'
|
'https': true
|
||||||
'username'
|
'software': 'fuuka'
|
||||||
else if type is 'MD5'
|
'boards': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'tg', 'vr']
|
||||||
'image'
|
'files': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'vr']
|
||||||
else
|
|
||||||
type
|
|
||||||
value = encodeURIComponent value
|
|
||||||
return if archiver is 'foolfuuka'
|
|
||||||
"#{base}/#{boardID}/search/#{type}/#{value}"
|
|
||||||
else if type is 'image'
|
|
||||||
"#{base}/#{boardID}/?task=search2&search_media_hash=#{value}"
|
|
||||||
else
|
|
||||||
"#{base}/#{boardID}/?task=search2&search_#{type}=#{value}"
|
|
||||||
|
|
||||||
{boardID, threadID, postID} = data
|
to: (dest, data) ->
|
||||||
# keep the number only if the location.hash was sent f.e.
|
archive = (if dest is 'search' then Redirect.thread else Redirect[dest])[data.boardID]
|
||||||
|
return '' unless archive
|
||||||
|
Redirect[dest] archive, data
|
||||||
|
|
||||||
|
protocol: (archive) ->
|
||||||
|
protocol = location.protocol
|
||||||
|
unless archive[protocol[0...-1]]
|
||||||
|
protocol = if protocol is 'https:' then 'http:' else 'https:'
|
||||||
|
"#{protocol}//"
|
||||||
|
|
||||||
|
thread: (archive, {boardID, threadID, postID}) ->
|
||||||
|
# Keep the post number only if the location.hash was sent f.e.
|
||||||
path = if threadID
|
path = if threadID
|
||||||
"#{boardID}/thread/#{threadID}"
|
"#{boardID}/thread/#{threadID}"
|
||||||
else
|
else
|
||||||
"#{boardID}/post/#{postID}"
|
"#{boardID}/post/#{postID}"
|
||||||
if archiver is 'foolfuuka'
|
if archive.software is 'foolfuuka'
|
||||||
path += '/'
|
path += '/'
|
||||||
if threadID and postID
|
if threadID and postID
|
||||||
path += if archiver is 'foolfuuka'
|
path += if archive.software is 'foolfuuka'
|
||||||
"##{postID}"
|
"##{postID}"
|
||||||
else
|
else
|
||||||
"#p#{postID}"
|
"#p#{postID}"
|
||||||
"#{base}/#{path}"
|
"#{Redirect.protocol archive}#{archive.domain}/#{path}"
|
||||||
|
|
||||||
|
post: (archive, {boardID, postID}) ->
|
||||||
|
# For fuuka-based archives:
|
||||||
|
# https://github.com/eksopl/fuuka/issues/27
|
||||||
|
protocol = Redirect.protocol archive
|
||||||
|
# XXX foolz had HSTS set for 120 days, which broke XHR+CORS+Redirection when on HTTP.
|
||||||
|
# Remove necessary HTTPS procotol in September 2013.
|
||||||
|
if ['Foolz', 'NSFW Foolz'].contains archive.name
|
||||||
|
protocol = 'https://'
|
||||||
|
"#{protocol}#{archive.domain}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
|
||||||
|
|
||||||
|
file: (archive, {boardID, filename}) ->
|
||||||
|
"#{Redirect.protocol archive}#{archive.domain}/#{boardID}/full_image/#{filename}"
|
||||||
|
|
||||||
|
search: (archive, {boardID, type, value}) ->
|
||||||
|
type = if type is 'name'
|
||||||
|
'username'
|
||||||
|
else if type is 'MD5'
|
||||||
|
'image'
|
||||||
|
else
|
||||||
|
type
|
||||||
|
value = encodeURIComponent value
|
||||||
|
path = if archive.software is 'foolfuuka'
|
||||||
|
"#{boardID}/search/#{type}/#{value}"
|
||||||
|
else
|
||||||
|
"#{boardID}/?task=search2&search_#{if type is 'image' then 'media_hash' else type}=#{value}"
|
||||||
|
"#{Redirect.protocol archive}#{archive.domain}/#{path}"
|
||||||
|
|||||||
@ -229,9 +229,9 @@ Config =
|
|||||||
true
|
true
|
||||||
'Bookmark threads.'
|
'Bookmark threads.'
|
||||||
]
|
]
|
||||||
'Persistent Thread Watcher': [
|
'Toggleable Thread Watcher': [
|
||||||
false
|
false
|
||||||
'Opens the thread watcher by default.'
|
'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.'
|
||||||
]
|
]
|
||||||
'Auto Watch': [
|
'Auto Watch': [
|
||||||
true
|
true
|
||||||
|
|||||||
@ -71,7 +71,7 @@ Get =
|
|||||||
if threadID
|
if threadID
|
||||||
$.cache "//api.4chan.org/#{boardID}/res/#{threadID}.json", ->
|
$.cache "//api.4chan.org/#{boardID}/res/#{threadID}.json", ->
|
||||||
Get.fetchedPost @, boardID, threadID, postID, root, context
|
Get.fetchedPost @, boardID, threadID, postID, root, context
|
||||||
else if url = Redirect.post boardID, postID
|
else if url = Redirect.to 'post', {boardID, postID}
|
||||||
$.cache url, ->
|
$.cache url, ->
|
||||||
Get.archivedPost @, boardID, postID, root, context
|
Get.archivedPost @, boardID, postID, root, context
|
||||||
insert: (post, root, context) ->
|
insert: (post, root, context) ->
|
||||||
@ -97,7 +97,7 @@ Get =
|
|||||||
{status} = req
|
{status} = req
|
||||||
unless [200, 304].contains status
|
unless [200, 304].contains status
|
||||||
# The thread can die by the time we check a quote.
|
# The thread can die by the time we check a quote.
|
||||||
if url = Redirect.post boardID, postID
|
if url = Redirect.to 'post', {boardID, postID}
|
||||||
$.cache url, ->
|
$.cache url, ->
|
||||||
Get.archivedPost @, boardID, postID, root, context
|
Get.archivedPost @, boardID, postID, root, context
|
||||||
else
|
else
|
||||||
@ -115,7 +115,7 @@ Get =
|
|||||||
break if post.no is postID # we found it!
|
break if post.no is postID # we found it!
|
||||||
if post.no > postID
|
if post.no > postID
|
||||||
# The post can be deleted by the time we check a quote.
|
# The post can be deleted by the time we check a quote.
|
||||||
if url = Redirect.post boardID, postID
|
if url = Redirect.to 'post', {boardID, postID}
|
||||||
$.cache url, ->
|
$.cache url, ->
|
||||||
Get.archivedPost @, boardID, postID, root, context
|
Get.archivedPost @, boardID, postID, root, context
|
||||||
else
|
else
|
||||||
|
|||||||
@ -82,7 +82,7 @@ Header =
|
|||||||
|
|
||||||
boardList = $.el 'span',
|
boardList = $.el 'span',
|
||||||
id: 'board-list'
|
id: 'board-list'
|
||||||
innerHTML: "<span id=custom-board-list></span><span id=full-board-list hidden><a href=javascript:; class='hide-board-list-button brackets-wrap'> - </a> #{fourchannav.innerHTML}</span>"
|
innerHTML: "<span id=custom-board-list></span><span id=full-board-list hidden><span class='hide-board-list-container brackets-wrap'><a href=javascript:; class='hide-board-list-button'> - </a></span> #{fourchannav.innerHTML}</span>"
|
||||||
fullBoardList = $ '#full-board-list', boardList
|
fullBoardList = $ '#full-board-list', boardList
|
||||||
btn = $ '.hide-board-list-button', fullBoardList
|
btn = $ '.hide-board-list-button', fullBoardList
|
||||||
$.on btn, 'click', Header.toggleBoardList
|
$.on btn, 'click', Header.toggleBoardList
|
||||||
|
|||||||
@ -23,8 +23,8 @@ Main =
|
|||||||
'Enabled Mascots nsfw': []
|
'Enabled Mascots nsfw': []
|
||||||
'Deleted Mascots': []
|
'Deleted Mascots': []
|
||||||
'Hidden Categories': ["Questionable"]
|
'Hidden Categories': ["Questionable"]
|
||||||
'archivers': {}
|
selectedArchives: {}
|
||||||
|
|
||||||
$.get Conf, Main.initFeatures
|
$.get Conf, Main.initFeatures
|
||||||
|
|
||||||
initFeatures: (items) ->
|
initFeatures: (items) ->
|
||||||
@ -69,7 +69,10 @@ Main =
|
|||||||
when 'images.4chan.org'
|
when 'images.4chan.org'
|
||||||
$.ready ->
|
$.ready ->
|
||||||
if Conf['404 Redirect'] and d.title is '4chan - 404 Not Found'
|
if Conf['404 Redirect'] and d.title is '4chan - 404 Not Found'
|
||||||
url = Redirect.image pathname[1], pathname[3]
|
Redirect.init()
|
||||||
|
url = Redirect.to 'file',
|
||||||
|
boardID: pathname[1]
|
||||||
|
filename: pathname[3]
|
||||||
location.href = url if url
|
location.href = url if url
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -159,7 +162,7 @@ Main =
|
|||||||
initReady: ->
|
initReady: ->
|
||||||
if d.title is '4chan - 404 Not Found'
|
if d.title is '4chan - 404 Not Found'
|
||||||
if Conf['404 Redirect'] and g.VIEW is 'thread'
|
if Conf['404 Redirect'] and g.VIEW is 'thread'
|
||||||
href = Redirect.to
|
href = Redirect.to 'thread',
|
||||||
boardID: g.BOARD.ID
|
boardID: g.BOARD.ID
|
||||||
threadID: g.THREADID
|
threadID: g.THREADID
|
||||||
postID: +location.hash.match /\d+/ # post number or 0
|
postID: +location.hash.match /\d+/ # post number or 0
|
||||||
@ -333,22 +336,9 @@ Main =
|
|||||||
|
|
||||||
errors: []
|
errors: []
|
||||||
logError: (data) ->
|
logError: (data) ->
|
||||||
unless Main.errors.length
|
|
||||||
$.on window, 'unload', Main.postErrors
|
|
||||||
c.error data.message, data.error.stack
|
c.error data.message, data.error.stack
|
||||||
Main.errors.push data
|
Main.errors.push data
|
||||||
|
|
||||||
postErrors: ->
|
|
||||||
errors = Main.errors.map (d) -> d.message + ' ' + d.error.stack
|
|
||||||
$.ajax '<%= meta.page %>errors', {},
|
|
||||||
sync: true
|
|
||||||
form: $.formData
|
|
||||||
n: "<%= meta.name %> v#{g.VERSION}"
|
|
||||||
t: '<%= type %>'
|
|
||||||
ua: window.navigator.userAgent
|
|
||||||
url: window.location.href
|
|
||||||
e: errors.join '\n'
|
|
||||||
|
|
||||||
isThisPageLegit: ->
|
isThisPageLegit: ->
|
||||||
# 404 error page or similar.
|
# 404 error page or similar.
|
||||||
unless 'thisPageIsLegit' of Main
|
unless 'thisPageIsLegit' of Main
|
||||||
|
|||||||
@ -30,7 +30,7 @@ Settings =
|
|||||||
else
|
else
|
||||||
$.on d, '4chanXInitFinished', Settings.open
|
$.on d, '4chanXInitFinished', Settings.open
|
||||||
$.set
|
$.set
|
||||||
lastupdate: Date.now()
|
lastchecked: Date.now()
|
||||||
previousversion: g.VERSION
|
previousversion: g.VERSION
|
||||||
|
|
||||||
Settings.addSection 'Style', Settings.style
|
Settings.addSection 'Style', Settings.style
|
||||||
@ -291,34 +291,101 @@ Settings =
|
|||||||
ta.value = item['QR.personas']
|
ta.value = item['QR.personas']
|
||||||
$.on ta, 'change', $.cb.value
|
$.on ta, 'change', $.cb.value
|
||||||
|
|
||||||
# Archiver
|
|
||||||
archiver = $ 'select[name=archiver]', section
|
|
||||||
toSelect = Redirect.select g.BOARD.ID
|
|
||||||
toSelect = ['No Archive Available'] unless toSelect[0]
|
|
||||||
|
|
||||||
$.add archiver, $.el('option', {textContent: name}) for name in toSelect
|
|
||||||
|
|
||||||
if toSelect[1]
|
|
||||||
Conf['archivers'][g.BOARD]
|
|
||||||
archiver.value = Conf['archivers'][g.BOARD] or toSelect[0]
|
|
||||||
$.on archiver, 'change', ->
|
|
||||||
Conf['archivers'][g.BOARD] = @value
|
|
||||||
$.set 'archivers', Conf.archivers
|
|
||||||
|
|
||||||
$.get items, (items) ->
|
$.get items, (items) ->
|
||||||
for key, val of items
|
for key, val of items
|
||||||
continue if ['emojiPos', 'archiver'].contains key
|
continue if ['emojiPos'].contains key
|
||||||
input = inputs[key]
|
input = inputs[key]
|
||||||
input.value = val
|
input.value = val
|
||||||
continue if key is 'usercss'
|
continue if key is 'usercss'
|
||||||
$.on input, event, Settings[key]
|
$.on input, event, Settings[key]
|
||||||
Settings[key].call input
|
Settings[key].call input
|
||||||
Rice.nodes sectionreturn
|
Rice.nodes section
|
||||||
|
|
||||||
$.on $('input[name=Interval]', section), 'change', ThreadUpdater.cb.interval
|
$.on $('input[name=Interval]', section), 'change', ThreadUpdater.cb.interval
|
||||||
$.on $('input[name="Custom CSS"]', section), 'change', Settings.togglecss
|
$.on $('input[name="Custom CSS"]', section), 'change', Settings.togglecss
|
||||||
$.on $.id('apply-css'), 'click', Settings.usercss
|
$.on $.id('apply-css'), 'click', Settings.usercss
|
||||||
|
|
||||||
|
boards = {}
|
||||||
|
for name, archive of Redirect.archives
|
||||||
|
for boardID in archive.boards
|
||||||
|
data = boards[boardID] or= {
|
||||||
|
thread: []
|
||||||
|
post: []
|
||||||
|
file: []
|
||||||
|
}
|
||||||
|
data.thread.push name
|
||||||
|
data.post.push name if archive.software is 'foolfuuka'
|
||||||
|
data.file.push name if archive.files.contains boardID
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
boardOptions = []
|
||||||
|
for boardID in Object.keys(boards).sort() # Alphabetical order
|
||||||
|
row = $.el 'tr',
|
||||||
|
className: "board-#{boardID}"
|
||||||
|
row.hidden = boardID isnt g.BOARD.ID
|
||||||
|
rows.push row
|
||||||
|
|
||||||
|
boardOptions.push $.el 'option',
|
||||||
|
textContent: "/#{boardID}/"
|
||||||
|
value: "board-#{boardID}"
|
||||||
|
selected: boardID is g.BOARD.ID
|
||||||
|
|
||||||
|
data = boards[boardID]
|
||||||
|
$.add row, [
|
||||||
|
Settings.addArchiveCell boardID, data, 'thread'
|
||||||
|
Settings.addArchiveCell boardID, data, 'post'
|
||||||
|
Settings.addArchiveCell boardID, data, 'file'
|
||||||
|
]
|
||||||
|
$.add $('tbody', section), rows
|
||||||
|
|
||||||
|
boardSelect = $('#archive-board-select', section)
|
||||||
|
$.add boardSelect, boardOptions
|
||||||
|
table = $.id 'archive-table'
|
||||||
|
$.on boardSelect, 'change', ->
|
||||||
|
$('tbody > :not([hidden])', table).hidden = true
|
||||||
|
$("tbody > .#{@value}", table).hidden = false
|
||||||
|
|
||||||
|
$.get 'selectedArchives', Conf['selectedArchives'], ({selectedArchives}) ->
|
||||||
|
for boardID, data of selectedArchives
|
||||||
|
for type, name of data
|
||||||
|
if option = $ "select[data-boardid='#{boardID}'][data-type='#{type}'] > option[value='#{name}']", section
|
||||||
|
option.selected = true
|
||||||
|
return
|
||||||
|
return
|
||||||
|
|
||||||
|
addArchiveCell: (boardID, data, type) ->
|
||||||
|
{length} = data[type]
|
||||||
|
td = $.el 'td',
|
||||||
|
className: 'archive-cell'
|
||||||
|
|
||||||
|
unless length
|
||||||
|
td.textContent = '--'
|
||||||
|
return td
|
||||||
|
|
||||||
|
options = []
|
||||||
|
i = 0
|
||||||
|
while i < length
|
||||||
|
archive = data[type][i++]
|
||||||
|
options.push $.el 'option',
|
||||||
|
textContent: archive
|
||||||
|
value: archive
|
||||||
|
|
||||||
|
td.innerHTML = '<select></select>'
|
||||||
|
select = td.firstElementChild
|
||||||
|
unless select.disabled = length is 1
|
||||||
|
# XXX GM can't into datasets
|
||||||
|
select.setAttribute 'data-boardid', boardID
|
||||||
|
select.setAttribute 'data-type', type
|
||||||
|
$.on select, 'change', Settings.saveSelectedArchive
|
||||||
|
$.add select, options
|
||||||
|
|
||||||
|
td
|
||||||
|
|
||||||
|
saveSelectedArchive: ->
|
||||||
|
$.get 'selectedArchives', Conf['selectedArchives'], ({selectedArchives}) =>
|
||||||
|
(selectedArchives[@dataset.boardid] or= {})[@dataset.type] = @value
|
||||||
|
$.set 'selectedArchives', selectedArchives
|
||||||
|
|
||||||
boardnav: ->
|
boardnav: ->
|
||||||
Header.generateBoardList @value
|
Header.generateBoardList @value
|
||||||
|
|
||||||
|
|||||||
@ -319,7 +319,8 @@ UI = do ->
|
|||||||
o.hover o.latestEvent if el.parentNode
|
o.hover o.latestEvent if el.parentNode
|
||||||
|
|
||||||
$.on root, endEvents, o.hoverend
|
$.on root, endEvents, o.hoverend
|
||||||
$.on d, 'keydown', o.hoverend
|
if $.x 'ancestor::div[contains(@class,"inline")][1]', root
|
||||||
|
$.on d, 'keydown', o.hoverend
|
||||||
$.on root, 'mousemove', o.hover
|
$.on root, 'mousemove', o.hover
|
||||||
|
|
||||||
hover = (e) ->
|
hover = (e) ->
|
||||||
@ -346,7 +347,7 @@ UI = do ->
|
|||||||
style.right = right
|
style.right = right
|
||||||
|
|
||||||
hoverend = (e) ->
|
hoverend = (e) ->
|
||||||
return if e.type is 'keydown' and e.keyCode isnt 13
|
return if e.type is 'keydown' and e.keyCode isnt 13 or e.target.nodeName is "TEXTAREA"
|
||||||
$.rm @el
|
$.rm @el
|
||||||
$.off @root, @endEvents, @hoverend
|
$.off @root, @endEvents, @hoverend
|
||||||
$.off d, 'keydown', @hoverend
|
$.off d, 'keydown', @hoverend
|
||||||
|
|||||||
58
src/General/css/burichan.css
Normal file
58
src/General/css/burichan.css
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* General */
|
||||||
|
:root.burichan .dialog {
|
||||||
|
background-color: #D6DAF0;
|
||||||
|
border-color: #B7C5D9;
|
||||||
|
}
|
||||||
|
:root.burichan .field:focus {
|
||||||
|
border-color: #98E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
:root.burichan #header-bar, :root.burichan #header-bar #notifications {
|
||||||
|
font-size: 11pt;
|
||||||
|
color: #89A;
|
||||||
|
}
|
||||||
|
:root.burichan #header-bar a, :root.burichan #header-bar #notifications a {
|
||||||
|
color: #34345C;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Settings */
|
||||||
|
:root.burichan #fourchanx-settings fieldset {
|
||||||
|
border-color: #B7C5D9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quote */
|
||||||
|
:root.burichan .backlink.deadlink {
|
||||||
|
color: #34345C !important;
|
||||||
|
}
|
||||||
|
:root.burichan .inline {
|
||||||
|
border-color: #B7C5D9;
|
||||||
|
background-color: rgba(255, 255, 255, .14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QR */
|
||||||
|
.burichan #dump-list::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #D6DAF0;
|
||||||
|
border-color: #B7C5D9;
|
||||||
|
}
|
||||||
|
:root.burichan .qr-preview {
|
||||||
|
background-color: rgba(0, 0, 0, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
:root.burichan #menu {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
:root.burichan .entry {
|
||||||
|
border-bottom: 1px solid #B7C5D9;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
:root.burichan .focused.entry {
|
||||||
|
background: rgba(255, 255, 255, .33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Watcher Favicon */
|
||||||
|
:root.burichan .watch-thread-link
|
||||||
|
{
|
||||||
|
background-image: url("data:image/svg+xml,<svg viewBox='0 0 26 26' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='rgb(0,0,0)' d='M24.132,7.971c-2.203-2.205-5.916-2.098-8.25,0.235L15.5,8.588l-0.382-0.382c-2.334-2.333-6.047-2.44-8.25-0.235c-2.204,2.203-2.098,5.916,0.235,8.249l8.396,8.396l8.396-8.396C26.229,13.887,26.336,10.174,24.132,7.971z'/></svg>");
|
||||||
|
}
|
||||||
58
src/General/css/futaba.css
Normal file
58
src/General/css/futaba.css
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* General */
|
||||||
|
:root.futaba .dialog {
|
||||||
|
background-color: #F0E0D6;
|
||||||
|
border-color: #D9BFB7;
|
||||||
|
}
|
||||||
|
:root.futaba .field:focus {
|
||||||
|
border-color: #EA8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
:root.futaba #header-bar, :root.futaba #notifications {
|
||||||
|
font-size: 11pt;
|
||||||
|
color: #B86;
|
||||||
|
}
|
||||||
|
:root.futaba #header-bar a, :root.futaba #notifications a {
|
||||||
|
color: #800000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Settings */
|
||||||
|
:root.futaba #fourchanx-settings fieldset {
|
||||||
|
border-color: #D9BFB7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quote */
|
||||||
|
:root.futaba .backlink.deadlink {
|
||||||
|
color: #00E !important;
|
||||||
|
}
|
||||||
|
:root.futaba .inline {
|
||||||
|
border-color: #D9BFB7;
|
||||||
|
background-color: rgba(255, 255, 255, .14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QR */
|
||||||
|
.futaba #dump-list::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #F0E0D6;
|
||||||
|
border-color: #D9BFB7;
|
||||||
|
}
|
||||||
|
:root.futaba .qr-preview {
|
||||||
|
background-color: rgba(0, 0, 0, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
:root.futaba #menu {
|
||||||
|
color: #800000;
|
||||||
|
}
|
||||||
|
:root.futaba .entry {
|
||||||
|
border-bottom: 1px solid #D9BFB7;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
:root.futaba .focused.entry {
|
||||||
|
background: rgba(255, 255, 255, .33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Watcher Favicon */
|
||||||
|
:root.futaba .watch-thread-link
|
||||||
|
{
|
||||||
|
background-image: url("data:image/svg+xml,<svg viewBox='0 0 26 26' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='rgb(128,0,0)' d='M24.132,7.971c-2.203-2.205-5.916-2.098-8.25,0.235L15.5,8.588l-0.382-0.382c-2.334-2.333-6.047-2.44-8.25-0.235c-2.204,2.203-2.098,5.916,0.235,8.249l8.396,8.396l8.396-8.396C26.229,13.887,26.336,10.174,24.132,7.971z'/></svg>");
|
||||||
|
}
|
||||||
@ -127,6 +127,9 @@ hr {
|
|||||||
margin: 0 0 1px;
|
margin: 0 0 1px;
|
||||||
#{if _conf['Hide Horizontal Rules'] then 'visibility: hidden;' else ''}
|
#{if _conf['Hide Horizontal Rules'] then 'visibility: hidden;' else ''}
|
||||||
}
|
}
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
.center {
|
.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@ -716,6 +719,19 @@ hide: "
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
"}
|
"}
|
||||||
|
.watch-thread-link {
|
||||||
|
padding-top: 18px;
|
||||||
|
width: 18px;
|
||||||
|
height: 0px;
|
||||||
|
display: inline-block;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
opacity: 0.2;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
.watch-thread-link.watched {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
/* Announcements */
|
/* Announcements */
|
||||||
#globalMessage {
|
#globalMessage {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -1569,6 +1585,9 @@ a:only-of-type > .remove {
|
|||||||
display: block;
|
display: block;
|
||||||
margin: 0 auto 6px;
|
margin: 0 auto 6px;
|
||||||
}
|
}
|
||||||
|
.section-advanced .archive-cell {
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
.section-advanced .selectrice {
|
.section-advanced .selectrice {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
clear: both;
|
clear: both;
|
||||||
|
|||||||
58
src/General/css/photon.css
Normal file
58
src/General/css/photon.css
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* General */
|
||||||
|
:root.photon .dialog {
|
||||||
|
background-color: #DDD;
|
||||||
|
border-color: #CCC;
|
||||||
|
}
|
||||||
|
:root.photon .field:focus {
|
||||||
|
border-color: #EA8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
:root.photon #header-bar, :root.photon #notifications {
|
||||||
|
font-size: 9pt;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
:root.photon #header-bar a, :root.photon #notifications a {
|
||||||
|
color: #FF6600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Settings */
|
||||||
|
:root.photon #fourchanx-settings fieldset {
|
||||||
|
border-color: #CCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quote */
|
||||||
|
:root.photon .backlink.deadlink {
|
||||||
|
color: #F60 !important;
|
||||||
|
}
|
||||||
|
:root.photon .inline {
|
||||||
|
border-color: #CCC;
|
||||||
|
background-color: rgba(255, 255, 255, .14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QR */
|
||||||
|
.photon #dump-list::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #DDD;
|
||||||
|
border-color: #CCC;
|
||||||
|
}
|
||||||
|
:root.photon .qr-preview {
|
||||||
|
background-color: rgba(0, 0, 0, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
:root.photon #menu {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
:root.photon .entry {
|
||||||
|
border-bottom: 1px solid #CCC;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
:root.photon .focused.entry {
|
||||||
|
background: rgba(255, 255, 255, .33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Watcher Favicon */
|
||||||
|
:root.photon .watch-thread-link
|
||||||
|
{
|
||||||
|
background-image: url("data:image/svg+xml,<svg viewBox='0 0 26 26' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='rgb(51,51,51)' d='M24.132,7.971c-2.203-2.205-5.916-2.098-8.25,0.235L15.5,8.588l-0.382-0.382c-2.334-2.333-6.047-2.44-8.25-0.235c-2.204,2.203-2.098,5.916,0.235,8.249l8.396,8.396l8.396-8.396C26.229,13.887,26.336,10.174,24.132,7.971z'/></svg>");
|
||||||
|
}
|
||||||
@ -201,6 +201,9 @@ a[style="cursor: pointer; float: right;"] ~ div[style^="width: 100%;"] > table {
|
|||||||
background: #{theme["Dialog Background"]};
|
background: #{theme["Dialog Background"]};
|
||||||
border: 1px solid #{theme["Dialog Border"]};
|
border: 1px solid #{theme["Dialog Border"]};
|
||||||
}
|
}
|
||||||
|
.watch-thread-link {
|
||||||
|
background-image: url("data:image/svg+xml,<svg viewBox='0 0 26 26' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='#{theme["Post Numbers"]}' d='M24.132,7.971c-2.203-2.205-5.916-2.098-8.25,0.235L15.5,8.588l-0.382-0.382c-2.334-2.333-6.047-2.44-8.25-0.235c-2.204,2.203-2.098,5.916,0.235,8.249l8.396,8.396l8.396-8.396C26.229,13.887,26.336,10.174,24.132,7.971z'/></svg>");
|
||||||
|
}
|
||||||
.deleteform::before,
|
.deleteform::before,
|
||||||
.deleteform,
|
.deleteform,
|
||||||
#qr .warning {
|
#qr .warning {
|
||||||
|
|||||||
64
src/General/css/tomorrow.css
Normal file
64
src/General/css/tomorrow.css
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* General */
|
||||||
|
:root.tomorrow .dialog {
|
||||||
|
background-color: #282A2E;
|
||||||
|
border-color: #111;
|
||||||
|
}
|
||||||
|
:root.tomorrow .field:focus {
|
||||||
|
border-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
:root.tomorrow #header-bar, :root.tomorrow #notifications {
|
||||||
|
font-size: 9pt;
|
||||||
|
color: #C5C8C6;
|
||||||
|
}
|
||||||
|
:root.tomorrow #header-bar a, :root.tomorrow #notifications a {
|
||||||
|
color: #81A2BE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Settings */
|
||||||
|
:root.tomorrow #fourchanx-settings fieldset {
|
||||||
|
border-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quote */
|
||||||
|
:root.tomorrow .backlink.deadlink {
|
||||||
|
color: #81A2BE !important;
|
||||||
|
}
|
||||||
|
:root.tomorrow .inline {
|
||||||
|
border-color: #111;
|
||||||
|
background-color: rgba(0, 0, 0, .14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QR */
|
||||||
|
.tomorrow #dump-list::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #282A2E;
|
||||||
|
border-color: #111;
|
||||||
|
}
|
||||||
|
:root.tomorrow #qr select {
|
||||||
|
color: #C5C8C6;
|
||||||
|
}
|
||||||
|
:root.tomorrow #qr option {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
:root.tomorrow .qr-preview {
|
||||||
|
background-color: rgba(255, 255, 255, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
:root.tomorrow #menu {
|
||||||
|
color: #C5C8C6;
|
||||||
|
}
|
||||||
|
:root.tomorrow .entry {
|
||||||
|
border-bottom: 1px solid #111;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
:root.tomorrow .focused.entry {
|
||||||
|
background: rgba(0, 0, 0, .33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Watcher Favicon */
|
||||||
|
:root.tomorrow .watch-thread-link
|
||||||
|
{
|
||||||
|
background-image: url("data:image/svg+xml,<svg viewBox='0 0 26 26' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='rgb(197,200,198)' d='M24.132,7.971c-2.203-2.205-5.916-2.098-8.25,0.235L15.5,8.588l-0.382-0.382c-2.334-2.333-6.047-2.44-8.25-0.235c-2.204,2.203-2.098,5.916,0.235,8.249l8.396,8.396l8.396-8.396C26.229,13.887,26.336,10.174,24.132,7.971z'/></svg>");
|
||||||
|
}
|
||||||
58
src/General/css/yotsuba-b.css
Normal file
58
src/General/css/yotsuba-b.css
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* General */
|
||||||
|
:root.yotsuba-b .dialog {
|
||||||
|
background-color: #D6DAF0;
|
||||||
|
border-color: #B7C5D9;
|
||||||
|
}
|
||||||
|
:root.yotsuba-b .field:focus {
|
||||||
|
border-color: #98E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
:root.yotsuba-b #header-bar, :root.yotsuba-b #notifications {
|
||||||
|
font-size: 9pt;
|
||||||
|
color: #89A;
|
||||||
|
}
|
||||||
|
:root.yotsuba-b #header-bar a, :root.yotsuba-b #notifications a {
|
||||||
|
color: #34345C;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Settings */
|
||||||
|
:root.yotsuba-b #fourchanx-settings fieldset {
|
||||||
|
border-color: #B7C5D9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quote */
|
||||||
|
:root.yotsuba-b .backlink.deadlink {
|
||||||
|
color: #34345C !important;
|
||||||
|
}
|
||||||
|
:root.yotsuba-b .inline {
|
||||||
|
border-color: #B7C5D9;
|
||||||
|
background-color: rgba(255, 255, 255, .14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QR */
|
||||||
|
.yotsuba-b #dump-list::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #D6DAF0;
|
||||||
|
border-color: #B7C5D9;
|
||||||
|
}
|
||||||
|
:root.yotsuba-b .qr-preview {
|
||||||
|
background-color: rgba(0, 0, 0, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
:root.yotsuba-b #menu {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
:root.yotsuba-b .entry {
|
||||||
|
border-bottom: 1px solid #B7C5D9;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
:root.yotsuba-b .focused.entry {
|
||||||
|
background: rgba(255, 255, 255, .33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Watcher Favicon */
|
||||||
|
:root.yotsuba-b .watch-thread-link
|
||||||
|
{
|
||||||
|
background-image: url("data:image/svg+xml,<svg viewBox='0 0 26 26' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='rgb(0,0,0)' d='M24.132,7.971c-2.203-2.205-5.916-2.098-8.25,0.235L15.5,8.588l-0.382-0.382c-2.334-2.333-6.047-2.44-8.25-0.235c-2.204,2.203-2.098,5.916,0.235,8.249l8.396,8.396l8.396-8.396C26.229,13.887,26.336,10.174,24.132,7.971z'/></svg>");
|
||||||
|
}
|
||||||
58
src/General/css/yotsuba.css
Normal file
58
src/General/css/yotsuba.css
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* General */
|
||||||
|
:root.yotsuba .dialog {
|
||||||
|
background-color: #F0E0D6;
|
||||||
|
border-color: #D9BFB7;
|
||||||
|
}
|
||||||
|
:root.yotsuba .field:focus {
|
||||||
|
border-color: #EA8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
:root.yotsuba #header-bar, :root.yotsuba #notifications {
|
||||||
|
font-size: 9pt;
|
||||||
|
color: #B86;
|
||||||
|
}
|
||||||
|
:root.yotsuba #header-bar a, :root.yotsuba #notifications a {
|
||||||
|
color: #800000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Settings */
|
||||||
|
:root.yotsuba #fourchanx-settings fieldset {
|
||||||
|
border-color: #D9BFB7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quote */
|
||||||
|
:root.yotsuba .backlink.deadlink {
|
||||||
|
color: #00E !important;
|
||||||
|
}
|
||||||
|
:root.yotsuba .inline {
|
||||||
|
border-color: #D9BFB7;
|
||||||
|
background-color: rgba(255, 255, 255, .14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QR */
|
||||||
|
.yotsuba #dump-list::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #F0E0D6;
|
||||||
|
border-color: #D9BFB7;
|
||||||
|
}
|
||||||
|
:root.yotsuba .qr-preview {
|
||||||
|
background-color: rgba(0, 0, 0, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
:root.yotsuba #menu {
|
||||||
|
color: #800000;
|
||||||
|
}
|
||||||
|
:root.yotsuba .entry {
|
||||||
|
border-bottom: 1px solid #D9BFB7;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
:root.yotsuba .focused.entry {
|
||||||
|
background: rgba(255, 255, 255, .33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Watcher Favicon */
|
||||||
|
:root.yotsuba .watch-thread-link
|
||||||
|
{
|
||||||
|
background-image: url("data:image/svg+xml,<svg viewBox='0 0 26 26' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='rgb(128,0,0)' d='M24.132,7.971c-2.203-2.205-5.916-2.098-8.25,0.235L15.5,8.588l-0.382-0.382c-2.334-2.333-6.047-2.44-8.25-0.235c-2.204,2.203-2.098,5.916,0.235,8.249l8.396,8.396l8.396-8.396C26.229,13.887,26.336,10.174,24.132,7.971z'/></svg>");
|
||||||
|
}
|
||||||
@ -1,10 +1,18 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Archiver</legend>
|
<legend>Archiver</legend>
|
||||||
<div>
|
<div class="warning" #{if Conf['404 Redirect'] then 'hidden' else ''}><code>404 Redirect</code> is disabled.</div>
|
||||||
Select an Archiver for this board:
|
<div><select id='archive-board-select'></select></div>
|
||||||
<select name=archiver></select>
|
<table id='archive-table'>
|
||||||
</div>
|
<thead>
|
||||||
|
<th>Thread redirection</th>
|
||||||
|
<th>Post fetching</th>
|
||||||
|
<th>File redirection</th>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
<span class=note>Disabled selections indicate that only one archive is available for that board and redirection type.</span>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Custom Board Navigation</legend>
|
<legend>Custom Board Navigation</legend>
|
||||||
<div><textarea name=boardnav class=field spellcheck=false></textarea></div>
|
<div><textarea name=boardnav class=field spellcheck=false></textarea></div>
|
||||||
|
|||||||
@ -141,7 +141,10 @@ ImageExpand =
|
|||||||
|
|
||||||
src = @src.split '/'
|
src = @src.split '/'
|
||||||
if src[2] is 'images.4chan.org'
|
if src[2] is 'images.4chan.org'
|
||||||
if URL = Redirect.image src[3], src[5]
|
URL = Redirect.to 'file',
|
||||||
|
boardID: src[3]
|
||||||
|
filename: src[5]
|
||||||
|
if URL
|
||||||
setTimeout ImageExpand.expand, 10000, post, URL
|
setTimeout ImageExpand.expand, 10000, post, URL
|
||||||
return
|
return
|
||||||
if g.DEAD or post.isDead or post.file.isDead
|
if g.DEAD or post.isDead or post.file.isDead
|
||||||
|
|||||||
@ -28,7 +28,10 @@ ImageHover =
|
|||||||
|
|
||||||
src = @src.split '/'
|
src = @src.split '/'
|
||||||
if src[2] is 'images.4chan.org'
|
if src[2] is 'images.4chan.org'
|
||||||
if URL = Redirect.image src[3], src[5].replace /\?.+$/, ''
|
URL = Redirect.to 'file',
|
||||||
|
boardID: src[3]
|
||||||
|
filename: src[5].replace /\?.+$/, ''
|
||||||
|
if URL
|
||||||
@src = URL
|
@src = URL
|
||||||
return
|
return
|
||||||
if g.DEAD or post.isDead or post.file.isDead
|
if g.DEAD or post.isDead or post.file.isDead
|
||||||
|
|||||||
@ -10,8 +10,7 @@ ArchiveLink =
|
|||||||
el: div
|
el: div
|
||||||
order: 90
|
order: 90
|
||||||
open: ({ID, thread, board}) ->
|
open: ({ID, thread, board}) ->
|
||||||
redirect = Redirect.to {postID: ID, threadID: thread.ID, boardID: board.ID}
|
!!Redirect.to 'thread', {postID: ID, threadID: thread.ID, boardID: board.ID}
|
||||||
redirect isnt "//boards.4chan.org/#{board}/"
|
|
||||||
subEntries: []
|
subEntries: []
|
||||||
|
|
||||||
for type in [
|
for type in [
|
||||||
@ -35,14 +34,14 @@ ArchiveLink =
|
|||||||
|
|
||||||
open = if type is 'post'
|
open = if type is 'post'
|
||||||
({ID, thread, board}) ->
|
({ID, thread, board}) ->
|
||||||
el.href = Redirect.to {postID: ID, threadID: thread.ID, boardID: board.ID}
|
el.href = Redirect.to 'thread', {postID: ID, threadID: thread.ID, boardID: board.ID}
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
(post) ->
|
(post) ->
|
||||||
value = Filter[type] post
|
value = Filter[type] post
|
||||||
# We want to parse the exact same stuff as the filter does already.
|
# We want to parse the exact same stuff as the filter does already.
|
||||||
return false unless value
|
return false unless value
|
||||||
el.href = Redirect.to
|
el.href = Redirect.to 'search',
|
||||||
boardID: post.board.ID
|
boardID: post.board.ID
|
||||||
type: type
|
type: type
|
||||||
value: value
|
value: value
|
||||||
|
|||||||
@ -5,7 +5,7 @@ CatalogLinks =
|
|||||||
el = $.el 'label',
|
el = $.el 'label',
|
||||||
id: 'toggleCatalog'
|
id: 'toggleCatalog'
|
||||||
href: 'javascript:;'
|
href: 'javascript:;'
|
||||||
innerHTML: "<input type=checkbox #{if Conf['Header catalog links'] then 'checked' else ''}>Catalog Links"
|
innerHTML: "<input type=checkbox #{if Conf['Header catalog links'] then 'checked' else ''}> Catalog Links"
|
||||||
title: "Turn catalog links #{if Conf['Header catalog links'] then 'off' else 'on'}."
|
title: "Turn catalog links #{if Conf['Header catalog links'] then 'off' else 'on'}."
|
||||||
|
|
||||||
input = $ 'input', el
|
input = $ 'input', el
|
||||||
@ -41,7 +41,6 @@ CatalogLinks =
|
|||||||
"//boards.4chan.org/#{board}/"
|
"//boards.4chan.org/#{board}/"
|
||||||
else
|
else
|
||||||
a.pathname = "/#{board}/#{path}"
|
a.pathname = "/#{board}/#{path}"
|
||||||
a.title = if useCatalog then "#{a.title} - Catalog" else a.title.replace(/\ -\ Catalog$/, '')
|
|
||||||
@title = "Turn catalog links #{if useCatalog then 'off' else 'on'}."
|
@title = "Turn catalog links #{if useCatalog then 'off' else 'on'}."
|
||||||
|
|
||||||
external: (board) ->
|
external: (board) ->
|
||||||
|
|||||||
@ -84,7 +84,7 @@ ExpandThread =
|
|||||||
if post = thread.posts[reply.no]
|
if post = thread.posts[reply.no]
|
||||||
nodes.push post.nodes.root
|
nodes.push post.nodes.root
|
||||||
continue
|
continue
|
||||||
node = Build.postFromObject reply, thread.board
|
node = Build.postFromObject reply, thread.board.ID
|
||||||
post = new Post node, thread, thread.board
|
post = new Post node, thread, thread.board
|
||||||
link = $ 'a[title="Highlight this post"]', node
|
link = $ 'a[title="Highlight this post"]', node
|
||||||
link.href = "res/#{thread}#p#{post}"
|
link.href = "res/#{thread}#p#{post}"
|
||||||
@ -94,4 +94,4 @@ ExpandThread =
|
|||||||
Main.callbackNodes Post, posts
|
Main.callbackNodes Post, posts
|
||||||
$.after a, nodes
|
$.after a, nodes
|
||||||
|
|
||||||
Fourchan.parseThread thread.ID, 1, nodes.length
|
Fourchan.parseThread thread.ID, 1, nodes.length
|
||||||
|
|||||||
@ -53,5 +53,4 @@ Favicon =
|
|||||||
Favicon.unread = Favicon.unreadNSFW
|
Favicon.unread = Favicon.unreadNSFW
|
||||||
Favicon.unreadY = Favicon.unreadNSFWY
|
Favicon.unreadY = Favicon.unreadNSFWY
|
||||||
|
|
||||||
empty: 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/empty.png", {encoding: "base64"}) %>'
|
dead: 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/dead.png", {encoding: "base64"}) %>'
|
||||||
dead: 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/dead.png", {encoding: "base64"}) %>'
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ ThreadWatcher =
|
|||||||
$.sync 'WatchedThreads', @refresh
|
$.sync 'WatchedThreads', @refresh
|
||||||
$.on $('.move>.close', ThreadWatcher.dialog), 'click', @toggleWatcher
|
$.on $('.move>.close', ThreadWatcher.dialog), 'click', @toggleWatcher
|
||||||
|
|
||||||
|
|
||||||
$.ready ->
|
$.ready ->
|
||||||
ThreadWatcher.refresh()
|
ThreadWatcher.refresh()
|
||||||
$.add d.body, ThreadWatcher.dialog
|
$.add d.body, ThreadWatcher.dialog
|
||||||
@ -18,8 +19,9 @@ ThreadWatcher =
|
|||||||
cb: @node
|
cb: @node
|
||||||
|
|
||||||
node: ->
|
node: ->
|
||||||
favicon = $.el 'img',
|
favicon = $.el 'a',
|
||||||
className: 'favicon'
|
className: 'watch-thread-link'
|
||||||
|
href: 'javascript:;'
|
||||||
$.on favicon, 'click', ThreadWatcher.cb.toggle
|
$.on favicon, 'click', ThreadWatcher.cb.toggle
|
||||||
$.before $('input', @OP.nodes.post), favicon
|
$.before $('input', @OP.nodes.post), favicon
|
||||||
return if g.VIEW isnt 'thread'
|
return if g.VIEW isnt 'thread'
|
||||||
@ -53,11 +55,11 @@ ThreadWatcher =
|
|||||||
|
|
||||||
watched = watched[g.BOARD] or {}
|
watched = watched[g.BOARD] or {}
|
||||||
for ID, thread of g.BOARD.threads
|
for ID, thread of g.BOARD.threads
|
||||||
favicon = $ '.favicon', thread.OP.nodes.post
|
favicon = $ '.watch-thread-link', thread.OP.nodes.post
|
||||||
favicon.src = if ID of watched
|
if ID of watched
|
||||||
Favicon.default
|
$.addClass favicon, 'watched'
|
||||||
else
|
else
|
||||||
Favicon.empty
|
$.rmClass favicon, 'watched'
|
||||||
return
|
return
|
||||||
|
|
||||||
toggleWatcher: ->
|
toggleWatcher: ->
|
||||||
@ -79,7 +81,7 @@ ThreadWatcher =
|
|||||||
ThreadWatcher.watch board.threads[threadID]
|
ThreadWatcher.watch board.threads[threadID]
|
||||||
|
|
||||||
toggle: (thread) ->
|
toggle: (thread) ->
|
||||||
if $('.favicon', thread.OP.nodes.post).src is Favicon.empty
|
unless $.hasClass $('.watch-thread-link', thread.OP.nodes.post), 'watched'
|
||||||
ThreadWatcher.watch thread
|
ThreadWatcher.watch thread
|
||||||
else
|
else
|
||||||
ThreadWatcher.unwatch thread.board, thread.ID
|
ThreadWatcher.unwatch thread.board, thread.ID
|
||||||
|
|||||||
@ -62,6 +62,7 @@ QR =
|
|||||||
$.on $('a[title="Quote this post"]', @nodes.info), 'click', QR.quote
|
$.on $('a[title="Quote this post"]', @nodes.info), 'click', QR.quote
|
||||||
|
|
||||||
persist: ->
|
persist: ->
|
||||||
|
return unless QR.postingIsEnabled
|
||||||
QR.open()
|
QR.open()
|
||||||
QR.hide() if Conf['Auto Hide QR']
|
QR.hide() if Conf['Auto Hide QR']
|
||||||
|
|
||||||
@ -1248,4 +1249,4 @@ QR =
|
|||||||
asapTest: -> true
|
asapTest: -> true
|
||||||
close: true
|
close: true
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@ -51,14 +51,14 @@ Quotify =
|
|||||||
a.setAttribute 'data-boardid', boardID
|
a.setAttribute 'data-boardid', boardID
|
||||||
a.setAttribute 'data-threadid', post.thread.ID
|
a.setAttribute 'data-threadid', post.thread.ID
|
||||||
a.setAttribute 'data-postid', postID
|
a.setAttribute 'data-postid', postID
|
||||||
else if redirect = Redirect.to {boardID, threadID: 0, postID}
|
else if redirect = Redirect.to 'thread', {boardID, threadID: 0, postID}
|
||||||
# Replace the .deadlink span if we can redirect.
|
# Replace the .deadlink span if we can redirect.
|
||||||
a = $.el 'a',
|
a = $.el 'a',
|
||||||
href: redirect
|
href: redirect
|
||||||
className: 'deadlink'
|
className: 'deadlink'
|
||||||
target: '_blank'
|
target: '_blank'
|
||||||
textContent: "#{quote}\u00A0(Dead)"
|
textContent: "#{quote}\u00A0(Dead)"
|
||||||
if Redirect.post boardID, postID
|
if Redirect.to 'post', {boardID, postID}
|
||||||
# Make it function as a normal quote if we can fetch the post.
|
# Make it function as a normal quote if we can fetch the post.
|
||||||
$.addClass a, 'quotelink'
|
$.addClass a, 'quotelink'
|
||||||
a.setAttribute 'data-boardid', boardID
|
a.setAttribute 'data-boardid', boardID
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user