Merge Zixaphir X

This commit is contained in:
seaweedchan 2013-08-12 00:07:39 -07:00
commit 875f0cd4f8
176 changed files with 3788 additions and 3166 deletions

3
.gitignore vendored
View File

@ -2,8 +2,7 @@ node_modules/
*~ *~
*.db *.db
tmp-crx/ tmp-crx/
tmp-userjs/
tmp-userscript/ tmp-userscript/
builds/4chan-X-Chrome.zip builds/4chan-X-Chrome.zip
builds/4chan-X-Opera.nex builds/4chan-X-Opera.nex
Gruntfile.js Gruntfile.js

21
CHANGELOG.md Normal file → Executable file
View 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 ### v1.2.25
*2013-08-04* *2013-08-04*
@ -54,7 +74,6 @@
### v1.2.17 ### v1.2.17
*2013-06-17* *2013-06-17*
**seaweedchan**: **seaweedchan**:
- Fix full images being forced onto their own line - Fix full images being forced onto their own line

138
Gruntfile.coffee Normal file → Executable file
View File

@ -1,18 +1,18 @@
module.exports = (grunt) -> module.exports = (grunt) ->
pkg = grunt.file.readJSON 'package.json'
concatOptions = concatOptions =
process: process: Object.create(null, data:
data: pkg get: -> grunt.config 'pkg'
enumerable: true
)
shellOptions = shellOptions =
stdout: true stdout: true
stderr: true stderr: true
failOnError: true failOnError: true
# Project configuration. # Project configuration.
grunt.initConfig grunt.initConfig
pkg: pkg pkg: grunt.file.readJSON 'package.json'
concat: concat:
coffee: coffee:
options: concatOptions options: concatOptions
@ -41,8 +41,8 @@ module.exports = (grunt) ->
meta: meta:
options: concatOptions options: concatOptions
files: files:
'LICENSE': 'src/General/meta/banner.js', 'LICENSE': 'src/General/meta/banner.js',
'latest.js': 'src/General/meta/latest.js' 'latest.js': 'src/General/meta/latest.js'
crx: crx:
options: concatOptions options: concatOptions
@ -51,19 +51,9 @@ module.exports = (grunt) ->
'builds/crx/script.js': [ 'builds/crx/script.js': [
'src/General/meta/botproc.js' 'src/General/meta/botproc.js'
'src/General/meta/banner.js' 'src/General/meta/banner.js'
'src/General/meta/usestrict.js'
'tmp-<%= pkg.type %>/script.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: userscript:
options: concatOptions options: concatOptions
files: files:
@ -72,13 +62,13 @@ module.exports = (grunt) ->
'src/General/meta/botproc.js' 'src/General/meta/botproc.js'
'src/General/meta/metadata.js' 'src/General/meta/metadata.js'
'src/General/meta/banner.js' 'src/General/meta/banner.js'
'src/General/meta/usestrict.js'
'tmp-<%= pkg.type %>/script.js' 'tmp-<%= pkg.type %>/script.js'
] ]
copy: copy:
crx: crx:
src: 'src/General/img/*.png' src: 'src/General/img/*.png'
dest: 'builds/crx/' dest: 'builds/crx/'
expand: true expand: true
flatten: true flatten: true
@ -91,24 +81,31 @@ module.exports = (grunt) ->
build: [ build: [
'concat:meta' 'concat:meta'
'build-crx' 'build-crx'
'build-userjs'
'build-userscript' 'build-userscript'
] ]
bump:
options:
updateConfigs: [
'pkg'
]
commit: false
createTag: false
push: false
shell: shell:
commit: commit:
options: shellOptions options: shellOptions
command: [ command: [
'git checkout <%= pkg.meta.mainBranch %>', 'git checkout <%= pkg.meta.mainBranch %>'
'git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>."', 'git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>."'
'git tag -a <%= pkg.version %> -m "<%= 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 %>."' 'git tag -af stable -m "<%= pkg.meta.name %> v<%= pkg.version %>."'
].join(' && ') ].join ' && '
stdout: true
push: push:
options: shellOptions options: shellOptions
command: 'git push origin --tags -f && git push origin --all' command: 'git push origin --tags -f && git push origin --all'
watch: watch:
all: all:
@ -124,35 +121,28 @@ module.exports = (grunt) ->
compress: compress:
crx: crx:
options: options:
archive: 'builds/4chan-X-Chrome.zip' archive: 'builds/<%= pkg.name %>.zip'
level: 9 level: 9
pretty: true pretty: true
expand: true expand: true
cwd: 'builds/crx/' flatten: true
src: '**' src: 'builds/crx/*'
dest: '/'
clean: clean:
builds: 'builds' builds: 'builds'
tmpcrx: 'tmp-crx' tmpcrx: 'tmp-crx'
tmpuserjs: 'tmp-userjs'
tmpuserscript: 'tmp-userscript' tmpuserscript: 'tmp-userscript'
grunt.loadNpmTasks 'grunt-bump' require('matchdep').filterDev('grunt-*').forEach grunt.loadNpmTasks
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'
grunt.registerTask 'default', [ grunt.registerTask 'default', [
'build' 'build'
] ]
grunt.registerTask 'set-build', 'Set the build type variable', (type) -> 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.log.ok 'pkg.type = %s', type
grunt.registerTask 'build', [ grunt.registerTask 'build', [
@ -168,14 +158,6 @@ module.exports = (grunt) ->
'clean:tmpcrx' 'clean:tmpcrx'
] ]
grunt.registerTask 'build-userjs', [
'set-build:userjs'
'concat:coffee'
'coffee:script'
'concat:userjs'
'clean:tmpuserjs'
]
grunt.registerTask 'build-userscript', [ grunt.registerTask 'build-userscript', [
'set-build:userscript' 'set-build:userscript'
'concat:coffee' 'concat:coffee'
@ -185,40 +167,36 @@ module.exports = (grunt) ->
] ]
grunt.registerTask 'release', [ grunt.registerTask 'release', [
'default' 'build'
'compress:crx'
'shell:commit' 'shell:commit'
'shell:push' 'shell:push'
'build-crx'
'compress:crx'
] ]
grunt.registerTask 'patch', [
grunt.registerTask 'patch', [ 'bump'
'bump-only'
'reloadPkg'
'updcl:3' 'updcl:3'
'release'
] ]
grunt.registerTask 'minor', [ grunt.registerTask 'minor', [
'bump-only:minor' 'bump:minor'
'reloadPkg'
'updcl:2' 'updcl:2'
'release'
] ]
grunt.registerTask 'major', [ grunt.registerTask 'major', [
'bump-only:major' 'bump:major'
'reloadPkg'
'updcl:1' 'updcl:1'
'release'
] ]
grunt.registerTask 'reloadPkg', 'Reload the package', -> grunt.registerTask 'updcl', 'Update the changelog', (headerLevel) ->
# Update the `pkg` object with the new version. headerPrefix = new Array(+headerLevel + 1).join '#'
pkg = grunt.file.readJSON('package.json') {version} = grunt.config 'pkg'
grunt.config.data.pkg = concatOptions.process.data = pkg today = grunt.template.today 'yyyy-mm-dd'
grunt.log.ok('pkg reloaded.') 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 + '.'

