Merge Zixaphir X
3
.gitignore
vendored
@ -2,8 +2,7 @@ node_modules/
|
||||
*~
|
||||
*.db
|
||||
tmp-crx/
|
||||
tmp-userjs/
|
||||
tmp-userscript/
|
||||
builds/4chan-X-Chrome.zip
|
||||
builds/4chan-X-Opera.nex
|
||||
Gruntfile.js
|
||||
Gruntfile.js
|
||||
|
||||
21
CHANGELOG.md
Normal file → Executable file
@ -1,3 +1,23 @@
|
||||
**MayhemYDG**:
|
||||
- **New feature**: `Show Dice Roll` (with @carboncopy)
|
||||
- Shows dice that were entered into the email field on /tg/.
|
||||
- Fix impossibility to create new threads when in dead threads.
|
||||
- Fix flag filtering on /sp/ and /int/.
|
||||
- Update archives. (with @woxxy and @proplex)
|
||||
- Minor fixes.
|
||||
- Minor optimizations.
|
||||
|
||||
**Zixaphir**:
|
||||
- Linkifier Rewrite.
|
||||
- Fix Quote Threading toggle.
|
||||
- Added Twitch.tv and Vine embedding (with @ihavenoface)
|
||||
- Keybinds to scroll to posts that quote you.
|
||||
- Minor optimizations.
|
||||
- Minor fixes.
|
||||
|
||||
**aeosynth**:
|
||||
- Update Gruntfile.coffee.
|
||||
|
||||
### v1.2.25
|
||||
*2013-08-04*
|
||||
|
||||
@ -54,7 +74,6 @@
|
||||
|
||||
### v1.2.17
|
||||
*2013-06-17*
|
||||
|
||||
**seaweedchan**:
|
||||
- Fix full images being forced onto their own line
|
||||
|
||||
|
||||
138
Gruntfile.coffee
Normal file → Executable file
@ -1,18 +1,18 @@
|
||||
module.exports = (grunt) ->
|
||||
|
||||
pkg = grunt.file.readJSON 'package.json'
|
||||
concatOptions =
|
||||
process:
|
||||
data: pkg
|
||||
|
||||
process: Object.create(null, data:
|
||||
get: -> grunt.config 'pkg'
|
||||
enumerable: true
|
||||
)
|
||||
shellOptions =
|
||||
stdout: true
|
||||
stderr: true
|
||||
stdout: true
|
||||
stderr: true
|
||||
failOnError: true
|
||||
|
||||
# Project configuration.
|
||||
grunt.initConfig
|
||||
pkg: pkg
|
||||
pkg: grunt.file.readJSON 'package.json'
|
||||
concat:
|
||||
coffee:
|
||||
options: concatOptions
|
||||
@ -41,8 +41,8 @@ module.exports = (grunt) ->
|
||||
meta:
|
||||
options: concatOptions
|
||||
files:
|
||||
'LICENSE': 'src/General/meta/banner.js',
|
||||
'latest.js': 'src/General/meta/latest.js'
|
||||
'LICENSE': 'src/General/meta/banner.js',
|
||||
'latest.js': 'src/General/meta/latest.js'
|
||||
|
||||
crx:
|
||||
options: concatOptions
|
||||
@ -51,19 +51,9 @@ module.exports = (grunt) ->
|
||||
'builds/crx/script.js': [
|
||||
'src/General/meta/botproc.js'
|
||||
'src/General/meta/banner.js'
|
||||
'src/General/meta/usestrict.js'
|
||||
'tmp-<%= pkg.type %>/script.js'
|
||||
]
|
||||
|
||||
userjs:
|
||||
options: concatOptions
|
||||
src: [
|
||||
'src/General/meta/botproc.js'
|
||||
'src/General/meta/metadata.js'
|
||||
'src/General/meta/banner.js'
|
||||
'tmp-<%= pkg.type %>/script.js'
|
||||
]
|
||||
dest: 'builds/<%= pkg.name %>.js'
|
||||
|
||||
userscript:
|
||||
options: concatOptions
|
||||
files:
|
||||
@ -72,13 +62,13 @@ module.exports = (grunt) ->
|
||||
'src/General/meta/botproc.js'
|
||||
'src/General/meta/metadata.js'
|
||||
'src/General/meta/banner.js'
|
||||
'src/General/meta/usestrict.js'
|
||||
'tmp-<%= pkg.type %>/script.js'
|
||||
]
|
||||
|
||||
copy:
|
||||
crx:
|
||||
src: 'src/General/img/*.png'
|
||||
dest: 'builds/crx/'
|
||||
src: 'src/General/img/*.png'
|
||||
dest: 'builds/crx/'
|
||||
expand: true
|
||||
flatten: true
|
||||
|
||||
@ -91,24 +81,31 @@ module.exports = (grunt) ->
|
||||
build: [
|
||||
'concat:meta'
|
||||
'build-crx'
|
||||
'build-userjs'
|
||||
'build-userscript'
|
||||
]
|
||||
|
||||
bump:
|
||||
options:
|
||||
updateConfigs: [
|
||||
'pkg'
|
||||
]
|
||||
commit: false
|
||||
createTag: false
|
||||
push: false
|
||||
|
||||
shell:
|
||||
commit:
|
||||
options: shellOptions
|
||||
command: [
|
||||
'git checkout <%= pkg.meta.mainBranch %>',
|
||||
'git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>."',
|
||||
'git tag -a <%= pkg.version %> -m "<%= pkg.meta.name %> v<%= pkg.version %>."',
|
||||
'git checkout <%= pkg.meta.mainBranch %>'
|
||||
'git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>."'
|
||||
'git tag -a <%= pkg.version %> -m "<%= pkg.meta.name %> v<%= pkg.version %>."'
|
||||
'git tag -af stable -m "<%= pkg.meta.name %> v<%= pkg.version %>."'
|
||||
].join(' && ')
|
||||
stdout: true
|
||||
].join ' && '
|
||||
|
||||
push:
|
||||
options: shellOptions
|
||||
command: 'git push origin --tags -f && git push origin --all'
|
||||
command: 'git push origin --tags -f && git push origin --all'
|
||||
|
||||
watch:
|
||||
all:
|
||||
@ -124,35 +121,28 @@ module.exports = (grunt) ->
|
||||
compress:
|
||||
crx:
|
||||
options:
|
||||
archive: 'builds/4chan-X-Chrome.zip'
|
||||
archive: 'builds/<%= pkg.name %>.zip'
|
||||
level: 9
|
||||
pretty: true
|
||||
expand: true
|
||||
cwd: 'builds/crx/'
|
||||
src: '**'
|
||||
|
||||
expand: true
|
||||
flatten: true
|
||||
src: 'builds/crx/*'
|
||||
dest: '/'
|
||||
clean:
|
||||
builds: 'builds'
|
||||
tmpcrx: 'tmp-crx'
|
||||
tmpuserjs: 'tmp-userjs'
|
||||
builds: 'builds'
|
||||
tmpcrx: 'tmp-crx'
|
||||
tmpuserscript: 'tmp-userscript'
|
||||
|
||||
grunt.loadNpmTasks 'grunt-bump'
|
||||
grunt.loadNpmTasks 'grunt-concurrent'
|
||||
grunt.loadNpmTasks 'grunt-contrib-clean'
|
||||
grunt.loadNpmTasks 'grunt-contrib-coffee'
|
||||
grunt.loadNpmTasks 'grunt-contrib-compress'
|
||||
grunt.loadNpmTasks 'grunt-contrib-concat'
|
||||
grunt.loadNpmTasks 'grunt-contrib-copy'
|
||||
grunt.loadNpmTasks 'grunt-contrib-watch'
|
||||
grunt.loadNpmTasks 'grunt-shell'
|
||||
require('matchdep').filterDev('grunt-*').forEach grunt.loadNpmTasks
|
||||
|
||||
grunt.registerTask 'default', [
|
||||
'build'
|
||||
]
|
||||
|
||||
grunt.registerTask 'set-build', 'Set the build type variable', (type) ->
|
||||
pkg.type = type;
|
||||
pkg = grunt.config 'pkg'
|
||||
pkg.type = type
|
||||
grunt.config 'pkg', pkg
|
||||
grunt.log.ok 'pkg.type = %s', type
|
||||
|
||||
grunt.registerTask 'build', [
|
||||
@ -168,14 +158,6 @@ module.exports = (grunt) ->
|
||||
'clean:tmpcrx'
|
||||
]
|
||||
|
||||
grunt.registerTask 'build-userjs', [
|
||||
'set-build:userjs'
|
||||
'concat:coffee'
|
||||
'coffee:script'
|
||||
'concat:userjs'
|
||||
'clean:tmpuserjs'
|
||||
]
|
||||
|
||||
grunt.registerTask 'build-userscript', [
|
||||
'set-build:userscript'
|
||||
'concat:coffee'
|
||||
@ -185,40 +167,36 @@ module.exports = (grunt) ->
|
||||
]
|
||||
|
||||
grunt.registerTask 'release', [
|
||||
'default'
|
||||
'compress:crx'
|
||||
'build'
|
||||
'shell:commit'
|
||||
'shell:push'
|
||||
'build-crx'
|
||||
'compress:crx'
|
||||
]
|
||||
|
||||
grunt.registerTask 'patch', [
|
||||
'bump-only'
|
||||
'reloadPkg'
|
||||
grunt.registerTask 'patch', [
|
||||
'bump'
|
||||
'updcl:3'
|
||||
'release'
|
||||
]
|
||||
|
||||
grunt.registerTask 'minor', [
|
||||
'bump-only:minor'
|
||||
'reloadPkg'
|
||||
grunt.registerTask 'minor', [
|
||||
'bump:minor'
|
||||
'updcl:2'
|
||||
'release'
|
||||
]
|
||||
|
||||
grunt.registerTask 'major', [
|
||||
'bump-only:major'
|
||||
'reloadPkg'
|
||||
grunt.registerTask 'major', [
|
||||
'bump:major'
|
||||
'updcl:1'
|
||||
'release'
|
||||
]
|
||||
|
||||
grunt.registerTask 'reloadPkg', 'Reload the package', ->
|
||||
# Update the `pkg` object with the new version.
|
||||
pkg = grunt.file.readJSON('package.json')
|
||||
grunt.config.data.pkg = concatOptions.process.data = pkg
|
||||
grunt.log.ok('pkg reloaded.')
|
||||
grunt.registerTask 'updcl', 'Update the changelog', (headerLevel) ->
|
||||
headerPrefix = new Array(+headerLevel + 1).join '#'
|
||||
{version} = grunt.config 'pkg'
|
||||
today = grunt.template.today 'yyyy-mm-dd'
|
||||
changelog = grunt.file.read 'CHANGELOG.md'
|
||||
|
||||
grunt.file.write 'CHANGELOG.md', "#{headerPrefix} #{version} - *#{today}*\n\n#{changelog}"
|
||||
grunt.log.ok "Changelog updated for v#{version}."
|
||||
|
||||
grunt.registerTask 'updcl', 'Update the changelog', (i) ->
|
||||
# i is the number of #s for markdown.
|
||||
version = []
|
||||
version.length = +i + 1
|
||||
version = version.join('#') + ' v' + pkg.version + '\n*' + grunt.template.today('yyyy-mm-dd') + '*\n'
|
||||
grunt.file.write 'CHANGELOG.md', version + '\n' + grunt.file.read('CHANGELOG.md')
|
||||
grunt.log.ok 'Changelog updated for v' + pkg.version + '.'
|
||||
2
README.md
Normal file → Executable file
@ -41,4 +41,4 @@ Note: this is only used to release new 4chan X versions, and is **not** needed o
|
||||
|
||||
- Edit the CoffeeScript sources.
|
||||
- If the edits affect regular users, edit the changelog.
|
||||
- Open a pull request.
|
||||
- Open a pull request.
|
||||
|
||||
0
builds/4chan-X.js
Normal file → Executable file
0
builds/4chan-X.meta.js
Normal file → Executable file
2219
builds/4chan-X.user.js
Normal file → Executable file
0
builds/crx/icon128.png
Normal file → Executable file
|
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 196 B |
0
builds/crx/icon16.png
Normal file → Executable file
|
Before Width: | Height: | Size: 157 B After Width: | Height: | Size: 157 B |
0
builds/crx/icon48.png
Normal file → Executable file
|
Before Width: | Height: | Size: 204 B After Width: | Height: | Size: 204 B |
3
builds/crx/manifest.json
Normal file → Executable file
@ -15,7 +15,8 @@
|
||||
"run_at": "document_start"
|
||||
}],
|
||||
"homepage_url": "http://seaweedchan.github.io/4chan-x/",
|
||||
"minimum_chrome_version": "26",
|
||||
"minimum_chrome_version": "27",
|
||||
"minimum_opera_version": "15",
|
||||
"permissions": [
|
||||
"storage"
|
||||
]
|
||||
|
||||
2183
builds/crx/script.js
Normal file → Executable file
110
json/archives.json
Executable file
@ -0,0 +1,110 @@
|
||||
[{
|
||||
"uid": 0,
|
||||
"name": "Foolz",
|
||||
"domain": "archive.foolz.us",
|
||||
"http": true,
|
||||
"https": true,
|
||||
"software": "foolfuuka",
|
||||
"boards": ["a", "co", "gd", "jp", "m", "q", "sp", "tg", "tv", "v", "vg", "vp", "vr", "wsg"],
|
||||
"files": ["a", "gd", "jp", "m", "q", "tg", "vg", "vp", "vr", "wsg"]
|
||||
}, {
|
||||
"uid": 1,
|
||||
"name": "NSFW Foolz",
|
||||
"domain": "nsfw.foolz.us",
|
||||
"http": true,
|
||||
"https": true,
|
||||
"software": "foolfuuka",
|
||||
"boards": ["u"],
|
||||
"files": ["u"]
|
||||
}, {
|
||||
"uid": 2,
|
||||
"name": "The Dark Cave",
|
||||
"domain": "archive.thedarkcave.org",
|
||||
"http": true,
|
||||
"https": true,
|
||||
"software": "foolfuuka",
|
||||
"boards": ["c", "int", "out", "po"],
|
||||
"files": ["c", "po"]
|
||||
}, {
|
||||
"uid": 3,
|
||||
"name": "4plebs",
|
||||
"domain": "archive.4plebs.org",
|
||||
"http": true,
|
||||
"https": false,
|
||||
"software": "foolfuuka",
|
||||
"boards": ["hr", "tg", "tv", "x"],
|
||||
"files": ["hr", "tg", "tv", "x"]
|
||||
}, {
|
||||
"uid": 4,
|
||||
"name": "Nyafuu",
|
||||
"domain": "archive.nyafuu.org",
|
||||
"http": true,
|
||||
"https": true,
|
||||
"software": "foolfuuka",
|
||||
"boards": ["c", "w", "wg"],
|
||||
"files": ["c", "w", "wg"]
|
||||
}, {
|
||||
"uid": 11,
|
||||
"name": "Foolz a Shit",
|
||||
"domain": "archive.foolzashit.com",
|
||||
"http": true,
|
||||
"https": true,
|
||||
"software": "foolfuuka",
|
||||
"boards": ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "pol", "s", "s4s", "t", "trv", "y"],
|
||||
"files": ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"]
|
||||
}, {
|
||||
"uid": 12,
|
||||
"name": "fap archive",
|
||||
"domain": "fuuka.worldathleticproject.org",
|
||||
"http": true,
|
||||
"https": false,
|
||||
"software": "foolfuuka",
|
||||
"boards": ["b", "e", "h", "hc", "p", "s", "u"],
|
||||
"files": ["b", "e", "h", "hc", "p", "s", "u"]
|
||||
}, {
|
||||
"uid": 7,
|
||||
"name": "Install Gentoo",
|
||||
"domain": "archive.installgentoo.net",
|
||||
"http": false,
|
||||
"https": true,
|
||||
"software": "fuuka",
|
||||
"boards": ["diy", "g", "sci"],
|
||||
"files": []
|
||||
}, {
|
||||
"uid": 8,
|
||||
"name": "Rebecca Black Tech",
|
||||
"domain": "rbt.asia",
|
||||
"http": true,
|
||||
"https": true,
|
||||
"software": "fuuka",
|
||||
"boards": ["cgl", "g", "mu", "w"],
|
||||
"files": ["cgl", "g", "mu", "w"]
|
||||
}, {
|
||||
"uid": 9,
|
||||
"name": "Heinessen",
|
||||
"domain": "archive.heinessen.com",
|
||||
"http": true,
|
||||
"https": false,
|
||||
"software": "fuuka",
|
||||
"boards": ["an", "fit", "k", "mlp", "r9k", "toy"],
|
||||
"files": ["an", "fit", "k", "r9k", "toy"]
|
||||
}, {
|
||||
"uid": 10,
|
||||
"name": "warosu",
|
||||
"domain": "fuuka.warosu.org",
|
||||
"http": true,
|
||||
"https": true,
|
||||
"software": "fuuka",
|
||||
"boards": ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "q", "tg", "vr"],
|
||||
"files": ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "q", "tg", "vr"]
|
||||
}, {
|
||||
"uid": 13,
|
||||
"name": "Foolz Beta",
|
||||
"domain": "beta.foolz.us",
|
||||
"http": true,
|
||||
"https": true,
|
||||
"withCredentials": true,
|
||||
"software": "foolfuuka",
|
||||
"boards": ["a", "co", "gd", "h", "jp", "m", "mlp", "q", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"],
|
||||
"files": ["a", "gd", "h", "jp", "m", "q", "tg", "u", "vg", "vp", "vr", "wsg"]
|
||||
}]
|
||||
11
package.json
Normal file → Executable file
@ -22,14 +22,15 @@
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-bump": "~0.0.11",
|
||||
"grunt-concurrent": "~0.2.0",
|
||||
"grunt-contrib-clean": "~0.4.1",
|
||||
"grunt-concurrent": "~0.3.0",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-coffee": "~0.7.0",
|
||||
"grunt-contrib-compress": "~0.5.1",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-concat": "~0.3.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"grunt-contrib-watch": "~0.4.4",
|
||||
"grunt-shell": "~0.2.2"
|
||||
"grunt-contrib-watch": "~0.5.0",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"matchdep": "~0.1.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
201
src/Archive/Redirect.coffee
Normal file → Executable file
@ -1,117 +1,124 @@
|
||||
Redirect =
|
||||
thread: {}
|
||||
post: {}
|
||||
file: {}
|
||||
data:
|
||||
thread: {}
|
||||
post: {}
|
||||
file: {}
|
||||
|
||||
init: ->
|
||||
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
|
||||
if archive = Redirect.archives[id]
|
||||
boards = archive[type] or archive['boards']
|
||||
continue unless boards.contains boardID
|
||||
Redirect.data[type][boardID] = archive
|
||||
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
|
||||
unless boardID of Redirect.data.thread
|
||||
Redirect.data.thread[boardID] = archive
|
||||
unless boardID of Redirect.data.post or archive.software isnt 'foolfuuka'
|
||||
Redirect.data.post[boardID] = archive
|
||||
unless boardID of Redirect.data.file or !archive.files.contains boardID
|
||||
Redirect.data.file[boardID] = archive
|
||||
return
|
||||
|
||||
archives:
|
||||
'Foolz':
|
||||
'domain': 'archive.foolz.us'
|
||||
'http': false
|
||||
'https': true
|
||||
'software': 'foolfuuka'
|
||||
'boards': ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg']
|
||||
'files': ['a', 'gd', 'jp', 'm', 'q', 'tg', 'vg', 'vp', 'vr', 'wsg']
|
||||
|
||||
'NSFW Foolz':
|
||||
'domain': 'nsfw.foolz.us'
|
||||
'http': false
|
||||
'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':
|
||||
'domain': 'archive.4plebs.org'
|
||||
'http': true
|
||||
'software': 'foolfuuka'
|
||||
'boards': ['hr', 'tg', 'tv', 'x']
|
||||
'files': ['hr', 'tg', 'tv', 'x']
|
||||
domain: 'archive.4plebs.org'
|
||||
http: true
|
||||
software: 'foolfuuka'
|
||||
boards: ['hr', 'tg', 'tv', 'x']
|
||||
files: ['hr', 'tg', 'tv', 'x']
|
||||
|
||||
'Nyafuu':
|
||||
'domain': 'archive.nyafuu.org'
|
||||
'http': true
|
||||
'https': true
|
||||
'software': 'foolfuuka'
|
||||
'boards': ['c', 'w', 'wg']
|
||||
'files': ['c', 'w', 'wg']
|
||||
'fap archive':
|
||||
domain: 'fuuka.worldathleticproject.org'
|
||||
http: true
|
||||
https: false
|
||||
software: 'foolfuuka'
|
||||
boards: ['b', 'e', 'h', 'hc', 'p', 's', 'u']
|
||||
files: ['b', 'e', 'h', 'hc', 'p', 's', 'u']
|
||||
|
||||
'Foolz':
|
||||
domain: 'archive.foolz.us'
|
||||
http: false
|
||||
https: true
|
||||
software: 'foolfuuka'
|
||||
boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg']
|
||||
files: ['a', 'gd', 'jp', 'm', 'q', 'tg', 'vg', 'vp', 'vr', 'wsg']
|
||||
|
||||
'Foolz a Shit':
|
||||
'domain': 'archive.foolzashit.com'
|
||||
'http': true
|
||||
'https': true
|
||||
'software': 'foolfuuka'
|
||||
'boards': ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
|
||||
'files': ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
|
||||
domain: 'archive.foolzashit.com'
|
||||
http: true
|
||||
https: true
|
||||
software: 'foolfuuka'
|
||||
boards: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
|
||||
files: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
|
||||
|
||||
'World Athletic Project':
|
||||
'domain': 'fuuka.worldathleticproject.org'
|
||||
'http': true
|
||||
'https': false
|
||||
'software': 'foolfuuka'
|
||||
'boards': ['e', 'h', 'hc', 'p', 's', 'u']
|
||||
'files': ['e', 'h', 'hc', 'p', 's', 'u']
|
||||
|
||||
'Install Gentoo':
|
||||
'domain': 'archive.installgentoo.net'
|
||||
'http': false
|
||||
'https': true
|
||||
'software': 'fuuka'
|
||||
'boards': ['diy', 'g', 'sci']
|
||||
'files': []
|
||||
|
||||
'warosu':
|
||||
'domain': 'fuuka.warosu.org'
|
||||
'http': true
|
||||
'https': true
|
||||
'software': 'fuuka'
|
||||
'boards': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 'tg', 'vr']
|
||||
'files': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 'tg', 'vr']
|
||||
|
||||
'Rebecca Black Tech':
|
||||
'domain': 'rbt.asia'
|
||||
'http': true
|
||||
'https': true
|
||||
'software': 'fuuka'
|
||||
'boards': ['cgl', 'g', 'mu', 'w']
|
||||
'files': ['cgl', 'g', 'mu', 'w']
|
||||
'Foolz Beta':
|
||||
domain: 'beta.foolz.us'
|
||||
http: true
|
||||
https: true
|
||||
withCredentials: true
|
||||
software: 'foolfuuka'
|
||||
boards: ['a', 'co', 'gd', 'h', 'jp', 'm', 'mlp', 'q', 'sp', 'tg', 'tv', 'u', 'v', 'vg', 'vp', 'vr', 'wsg'],
|
||||
files: ['a', 'gd', 'h', 'jp', 'm', 'q', 'tg', 'u', 'vg', 'vp', 'vr', 'wsg']
|
||||
|
||||
'Heinessen':
|
||||
'domain': 'archive.heinessen.com'
|
||||
'http': true
|
||||
'software': 'fuuka'
|
||||
'boards': ['an', 'fit', 'k', 'mlp', 'r9k', 'toy']
|
||||
'files': ['an', 'k', 'toy']
|
||||
domain: 'archive.heinessen.com'
|
||||
http: true
|
||||
software: 'fuuka'
|
||||
boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy']
|
||||
files: ['an', 'k', 'toy']
|
||||
|
||||
'Install Gentoo':
|
||||
domain: 'archive.installgentoo.net'
|
||||
http: false
|
||||
https: true
|
||||
software: 'fuuka'
|
||||
boards: ['diy', 'g', 'sci']
|
||||
files: []
|
||||
|
||||
'NSFW Foolz':
|
||||
domain: 'nsfw.foolz.us'
|
||||
http: false
|
||||
https: true
|
||||
software: 'foolfuuka'
|
||||
boards: ['u']
|
||||
files: ['u']
|
||||
|
||||
'Nyafuu':
|
||||
domain: 'archive.nyafuu.org'
|
||||
http: true
|
||||
https: true
|
||||
software: 'foolfuuka'
|
||||
boards: ['c', 'w', 'wg']
|
||||
files: ['c', 'w', 'wg']
|
||||
|
||||
'Rebecca Black Tech':
|
||||
domain: 'rbt.asia'
|
||||
http: true
|
||||
https: true
|
||||
software: 'fuuka'
|
||||
boards: ['cgl', 'g', 'mu', 'w']
|
||||
files: ['cgl', 'g', 'mu', 'w']
|
||||
|
||||
'The Dark Cave':
|
||||
domain: 'archive.thedarkcave.org'
|
||||
http: true
|
||||
https: true
|
||||
software: 'foolfuuka'
|
||||
boards: ['c', 'int', 'out', 'po']
|
||||
files: ['c', 'po']
|
||||
|
||||
'warosu':
|
||||
domain: 'fuuka.warosu.org'
|
||||
http: true
|
||||
https: true
|
||||
software: 'fuuka'
|
||||
boards: ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 'tg', 'vr']
|
||||
files: ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 'tg', 'vr']
|
||||
|
||||
to: (dest, data) ->
|
||||
archive = (if dest is 'search' then Redirect.thread else Redirect[dest])[data.boardID]
|
||||
archive = (if dest is 'search' then Redirect.data.thread else Redirect.data[dest])[data.boardID]
|
||||
return '' unless archive
|
||||
Redirect[dest] archive, data
|
||||
|
||||
@ -144,7 +151,9 @@ Redirect =
|
||||
# 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}"
|
||||
URL = new String "#{protocol}#{archive.domain}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
|
||||
URL.archive = archive
|
||||
URL
|
||||
|
||||
file: (archive, {boardID, filename}) ->
|
||||
"#{Redirect.protocol archive}#{archive.domain}/#{boardID}/full_image/#{filename}"
|
||||
|
||||
0
src/Filtering/Anonymize.coffee
Normal file → Executable file
2
src/Filtering/Filter.coffee
Normal file → Executable file
@ -209,7 +209,7 @@ Filter =
|
||||
el = $.el 'a',
|
||||
href: 'javascript:;'
|
||||
textContent: text
|
||||
el.setAttribute 'data-type', type
|
||||
el.dataset.type = type
|
||||
$.on el, 'click', Filter.menu.makeFilter
|
||||
|
||||
return {
|
||||
|
||||
25
src/Filtering/PostHiding.coffee
Normal file → Executable file
@ -17,7 +17,7 @@ PostHiding =
|
||||
PostHiding.hide @, data.makeStub, data.hideRecursively
|
||||
else
|
||||
Recursive.apply PostHiding.hide, @, data.makeStub, true
|
||||
Recursive.add PostHiding.hide, @, data.makeStub, true
|
||||
Recursive.add PostHiding.hide, @, data.makeStub, true
|
||||
return unless Conf['Reply Hiding Buttons']
|
||||
$.replace $('.sideArrows', @nodes.root), PostHiding.makeButton @, 'hide'
|
||||
|
||||
@ -108,11 +108,12 @@ PostHiding =
|
||||
PostHiding.hide post, makeStub, replies
|
||||
else if replies
|
||||
Recursive.apply PostHiding.hide, post, makeStub, true
|
||||
Recursive.add PostHiding.hide, post, makeStub, true
|
||||
Recursive.add PostHiding.hide, post, makeStub, true
|
||||
else
|
||||
return
|
||||
PostHiding.saveHiddenState post, true, thisPost, makeStub, replies
|
||||
$.event 'CloseMenu'
|
||||
|
||||
show: ->
|
||||
parent = @parentNode
|
||||
thisPost = $('input[name=thisPost]', parent).checked
|
||||
@ -122,7 +123,7 @@ PostHiding =
|
||||
PostHiding.show post, replies
|
||||
else if replies
|
||||
Recursive.apply PostHiding.show, post, true
|
||||
Recursive.rm PostHiding.hide, post, true
|
||||
Recursive.rm PostHiding.hide, post, true
|
||||
else
|
||||
return
|
||||
if data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
|
||||
@ -158,10 +159,7 @@ PostHiding =
|
||||
|
||||
toggle: ->
|
||||
post = Get.postFromNode @
|
||||
if post.isHidden
|
||||
PostHiding.show post
|
||||
else
|
||||
PostHiding.hide post
|
||||
PostHiding[(if post.isHidden then 'show' else 'hide')] post
|
||||
PostHiding.saveHiddenState post, post.isHidden
|
||||
|
||||
hide: (post, makeStub=Conf['Stubs'], hideRecursively=Conf['Recursive Hiding']) ->
|
||||
@ -170,7 +168,7 @@ PostHiding =
|
||||
|
||||
if hideRecursively
|
||||
Recursive.apply PostHiding.hide, post, makeStub, true
|
||||
Recursive.add PostHiding.hide, post, makeStub, true
|
||||
Recursive.add PostHiding.hide, post, makeStub, true
|
||||
|
||||
for quotelink in Get.allQuotelinksLinkingTo post
|
||||
$.addClass quotelink, 'filtered'
|
||||
@ -184,13 +182,14 @@ PostHiding =
|
||||
if Conf['Anonymize']
|
||||
'Anonymous'
|
||||
else
|
||||
$('.nameBlock', post.nodes.info).textContent
|
||||
post.info.name
|
||||
$.add a, $.tn " #{postInfo}"
|
||||
post.nodes.stub = $.el 'div',
|
||||
className: 'stub'
|
||||
$.add post.nodes.stub, a
|
||||
if Conf['Menu']
|
||||
$.add post.nodes.stub, [$.tn(' '), Menu.makeButton post]
|
||||
$.add post.nodes.stub, unless Conf['Menu']
|
||||
a
|
||||
else
|
||||
[a, $.tn(' '), button = Menu.makeButton post]
|
||||
$.prepend post.nodes.root, post.nodes.stub
|
||||
|
||||
show: (post, showRecursively=Conf['Recursive Hiding']) ->
|
||||
@ -202,7 +201,7 @@ PostHiding =
|
||||
post.isHidden = false
|
||||
if showRecursively
|
||||
Recursive.apply PostHiding.show, post, true
|
||||
Recursive.rm PostHiding.hide, post
|
||||
Recursive.rm PostHiding.hide, post
|
||||
for quotelink in Get.allQuotelinksLinkingTo post
|
||||
$.rmClass quotelink, 'filtered'
|
||||
return
|
||||
0
src/Filtering/Recursive.coffee
Normal file → Executable file
59
src/Filtering/ThreadHiding.coffee
Normal file → Executable file
@ -71,11 +71,6 @@ ThreadHiding =
|
||||
makeStub = $.el 'label',
|
||||
innerHTML: "<input type=checkbox #{if Conf['Stubs'] then 'checked' else ''}> Make stub"
|
||||
|
||||
hideStubLink = $.el 'a',
|
||||
textContent: 'Hide stub'
|
||||
href: 'javascript:;'
|
||||
$.on hideStubLink, 'click', ThreadHiding.menu.hideStub
|
||||
|
||||
$.event 'AddMenuEntry',
|
||||
type: 'post'
|
||||
el: div
|
||||
@ -87,6 +82,27 @@ ThreadHiding =
|
||||
true
|
||||
subEntries: [el: apply; el: makeStub]
|
||||
|
||||
div = $.el 'a',
|
||||
className: 'show-thread-link'
|
||||
textContent: 'Show thread'
|
||||
href: 'javascript:;'
|
||||
$.on div, 'click', ThreadHiding.menu.show
|
||||
|
||||
$.event 'AddMenuEntry',
|
||||
type: 'post'
|
||||
el: div
|
||||
order: 20
|
||||
open: ({thread, isReply}) ->
|
||||
if isReply or !thread.isHidden
|
||||
return false
|
||||
ThreadHiding.menu.thread = thread
|
||||
true
|
||||
|
||||
hideStubLink = $.el 'a',
|
||||
textContent: 'Hide stub'
|
||||
href: 'javascript:;'
|
||||
$.on hideStubLink, 'click', ThreadHiding.menu.hideStub
|
||||
|
||||
$.event 'AddMenuEntry',
|
||||
type: 'post'
|
||||
el: hideStubLink
|
||||
@ -102,6 +118,13 @@ ThreadHiding =
|
||||
ThreadHiding.hide thread, makeStub
|
||||
ThreadHiding.saveHiddenState thread, makeStub
|
||||
$.event 'CloseMenu'
|
||||
|
||||
show: ->
|
||||
{thread} = ThreadHiding.menu
|
||||
ThreadHiding.show thread
|
||||
ThreadHiding.saveHiddenState thread
|
||||
$.event 'CloseMenu'
|
||||
|
||||
hideStub: ->
|
||||
{thread} = ThreadHiding.menu
|
||||
ThreadHiding.hide thread, false
|
||||
@ -113,7 +136,7 @@ ThreadHiding =
|
||||
className: "#{type}-thread-button"
|
||||
innerHTML: "<span class=fourchanx-link> #{if type is 'hide' then '-' else '+'} </span>"
|
||||
href: 'javascript:;'
|
||||
a.setAttribute 'data-fullid', thread.fullID
|
||||
a.dataset.fullID = thread.fullID
|
||||
$.on a, 'click', ThreadHiding.toggle
|
||||
a
|
||||
|
||||
@ -134,7 +157,7 @@ ThreadHiding =
|
||||
|
||||
toggle: (thread) ->
|
||||
unless thread instanceof Thread
|
||||
thread = g.threads[@dataset.fullid]
|
||||
thread = g.threads[@dataset.fullID]
|
||||
if thread.isHidden
|
||||
ThreadHiding.show thread
|
||||
else
|
||||
@ -150,24 +173,28 @@ ThreadHiding =
|
||||
threadRoot.hidden = threadRoot.nextElementSibling.hidden = true # <hr>
|
||||
return
|
||||
|
||||
numReplies = 0
|
||||
if span = $ '.summary', threadRoot
|
||||
numReplies = +span.textContent.match /\d+/
|
||||
numReplies += $$('.opContainer ~ .replyContainer', threadRoot).length
|
||||
numReplies = if numReplies is 1 then '1 reply' else "#{numReplies} replies"
|
||||
numReplies = (
|
||||
if span = $ '.summary', threadRoot
|
||||
+span.textContent.match /\d+/
|
||||
else
|
||||
0
|
||||
) +
|
||||
$$('.opContainer ~ .replyContainer', threadRoot).length
|
||||
numReplies = if numReplies is 1 then '1 reply' else "#{numReplies or 'No'} replies"
|
||||
opInfo =
|
||||
if Conf['Anonymize']
|
||||
'Anonymous'
|
||||
else
|
||||
$('.nameBlock', OP.nodes.info).textContent
|
||||
OP.info.name
|
||||
|
||||
a = ThreadHiding.makeButton thread, 'show'
|
||||
$.add a, $.tn " #{opInfo} (#{numReplies})"
|
||||
thread.stub = $.el 'div',
|
||||
className: 'stub'
|
||||
$.add thread.stub, a
|
||||
if Conf['Menu']
|
||||
$.add thread.stub, [$.tn(' '), Menu.makeButton OP]
|
||||
$.add thread.stub, unless Conf['Menu']
|
||||
a
|
||||
else
|
||||
[a, $.tn(' '), button = Menu.makeButton OP]
|
||||
$.prepend threadRoot, thread.stub
|
||||
|
||||
show: (thread) ->
|
||||
|
||||
115
src/General/Build.coffee
Normal file → Executable file
@ -27,6 +27,7 @@ Build =
|
||||
date: data.now
|
||||
dateUTC: data.time
|
||||
comment: data.com
|
||||
capReps: data.capcode_replies
|
||||
# thread status
|
||||
isSticky: !!data.sticky
|
||||
isClosed: !!data.closed
|
||||
@ -58,7 +59,7 @@ Build =
|
||||
postID, threadID, boardID
|
||||
name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC
|
||||
isSticky, isClosed
|
||||
comment
|
||||
comment, capReps
|
||||
file
|
||||
} = o
|
||||
isOP = postID is threadID
|
||||
@ -108,12 +109,12 @@ Build =
|
||||
capcodeStart = ''
|
||||
capcode = ''
|
||||
|
||||
flag =
|
||||
if flagCode
|
||||
" <img src='#{staticPath}country/#{if boardID is 'pol' then 'troll/' else ''}" +
|
||||
flagCode.toLowerCase() + ".gif' alt=#{flagCode} title='#{flagName}' class=countryFlag>"
|
||||
else
|
||||
''
|
||||
flag = unless flagCode
|
||||
''
|
||||
else if boardID is 'pol'
|
||||
" <img src='#{staticPath}country/troll/#{flagCode.toLowerCase()}.gif' alt=#{flagCode} title='#{flagName}' class=countryFlag>"
|
||||
else
|
||||
" <span title='#{flagName}' class='flag flag-#{flagCode.toLowerCase()}'></span>"
|
||||
|
||||
if file?.isDeleted
|
||||
fileHTML = if isOP
|
||||
@ -176,78 +177,44 @@ Build =
|
||||
else
|
||||
fileHTML = ''
|
||||
|
||||
tripcode =
|
||||
if tripcode
|
||||
" <span class=postertrip>#{tripcode}</span>"
|
||||
else
|
||||
''
|
||||
tripcode = if tripcode
|
||||
" <span class=postertrip>#{tripcode}</span>"
|
||||
else
|
||||
''
|
||||
|
||||
sticky =
|
||||
if isSticky
|
||||
" <img src=#{staticPath}sticky.gif alt=Sticky title=Sticky class=stickyIcon>"
|
||||
else
|
||||
''
|
||||
closed =
|
||||
if isClosed
|
||||
" <img src=#{staticPath}closed.gif alt=Closed title=Closed class=closedIcon>"
|
||||
else
|
||||
''
|
||||
sticky = if isSticky
|
||||
" <img src=#{staticPath}sticky.gif alt=Sticky title=Sticky class=stickyIcon>"
|
||||
else
|
||||
''
|
||||
closed = if isClosed
|
||||
" <img src=#{staticPath}closed.gif alt=Closed title=Closed class=closedIcon>"
|
||||
else
|
||||
''
|
||||
|
||||
capcodeReplies = ''
|
||||
if capReps
|
||||
generateCapcodeReplies = (capcodeType, array) ->
|
||||
"<span class=smaller><span class=bold>#{
|
||||
switch capcodeType
|
||||
when 'admin'
|
||||
'Administrator'
|
||||
when 'mod'
|
||||
'Moderator'
|
||||
when 'developer'
|
||||
'Developer'
|
||||
} Repl#{if array.length > 1 then 'ies' else 'y'}:</span> #{
|
||||
array.map (ID) ->
|
||||
"<a href='/#{boardID}/res/#{threadID}#p#{ID}' class=quotelink>>>#{ID}</a>"
|
||||
.join ' '
|
||||
}</span><br>"
|
||||
for capcodeType, array of capReps
|
||||
capcodeReplies += generateCapcodeReplies capcodeType, array
|
||||
capcodeReplies = "<br><br><span class=capcodeReplies>#{capcodeReplies}</span>"
|
||||
|
||||
container = $.el 'div',
|
||||
id: "pc#{postID}"
|
||||
className: "postContainer #{if isOP then 'op' else 'reply'}Container"
|
||||
innerHTML: \
|
||||
(if isOP then '' else "<div class=sideArrows id=sa#{postID}>>></div>") +
|
||||
"<div id=p#{postID} class='post #{if isOP then 'op' else 'reply'}#{
|
||||
if capcode is 'admin_highlight'
|
||||
' highlightPost'
|
||||
else
|
||||
''
|
||||
}'>" +
|
||||
|
||||
"<div class='postInfoM mobile' id=pim#{postID}>" +
|
||||
"<span class='nameBlock#{capcodeClass}'>" +
|
||||
"<span class=name>#{name or ''}</span>" + tripcode +
|
||||
capcodeStart + capcode + userID + flag + sticky + closed +
|
||||
"<br>#{subject}" +
|
||||
"</span><span class='dateTime postNum' data-utc=#{dateUTC}>#{date}" +
|
||||
"<a href=#{"/#{boardID}/res/#{threadID}#p#{postID}"}>No.</a>" +
|
||||
"<a href='#{
|
||||
if g.VIEW is 'thread' and g.THREADID is +threadID
|
||||
"javascript:quote(#{postID})"
|
||||
else
|
||||
"/#{boardID}/res/#{threadID}#q#{postID}"
|
||||
}'>#{postID}</a>" +
|
||||
'</span>' +
|
||||
'</div>' +
|
||||
|
||||
(if isOP then fileHTML else '') +
|
||||
|
||||
"<div class='postInfo desktop' id=pi#{postID}>" +
|
||||
"<input type=checkbox name=#{postID} value=delete> " +
|
||||
"#{subject} " +
|
||||
"<span class='nameBlock#{capcodeClass}'>" +
|
||||
emailStart +
|
||||
"<span class=name>#{name or ''}</span>" + tripcode +
|
||||
capcodeStart + emailEnd + capcode + userID + flag + sticky + closed +
|
||||
' </span> ' +
|
||||
"<span class=dateTime data-utc=#{dateUTC}>#{date}</span> " +
|
||||
"<span class='postNum desktop'>" +
|
||||
"<a href=#{"/#{boardID}/res/#{threadID}#p#{postID}"} title='Highlight this post'>No.</a>" +
|
||||
"<a href='#{
|
||||
if g.VIEW is 'thread' and g.THREADID is +threadID
|
||||
"javascript:quote(#{postID})"
|
||||
else
|
||||
"/#{boardID}/res/#{threadID}#q#{postID}"
|
||||
}' title='Quote this post'>#{postID}</a>" +
|
||||
'</span>' +
|
||||
'</div>' +
|
||||
|
||||
(if isOP then '' else fileHTML) +
|
||||
|
||||
"<blockquote class=postMessage id=m#{postID}>#{comment or ''}</blockquote> " +
|
||||
|
||||
'</div>'
|
||||
innerHTML: <%= grunt.file.read('src/General/html/Build/post.html').replace(/>\s+/g, '>').replace(/\s+</g, '<').replace(/\s+/g, ' ').trim() %>
|
||||
|
||||
for quote in $$ '.quotelink', container
|
||||
href = quote.getAttribute 'href'
|
||||
|
||||
12
src/General/Config.coffee
Normal file → Executable file
@ -53,6 +53,10 @@ Config =
|
||||
false
|
||||
'Add buttons to navigate to top / bottom of thread.'
|
||||
]
|
||||
'Show Dice Roll': [
|
||||
true
|
||||
'Show dice that were entered into the email field.'
|
||||
]
|
||||
<% if (type !== 'crx') { %>
|
||||
'Check for Updates': [
|
||||
true
|
||||
@ -641,6 +645,14 @@ q-replace
|
||||
'x'
|
||||
'Hide thread.'
|
||||
]
|
||||
'Previous Post Quoting You': [
|
||||
'Alt+Up'
|
||||
'Scroll to the previous post that quotes you.'
|
||||
]
|
||||
'Next Post Quoting You': [
|
||||
'Alt+Down'
|
||||
'Scroll to the next post that quotes you.'
|
||||
]
|
||||
|
||||
updater:
|
||||
checkbox:
|
||||
|
||||
78
src/General/Get.coffee
Normal file → Executable file
@ -18,8 +18,8 @@ Get =
|
||||
post = g.posts["#{boardID}.#{postID}"]
|
||||
if index then post.clones[index] else post
|
||||
postFromNode: (root) ->
|
||||
Get.postFromRoot $.x 'ancestor::div[contains(@class,"postContainer")][1]', root
|
||||
contextFromLink: (quotelink) ->
|
||||
Get.postFromRoot $.x '(ancestor::div[contains(@class,"postContainer")][1]|following::div[contains(@class,"postContainer")][1])', root
|
||||
contextFromNode: (quotelink) ->
|
||||
Get.postFromRoot $.x 'ancestor::div[parent::div[@class="thread"]][1]', quotelink
|
||||
postDataFromLink: (link) ->
|
||||
if link.hostname is 'boards.4chan.org'
|
||||
@ -28,9 +28,8 @@ Get =
|
||||
threadID = path[3]
|
||||
postID = link.hash[2..]
|
||||
else # resurrected quote
|
||||
boardID = link.dataset.boardid
|
||||
threadID = link.dataset.threadid or 0
|
||||
postID = link.dataset.postid
|
||||
{boardID, threadID, postID} = link.dataset
|
||||
threadID or= 0
|
||||
return {
|
||||
boardID: boardID
|
||||
threadID: +threadID
|
||||
@ -72,8 +71,10 @@ Get =
|
||||
$.cache "//api.4chan.org/#{boardID}/res/#{threadID}.json", ->
|
||||
Get.fetchedPost @, boardID, threadID, postID, root, context
|
||||
else if url = Redirect.to 'post', {boardID, postID}
|
||||
$.cache url, ->
|
||||
Get.archivedPost @, boardID, postID, root, context
|
||||
$.cache url,
|
||||
-> Get.archivedPost @, boardID, postID, root, context
|
||||
,
|
||||
withCredentials: url.archive.withCredentials
|
||||
insert: (post, root, context) ->
|
||||
# Stop here if the container has been removed while loading.
|
||||
return unless root.parentNode
|
||||
@ -98,8 +99,10 @@ Get =
|
||||
unless [200, 304].contains status
|
||||
# The thread can die by the time we check a quote.
|
||||
if url = Redirect.to 'post', {boardID, postID}
|
||||
$.cache url, ->
|
||||
Get.archivedPost @, boardID, postID, root, context
|
||||
$.cache url,
|
||||
-> Get.archivedPost @, boardID, postID, root, context
|
||||
,
|
||||
withCredentials: url.archive.withCredentials
|
||||
else
|
||||
$.addClass root, 'warning'
|
||||
root.textContent =
|
||||
@ -116,8 +119,10 @@ Get =
|
||||
if post.no > postID
|
||||
# The post can be deleted by the time we check a quote.
|
||||
if url = Redirect.to 'post', {boardID, postID}
|
||||
$.cache url, ->
|
||||
Get.archivedPost @, boardID, postID, root, context
|
||||
$.cache url,
|
||||
-> Get.archivedPost @, boardID, postID, root, context
|
||||
,
|
||||
withCredentials: url.archive.withCredentials
|
||||
else
|
||||
$.addClass root, 'warning'
|
||||
root.textContent = "Post No.#{postID} was not found."
|
||||
@ -154,30 +159,7 @@ Get =
|
||||
| \[/?code\]
|
||||
| \[/?moot\]
|
||||
| \[/?banned\]
|
||||
///g, (text) ->
|
||||
switch text
|
||||
when '\n'
|
||||
'<br>'
|
||||
when '[b]'
|
||||
'<b>'
|
||||
when '[/b]'
|
||||
'</b>'
|
||||
when '[spoiler]'
|
||||
'<s>'
|
||||
when '[/spoiler]'
|
||||
'</s>'
|
||||
when '[code]'
|
||||
'<pre class=prettyprint>'
|
||||
when '[/code]'
|
||||
'</pre>'
|
||||
when '[moot]'
|
||||
'<div style="padding:5px;margin-left:.5em;border-color:#faa;border:2px dashed rgba(255,0,0,.1);border-radius:2px">'
|
||||
when '[/moot]'
|
||||
'</div>'
|
||||
when '[banned]'
|
||||
'<b style="color: red;">'
|
||||
when '[/banned]'
|
||||
'</b>'
|
||||
///g, Get.parseMarkup
|
||||
|
||||
comment = bq.innerHTML
|
||||
# greentext
|
||||
@ -185,7 +167,7 @@ Get =
|
||||
# quotes
|
||||
.replace /((>){2}(>\/[a-z\d]+\/)?\d+)/g, '<span class=deadlink>$1</span>'
|
||||
|
||||
threadID = data.thread_num
|
||||
threadID = +data.thread_num
|
||||
o =
|
||||
# id
|
||||
postID: "#{postID}"
|
||||
@ -229,3 +211,27 @@ Get =
|
||||
isArchived: true
|
||||
Main.callbackNodes Post, [post]
|
||||
Get.insert post, root, context
|
||||
parseMarkup: (text) ->
|
||||
switch text
|
||||
when '\n'
|
||||
'<br>'
|
||||
when '[b]'
|
||||
'<b>'
|
||||
when '[/b]'
|
||||
'</b>'
|
||||
when '[spoiler]'
|
||||
'<s>'
|
||||
when '[/spoiler]'
|
||||
'</s>'
|
||||
when '[code]'
|
||||
'<pre class=prettyprint>'
|
||||
when '[/code]'
|
||||
'</pre>'
|
||||
when '[moot]'
|
||||
'<div style="padding:5px;margin-left:.5em;border-color:#faa;border:2px dashed rgba(255,0,0,.1);border-radius:2px">'
|
||||
when '[/moot]'
|
||||
'</div>'
|
||||
when '[banned]'
|
||||
'<b style="color: red;">'
|
||||
when '[/banned]'
|
||||
'</b>'
|
||||
|
||||
6
src/General/Globals.coffee
Normal file → Executable file
@ -1,9 +1,3 @@
|
||||
<% if (type === 'userjs') { %>
|
||||
# Opera doesn't support the @match metadata key,
|
||||
# return 4chan X here if we're not on 4chan.
|
||||
return unless /^(boards|images|sys)\.4chan\.org$/.test location.hostname
|
||||
<% } %>
|
||||
|
||||
Conf = {}
|
||||
c = console
|
||||
d = document
|
||||
|
||||
15
src/General/Header.coffee
Normal file → Executable file
@ -70,7 +70,7 @@ Header =
|
||||
return unless Main.isThisPageLegit()
|
||||
# Wait for #boardNavMobile instead of #boardNavDesktop,
|
||||
# it might be incomplete otherwise.
|
||||
$.asap (-> $.id('boardNavMobile') or d.readyState in ['interactive', 'complete']), Header.setBoardList
|
||||
$.asap (-> $.id('boardNavMobile') or d.readyState isnt 'loading'), Header.setBoardList
|
||||
$.prepend d.body, @bar
|
||||
$.add d.body, Header.hover
|
||||
@setBarPosition Conf['Bottom Header']
|
||||
@ -131,7 +131,7 @@ Header =
|
||||
list = $ '#custom-board-list', Header.bar
|
||||
$.rmAll list
|
||||
return unless text
|
||||
as = $$('#full-board-list a', Header.bar)
|
||||
as = $$ '#full-board-list a[title]', Header.bar
|
||||
nodes = text.match(/[\w@]+((-(all|title|replace|full|index|catalog|url:"[^"]+[^"]"|text:"[^"]+")|\,"[^"]+[^"]"))*|[^\w@]+/g).map (t) ->
|
||||
if /^[^\w@]/.test t
|
||||
return $.tn t
|
||||
@ -166,10 +166,13 @@ Header =
|
||||
a.textContent
|
||||
|
||||
if m = t.match /-(index|catalog)/
|
||||
a.setAttribute 'data-only', m[1]
|
||||
a.dataset.only = m[1]
|
||||
a.href = "//boards.4chan.org/#{board}/"
|
||||
if m[1] is 'catalog'
|
||||
a.href += 'catalog'
|
||||
if Conf['External Catalog']
|
||||
a.href = CatalogLinks.external board
|
||||
else
|
||||
a.href += 'catalog'
|
||||
$.addClass a, 'catalog'
|
||||
|
||||
$.addClass a, 'navSmall' if board is '@'
|
||||
@ -302,8 +305,8 @@ Header =
|
||||
{top} = post.getBoundingClientRect()
|
||||
if Conf['Fixed Header'] and not Conf['Bottom Header']
|
||||
headRect = Header.bar.getBoundingClientRect()
|
||||
top += - headRect.top - headRect.height
|
||||
<% if (type === 'crx') { %>d.body<% } else { %>doc<% } %>.scrollTop += top
|
||||
top -= headRect.top + headRect.height
|
||||
window.scrollBy 0, top
|
||||
|
||||
addShortcut: (el) ->
|
||||
shortcut = $.el 'span',
|
||||
|
||||
143
src/General/Main.coffee
Normal file → Executable file
@ -15,11 +15,12 @@ Main =
|
||||
for db in DataBoards
|
||||
Conf[db] = boards: {}
|
||||
Conf['selectedArchives'] = {}
|
||||
Conf['CachedTitles'] = []
|
||||
|
||||
$.get Conf, Main.initFeatures
|
||||
|
||||
$.on d, '4chanMainInit', Main.initStyle
|
||||
$.asap (-> d.head and $('link[rel="shortcut icon"]', d.head) or d.readyState in ['interactive', 'complete']),
|
||||
$.asap (-> d.head and $('link[rel="shortcut icon"]', d.head) or d.readyState isnt 'loading'),
|
||||
Main.initStyle
|
||||
|
||||
initFeatures: (items) ->
|
||||
@ -47,7 +48,7 @@ Main =
|
||||
return
|
||||
when 'images.4chan.org'
|
||||
$.ready ->
|
||||
if Conf['404 Redirect'] and d.title is '4chan - 404 Not Found'
|
||||
if Conf['404 Redirect'] and ['4chan - Temporarily Offline', '4chan - 404 Not Found'].contains d.title
|
||||
Redirect.init()
|
||||
pathname = location.pathname.split '/'
|
||||
URL = Redirect.to 'file',
|
||||
@ -72,61 +73,62 @@ Main =
|
||||
# c.time 'All initializations'
|
||||
|
||||
init
|
||||
'Polyfill': Polyfill
|
||||
'Redirect': Redirect
|
||||
'Header': Header
|
||||
'Catalog Links': CatalogLinks
|
||||
'Settings': Settings
|
||||
'Announcement Hiding': PSAHiding
|
||||
'Fourchan thingies': Fourchan
|
||||
'Emoji': Emoji
|
||||
'Color User IDs': IDColor
|
||||
'Remove Spoilers': RemoveSpoilers
|
||||
'Custom CSS': CustomCSS
|
||||
'Linkify': Linkify
|
||||
'Resurrect Quotes': Quotify
|
||||
'Filter': Filter
|
||||
'Thread Hiding Buttons': ThreadHiding
|
||||
'Reply Hiding Buttons': PostHiding
|
||||
'Recursive': Recursive
|
||||
'Strike-through Quotes': QuoteStrikeThrough
|
||||
'Quick Reply': QR
|
||||
'Menu': Menu
|
||||
'Report Link': ReportLink
|
||||
'Thread Hiding (Menu)': ThreadHiding.menu
|
||||
'Reply Hiding (Menu)': PostHiding.menu
|
||||
'Delete Link': DeleteLink
|
||||
'Filter (Menu)': Filter.menu
|
||||
'Download Link': DownloadLink
|
||||
'Archive Link': ArchiveLink
|
||||
'Quote Inlining': QuoteInline
|
||||
'Quote Previewing': QuotePreview
|
||||
'Quote Backlinks': QuoteBacklink
|
||||
'Mark Quotes of You': QuoteYou
|
||||
'Mark OP Quotes': QuoteOP
|
||||
'Mark Cross-thread Quotes': QuoteCT
|
||||
'Anonymize': Anonymize
|
||||
'Time Formatting': Time
|
||||
'Relative Post Dates': RelativeDates
|
||||
'File Info Formatting': FileInfo
|
||||
'Fappe Tyme': FappeTyme
|
||||
'Sauce': Sauce
|
||||
'Image Expansion': ImageExpand
|
||||
'Image Expansion (Menu)': ImageExpand.menu
|
||||
'Reveal Spoilers': RevealSpoilers
|
||||
'Image Loading': ImageLoader
|
||||
'Image Hover': ImageHover
|
||||
'Comment Expansion': ExpandComment
|
||||
'Thread Expansion': ExpandThread
|
||||
'Thread Excerpt': ThreadExcerpt
|
||||
'Favicon': Favicon
|
||||
'Unread': Unread
|
||||
'Quote Threading': QuoteThreading
|
||||
'Thread Stats': ThreadStats
|
||||
'Thread Updater': ThreadUpdater
|
||||
'Thread Watcher': ThreadWatcher
|
||||
'Index Navigation': Nav
|
||||
'Keybinds': Keybinds
|
||||
'Polyfill': Polyfill
|
||||
'Redirect': Redirect
|
||||
'Header': Header
|
||||
'Catalog Links': CatalogLinks
|
||||
'Settings': Settings
|
||||
'Announcement Hiding': PSAHiding
|
||||
'Fourchan thingies': Fourchan
|
||||
'Emoji': Emoji
|
||||
'Color User IDs': IDColor
|
||||
'Reveal Spoilers': RemoveSpoilers
|
||||
'Custom CSS': CustomCSS
|
||||
'Linkify': Linkify
|
||||
'Resurrect Quotes': Quotify
|
||||
'Filter': Filter
|
||||
'Thread Hiding Buttons': ThreadHiding
|
||||
'Reply Hiding Buttons': PostHiding
|
||||
'Recursive': Recursive
|
||||
'Strike-through Quotes': QuoteStrikeThrough
|
||||
'Quick Reply': QR
|
||||
'Menu': Menu
|
||||
'Report Link': ReportLink
|
||||
'Thread Hiding (Menu)': ThreadHiding.menu
|
||||
'Reply Hiding (Menu)': PostHiding.menu
|
||||
'Delete Link': DeleteLink
|
||||
'Filter (Menu)': Filter.menu
|
||||
'Download Link': DownloadLink
|
||||
'Archive Link': ArchiveLink
|
||||
'Quote Inlining': QuoteInline
|
||||
'Quote Previewing': QuotePreview
|
||||
'Quote Backlinks': QuoteBacklink
|
||||
'Mark Quotes of You': QuoteYou
|
||||
'Mark OP Quotes': QuoteOP
|
||||
'Mark Cross-thread Quotes': QuoteCT
|
||||
'Anonymize': Anonymize
|
||||
'Time Formatting': Time
|
||||
'Relative Post Dates': RelativeDates
|
||||
'File Info Formatting': FileInfo
|
||||
'Fappe Tyme': FappeTyme
|
||||
'Sauce': Sauce
|
||||
'Image Expansion': ImageExpand
|
||||
'Image Expansion (Menu)': ImageExpand.menu
|
||||
'Reveal Spoiler Thumbnails': RevealSpoilers
|
||||
'Image Loading': ImageLoader
|
||||
'Image Hover': ImageHover
|
||||
'Comment Expansion': ExpandComment
|
||||
'Thread Expansion': ExpandThread
|
||||
'Thread Excerpt': ThreadExcerpt
|
||||
'Favicon': Favicon
|
||||
'Unread': Unread
|
||||
'Quote Threading': QuoteThreading
|
||||
'Thread Stats': ThreadStats
|
||||
'Thread Updater': ThreadUpdater
|
||||
'Thread Watcher': ThreadWatcher
|
||||
'Index Navigation': Nav
|
||||
'Keybinds': Keybinds
|
||||
'Show Dice Roll': Dice
|
||||
|
||||
# c.timeEnd 'All initializations'
|
||||
|
||||
@ -139,10 +141,7 @@ Main =
|
||||
# disable the mobile layout
|
||||
$('link[href*=mobile]', d.head)?.disabled = true
|
||||
<% if (type === 'crx') { %>
|
||||
$.addClass doc, 'webkit'
|
||||
$.addClass doc, 'blink'
|
||||
<% } else if (type === 'userjs') { %>
|
||||
$.addClass doc, 'presto'
|
||||
<% } else { %>
|
||||
$.addClass doc, 'gecko'
|
||||
<% } %>
|
||||
@ -166,13 +165,9 @@ Main =
|
||||
$.addClass doc, style
|
||||
setStyle()
|
||||
return unless mainStyleSheet
|
||||
if window.MutationObserver
|
||||
observer = new MutationObserver setStyle
|
||||
observer.observe mainStyleSheet,
|
||||
attributes: true
|
||||
attributeFilter: ['href']
|
||||
else
|
||||
$.on mainStyleSheet, 'DOMAttrModified', setStyle
|
||||
new MutationObserver(setStyle).observe mainStyleSheet,
|
||||
attributes: true
|
||||
attributeFilter: ['href']
|
||||
|
||||
initReady: ->
|
||||
if d.title is '4chan - 404 Not Found'
|
||||
@ -192,20 +187,18 @@ Main =
|
||||
threads = []
|
||||
posts = []
|
||||
|
||||
for boardChild in board.children
|
||||
continue unless $.hasClass boardChild, 'thread'
|
||||
thread = new Thread boardChild.id[1..], g.BOARD
|
||||
for threadRoot in $$ '.board > .thread', board
|
||||
thread = new Thread +threadRoot.id[1..], g.BOARD
|
||||
threads.push thread
|
||||
for threadChild in boardChild.children
|
||||
continue unless $.hasClass threadChild, 'postContainer'
|
||||
for postRoot in $$ '.thread > .postContainer', threadRoot
|
||||
try
|
||||
posts.push new Post threadChild, thread, g.BOARD
|
||||
posts.push new Post postRoot, thread, g.BOARD
|
||||
catch err
|
||||
# Skip posts that we failed to parse.
|
||||
unless errors
|
||||
errors = []
|
||||
errors.push
|
||||
message: "Parsing of Post No.#{threadChild.id.match(/\d+/)} failed. Post will be skipped."
|
||||
message: "Parsing of Post No.#{postRoot.id.match(/\d+/)} failed. Post will be skipped."
|
||||
error: err
|
||||
Main.handleErrors errors if errors
|
||||
|
||||
@ -373,7 +366,7 @@ Main =
|
||||
unless 'thisPageIsLegit' of Main
|
||||
Main.thisPageIsLegit = location.hostname is 'boards.4chan.org' and
|
||||
!$('link[href*="favicon-status.ico"]', d.head) and
|
||||
d.title not in ['4chan - Temporarily Offline', '4chan - Error']
|
||||
d.title not in ['4chan - Temporarily Offline', '4chan - Error', '504 Gateway Time-out']
|
||||
Main.thisPageIsLegit
|
||||
|
||||
css: """
|
||||
|
||||
4
src/General/Settings.coffee
Normal file → Executable file
@ -262,8 +262,7 @@ Settings =
|
||||
'%board'
|
||||
else
|
||||
c
|
||||
for key, val of Config.hotkeys
|
||||
continue unless key of data.Conf
|
||||
for key, val of Config.hotkeys when key of data.Conf
|
||||
data.Conf[key] = data.Conf[key].replace(/ctrl|alt|meta/g, (s) -> "#{s[0].toUpperCase()}#{s[1..]}").replace /(^|.+\+)[A-Z]$/g, (s) ->
|
||||
"Shift+#{s[0...-1]}#{s[-1..].toLowerCase()}"
|
||||
data.Conf.WatchedThreads = data.WatchedThreads
|
||||
@ -467,7 +466,6 @@ Settings =
|
||||
$.cb.checked.call @
|
||||
usercss: ->
|
||||
CustomCSS.update()
|
||||
|
||||
keybinds: (section) ->
|
||||
section.innerHTML = """
|
||||
<%= grunt.file.read('src/General/html/Settings/Keybinds.html').replace(/>\s+</g, '><').trim() %>
|
||||
|
||||
25
src/General/UI.coffee
Normal file → Executable file
@ -70,8 +70,8 @@ UI = do ->
|
||||
# Position
|
||||
mRect = menu.getBoundingClientRect()
|
||||
bRect = button.getBoundingClientRect()
|
||||
bTop = doc.scrollTop + d.body.scrollTop + bRect.top
|
||||
bLeft = doc.scrollLeft + d.body.scrollLeft + bRect.left
|
||||
bTop = window.scrollY + bRect.top
|
||||
bLeft = window.scrollX + bRect.left
|
||||
cHeight = doc.clientHeight
|
||||
cWidth = doc.clientWidth
|
||||
[top, bottom] = if bRect.top + bRect.height + mRect.height < cHeight
|
||||
@ -306,12 +306,12 @@ UI = do ->
|
||||
|
||||
hoverstart = ({root, el, latestEvent, endEvents, asapTest, cb}) ->
|
||||
o = {
|
||||
root: root
|
||||
el: el
|
||||
style: el.style
|
||||
cb: cb
|
||||
endEvents: endEvents
|
||||
latestEvent: latestEvent
|
||||
root
|
||||
el
|
||||
style: el.style
|
||||
cb
|
||||
endEvents
|
||||
latestEvent
|
||||
clientHeight: doc.clientHeight
|
||||
clientWidth: doc.clientWidth
|
||||
}
|
||||
@ -327,6 +327,11 @@ UI = do ->
|
||||
if $.x 'ancestor::div[contains(@class,"inline")][1]', root
|
||||
$.on d, 'keydown', o.hoverend
|
||||
$.on root, 'mousemove', o.hover
|
||||
<% if (type === 'userscript') { %>
|
||||
# Workaround for https://github.com/MayhemYDG/4chan-x/issues/377
|
||||
o.workaround = (e) -> o.hoverend() unless root.contains e.target
|
||||
$.on doc, 'mousemove', o.workaround
|
||||
<% } %>
|
||||
|
||||
hover = (e) ->
|
||||
@latestEvent = e
|
||||
@ -357,6 +362,10 @@ UI = do ->
|
||||
$.off @root, @endEvents, @hoverend
|
||||
$.off d, 'keydown', @hoverend
|
||||
$.off @root, 'mousemove', @hover
|
||||
<% if (type === 'userscript') { %>
|
||||
# Workaround for https://github.com/MayhemYDG/4chan-x/issues/377
|
||||
$.off doc, 'mousemove', @workaround
|
||||
<% } %>
|
||||
@cb.call @ if @cb
|
||||
|
||||
|
||||
|
||||
0
src/General/audio/beep.wav
Normal file → Executable file
0
src/General/css/burichan.css
Normal file → Executable file
0
src/General/css/futaba.css
Normal file → Executable file
0
src/General/css/photon.css
Normal file → Executable file
34
src/General/css/style.css
Normal file → Executable file
@ -304,10 +304,8 @@ a {
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 15px rgba(0, 0, 0, .15);
|
||||
height: 600px;
|
||||
min-height: 0;
|
||||
max-height: 100%;
|
||||
width: 900px;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
margin: auto;
|
||||
padding: 3px;
|
||||
@ -315,7 +313,6 @@ a {
|
||||
left: 50%;
|
||||
-moz-transform: translate(-50%, -50%);
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
-o-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
#fourchanx-settings > nav {
|
||||
@ -392,14 +389,17 @@ a {
|
||||
position: absolute;
|
||||
}
|
||||
.section-advanced .note {
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.section-advanced .note code {
|
||||
font-style: normal;
|
||||
font-size: 11px;
|
||||
}
|
||||
.section-keybinds .field {
|
||||
font-family: monospace;
|
||||
}
|
||||
#fourchanx-settings fieldset {
|
||||
border: 1px solid;
|
||||
border-radius: 3px;
|
||||
@ -533,7 +533,8 @@ a.hide-announcement {
|
||||
.deadlink {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.backlink.deadlink:not(.forwardlink), .quotelink.deadlink:not(.forwardlink) {
|
||||
.backlink.deadlink:not(.forwardlink),
|
||||
.quotelink.deadlink:not(.forwardlink) {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
.inlined {
|
||||
@ -576,16 +577,14 @@ a.hide-announcement {
|
||||
padding: 2px 2px 5px;
|
||||
}
|
||||
#qp img {
|
||||
max-height: 300px;
|
||||
max-width: 500px;
|
||||
max-height: 80vh;
|
||||
max-width: 50vw;
|
||||
}
|
||||
.qphl {
|
||||
outline: 2px solid rgba(216, 94, 49, .7);
|
||||
}
|
||||
:root.highlight-own .yourPost>.reply,
|
||||
:root.highlight-you .quotesYou>.reply {
|
||||
:root.highlight-own .yourPost > .reply,
|
||||
:root.highlight-you .quotesYou > .reply {
|
||||
border-left: 2px solid rgba(221,0,0,.5);
|
||||
}
|
||||
/* Quote Threading */
|
||||
@ -613,8 +612,7 @@ a.hide-announcement {
|
||||
:root.fit-width .full-image {
|
||||
max-width: 100%;
|
||||
}
|
||||
:root.gecko.fit-width .full-image,
|
||||
:root.presto.fit-width .full-image {
|
||||
:root.gecko.fit-width .full-image {
|
||||
width: 100%;
|
||||
}
|
||||
#ihover {
|
||||
@ -671,7 +669,10 @@ a.hide-announcement {
|
||||
#file-n-submit:not(.has-file) #qr-filerm {
|
||||
display: none;
|
||||
}
|
||||
#qr select, #dump-button, .remove, .captcha-img {
|
||||
#qr select,
|
||||
#dump-button,
|
||||
.remove,
|
||||
.captcha-img {
|
||||
cursor: pointer;
|
||||
}
|
||||
#qr {
|
||||
@ -728,7 +729,8 @@ a.hide-announcement {
|
||||
height: 9em;
|
||||
}
|
||||
input.field.tripped:not(:hover):not(:focus) {
|
||||
color: transparent !important; text-shadow: none !important;
|
||||
color: transparent !important;
|
||||
text-shadow: none !important;
|
||||
}
|
||||
#qr textarea {
|
||||
resize: both;
|
||||
@ -910,7 +912,9 @@ a:only-of-type > .remove {
|
||||
.qr-preview > label {
|
||||
background: rgba(0,0,0,.5);
|
||||
color: #fff;
|
||||
right: 0; bottom: 0; left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
0
src/General/css/tomorrow.css
Normal file → Executable file
0
src/General/css/yotsuba-b.css
Normal file → Executable file
0
src/General/css/yotsuba.css
Normal file → Executable file
59
src/General/html/Build/post.html
Executable file
@ -0,0 +1,59 @@
|
||||
"""#{if isOP then '' else "<div class=sideArrows id=sa#{postID}>>></div>"}
|
||||
<div id=p#{postID} class='post #{if isOP then 'op' else 'reply'}#{
|
||||
if capcode is 'admin_highlight' then
|
||||
' highlightPost'
|
||||
else
|
||||
''
|
||||
}'>
|
||||
|
||||
<div class='postInfoM mobile' id=pim#{postID}>
|
||||
<span class='nameBlock#{capcodeClass}'>
|
||||
<span class=name>
|
||||
#{name or ''}
|
||||
</span>
|
||||
#{tripcode + capcodeStart + capcode + userID + flag + sticky + closed}
|
||||
<br>#{subject}
|
||||
</span>
|
||||
<span class='dateTime postNum' data-utc=#{dateUTC}>
|
||||
#{date}
|
||||
<a href=#{"/#{boardID}/res/#{threadID}#p#{postID}"}>
|
||||
No.
|
||||
</a>
|
||||
<a href='#{
|
||||
if g.VIEW is 'thread' and g.THREADID is +threadID then
|
||||
"javascript:quote(#{postID})"
|
||||
else
|
||||
"/#{boardID}/res/#{threadID}#q#{postID}"
|
||||
}'>
|
||||
#{postID}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
#{if isOP then fileHTML else ''}
|
||||
|
||||
<div class='postInfo desktop' id=pi#{postID}>
|
||||
<input type=checkbox name=#{postID} value=delete>
|
||||
#{subject}
|
||||
<span class='nameBlock#{capcodeClass}'>
|
||||
#{emailStart}
|
||||
<span class=name>#{name or ''}</span>
|
||||
#{tripcode + capcodeStart + emailEnd + capcode + userID + flag + sticky + closed}
|
||||
</span>#{" "}
|
||||
<span class=dateTime data-utc=#{dateUTC}>#{date}</span>#{" "}
|
||||
<span class='postNum desktop'>
|
||||
<a href=#{"/#{boardID}/res/#{threadID}#p#{postID}"} title='Highlight this post'>No.</a>
|
||||
<a href='#{
|
||||
if g.VIEW is 'thread' and g.THREADID is +threadID then
|
||||
"javascript:quote(#{postID})"
|
||||
else
|
||||
"/#{boardID}/res/#{threadID}#q#{postID}"
|
||||
}' title='Quote this post'>#{postID}</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
#{if isOP then '' else fileHTML}
|
||||
|
||||
<blockquote class=postMessage id=m#{postID}>#{comment or ''}#{capcodeReplies}</blockquote>#{" "}
|
||||
|
||||
</div>"""
|
||||
0
src/General/html/Features/QuickReply.html
Normal file → Executable file
0
src/General/html/Settings/Advanced.html
Normal file → Executable file
4
src/General/html/Settings/Filter-guide.html
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
<div class=warning #{if Conf['Filter'] then 'hidden' else ''}><code>Filter</code> is disabled.</div>
|
||||
<p>
|
||||
Use <a href=https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions>regular expressions</a>, one per line.<br>
|
||||
Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">regular expressions</a>, one per line.<br>
|
||||
Lines starting with a <code>#</code> will be ignored.<br>
|
||||
For example, <code>/weeaboo/i</code> will filter posts containing the string `<code>weeaboo</code>`, case-insensitive.<br>
|
||||
MD5 filtering uses exact string matching, not regular expressions.
|
||||
@ -26,4 +26,4 @@
|
||||
Highlighted OPs will have their threads put on top of board pages by default.<br>
|
||||
For example: <code>top:yes;</code> or <code>top:no;</code>.
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
0
src/General/html/Settings/Filter-select.html
Normal file → Executable file
0
src/General/html/Settings/Keybinds.html
Normal file → Executable file
0
src/General/html/Settings/Sauce.html
Normal file → Executable file
0
src/General/html/Settings/Settings.html
Normal file → Executable file
0
src/General/img/changelog/1.1.18.png
Normal file → Executable file
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
0
src/General/img/changelog/1.2.0.png
Normal file → Executable file
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
0
src/General/img/emoji/SS-sage.png
Normal file → Executable file
|
Before Width: | Height: | Size: 576 B After Width: | Height: | Size: 576 B |
0
src/General/img/emoji/appchan-sage.png
Normal file → Executable file
|
Before Width: | Height: | Size: 659 B After Width: | Height: | Size: 659 B |
0
src/General/img/emoji/arch.png
Normal file → Executable file
|
Before Width: | Height: | Size: 567 B After Width: | Height: | Size: 567 B |
0
src/General/img/emoji/baka.png
Normal file → Executable file
|
Before Width: | Height: | Size: 987 B After Width: | Height: | Size: 987 B |
0
src/General/img/emoji/centos.png
Normal file → Executable file
|
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 858 B |
0
src/General/img/emoji/crunchbang.png
Normal file → Executable file
|
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 297 B |
0
src/General/img/emoji/debian.png
Normal file → Executable file
|
Before Width: | Height: | Size: 559 B After Width: | Height: | Size: 559 B |
0
src/General/img/emoji/fedora.png
Normal file → Executable file
|
Before Width: | Height: | Size: 631 B After Width: | Height: | Size: 631 B |
0
src/General/img/emoji/freebsd.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
0
src/General/img/emoji/gentoo.png
Normal file → Executable file
|
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
0
src/General/img/emoji/gnu.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
0
src/General/img/emoji/madotsuki.png
Normal file → Executable file
|
Before Width: | Height: | Size: 231 B After Width: | Height: | Size: 231 B |
0
src/General/img/emoji/mint.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1006 B After Width: | Height: | Size: 1006 B |
0
src/General/img/emoji/neko.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1012 B After Width: | Height: | Size: 1012 B |
0
src/General/img/emoji/openbsd.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1002 B After Width: | Height: | Size: 1002 B |
0
src/General/img/emoji/osx.png
Normal file → Executable file
|
Before Width: | Height: | Size: 820 B After Width: | Height: | Size: 820 B |
0
src/General/img/emoji/plan9.png
Normal file → Executable file
|
Before Width: | Height: | Size: 668 B After Width: | Height: | Size: 668 B |
0
src/General/img/emoji/ponyo.png
Normal file → Executable file
|
Before Width: | Height: | Size: 884 B After Width: | Height: | Size: 884 B |
0
src/General/img/emoji/rabite.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
0
src/General/img/emoji/rhel.png
Normal file → Executable file
|
Before Width: | Height: | Size: 797 B After Width: | Height: | Size: 797 B |
0
src/General/img/emoji/sabayon.png
Normal file → Executable file
|
Before Width: | Height: | Size: 830 B After Width: | Height: | Size: 830 B |
0
src/General/img/emoji/sakamoto.png
Normal file → Executable file
|
Before Width: | Height: | Size: 934 B After Width: | Height: | Size: 934 B |
0
src/General/img/emoji/sega.png
Normal file → Executable file
|
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 339 B |
0
src/General/img/emoji/slackware.png
Normal file → Executable file
|
Before Width: | Height: | Size: 912 B After Width: | Height: | Size: 912 B |
0
src/General/img/emoji/trisquel.png
Normal file → Executable file
|
Before Width: | Height: | Size: 820 B After Width: | Height: | Size: 820 B |
0
src/General/img/emoji/ubuntu.png
Normal file → Executable file
|
Before Width: | Height: | Size: 625 B After Width: | Height: | Size: 625 B |
0
src/General/img/emoji/windows.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
0
src/General/img/emoji/yuno.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
0
src/General/img/favicons/Mayhem/unreadDead.png
Normal file → Executable file
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 346 B |
0
src/General/img/favicons/Mayhem/unreadDeadY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 456 B |
0
src/General/img/favicons/Mayhem/unreadNSFW.png
Normal file → Executable file
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 323 B |
0
src/General/img/favicons/Mayhem/unreadNSFWY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 450 B |
0
src/General/img/favicons/Mayhem/unreadSFW.png
Normal file → Executable file
|
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 321 B |
0
src/General/img/favicons/Mayhem/unreadSFWY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 450 B |
0
src/General/img/favicons/Original/unreadDead.gif
Normal file → Executable file
|
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 110 B |
0
src/General/img/favicons/Original/unreadDeadY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 232 B After Width: | Height: | Size: 232 B |
0
src/General/img/favicons/Original/unreadNSFW.gif
Normal file → Executable file
|
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 110 B |
0
src/General/img/favicons/Original/unreadNSFWY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 232 B After Width: | Height: | Size: 232 B |
0
src/General/img/favicons/Original/unreadSFW.gif
Normal file → Executable file
|
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 110 B |
0
src/General/img/favicons/Original/unreadSFWY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 232 B After Width: | Height: | Size: 232 B |
0
src/General/img/favicons/dead.gif
Normal file → Executable file
|
Before Width: | Height: | Size: 94 B After Width: | Height: | Size: 94 B |
0
src/General/img/favicons/empty.gif
Normal file → Executable file
|
Before Width: | Height: | Size: 94 B After Width: | Height: | Size: 94 B |
0
src/General/img/favicons/exclamation.png
Normal file → Executable file
|
Before Width: | Height: | Size: 114 B After Width: | Height: | Size: 114 B |
0
src/General/img/favicons/ferongr/unreadDead.gif
Normal file → Executable file
|
Before Width: | Height: | Size: 172 B After Width: | Height: | Size: 172 B |
0
src/General/img/favicons/ferongr/unreadDeadY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 274 B |
0
src/General/img/favicons/ferongr/unreadNSFW.gif
Normal file → Executable file
|
Before Width: | Height: | Size: 172 B After Width: | Height: | Size: 172 B |
0
src/General/img/favicons/ferongr/unreadNSFWY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 274 B |
0
src/General/img/favicons/ferongr/unreadSFW.gif
Normal file → Executable file
|
Before Width: | Height: | Size: 172 B After Width: | Height: | Size: 172 B |
0
src/General/img/favicons/ferongr/unreadSFWY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 270 B After Width: | Height: | Size: 270 B |
0
src/General/img/favicons/xat-/unreadDead.png
Normal file → Executable file
|
Before Width: | Height: | Size: 273 B After Width: | Height: | Size: 273 B |
0
src/General/img/favicons/xat-/unreadDeadY.png
Normal file → Executable file
|
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
0
src/General/img/favicons/xat-/unreadNSFW.png
Normal file → Executable file
|
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 281 B |