0
LICENSE Normal file → Executable file
View File

2
README.md Normal file → Executable file
View 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. - Edit the CoffeeScript sources.
- If the edits affect regular users, edit the changelog. - 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
View File

0
builds/4chan-X.meta.js Normal file → Executable file
View File

2219
builds/4chan-X.user.js Normal file → Executable file

File diff suppressed because one or more lines are too long

0
builds/crx/icon128.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 196 B

0
builds/crx/icon16.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 157 B

After

Width:  |  Height:  |  Size: 157 B

0
builds/crx/icon48.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 204 B

After

Width:  |  Height:  |  Size: 204 B

3
builds/crx/manifest.json Normal file → Executable file
View File

@ -15,7 +15,8 @@
"run_at": "document_start" "run_at": "document_start"
}], }],
"homepage_url": "http://seaweedchan.github.io/4chan-x/", "homepage_url": "http://seaweedchan.github.io/4chan-x/",
"minimum_chrome_version": "26", "minimum_chrome_version": "27",
"minimum_opera_version": "15",
"permissions": [ "permissions": [
"storage" "storage"
] ]

2183
builds/crx/script.js Normal file → Executable file

File diff suppressed because one or more lines are too long

110
json/archives.json Executable file
View 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"]
}]

0
latest.js Normal file → Executable file
View File

11
package.json Normal file → Executable file
View File

@ -22,14 +22,15 @@
"devDependencies": { "devDependencies": {
"grunt": "~0.4.1", "grunt": "~0.4.1",
"grunt-bump": "~0.0.11", "grunt-bump": "~0.0.11",
"grunt-concurrent": "~0.2.0", "grunt-concurrent": "~0.3.0",
"grunt-contrib-clean": "~0.4.1", "grunt-contrib-clean": "~0.5.0",
"grunt-contrib-coffee": "~0.7.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-concat": "~0.3.0",
"grunt-contrib-copy": "~0.4.1", "grunt-contrib-copy": "~0.4.1",
"grunt-contrib-watch": "~0.4.4", "grunt-contrib-watch": "~0.5.0",
"grunt-shell": "~0.2.2" "grunt-shell": "~0.3.1",
"matchdep": "~0.1.2"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

201
src/Archive/Redirect.coffee Normal file → Executable file
View File

@ -1,117 +1,124 @@
Redirect = Redirect =
thread: {} data:
post: {} thread: {}
file: {} post: {}
file: {}
init: -> init: ->
for boardID, data of Conf['selectedArchives'] for boardID, data of Conf['selectedArchives']
for type, id of data for type, id of data
for name, archive of Redirect.archives if archive = Redirect.archives[id]
continue if name isnt id or type is 'post' and archive.software isnt 'foolfuuka' boards = archive[type] or archive['boards']
arr = if type is 'file' continue unless boards.contains boardID
archive.files Redirect.data[type][boardID] = archive
else
archive.boards
Redirect[type][boardID] = archive if arr.contains boardID
for name, archive of Redirect.archives for name, archive of Redirect.archives
for boardID in archive.boards for boardID in archive.boards
unless boardID of Redirect.thread unless boardID of Redirect.data.thread
Redirect.thread[boardID] = archive Redirect.data.thread[boardID] = archive
unless boardID of Redirect.post or archive.software isnt 'foolfuuka' unless boardID of Redirect.data.post or archive.software isnt 'foolfuuka'
Redirect.post[boardID] = archive Redirect.data.post[boardID] = archive
unless boardID of Redirect.file or !archive.files.contains boardID unless boardID of Redirect.data.file or !archive.files.contains boardID
Redirect.file[boardID] = archive Redirect.data.file[boardID] = archive
return return
archives: 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': '4plebs':
'domain': 'archive.4plebs.org' domain: 'archive.4plebs.org'
'http': true http: true
'software': 'foolfuuka' software: 'foolfuuka'
'boards': ['hr', 'tg', 'tv', 'x'] boards: ['hr', 'tg', 'tv', 'x']
'files': ['hr', 'tg', 'tv', 'x'] files: ['hr', 'tg', 'tv', 'x']
'Nyafuu': 'fap archive':
'domain': 'archive.nyafuu.org' domain: 'fuuka.worldathleticproject.org'
'http': true http: true
'https': true https: false
'software': 'foolfuuka' software: 'foolfuuka'
'boards': ['c', 'w', 'wg'] boards: ['b', 'e', 'h', 'hc', 'p', 's', 'u']
'files': ['c', 'w', 'wg'] 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': 'Foolz a Shit':
'domain': 'archive.foolzashit.com' domain: 'archive.foolzashit.com'
'http': true http: true
'https': true https: true
'software': 'foolfuuka' software: 'foolfuuka'
'boards': ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv'] boards: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
'files': ['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': 'Foolz Beta':
'domain': 'fuuka.worldathleticproject.org' domain: 'beta.foolz.us'
'http': true http: true
'https': false https: true
'software': 'foolfuuka' withCredentials: true
'boards': ['e', 'h', 'hc', 'p', 's', 'u'] software: 'foolfuuka'
'files': ['e', 'h', 'hc', 'p', 's', 'u'] 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']
'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']
'Heinessen': 'Heinessen':
'domain': 'archive.heinessen.com' domain: 'archive.heinessen.com'
'http': true http: true
'software': 'fuuka' software: 'fuuka'
'boards': ['an', 'fit', 'k', 'mlp', 'r9k', 'toy'] boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy']
'files': ['an', 'k', '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) -> 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 return '' unless archive
Redirect[dest] archive, data Redirect[dest] archive, data
@ -144,7 +151,9 @@ Redirect =
# Remove necessary HTTPS procotol in September 2013. # Remove necessary HTTPS procotol in September 2013.
if ['Foolz', 'NSFW Foolz'].contains archive.name if ['Foolz', 'NSFW Foolz'].contains archive.name
protocol = 'https://' 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}) -> file: (archive, {boardID, filename}) ->
"#{Redirect.protocol archive}#{archive.domain}/#{boardID}/full_image/#{filename}" "#{Redirect.protocol archive}#{archive.domain}/#{boardID}/full_image/#{filename}"

0
src/Filtering/Anonymize.coffee Normal file → Executable file
View File

2
src/Filtering/Filter.coffee Normal file → Executable file
View File

@ -209,7 +209,7 @@ Filter =
el = $.el 'a', el = $.el 'a',
href: 'javascript:;' href: 'javascript:;'
textContent: text textContent: text
el.setAttribute 'data-type', type el.dataset.type = type
$.on el, 'click', Filter.menu.makeFilter $.on el, 'click', Filter.menu.makeFilter
return { return {

25
src/Filtering/PostHiding.coffee Normal file → Executable file
View File

@ -17,7 +17,7 @@ PostHiding =
PostHiding.hide @, data.makeStub, data.hideRecursively PostHiding.hide @, data.makeStub, data.hideRecursively
else else
Recursive.apply PostHiding.hide, @, data.makeStub, true 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'] return unless Conf['Reply Hiding Buttons']
$.replace $('.sideArrows', @nodes.root), PostHiding.makeButton @, 'hide' $.replace $('.sideArrows', @nodes.root), PostHiding.makeButton @, 'hide'
@ -108,11 +108,12 @@ PostHiding =
PostHiding.hide post, makeStub, replies PostHiding.hide post, makeStub, replies
else if replies else if replies
Recursive.apply PostHiding.hide, post, makeStub, true Recursive.apply PostHiding.hide, post, makeStub, true
Recursive.add PostHiding.hide, post, makeStub, true Recursive.add PostHiding.hide, post, makeStub, true
else else
return return
PostHiding.saveHiddenState post, true, thisPost, makeStub, replies PostHiding.saveHiddenState post, true, thisPost, makeStub, replies
$.event 'CloseMenu' $.event 'CloseMenu'
show: -> show: ->
parent = @parentNode parent = @parentNode
thisPost = $('input[name=thisPost]', parent).checked thisPost = $('input[name=thisPost]', parent).checked
@ -122,7 +123,7 @@ PostHiding =
PostHiding.show post, replies PostHiding.show post, replies
else if replies else if replies
Recursive.apply PostHiding.show, post, true Recursive.apply PostHiding.show, post, true
Recursive.rm PostHiding.hide, post, true Recursive.rm PostHiding.hide, post, true
else else
return return
if data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID} if data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
@ -158,10 +159,7 @@ PostHiding =
toggle: -> toggle: ->
post = Get.postFromNode @ post = Get.postFromNode @
if post.isHidden PostHiding[(if post.isHidden then 'show' else 'hide')] post
PostHiding.show post
else
PostHiding.hide post
PostHiding.saveHiddenState post, post.isHidden PostHiding.saveHiddenState post, post.isHidden
hide: (post, makeStub=Conf['Stubs'], hideRecursively=Conf['Recursive Hiding']) -> hide: (post, makeStub=Conf['Stubs'], hideRecursively=Conf['Recursive Hiding']) ->
@ -170,7 +168,7 @@ PostHiding =
if hideRecursively if hideRecursively
Recursive.apply PostHiding.hide, post, makeStub, true 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 for quotelink in Get.allQuotelinksLinkingTo post
$.addClass quotelink, 'filtered' $.addClass quotelink, 'filtered'
@ -184,13 +182,14 @@ PostHiding =
if Conf['Anonymize'] if Conf['Anonymize']
'Anonymous' 'Anonymous'
else else
$('.nameBlock', post.nodes.info).textContent post.info.name
$.add a, $.tn " #{postInfo}" $.add a, $.tn " #{postInfo}"
post.nodes.stub = $.el 'div', post.nodes.stub = $.el 'div',
className: 'stub' className: 'stub'
$.add post.nodes.stub, a $.add post.nodes.stub, unless Conf['Menu']
if Conf['Menu'] a
$.add post.nodes.stub, [$.tn(' '), Menu.makeButton post] else
[a, $.tn(' '), button = Menu.makeButton post]
$.prepend post.nodes.root, post.nodes.stub $.prepend post.nodes.root, post.nodes.stub
show: (post, showRecursively=Conf['Recursive Hiding']) -> show: (post, showRecursively=Conf['Recursive Hiding']) ->
@ -202,7 +201,7 @@ PostHiding =
post.isHidden = false post.isHidden = false
if showRecursively if showRecursively
Recursive.apply PostHiding.show, post, true Recursive.apply PostHiding.show, post, true
Recursive.rm PostHiding.hide, post Recursive.rm PostHiding.hide, post
for quotelink in Get.allQuotelinksLinkingTo post for quotelink in Get.allQuotelinksLinkingTo post
$.rmClass quotelink, 'filtered' $.rmClass quotelink, 'filtered'
return return

0
src/Filtering/Recursive.coffee Normal file → Executable file
View File

59
src/Filtering/ThreadHiding.coffee Normal file → Executable file
View File

@ -71,11 +71,6 @@ ThreadHiding =
makeStub = $.el 'label', makeStub = $.el 'label',
innerHTML: "<input type=checkbox #{if Conf['Stubs'] then 'checked' else ''}> Make stub" 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', $.event 'AddMenuEntry',
type: 'post' type: 'post'
el: div el: div
@ -87,6 +82,27 @@ ThreadHiding =
true true
subEntries: [el: apply; el: makeStub] 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', $.event 'AddMenuEntry',
type: 'post' type: 'post'
el: hideStubLink el: hideStubLink
@ -102,6 +118,13 @@ ThreadHiding =
ThreadHiding.hide thread, makeStub ThreadHiding.hide thread, makeStub
ThreadHiding.saveHiddenState thread, makeStub ThreadHiding.saveHiddenState thread, makeStub
$.event 'CloseMenu' $.event 'CloseMenu'
show: ->
{thread} = ThreadHiding.menu
ThreadHiding.show thread
ThreadHiding.saveHiddenState thread
$.event 'CloseMenu'
hideStub: -> hideStub: ->
{thread} = ThreadHiding.menu {thread} = ThreadHiding.menu
ThreadHiding.hide thread, false ThreadHiding.hide thread, false
@ -113,7 +136,7 @@ ThreadHiding =
className: "#{type}-thread-button" className: "#{type}-thread-button"
innerHTML: "<span class=fourchanx-link>&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;</span>" innerHTML: "<span class=fourchanx-link>&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;</span>"
href: 'javascript:;' href: 'javascript:;'
a.setAttribute 'data-fullid', thread.fullID a.dataset.fullID = thread.fullID
$.on a, 'click', ThreadHiding.toggle $.on a, 'click', ThreadHiding.toggle
a a
@ -134,7 +157,7 @@ ThreadHiding =
toggle: (thread) -> toggle: (thread) ->
unless thread instanceof Thread unless thread instanceof Thread
thread = g.threads[@dataset.fullid] thread = g.threads[@dataset.fullID]
if thread.isHidden if thread.isHidden
ThreadHiding.show thread ThreadHiding.show thread
else else
@ -150,24 +173,28 @@ ThreadHiding =
threadRoot.hidden = threadRoot.nextElementSibling.hidden = true # <hr> threadRoot.hidden = threadRoot.nextElementSibling.hidden = true # <hr>
return return
numReplies = 0 numReplies = (
if span = $ '.summary', threadRoot if span = $ '.summary', threadRoot
numReplies = +span.textContent.match /\d+/ +span.textContent.match /\d+/
numReplies += $$('.opContainer ~ .replyContainer', threadRoot).length else
numReplies = if numReplies is 1 then '1 reply' else "#{numReplies} replies" 0
) +
$$('.opContainer ~ .replyContainer', threadRoot).length
numReplies = if numReplies is 1 then '1 reply' else "#{numReplies or 'No'} replies"
opInfo = opInfo =
if Conf['Anonymize'] if Conf['Anonymize']
'Anonymous' 'Anonymous'
else else
$('.nameBlock', OP.nodes.info).textContent OP.info.name
a = ThreadHiding.makeButton thread, 'show' a = ThreadHiding.makeButton thread, 'show'
$.add a, $.tn " #{opInfo} (#{numReplies})" $.add a, $.tn " #{opInfo} (#{numReplies})"
thread.stub = $.el 'div', thread.stub = $.el 'div',
className: 'stub' className: 'stub'
$.add thread.stub, a $.add thread.stub, unless Conf['Menu']
if Conf['Menu'] a
$.add thread.stub, [$.tn(' '), Menu.makeButton OP] else
[a, $.tn(' '), button = Menu.makeButton OP]
$.prepend threadRoot, thread.stub $.prepend threadRoot, thread.stub
show: (thread) -> show: (thread) ->

115
src/General/Build.coffee Normal file → Executable file
View File

@ -27,6 +27,7 @@ Build =
date: data.now date: data.now
dateUTC: data.time dateUTC: data.time
comment: data.com comment: data.com
capReps: data.capcode_replies
# thread status # thread status
isSticky: !!data.sticky isSticky: !!data.sticky
isClosed: !!data.closed isClosed: !!data.closed
@ -58,7 +59,7 @@ Build =
postID, threadID, boardID postID, threadID, boardID
name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC
isSticky, isClosed isSticky, isClosed
comment comment, capReps
file file
} = o } = o
isOP = postID is threadID isOP = postID is threadID
@ -108,12 +109,12 @@ Build =
capcodeStart = '' capcodeStart = ''
capcode = '' capcode = ''
flag = flag = unless flagCode
if flagCode ''
" <img src='#{staticPath}country/#{if boardID is 'pol' then 'troll/' else ''}" + else if boardID is 'pol'
flagCode.toLowerCase() + ".gif' alt=#{flagCode} title='#{flagName}' class=countryFlag>" " <img src='#{staticPath}country/troll/#{flagCode.toLowerCase()}.gif' alt=#{flagCode} title='#{flagName}' class=countryFlag>"
else else
'' " <span title='#{flagName}' class='flag flag-#{flagCode.toLowerCase()}'></span>"
if file?.isDeleted if file?.isDeleted
fileHTML = if isOP fileHTML = if isOP
@ -176,78 +177,44 @@ Build =
else else
fileHTML = '' fileHTML = ''
tripcode = tripcode = if tripcode
if tripcode " <span class=postertrip>#{tripcode}</span>"
" <span class=postertrip>#{tripcode}</span>" else
else ''
''
sticky = sticky = if isSticky
if isSticky " <img src=#{staticPath}sticky.gif alt=Sticky title=Sticky class=stickyIcon>"
" <img src=#{staticPath}sticky.gif alt=Sticky title=Sticky class=stickyIcon>" else
else ''
'' closed = if isClosed
closed = " <img src=#{staticPath}closed.gif alt=Closed title=Closed class=closedIcon>"
if isClosed else
" <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>&gt;&gt;#{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', container = $.el 'div',
id: "pc#{postID}" id: "pc#{postID}"
className: "postContainer #{if isOP then 'op' else 'reply'}Container" className: "postContainer #{if isOP then 'op' else 'reply'}Container"
innerHTML: \ innerHTML: <%= grunt.file.read('src/General/html/Build/post.html').replace(/>\s+/g, '>').replace(/\s+</g, '<').replace(/\s+/g, ' ').trim() %>
(if isOP then '' else "<div class=sideArrows id=sa#{postID}>&gt;&gt;</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>'
for quote in $$ '.quotelink', container for quote in $$ '.quotelink', container
href = quote.getAttribute 'href' href = quote.getAttribute 'href'

12
src/General/Config.coffee Normal file → Executable file
View File

@ -53,6 +53,10 @@ Config =
false false
'Add buttons to navigate to top / bottom of thread.' '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') { %> <% if (type !== 'crx') { %>
'Check for Updates': [ 'Check for Updates': [
true true
@ -641,6 +645,14 @@ q-replace
'x' 'x'
'Hide thread.' '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: updater:
checkbox: checkbox:

78
src/General/Get.coffee Normal file → Executable file
View File

@ -18,8 +18,8 @@ Get =
post = g.posts["#{boardID}.#{postID}"] post = g.posts["#{boardID}.#{postID}"]
if index then post.clones[index] else post if index then post.clones[index] else post
postFromNode: (root) -> postFromNode: (root) ->
Get.postFromRoot $.x 'ancestor::div[contains(@class,"postContainer")][1]', root Get.postFromRoot $.x '(ancestor::div[contains(@class,"postContainer")][1]|following::div[contains(@class,"postContainer")][1])', root
contextFromLink: (quotelink) -> contextFromNode: (quotelink) ->
Get.postFromRoot $.x 'ancestor::div[parent::div[@class="thread"]][1]', quotelink Get.postFromRoot $.x 'ancestor::div[parent::div[@class="thread"]][1]', quotelink
postDataFromLink: (link) -> postDataFromLink: (link) ->
if link.hostname is 'boards.4chan.org' if link.hostname is 'boards.4chan.org'
@ -28,9 +28,8 @@ Get =
threadID = path[3] threadID = path[3]
postID = link.hash[2..] postID = link.hash[2..]
else # resurrected quote else # resurrected quote
boardID = link.dataset.boardid {boardID, threadID, postID} = link.dataset
threadID = link.dataset.threadid or 0 threadID or= 0
postID = link.dataset.postid
return { return {
boardID: boardID boardID: boardID
threadID: +threadID threadID: +threadID
@ -72,8 +71,10 @@ Get =
$.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.to '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
,
withCredentials: url.archive.withCredentials
insert: (post, root, context) -> insert: (post, root, context) ->
# Stop here if the container has been removed while loading. # Stop here if the container has been removed while loading.
return unless root.parentNode return unless root.parentNode
@ -98,8 +99,10 @@ Get =
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.to '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
,
withCredentials: url.archive.withCredentials
else else
$.addClass root, 'warning' $.addClass root, 'warning'
root.textContent = root.textContent =
@ -116,8 +119,10 @@ Get =
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.to '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
,
withCredentials: url.archive.withCredentials
else else
$.addClass root, 'warning' $.addClass root, 'warning'
root.textContent = "Post No.#{postID} was not found." root.textContent = "Post No.#{postID} was not found."
@ -154,30 +159,7 @@ Get =
| \[/?code\] | \[/?code\]
| \[/?moot\] | \[/?moot\]
| \[/?banned\] | \[/?banned\]
///g, (text) -> ///g, Get.parseMarkup
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>'
comment = bq.innerHTML comment = bq.innerHTML
# greentext # greentext
@ -185,7 +167,7 @@ Get =
# quotes # quotes
.replace /((&gt;){2}(&gt;\/[a-z\d]+\/)?\d+)/g, '<span class=deadlink>$1</span>' .replace /((&gt;){2}(&gt;\/[a-z\d]+\/)?\d+)/g, '<span class=deadlink>$1</span>'
threadID = data.thread_num threadID = +data.thread_num
o = o =
# id # id
postID: "#{postID}" postID: "#{postID}"
@ -229,3 +211,27 @@ Get =
isArchived: true isArchived: true
Main.callbackNodes Post, [post] Main.callbackNodes Post, [post]
Get.insert post, root, context 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
View 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 = {} Conf = {}
c = console c = console
d = document d = document

15
src/General/Header.coffee Normal file → Executable file
View File

@ -70,7 +70,7 @@ Header =
return unless Main.isThisPageLegit() return unless Main.isThisPageLegit()
# Wait for #boardNavMobile instead of #boardNavDesktop, # Wait for #boardNavMobile instead of #boardNavDesktop,
# it might be incomplete otherwise. # 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 $.prepend d.body, @bar
$.add d.body, Header.hover $.add d.body, Header.hover
@setBarPosition Conf['Bottom Header'] @setBarPosition Conf['Bottom Header']
@ -131,7 +131,7 @@ Header =
list = $ '#custom-board-list', Header.bar list = $ '#custom-board-list', Header.bar
$.rmAll list $.rmAll list
return unless text 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) -> nodes = text.match(/[\w@]+((-(all|title|replace|full|index|catalog|url:"[^"]+[^"]"|text:"[^"]+")|\,"[^"]+[^"]"))*|[^\w@]+/g).map (t) ->
if /^[^\w@]/.test t if /^[^\w@]/.test t
return $.tn t return $.tn t
@ -166,10 +166,13 @@ Header =
a.textContent a.textContent
if m = t.match /-(index|catalog)/ if m = t.match /-(index|catalog)/
a.setAttribute 'data-only', m[1] a.dataset.only = m[1]
a.href = "//boards.4chan.org/#{board}/" a.href = "//boards.4chan.org/#{board}/"
if m[1] is 'catalog' 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, 'catalog'
$.addClass a, 'navSmall' if board is '@' $.addClass a, 'navSmall' if board is '@'
@ -302,8 +305,8 @@ Header =
{top} = post.getBoundingClientRect() {top} = post.getBoundingClientRect()
if Conf['Fixed Header'] and not Conf['Bottom Header'] if Conf['Fixed Header'] and not Conf['Bottom Header']
headRect = Header.bar.getBoundingClientRect() headRect = Header.bar.getBoundingClientRect()
top += - headRect.top - headRect.height top -= headRect.top + headRect.height
<% if (type === 'crx') { %>d.body<% } else { %>doc<% } %>.scrollTop += top window.scrollBy 0, top
addShortcut: (el) -> addShortcut: (el) ->
shortcut = $.el 'span', shortcut = $.el 'span',

143
src/General/Main.coffee Normal file → Executable file
View File

@ -15,11 +15,12 @@ Main =
for db in DataBoards for db in DataBoards
Conf[db] = boards: {} Conf[db] = boards: {}
Conf['selectedArchives'] = {} Conf['selectedArchives'] = {}
Conf['CachedTitles'] = []
$.get Conf, Main.initFeatures $.get Conf, Main.initFeatures
$.on d, '4chanMainInit', Main.initStyle $.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 Main.initStyle
initFeatures: (items) -> initFeatures: (items) ->
@ -47,7 +48,7 @@ Main =
return return
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 ['4chan - Temporarily Offline', '4chan - 404 Not Found'].contains d.title
Redirect.init() Redirect.init()
pathname = location.pathname.split '/' pathname = location.pathname.split '/'
URL = Redirect.to 'file', URL = Redirect.to 'file',
@ -72,61 +73,62 @@ Main =
# c.time 'All initializations' # c.time 'All initializations'
init init
'Polyfill': Polyfill 'Polyfill': Polyfill
'Redirect': Redirect 'Redirect': Redirect
'Header': Header 'Header': Header
'Catalog Links': CatalogLinks 'Catalog Links': CatalogLinks
'Settings': Settings 'Settings': Settings
'Announcement Hiding': PSAHiding 'Announcement Hiding': PSAHiding
'Fourchan thingies': Fourchan 'Fourchan thingies': Fourchan
'Emoji': Emoji 'Emoji': Emoji
'Color User IDs': IDColor 'Color User IDs': IDColor
'Remove Spoilers': RemoveSpoilers 'Reveal Spoilers': RemoveSpoilers
'Custom CSS': CustomCSS 'Custom CSS': CustomCSS
'Linkify': Linkify 'Linkify': Linkify
'Resurrect Quotes': Quotify 'Resurrect Quotes': Quotify
'Filter': Filter 'Filter': Filter
'Thread Hiding Buttons': ThreadHiding 'Thread Hiding Buttons': ThreadHiding
'Reply Hiding Buttons': PostHiding 'Reply Hiding Buttons': PostHiding
'Recursive': Recursive 'Recursive': Recursive
'Strike-through Quotes': QuoteStrikeThrough 'Strike-through Quotes': QuoteStrikeThrough
'Quick Reply': QR 'Quick Reply': QR
'Menu': Menu 'Menu': Menu
'Report Link': ReportLink 'Report Link': ReportLink
'Thread Hiding (Menu)': ThreadHiding.menu 'Thread Hiding (Menu)': ThreadHiding.menu
'Reply Hiding (Menu)': PostHiding.menu 'Reply Hiding (Menu)': PostHiding.menu
'Delete Link': DeleteLink 'Delete Link': DeleteLink
'Filter (Menu)': Filter.menu 'Filter (Menu)': Filter.menu
'Download Link': DownloadLink 'Download Link': DownloadLink
'Archive Link': ArchiveLink 'Archive Link': ArchiveLink
'Quote Inlining': QuoteInline 'Quote Inlining': QuoteInline
'Quote Previewing': QuotePreview 'Quote Previewing': QuotePreview
'Quote Backlinks': QuoteBacklink 'Quote Backlinks': QuoteBacklink
'Mark Quotes of You': QuoteYou 'Mark Quotes of You': QuoteYou
'Mark OP Quotes': QuoteOP 'Mark OP Quotes': QuoteOP
'Mark Cross-thread Quotes': QuoteCT 'Mark Cross-thread Quotes': QuoteCT
'Anonymize': Anonymize 'Anonymize': Anonymize
'Time Formatting': Time 'Time Formatting': Time
'Relative Post Dates': RelativeDates 'Relative Post Dates': RelativeDates
'File Info Formatting': FileInfo 'File Info Formatting': FileInfo
'Fappe Tyme': FappeTyme 'Fappe Tyme': FappeTyme
'Sauce': Sauce 'Sauce': Sauce
'Image Expansion': ImageExpand 'Image Expansion': ImageExpand
'Image Expansion (Menu)': ImageExpand.menu 'Image Expansion (Menu)': ImageExpand.menu
'Reveal Spoilers': RevealSpoilers 'Reveal Spoiler Thumbnails': RevealSpoilers
'Image Loading': ImageLoader 'Image Loading': ImageLoader
'Image Hover': ImageHover 'Image Hover': ImageHover
'Comment Expansion': ExpandComment 'Comment Expansion': ExpandComment
'Thread Expansion': ExpandThread 'Thread Expansion': ExpandThread
'Thread Excerpt': ThreadExcerpt 'Thread Excerpt': ThreadExcerpt
'Favicon': Favicon 'Favicon': Favicon
'Unread': Unread 'Unread': Unread
'Quote Threading': QuoteThreading 'Quote Threading': QuoteThreading
'Thread Stats': ThreadStats 'Thread Stats': ThreadStats
'Thread Updater': ThreadUpdater 'Thread Updater': ThreadUpdater
'Thread Watcher': ThreadWatcher 'Thread Watcher': ThreadWatcher
'Index Navigation': Nav 'Index Navigation': Nav
'Keybinds': Keybinds 'Keybinds': Keybinds
'Show Dice Roll': Dice
# c.timeEnd 'All initializations' # c.timeEnd 'All initializations'
@ -139,10 +141,7 @@ Main =
# disable the mobile layout # disable the mobile layout
$('link[href*=mobile]', d.head)?.disabled = true $('link[href*=mobile]', d.head)?.disabled = true
<% if (type === 'crx') { %> <% if (type === 'crx') { %>
$.addClass doc, 'webkit'
$.addClass doc, 'blink' $.addClass doc, 'blink'
<% } else if (type === 'userjs') { %>
$.addClass doc, 'presto'
<% } else { %> <% } else { %>
$.addClass doc, 'gecko' $.addClass doc, 'gecko'
<% } %> <% } %>
@ -166,13 +165,9 @@ Main =
$.addClass doc, style $.addClass doc, style
setStyle() setStyle()
return unless mainStyleSheet return unless mainStyleSheet
if window.MutationObserver new MutationObserver(setStyle).observe mainStyleSheet,
observer = new MutationObserver setStyle attributes: true
observer.observe mainStyleSheet, attributeFilter: ['href']
attributes: true
attributeFilter: ['href']
else
$.on mainStyleSheet, 'DOMAttrModified', setStyle
initReady: -> initReady: ->
if d.title is '4chan - 404 Not Found' if d.title is '4chan - 404 Not Found'
@ -192,20 +187,18 @@ Main =
threads = [] threads = []
posts = [] posts = []
for boardChild in board.children for threadRoot in $$ '.board > .thread', board
continue unless $.hasClass boardChild, 'thread' thread = new Thread +threadRoot.id[1..], g.BOARD
thread = new Thread boardChild.id[1..], g.BOARD
threads.push thread threads.push thread
for threadChild in boardChild.children for postRoot in $$ '.thread > .postContainer', threadRoot
continue unless $.hasClass threadChild, 'postContainer'
try try
posts.push new Post threadChild, thread, g.BOARD posts.push new Post postRoot, thread, g.BOARD
catch err catch err
# Skip posts that we failed to parse. # Skip posts that we failed to parse.
unless errors unless errors
errors = [] errors = []
errors.push 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 error: err
Main.handleErrors errors if errors Main.handleErrors errors if errors
@ -373,7 +366,7 @@ Main =
unless 'thisPageIsLegit' of Main unless 'thisPageIsLegit' of Main
Main.thisPageIsLegit = location.hostname is 'boards.4chan.org' and Main.thisPageIsLegit = location.hostname is 'boards.4chan.org' and
!$('link[href*="favicon-status.ico"]', d.head) 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 Main.thisPageIsLegit
css: """ css: """

4
src/General/Settings.coffee Normal file → Executable file
View File

@ -262,8 +262,7 @@ Settings =
'%board' '%board'
else else
c c
for key, val of Config.hotkeys for key, val of Config.hotkeys when key of data.Conf
continue unless 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) -> 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()}" "Shift+#{s[0...-1]}#{s[-1..].toLowerCase()}"
data.Conf.WatchedThreads = data.WatchedThreads data.Conf.WatchedThreads = data.WatchedThreads
@ -467,7 +466,6 @@ Settings =
$.cb.checked.call @ $.cb.checked.call @
usercss: -> usercss: ->
CustomCSS.update() CustomCSS.update()
keybinds: (section) -> keybinds: (section) ->
section.innerHTML = """ section.innerHTML = """
<%= grunt.file.read('src/General/html/Settings/Keybinds.html').replace(/>\s+</g, '><').trim() %> <%= grunt.file.read('src/General/html/Settings/Keybinds.html').replace(/>\s+</g, '><').trim() %>

25
src/General/UI.coffee Normal file → Executable file
View File

@ -70,8 +70,8 @@ UI = do ->
# Position # Position
mRect = menu.getBoundingClientRect() mRect = menu.getBoundingClientRect()
bRect = button.getBoundingClientRect() bRect = button.getBoundingClientRect()
bTop = doc.scrollTop + d.body.scrollTop + bRect.top bTop = window.scrollY + bRect.top
bLeft = doc.scrollLeft + d.body.scrollLeft + bRect.left bLeft = window.scrollX + bRect.left
cHeight = doc.clientHeight cHeight = doc.clientHeight
cWidth = doc.clientWidth cWidth = doc.clientWidth
[top, bottom] = if bRect.top + bRect.height + mRect.height < cHeight [top, bottom] = if bRect.top + bRect.height + mRect.height < cHeight
@ -306,12 +306,12 @@ UI = do ->
hoverstart = ({root, el, latestEvent, endEvents, asapTest, cb}) -> hoverstart = ({root, el, latestEvent, endEvents, asapTest, cb}) ->
o = { o = {
root: root root
el: el el
style: el.style style: el.style
cb: cb cb
endEvents: endEvents endEvents
latestEvent: latestEvent latestEvent
clientHeight: doc.clientHeight clientHeight: doc.clientHeight
clientWidth: doc.clientWidth clientWidth: doc.clientWidth
} }
@ -327,6 +327,11 @@ UI = do ->
if $.x 'ancestor::div[contains(@class,"inline")][1]', root if $.x 'ancestor::div[contains(@class,"inline")][1]', root
$.on d, 'keydown', o.hoverend $.on d, 'keydown', o.hoverend
$.on root, 'mousemove', o.hover $.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) -> hover = (e) ->
@latestEvent = e @latestEvent = e
@ -357,6 +362,10 @@ UI = do ->
$.off @root, @endEvents, @hoverend $.off @root, @endEvents, @hoverend
$.off d, 'keydown', @hoverend $.off d, 'keydown', @hoverend
$.off @root, 'mousemove', @hover $.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 @cb.call @ if @cb

0
src/General/audio/beep.wav Normal file → Executable file
View File

0
src/General/css/burichan.css Normal file → Executable file
View File

0
src/General/css/futaba.css Normal file → Executable file
View File

0
src/General/css/photon.css Normal file → Executable file
View File

34
src/General/css/style.css Normal file → Executable file
View File

@ -304,10 +304,8 @@ a {
box-sizing: border-box; box-sizing: border-box;
box-shadow: 0 0 15px rgba(0, 0, 0, .15); box-shadow: 0 0 15px rgba(0, 0, 0, .15);
height: 600px; height: 600px;
min-height: 0;
max-height: 100%; max-height: 100%;
width: 900px; width: 900px;
min-width: 0;
max-width: 100%; max-width: 100%;
margin: auto; margin: auto;
padding: 3px; padding: 3px;
@ -315,7 +313,6 @@ a {
left: 50%; left: 50%;
-moz-transform: translate(-50%, -50%); -moz-transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
#fourchanx-settings > nav { #fourchanx-settings > nav {
@ -392,14 +389,17 @@ a {
position: absolute; position: absolute;
} }
.section-advanced .note { .section-advanced .note {
font-size: 0.8em; font-size: 0.8em;
font-style: italic; font-style: italic;
margin-left: 10px; margin-left: 10px;
} }
.section-advanced .note code { .section-advanced .note code {
font-style: normal; font-style: normal;
font-size: 11px; font-size: 11px;
} }
.section-keybinds .field {
font-family: monospace;
}
#fourchanx-settings fieldset { #fourchanx-settings fieldset {
border: 1px solid; border: 1px solid;
border-radius: 3px; border-radius: 3px;
@ -533,7 +533,8 @@ a.hide-announcement {
.deadlink { .deadlink {
text-decoration: none !important; text-decoration: none !important;
} }
.backlink.deadlink:not(.forwardlink), .quotelink.deadlink:not(.forwardlink) { .backlink.deadlink:not(.forwardlink),
.quotelink.deadlink:not(.forwardlink) {
text-decoration: underline !important; text-decoration: underline !important;
} }
.inlined { .inlined {
@ -576,16 +577,14 @@ a.hide-announcement {
padding: 2px 2px 5px; padding: 2px 2px 5px;
} }
#qp img { #qp img {
max-height: 300px;
max-width: 500px;
max-height: 80vh; max-height: 80vh;
max-width: 50vw; max-width: 50vw;
} }
.qphl { .qphl {
outline: 2px solid rgba(216, 94, 49, .7); outline: 2px solid rgba(216, 94, 49, .7);
} }
:root.highlight-own .yourPost>.reply, :root.highlight-own .yourPost > .reply,
:root.highlight-you .quotesYou>.reply { :root.highlight-you .quotesYou > .reply {
border-left: 2px solid rgba(221,0,0,.5); border-left: 2px solid rgba(221,0,0,.5);
} }
/* Quote Threading */ /* Quote Threading */
@ -613,8 +612,7 @@ a.hide-announcement {
:root.fit-width .full-image { :root.fit-width .full-image {
max-width: 100%; max-width: 100%;
} }
:root.gecko.fit-width .full-image, :root.gecko.fit-width .full-image {
:root.presto.fit-width .full-image {
width: 100%; width: 100%;
} }
#ihover { #ihover {
@ -671,7 +669,10 @@ a.hide-announcement {
#file-n-submit:not(.has-file) #qr-filerm { #file-n-submit:not(.has-file) #qr-filerm {
display: none; display: none;
} }
#qr select, #dump-button, .remove, .captcha-img { #qr select,
#dump-button,
.remove,
.captcha-img {
cursor: pointer; cursor: pointer;
} }
#qr { #qr {
@ -728,7 +729,8 @@ a.hide-announcement {
height: 9em; height: 9em;
} }
input.field.tripped:not(:hover):not(:focus) { input.field.tripped:not(:hover):not(:focus) {
color: transparent !important; text-shadow: none !important; color: transparent !important;
text-shadow: none !important;
} }
#qr textarea { #qr textarea {
resize: both; resize: both;
@ -910,7 +912,9 @@ a:only-of-type > .remove {
.qr-preview > label { .qr-preview > label {
background: rgba(0,0,0,.5); background: rgba(0,0,0,.5);
color: #fff; color: #fff;
right: 0; bottom: 0; left: 0; right: 0;
bottom: 0;
left: 0;
position: absolute; position: absolute;
text-align: center; text-align: center;
} }

0
src/General/css/tomorrow.css Normal file → Executable file
View File

0
src/General/css/yotsuba-b.css Normal file → Executable file
View File

0
src/General/css/yotsuba.css Normal file → Executable file
View File

View File

@ -0,0 +1,59 @@
"""#{if isOP then '' else "<div class=sideArrows id=sa#{postID}>&gt;&gt;</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
View File

0
src/General/html/Settings/Advanced.html Normal file → Executable file
View File

4
src/General/html/Settings/Filter-guide.html Normal file → Executable file
View File

@ -1,6 +1,6 @@
<div class=warning #{if Conf['Filter'] then 'hidden' else ''}><code>Filter</code> is disabled.</div> <div class=warning #{if Conf['Filter'] then 'hidden' else ''}><code>Filter</code> is disabled.</div>
<p> <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> 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> 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. 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> 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>. For example: <code>top:yes;</code> or <code>top:no;</code>.
</li> </li>
</ul> </ul>

0
src/General/html/Settings/Filter-select.html Normal file → Executable file
View File

0
src/General/html/Settings/Keybinds.html Normal file → Executable file
View File

0
src/General/html/Settings/Sauce.html Normal file → Executable file
View File

0
src/General/html/Settings/Settings.html Normal file → Executable file
View File

0
src/General/img/changelog/1.1.18.png Normal file → Executable file
View 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
View 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
View 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
View File

Before

Width:  |  Height:  |  Size: 659 B

After

Width:  |  Height:  |  Size: 659 B

0
src/General/img/emoji/arch.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 567 B

After

Width:  |  Height:  |  Size: 567 B

0
src/General/img/emoji/baka.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 987 B

After

Width:  |  Height:  |  Size: 987 B

0
src/General/img/emoji/centos.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 858 B

After

Width:  |  Height:  |  Size: 858 B

0
src/General/img/emoji/crunchbang.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

0
src/General/img/emoji/debian.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 559 B

0
src/General/img/emoji/fedora.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 631 B

After

Width:  |  Height:  |  Size: 631 B

0
src/General/img/emoji/freebsd.png Normal file → Executable file
View 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
View File

Before

Width:  |  Height:  |  Size: 882 B

After

Width:  |  Height:  |  Size: 882 B

0
src/General/img/emoji/gnu.png Normal file → Executable file
View 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
View File

Before

Width:  |  Height:  |  Size: 231 B

After

Width:  |  Height:  |  Size: 231 B

0
src/General/img/emoji/mint.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1006 B

After

Width:  |  Height:  |  Size: 1006 B

0
src/General/img/emoji/neko.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1012 B

After

Width:  |  Height:  |  Size: 1012 B

0
src/General/img/emoji/openbsd.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1002 B

After

Width:  |  Height:  |  Size: 1002 B

0
src/General/img/emoji/osx.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 820 B

After

Width:  |  Height:  |  Size: 820 B

0
src/General/img/emoji/plan9.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 668 B

After

Width:  |  Height:  |  Size: 668 B

0
src/General/img/emoji/ponyo.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 884 B

After

Width:  |  Height:  |  Size: 884 B

0
src/General/img/emoji/rabite.png Normal file → Executable file
View 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
View File

Before

Width:  |  Height:  |  Size: 797 B

After

Width:  |  Height:  |  Size: 797 B

0
src/General/img/emoji/sabayon.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 830 B

After

Width:  |  Height:  |  Size: 830 B

0
src/General/img/emoji/sakamoto.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 934 B

After

Width:  |  Height:  |  Size: 934 B

0
src/General/img/emoji/sega.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 339 B

0
src/General/img/emoji/slackware.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 912 B

After

Width:  |  Height:  |  Size: 912 B

0
src/General/img/emoji/trisquel.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 820 B

After

Width:  |  Height:  |  Size: 820 B

0
src/General/img/emoji/ubuntu.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 625 B

0
src/General/img/emoji/windows.png Normal file → Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

Before

Width:  |  Height:  |  Size: 232 B

After

Width:  |  Height:  |  Size: 232 B

0
src/General/img/favicons/dead.gif Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 94 B

After

Width:  |  Height:  |  Size: 94 B

0
src/General/img/favicons/empty.gif Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 94 B

After

Width:  |  Height:  |  Size: 94 B

0
src/General/img/favicons/exclamation.png Normal file → Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

Before

Width:  |  Height:  |  Size: 281 B

After

Width:  |  Height:  |  Size: 281 B

Some files were not shown because too many files have changed in this diff Show More