From b83e536c86a5a6d98dffba76ffae56f1c8e3d523 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 1 Aug 2013 20:34:00 +0200 Subject: [PATCH 01/20] Don't save the unread count if the thread is dead. --- src/Monitoring/Unread.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index ff816c6b8..c31c63b56 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -132,6 +132,7 @@ Unread = Unread.update() if e saveLastReadPost: -> + return if Unread.thread.isDead Unread.db.set boardID: Unread.thread.board.ID threadID: Unread.thread.ID From e07346a35f3a3ef564754e42787ca408e4514b10 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 1 Aug 2013 21:42:53 +0200 Subject: [PATCH 02/20] 'use strict'; --- Gruntfile.js | 2 ++ src/Meta/usestrict.js | 1 + 2 files changed, 3 insertions(+) create mode 100644 src/Meta/usestrict.js diff --git a/Gruntfile.js b/Gruntfile.js index 69100ad0f..7eeca8da7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -52,6 +52,7 @@ module.exports = function(grunt) { 'builds/crx/manifest.json': 'src/Meta/manifest.json', 'builds/crx/script.js': [ 'src/Meta/banner.js', + 'src/Meta/usestrict.js', 'tmp-<%= pkg.type %>/script.js' ] } @@ -63,6 +64,7 @@ module.exports = function(grunt) { 'builds/<%= pkg.name %>.user.js': [ 'src/Meta/metadata.js', 'src/Meta/banner.js', + 'src/Meta/usestrict.js', 'tmp-<%= pkg.type %>/script.js' ] } diff --git a/src/Meta/usestrict.js b/src/Meta/usestrict.js new file mode 100644 index 000000000..ad9a93a7c --- /dev/null +++ b/src/Meta/usestrict.js @@ -0,0 +1 @@ +'use strict'; From e5db696b87674e91cdeaa30f713b325fddbbfc57 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 1 Aug 2013 21:51:26 +0200 Subject: [PATCH 03/20] Remove the .webkit class. Use .blink instead. --- src/General/Main.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 197e7aa50..0105d43f6 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -125,7 +125,6 @@ Main = # disable the mobile layout $('link[href*=mobile]', d.head)?.disabled = true <% if (type === 'crx') { %> - $.addClass doc, 'webkit' $.addClass doc, 'blink' <% } else { %> $.addClass doc, 'gecko' From 03a8435a94fee6c68214ab8c6510cbd5890b2103 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 1 Aug 2013 22:10:51 +0200 Subject: [PATCH 04/20] Fix duplicate data property in object literal not allowed in strict mode. --- src/Archive/Redirect.coffee | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Archive/Redirect.coffee b/src/Archive/Redirect.coffee index 8cf6954bb..edc4e621c 100644 --- a/src/Archive/Redirect.coffee +++ b/src/Archive/Redirect.coffee @@ -1,8 +1,9 @@ Redirect = archives: `<%= JSON.stringify(grunt.file.readJSON('json/archives.json')) %>` - thread: {} - post: {} - file: {} + data: + thread: {} + post: {} + file: {} init: -> for boardID, data of Conf['selectedArchives'] @@ -13,15 +14,15 @@ Redirect = archive.files else archive.boards - Redirect[type][boardID] = archive if boardID in arr + Redirect.data[type][boardID] = archive if boardID in arr for archive in Conf['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 boardID not in archive.files - 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 boardID not in archive.files + Redirect.data.file[boardID] = archive Redirect.update() @@ -40,7 +41,7 @@ Redirect = cb? now 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 From 4c97408c26f9cdac7db3b59f040b0414dbc0d734 Mon Sep 17 00:00:00 2001 From: NemDiggers Date: Fri, 2 Aug 2013 03:08:52 -0400 Subject: [PATCH 05/20] Rename archive; add support for /hc/ --- json/archives.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json/archives.json b/json/archives.json index 8fd76aebf..42edc592c 100644 --- a/json/archives.json +++ b/json/archives.json @@ -54,13 +54,13 @@ "files": ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"] }, { "uid": 12, - "name": "worldathleticproject", + "name": "fap archive", "domain": "fuuka.worldathleticproject.org", "http": true, "https": false, "software": "foolfuuka", - "boards": ["e", "h", "p", "s", "u"], - "files": ["e", "h", "p", "s", "u"] + "boards": ["e", "h", "p", "s", "u", "hc"], + "files": ["e", "h", "p", "s", "u", "hc"] }, { "uid": 7, "name": "Install Gentoo", From 46c57947ce77320ee6f03e7b7f4dbd9fa776cfce Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 2 Aug 2013 09:53:25 +0200 Subject: [PATCH 06/20] Sort "fap archive" boards & files arrays. --- json/archives.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json/archives.json b/json/archives.json index 42edc592c..b59fa5145 100644 --- a/json/archives.json +++ b/json/archives.json @@ -59,8 +59,8 @@ "http": true, "https": false, "software": "foolfuuka", - "boards": ["e", "h", "p", "s", "u", "hc"], - "files": ["e", "h", "p", "s", "u", "hc"] + "boards": ["e", "h", "hc", "p", "s", "u"], + "files": ["e", "h", "hc", "p", "s", "u"] }, { "uid": 7, "name": "Install Gentoo", From 6d3afcd005b66aaf1f13a8cc8db27b37f862fd6b Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 2 Aug 2013 21:13:32 +0200 Subject: [PATCH 07/20] Simplify $.open with GM_openInTab. --- lib/$.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/$.coffee b/lib/$.coffee index 2d7da3708..811614b78 100644 --- a/lib/$.coffee +++ b/lib/$.coffee @@ -147,7 +147,7 @@ $.off = (el, events, handler) -> $.event = (event, detail, root=d) -> root.dispatchEvent new CustomEvent event, {bubbles: true, detail} <% if (type === 'userscript') { %> -$.open = (URL) -> GM_openInTab URL +$.open = GM_openInTab <% } else { %> $.open = (URL) -> window.open URL, '_blank' <% } %> From eef94f971cc75c9350b2ef200b398feeeed18851 Mon Sep 17 00:00:00 2001 From: James Campos Date: Fri, 2 Aug 2013 15:12:10 -0700 Subject: [PATCH 08/20] Gruntfile.js -> Gruntfile.coffee Close #1209 --- Gruntfile.coffee | 181 +++++++++++++++++++++++++++++++++++++++++ Gruntfile.js | 208 ----------------------------------------------- 2 files changed, 181 insertions(+), 208 deletions(-) create mode 100644 Gruntfile.coffee delete mode 100644 Gruntfile.js diff --git a/Gruntfile.coffee b/Gruntfile.coffee new file mode 100644 index 000000000..ce531b6c7 --- /dev/null +++ b/Gruntfile.coffee @@ -0,0 +1,181 @@ +module.exports = (grunt) -> + + concatOptions = + process: Object.create(null, data: + get: -> grunt.config 'pkg' + enumerable: true + ) + shellOptions = + stdout: true + stderr: true + failOnError: true + + # Project configuration. + grunt.initConfig + pkg: grunt.file.readJSON 'package.json' + concat: + coffee: + options: concatOptions + src: [ + 'src/General/Config.coffee' + 'src/General/Globals.coffee' + 'lib/**/*' + 'src/General/UI.coffee' + 'src/General/Header.coffee' + 'src/General/Notification.coffee' + 'src/General/Settings.coffee' + 'src/General/Get.coffee' + 'src/General/Build.coffee' + # Features --> + 'src/Filtering/**/*' + 'src/Quotelinks/**/*' + 'src/Posting/**/*' + 'src/Images/**/*' + 'src/Menu/**/*' + 'src/Monitoring/**/*' + 'src/Archive/**/*' + 'src/Miscellaneous/**/*' + # <--| + 'src/General/Board.coffee' + 'src/General/Thread.coffee' + 'src/General/Post.coffee' + 'src/General/Clone.coffee' + 'src/General/DataBoard.coffee' + 'src/General/Main.coffee' + ] + dest: 'tmp-<%= pkg.type %>/script.coffee' + crx: + options: concatOptions + files: + 'builds/crx/manifest.json': 'src/Meta/manifest.json' + 'builds/crx/script.js': [ + 'src/Meta/banner.js' + 'src/Meta/usestrict.js' + 'tmp-<%= pkg.type %>/script.js' + ] + userscript: + options: concatOptions + files: + 'builds/<%= pkg.name %>.meta.js': 'src/Meta/metadata.js' + 'builds/<%= pkg.name %>.user.js': [ + 'src/Meta/metadata.js' + 'src/Meta/banner.js' + 'src/Meta/usestrict.js' + 'tmp-<%= pkg.type %>/script.js' + ] + copy: + crx: + src: 'img/*.png' + dest: 'builds/crx/' + expand: true + flatten: true + # for_d19 + # 19 juin 2013 10:32:22 + # We're currently sniffing the type of the file based on file extension. + # We have a different type of content, Themes, which use a pure zip-file with a .zip ending. + # This solution is sub-optimal and will be changed in the future. + # For now, upload an unsigned ZIP-file with the ending .nex or .crx. + nex: + src: 'builds/<%= pkg.name %>.zip' + dest: 'builds/<%= pkg.name %>.nex' + coffee: + script: + src: 'tmp-<%= pkg.type %>/script.coffee' + dest: 'tmp-<%= pkg.type %>/script.js' + concurrent: + build: ['build-crx', '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 tag -af stable-v3 -m "<%= pkg.meta.name %> v<%= pkg.version %>."' + ].join(' && ') + push: + options: shellOptions + command: 'git push origin --tags -f && git push origin --all' + watch: + all: + options: + interrupt: true + files: [ + 'Gruntfile.coffee' + 'package.json' + 'lib/**/*' + 'src/**/*' + 'html/**/*' + 'css/**/*' + 'json/**/*' + 'img/**/*' + ] + tasks: 'build' + compress: + crx: + options: + archive: 'builds/<%= pkg.name %>.zip' + level: 9 + pretty: true + expand: true + flatten: true + src: 'builds/crx/*' + dest: '/' + clean: + 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' + + grunt.registerTask 'default', ['build'] + + grunt.registerTask 'set-build', 'Set the build type variable', (type) -> + pkg = grunt.config 'pkg' + pkg.type = type + grunt.config 'pkg', pkg + grunt.log.ok 'pkg.type = %s', type + grunt.registerTask 'build', ['concurrent:build'] + grunt.registerTask 'build-crx', [ + 'set-build:crx' + 'concat:coffee' + 'coffee:script' + 'concat:crx' + 'copy:crx' + 'clean:tmpcrx' + ] + grunt.registerTask 'build-userscript', [ + 'set-build:userscript' + 'concat:coffee' + 'coffee:script' + 'concat:userscript' + 'clean:tmpuserscript' + ] + + grunt.registerTask 'release', ['shell:commit', 'shell:push', 'build-crx', 'compress:crx', 'copy:nex'] + grunt.registerTask 'patch', ['bump', 'updcl:3', 'release'] + grunt.registerTask 'minor', ['bump:minor', 'updcl:2', 'release'] + grunt.registerTask 'major', ['bump:major', 'updcl:1', 'release'] + + 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}." diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 7eeca8da7..000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,208 +0,0 @@ -module.exports = function(grunt) { - - var concatOptions = { - process: { - get data() { return grunt.config('pkg'); } - } - }; - var shellOptions = { - stdout: true, - stderr: true, - failOnError: true - }; - - // Project configuration. - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - concat: { - coffee: { - options: concatOptions, - src: [ - 'src/General/Config.coffee', - 'src/General/Globals.coffee', - 'lib/**/*', - 'src/General/UI.coffee', - 'src/General/Header.coffee', - 'src/General/Notification.coffee', - 'src/General/Settings.coffee', - 'src/General/Get.coffee', - 'src/General/Build.coffee', - // Features --> - 'src/Filtering/**/*', - 'src/Quotelinks/**/*', - 'src/Posting/**/*', - 'src/Images/**/*', - 'src/Menu/**/*', - 'src/Monitoring/**/*', - 'src/Archive/**/*', - 'src/Miscellaneous/**/*', - // <--| - 'src/General/Board.coffee', - 'src/General/Thread.coffee', - 'src/General/Post.coffee', - 'src/General/Clone.coffee', - 'src/General/DataBoard.coffee', - 'src/General/Main.coffee' - ], - dest: 'tmp-<%= pkg.type %>/script.coffee' - }, - crx: { - options: concatOptions, - files: { - 'builds/crx/manifest.json': 'src/Meta/manifest.json', - 'builds/crx/script.js': [ - 'src/Meta/banner.js', - 'src/Meta/usestrict.js', - 'tmp-<%= pkg.type %>/script.js' - ] - } - }, - userscript: { - options: concatOptions, - files: { - 'builds/<%= pkg.name %>.meta.js': 'src/Meta/metadata.js', - 'builds/<%= pkg.name %>.user.js': [ - 'src/Meta/metadata.js', - 'src/Meta/banner.js', - 'src/Meta/usestrict.js', - 'tmp-<%= pkg.type %>/script.js' - ] - } - } - }, - copy: { - crx: { - src: 'img/*.png', - dest: 'builds/crx/', - expand: true, - flatten: true - }, - // for_d19 - // 19 juin 2013 10:32:22 - // We're currently sniffing the type of the file based on file extension. - // We have a different type of content, Themes, which use a pure zip-file with a .zip ending. - // This solution is sub-optimal and will be changed in the future. - // For now, upload an unsigned ZIP-file with the ending .nex or .crx. - nex: { - src: 'builds/<%= pkg.name %>.zip', - dest: 'builds/<%= pkg.name %>.nex' - } - }, - coffee: { - script: { - src: 'tmp-<%= pkg.type %>/script.coffee', - dest: 'tmp-<%= pkg.type %>/script.js' - } - }, - concurrent: { - build: ['build-crx', '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 tag -af stable-v3 -m "<%= pkg.meta.name %> v<%= pkg.version %>."' - ].join(' && ') - }, - push: { - options: shellOptions, - command: 'git push origin --tags -f && git push origin --all' - } - }, - watch: { - all: { - options: { - interrupt: true - }, - files: [ - 'Gruntfile.js', - 'package.json', - 'lib/**/*', - 'src/**/*', - 'html/**/*', - 'css/**/*', - 'json/**/*', - 'img/**/*' - ], - tasks: 'build' - } - }, - compress: { - crx: { - options: { - archive: 'builds/<%= pkg.name %>.zip', - level: 9, - pretty: true - }, - expand: true, - flatten: true, - src: 'builds/crx/*', - dest: '/' - } - }, - clean: { - 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'); - - grunt.registerTask('default', ['build']); - - grunt.registerTask('set-build', 'Set the build type variable', function(type) { - var pkg = grunt.config('pkg'); - pkg.type = type; - grunt.config('pkg', pkg); - grunt.log.ok('pkg.type = %s', type); - }); - grunt.registerTask('build', ['concurrent:build']); - grunt.registerTask('build-crx', [ - 'set-build:crx', - 'concat:coffee', - 'coffee:script', - 'concat:crx', - 'copy:crx', - 'clean:tmpcrx' - ]); - grunt.registerTask('build-userscript', [ - 'set-build:userscript', - 'concat:coffee', - 'coffee:script', - 'concat:userscript', - 'clean:tmpuserscript' - ]); - - grunt.registerTask('release', ['shell:commit', 'shell:push', 'build-crx', 'compress:crx', 'copy:nex']); - grunt.registerTask('patch', ['bump', 'updcl:3', 'release']); - grunt.registerTask('minor', ['bump:minor', 'updcl:2', 'release']); - grunt.registerTask('major', ['bump:major', 'updcl:1', 'release']); - - grunt.registerTask('updcl', 'Update the changelog', function(i) { - // i is the number of #s for markdown. - var pkg = grunt.config('pkg'); - var version = new Array(+i + 1).join('#') + ' ' + pkg.version + ' - *' + grunt.template.today('yyyy-mm-dd') + '*'; - grunt.file.write('CHANGELOG.md', version + '\n\n' + grunt.file.read('CHANGELOG.md')); - grunt.log.ok('Changelog updated for v' + pkg.version + '.'); - }); -}; From 0b6f66ca81142c9c96b9fb6a6a71c02cc01ce93f Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 3 Aug 2013 00:27:36 +0200 Subject: [PATCH 09/20] A few alignement tweaks. --- Gruntfile.coffee | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index ce531b6c7..268a8826c 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -65,9 +65,9 @@ module.exports = (grunt) -> ] copy: crx: - src: 'img/*.png' + src: 'img/*.png' dest: 'builds/crx/' - expand: true + expand: true flatten: true # for_d19 # 19 juin 2013 10:32:22 @@ -76,20 +76,20 @@ module.exports = (grunt) -> # This solution is sub-optimal and will be changed in the future. # For now, upload an unsigned ZIP-file with the ending .nex or .crx. nex: - src: 'builds/<%= pkg.name %>.zip' + src: 'builds/<%= pkg.name %>.zip' dest: 'builds/<%= pkg.name %>.nex' coffee: script: - src: 'tmp-<%= pkg.type %>/script.coffee' + src: 'tmp-<%= pkg.type %>/script.coffee' dest: 'tmp-<%= pkg.type %>/script.js' concurrent: build: ['build-crx', 'build-userscript'] bump: options: updateConfigs: ['pkg'] - commit: false + commit: false createTag: false - push: false + push: false shell: commit: options: shellOptions @@ -98,7 +98,7 @@ module.exports = (grunt) -> '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-v3 -m "<%= pkg.meta.name %> v<%= pkg.version %>."' - ].join(' && ') + ].join ' && ' push: options: shellOptions command: 'git push origin --tags -f && git push origin --all' @@ -123,7 +123,7 @@ module.exports = (grunt) -> archive: 'builds/<%= pkg.name %>.zip' level: 9 pretty: true - expand: true + expand: true flatten: true src: 'builds/crx/*' dest: '/' @@ -167,7 +167,7 @@ module.exports = (grunt) -> ] grunt.registerTask 'release', ['shell:commit', 'shell:push', 'build-crx', 'compress:crx', 'copy:nex'] - grunt.registerTask 'patch', ['bump', 'updcl:3', 'release'] + grunt.registerTask 'patch', ['bump', 'updcl:3', 'release'] grunt.registerTask 'minor', ['bump:minor', 'updcl:2', 'release'] grunt.registerTask 'major', ['bump:major', 'updcl:1', 'release'] From 82d3afba0adfa77ba2ad6bae77a561376360fd9a Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 3 Aug 2013 00:52:16 +0200 Subject: [PATCH 10/20] Tweak Gruntfile tasks loading. --- Gruntfile.coffee | 10 +--------- package.json | 3 ++- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 268a8826c..9410f0c6b 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -132,15 +132,7 @@ module.exports = (grunt) -> 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'] diff --git a/package.json b/package.json index b01920f2d..33b87d4d9 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "grunt-contrib-concat": "~0.3.0", "grunt-contrib-copy": "~0.4.1", "grunt-contrib-watch": "~0.5.0", - "grunt-shell": "~0.3.1" + "grunt-shell": "~0.3.1", + "matchdep": "~0.1.2" }, "repository": { "type": "git", From 68214969d8707f919b0b689ffb6924bd3a7c6b48 Mon Sep 17 00:00:00 2001 From: NemDiggers Date: Sat, 3 Aug 2013 01:04:38 -0400 Subject: [PATCH 11/20] I'm crazy I'm going to give it a shot. I've been archiving /b/ for awhile now and see nothing blatantly illegal. I'm hoping users will report anything van worthy. If shit hits the fan, I'll just submit another PR removing it. --- json/archives.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json/archives.json b/json/archives.json index b59fa5145..a5cee414f 100644 --- a/json/archives.json +++ b/json/archives.json @@ -59,8 +59,8 @@ "http": true, "https": false, "software": "foolfuuka", - "boards": ["e", "h", "hc", "p", "s", "u"], - "files": ["e", "h", "hc", "p", "s", "u"] + "boards": ["b" "e", "h", "hc", "p", "s", "u"], + "files": ["b" "e", "h", "hc", "p", "s", "u"] }, { "uid": 7, "name": "Install Gentoo", From fbebf6cbd376b09d2ac94d6b2c4bd720902c20cb Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 3 Aug 2013 18:05:53 +0200 Subject: [PATCH 12/20] Fix missing comma. @Proplex --- json/archives.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json/archives.json b/json/archives.json index a5cee414f..f0c788108 100644 --- a/json/archives.json +++ b/json/archives.json @@ -59,8 +59,8 @@ "http": true, "https": false, "software": "foolfuuka", - "boards": ["b" "e", "h", "hc", "p", "s", "u"], - "files": ["b" "e", "h", "hc", "p", "s", "u"] + "boards": ["b", "e", "h", "hc", "p", "s", "u"], + "files": ["b", "e", "h", "hc", "p", "s", "u"] }, { "uid": 7, "name": "Install Gentoo", From 8e79a53701e07064abd56882945df5902506fd91 Mon Sep 17 00:00:00 2001 From: Enzo Moretti Date: Sun, 4 Aug 2013 15:32:52 +0200 Subject: [PATCH 13/20] Adding Foolz Archive Beta as archive option. --- json/archives.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/json/archives.json b/json/archives.json index f0c788108..e83401a89 100644 --- a/json/archives.json +++ b/json/archives.json @@ -97,4 +97,13 @@ "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": 11, + "name": "Foolz Beta", + "domain": "beta.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"] }] From 6b0ba6f96e59eda8ce85c6d566c83c1a11b69a14 Mon Sep 17 00:00:00 2001 From: Enzo Moretti Date: Sun, 4 Aug 2013 16:00:12 +0200 Subject: [PATCH 14/20] Adding also /mlp/, /h/ and /u/, and fixing the unique id. --- json/archives.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json/archives.json b/json/archives.json index e83401a89..15c52e369 100644 --- a/json/archives.json +++ b/json/archives.json @@ -98,12 +98,12 @@ "boards": ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "q", "tg", "vr"], "files": ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "q", "tg", "vr"] }, { - "uid": 11, + "uid": 13, "name": "Foolz Beta", "domain": "beta.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"] + "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"] }] From ebb2d0bf75866361fc37144d3cfa452628994d56 Mon Sep 17 00:00:00 2001 From: Jordan Bates Date: Sun, 4 Aug 2013 14:22:26 -0700 Subject: [PATCH 15/20] Not sure how no one caught this. --- LICENSE | 2 +- builds/4chan-X.js | 398 ++++++++++++++++++++++++++++++- builds/4chan-X.user.js | 397 +++++++++++++++++++++++++++++- builds/crx/script.js | 394 +++++++++++++++++++++++++++++- src/General/Config.coffee | 4 +- src/Images/RevealSpoilers.coffee | 4 +- 6 files changed, 1182 insertions(+), 17 deletions(-) diff --git a/LICENSE b/LICENSE index 8758af562..391e259a5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.2.24 - 2013-07-24 +* 4chan X - Version 1.2.24 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.js b/builds/4chan-X.js index 7fe4d2e99..b2fa58069 100644 --- a/builds/4chan-X.js +++ b/builds/4chan-X.js @@ -19,7 +19,7 @@ // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC // ==/UserScript== /* -* 4chan X - Version 1.2.24 - 2013-07-24 +* 4chan X - Version 1.2.24 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -159,7 +159,7 @@ 'Image Expansion': [true, 'Expand images.'], 'Image Hover': [true, 'Show full image on mouseover.'], 'Sauce': [true, 'Add sauce links to images.'], - 'Reveal Spoilers': [false, 'Reveal spoiler thumbnails.'], + 'Reveal Spoiler Thumbnails': [false, 'Replace spoiler thumbnails with the original image.'], 'Replace GIF': [false, 'Replace thumbnail of gifs with its actual image.'], 'Replace PNG': [false, 'Replace pngs.'], 'Replace JPG': [false, 'Replace jpgs.'], @@ -340,6 +340,7 @@ Array.prototype.add = function(object, position) { var keep; + keep = this.slice(position); this.length = position; this.push(object); @@ -352,6 +353,7 @@ Array.prototype.indexOf = function(object) { var i; + i = this.length; while (i--) { if (this[i] === object) { @@ -363,6 +365,7 @@ Array.prototype.pushArrays = function() { var arg, args, _i, _len; + args = arguments; for (_i = 0, _len = args.length; _i < _len; _i++) { arg = args[_i]; @@ -373,6 +376,7 @@ Array.prototype.remove = function(object) { var index; + if ((index = this.indexOf(object)) > -1) { return this.splice(index, 1); } else { @@ -389,6 +393,7 @@ $.extend = function(object, properties) { var key, val; + for (key in properties) { val = properties[key]; if (!properties.hasOwnProperty(key)) { @@ -406,6 +411,7 @@ $.ready = function(fc) { var cb, _ref; + if ((_ref = d.readyState) === 'interactive' || _ref === 'complete') { $.queueTask(fc); return; @@ -419,6 +425,7 @@ $.formData = function(form) { var fd, key, val; + if (form instanceof HTMLFormElement) { return new FormData(form); } @@ -439,6 +446,7 @@ $.ajax = function(url, callbacks, opts) { var cred, err, form, headers, key, r, sync, type, upCallbacks, val; + if (opts == null) { opts = {}; } @@ -464,9 +472,11 @@ $.cache = (function() { var reqs; + reqs = {}; return function(url, cb) { var err, req, rm; + if (req = reqs[url]) { if (req.readyState === 4) { cb.call(req, req.evt); @@ -482,6 +492,7 @@ req = $.ajax(url, { onload: function(e) { var _i, _len, _ref; + _ref = this.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { cb = _ref[_i]; @@ -523,6 +534,7 @@ $.addStyle = function(css, id) { var style; + style = $.el('style', { id: id, textContent: css @@ -569,6 +581,7 @@ } else { return function(el) { var _ref; + return (_ref = el.parentNode) != null ? _ref.removeChild(el) : void 0; }; } @@ -576,6 +589,7 @@ $.rmAll = function(root) { var node; + while (node = root.firstChild) { root.removeChild(node); } @@ -591,6 +605,7 @@ $.nodes = function(nodes) { var frag, node, _i, _len; + if (!(nodes instanceof Array)) { return nodes; } @@ -624,6 +639,7 @@ $.el = function(tag, properties) { var el; + el = d.createElement(tag); if (properties) { $.extend(el, properties); @@ -633,6 +649,7 @@ $.on = function(el, events, handler) { var event, _i, _len, _ref; + _ref = events.split(' '); for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; @@ -642,6 +659,7 @@ $.off = function(el, events, handler) { var event, _i, _len, _ref; + _ref = events.split(' '); for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; @@ -665,6 +683,7 @@ $.debounce = function(wait, fn) { var args, exec, lastCall, that, timeout; + lastCall = 0; timeout = null; that = null; @@ -686,9 +705,11 @@ $.queueTask = (function() { var execTask, taskChannel, taskQueue; + taskQueue = []; execTask = function() { var args, func, task; + task = taskQueue.shift(); func = task[0]; args = Array.prototype.slice.call(task, 1); @@ -711,6 +732,7 @@ $.globalEval = function(code) { var script; + script = $.el('script', { textContent: code }); @@ -720,6 +742,7 @@ $.bytesToString = function(size) { var unit; + unit = 0; while (size >= 1024) { size /= 1024; @@ -738,6 +761,7 @@ $.sync = (function() { window.addEventListener('storage', function(e) { var cb; + if (cb = $.syncing[e.key]) { return cb(JSON.parse(e.newValue)); } @@ -749,6 +773,7 @@ $.item = function(key, val) { var item; + item = {}; item[key] = val; return item; @@ -756,9 +781,11 @@ (function() { var scriptStorage; + scriptStorage = opera.scriptStorage; $["delete"] = function(keys) { var key, _i, _len; + if (!(keys instanceof Array)) { keys = [keys]; } @@ -771,6 +798,7 @@ }; $.get = function(key, val, cb) { var items; + if (typeof cb === 'function') { items = $.item(key, val); } else { @@ -788,6 +816,7 @@ }; $.set = (function() { var set; + set = function(key, val) { key = g.NAMESPACE + key; val = JSON.stringify(val); @@ -798,6 +827,7 @@ }; return function(keys, val) { var key; + if (typeof keys === 'string') { set(keys, val); return; @@ -866,6 +896,7 @@ function Post(root, thread, board, that) { var alt, anchor, capcode, date, email, file, fileInfo, flag, info, name, post, size, subject, thumb, tripcode, uniqueID, unit; + this.thread = thread; this.board = board; if (that == null) { @@ -964,6 +995,7 @@ Post.prototype.parseComment = function() { var bq, data, i, node, nodes, text, _i, _len, _ref; + bq = this.nodes.comment.cloneNode(true); _ref = $$('.abbr, .capcodeReplies, .exif, b', bq); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -981,6 +1013,7 @@ Post.prototype.parseQuotes = function() { var hash, pathname, quotelink, quotes, _i, _len, _ref; + quotes = {}; _ref = $$('.quotelink', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1010,6 +1043,7 @@ Post.prototype.kill = function(file, now) { var clone, quotelink, strong, _i, _j, _len, _len1, _ref, _ref1; + now || (now = new Date()); if (file) { if (this.file.isDead) { @@ -1058,6 +1092,7 @@ Post.prototype.resurrect = function() { var clone, quotelink, strong, _i, _j, _len, _len1, _ref, _ref1; + delete this.isDead; delete this.timeOfDeath; $.rmClass(this.nodes.root, 'deleted-post'); @@ -1091,6 +1126,7 @@ Post.prototype.rmClone = function(index) { var clone, _i, _len, _ref; + this.clones.splice(index, 1); _ref = this.clones.slice(index); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1108,6 +1144,7 @@ function Clone(origin, context) { var file, index, info, inline, inlined, key, nodes, post, root, val, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; + this.origin = origin; this.context = context; _ref = ['ID', 'fullID', 'board', 'thread', 'info', 'quotes', 'isReply']; @@ -1196,6 +1233,7 @@ function DataBoard(key, sync) { var init, _this = this; + this.key = key; this.data = Conf[key]; $.sync(key, this.onSync.bind(this)); @@ -1212,6 +1250,7 @@ DataBoard.prototype["delete"] = function(_arg) { var boardID, postID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID; if (postID) { delete this.data.boards[boardID][threadID][postID]; @@ -1232,6 +1271,7 @@ DataBoard.prototype.deleteIfEmpty = function(_arg) { var boardID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID; if (threadID) { if (!Object.keys(this.data.boards[boardID][threadID]).length) { @@ -1247,6 +1287,7 @@ DataBoard.prototype.set = function(_arg) { var boardID, postID, threadID, val, _base, _base1, _base2; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID, val = _arg.val; if (postID !== void 0) { ((_base = ((_base1 = this.data.boards)[boardID] || (_base1[boardID] = {})))[threadID] || (_base[threadID] = {}))[postID] = val; @@ -1260,6 +1301,7 @@ DataBoard.prototype.get = function(_arg) { var ID, board, boardID, defaultValue, postID, thread, threadID, val, _i, _len; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID, defaultValue = _arg.defaultValue; if (board = this.data.boards[boardID]) { if (!threadID) { @@ -1283,6 +1325,7 @@ DataBoard.prototype.clean = function() { var boardID, now, val, _ref; + _ref = this.data.boards; for (boardID in _ref) { val = _ref[boardID]; @@ -1302,8 +1345,10 @@ DataBoard.prototype.ajaxClean = function(boardID) { var _this = this; + return $.cache("//api.4chan.org/" + boardID + "/threads.json", function(e) { var board, page, thread, threads, _i, _j, _len, _len1, _ref, _ref1; + if (e.target.status === 404) { _this["delete"](boardID); } else if (e.target.status === 200) { @@ -1414,6 +1459,7 @@ init: function() { var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler, linkJustifyToggler, _this = this; + this.menu = new UI.Menu('header'); this.menuButton = $.el('span', { className: 'menu-button', @@ -1497,6 +1543,7 @@ } $.asap((function() { var _ref; + return $.id('boardNavMobile') || ((_ref = d.readyState) === 'interactive' || _ref === 'complete'); }), Header.setBoardList); $.prepend(d.body, _this.bar); @@ -1505,6 +1552,7 @@ }); return $.ready(function() { var a, cs; + _this.footer = $.id('boardNavDesktopFoot'); if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) { a.className = 'current'; @@ -1538,6 +1586,7 @@ }), setBoardList: function() { var a, boardList, btn, fourchannav, fullBoardList; + fourchannav = $.id('boardNavDesktop'); if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) { a.className = 'current'; @@ -1559,6 +1608,7 @@ }, generateBoardList: function(text) { var as, list, nodes; + list = $('#custom-board-list', Header.bar); $.rmAll(list); if (!text) { @@ -1567,6 +1617,7 @@ as = $$('#full-board-list a', Header.bar); nodes = text.match(/[\w@]+((-(all|title|replace|full|index|catalog|url:"[^"]+[^"]"|text:"[^"]+")|\,"[^"]+[^"]"))*|[^\w@]+/g).map(function(t) { var a, board, m, _i, _len; + if (/^[^\w@]/.test(t)) { return $.tn(t); } @@ -1613,6 +1664,7 @@ }, toggleBoardList: function() { var bar, custom, full, showBoardList; + bar = Header.bar; custom = $('#custom-board-list', bar); full = $('#full-board-list', bar); @@ -1648,6 +1700,7 @@ }, toggleLinkJustify: function() { var centered; + $.event('CloseMenu'); centered = this.nodeName === 'INPUT' ? this.checked : void 0; Header.setLinkJustify(centered); @@ -1677,6 +1730,7 @@ }, toggleBarVisibility: function(e) { var hide, message; + if (e.type === 'mousedown' && e.button !== 0) { return; } @@ -1693,6 +1747,7 @@ }, toggleFooterVisibility: function() { var hide, message; + $.event('CloseMenu'); hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden; Header.setFooterVisibility(hide); @@ -1702,6 +1757,7 @@ }, setCustomNav: function(show) { var btn, cust, full, _ref; + Header.customNavToggler.checked = show; cust = $('#custom-board-list', Header.bar); full = $('#full-board-list', Header.bar); @@ -1714,12 +1770,14 @@ }, editCustomNav: function() { var settings; + Settings.open('Advanced'); settings = $.id('fourchanx-settings'); return $('input[name=boardnav]', settings).focus(); }, hashScroll: function() { var hash, post; + if (!((hash = this.location.hash.slice(1)) && (post = $.id(hash)))) { return; } @@ -1730,6 +1788,7 @@ }, scrollToPost: function(post) { var headRect, top; + top = post.getBoundingClientRect().top; if (Conf['Fixed Header'] && !Conf['Bottom Header']) { headRect = Header.bar.getBoundingClientRect(); @@ -1739,6 +1798,7 @@ }, addShortcut: function(el) { var shortcut; + shortcut = $.el('span', { className: 'shortcut fourchanx-link' }); @@ -1750,6 +1810,7 @@ }, createNotification: function(e) { var cb, content, lifetime, notif, type, _ref; + _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb; notif = new Notification(type, content, lifetime); if (cb) { @@ -1762,6 +1823,7 @@ spoilerRange: {}, shortFilename: function(filename, isReply) { var threshold; + threshold = isReply ? 30 : 40; if (filename.length - 4 > threshold) { return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3); @@ -1771,6 +1833,7 @@ }, postFromObject: function(data, boardID) { var o; + o = { postID: data.no, threadID: data.resto || data.no, @@ -1814,6 +1877,7 @@ */ var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref; + postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file; isOP = postID === threadID; staticPath = '//static.4chan.org/image/'; @@ -1909,6 +1973,7 @@ Get = { threadExcerpt: function(thread) { var OP, excerpt, _ref; + OP = thread.OP; excerpt = ((_ref = OP.info.subject) != null ? _ref.trim() : void 0) || OP.info.comment.replace(/\n+/g, ' // ') || Conf['Anonymize'] && 'Anonymous' || $('.nameBlock', OP.nodes.info).textContent.trim(); if (excerpt.length > 70) { @@ -1921,6 +1986,7 @@ }, postFromRoot: function(root) { var boardID, index, link, post, postID; + link = $('a[title="Highlight this post"]', root); boardID = link.pathname.split('/')[1]; postID = link.hash.slice(2); @@ -1940,6 +2006,7 @@ }, postDataFromLink: function(link) { var boardID, path, postID, threadID; + if (link.hostname === 'boards.4chan.org') { path = link.pathname.split('/'); boardID = path[1]; @@ -1958,6 +2025,7 @@ }, allQuotelinksLinkingTo: function(post) { var ID, quote, quotedPost, quotelinks, quoterPost, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; + quotelinks = []; _ref = g.posts; for (ID in _ref) { @@ -1986,12 +2054,14 @@ } return quotelinks.filter(function(quotelink) { var boardID, postID, _ref4; + _ref4 = Get.postDataFromLink(quotelink), boardID = _ref4.boardID, postID = _ref4.postID; return boardID === post.board.ID && postID === post.ID; }); }, postClone: function(boardID, threadID, postID, root, context) { var post, url; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2012,6 +2082,7 @@ }, insert: function(post, root, context) { var clone, nodes; + if (!root.parentNode) { return; } @@ -2025,6 +2096,7 @@ }, fetchedPost: function(req, boardID, threadID, postID, root, context) { var board, post, posts, status, thread, url, _i, _len; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2074,6 +2146,7 @@ }, archivedPost: function(req, boardID, postID, root, context) { var board, bq, comment, data, o, post, thread, threadID, _ref; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2167,8 +2240,10 @@ UI = (function() { var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove; + dialog = function(id, position, html) { var child, el, move, _i, _len, _ref; + el = $.el('div', { className: 'dialog', innerHTML: html, @@ -2208,6 +2283,7 @@ Menu.prototype.makeMenu = function() { var menu; + menu = $.el('div', { className: 'dialog', id: 'menu', @@ -2222,6 +2298,7 @@ Menu.prototype.toggle = function(e, button, data) { var previousButton; + e.preventDefault(); e.stopPropagation(); if (currentMenu) { @@ -2239,6 +2316,7 @@ Menu.prototype.open = function(button, data) { var bLeft, bRect, bTop, bottom, cHeight, cWidth, entry, left, mRect, menu, right, style, top, _i, _len, _ref, _ref1, _ref2; + menu = this.makeMenu(); currentMenu = menu; lastToggledButton = button; @@ -2277,6 +2355,7 @@ Menu.prototype.insertEntry = function(entry, parent, data) { var subEntry, submenu, _i, _len, _ref; + if (typeof entry.open === 'function') { if (!entry.open(data)) { return; @@ -2310,6 +2389,7 @@ Menu.prototype.findNextEntry = function(entry, direction) { var entries; + entries = __slice.call(entry.parentNode.children); entries.sort(function(first, second) { return +(first.style.order || first.style.webkitOrder) - +(second.style.order || second.style.webkitOrder); @@ -2319,6 +2399,7 @@ Menu.prototype.keybinds = function(e) { var entry, next, nextPrev, subEntry, submenu; + entry = $('.focused', currentMenu); while (subEntry = $('.focused', entry)) { entry = subEntry; @@ -2364,6 +2445,7 @@ Menu.prototype.focus = function(entry) { var bottom, cHeight, cWidth, eRect, focused, left, right, sRect, style, submenu, top, _i, _len, _ref, _ref1, _ref2; + while (focused = $.x('parent::*/child::*[contains(@class,"focused")]', entry)) { $.rmClass(focused, 'focused'); } @@ -2391,6 +2473,7 @@ Menu.prototype.addEntry = function(e) { var entry; + entry = e.detail; if (entry.type !== this.type) { return; @@ -2401,6 +2484,7 @@ Menu.prototype.parseEntry = function(entry) { var el, style, subEntries, subEntry, _i, _len; + el = entry.el, subEntries = entry.subEntries; $.addClass(el, 'entry'); $.on(el, 'focus mouseover', (function(e) { @@ -2424,6 +2508,7 @@ })(); dragstart = function(e) { var el, isTouching, o, rect, screenHeight, screenWidth, _ref; + if (e.type === 'mousedown' && e.button !== 0) { return; } @@ -2462,6 +2547,7 @@ }; touchmove = function(e) { var touch, _i, _len, _ref; + _ref = e.changedTouches; for (_i = 0, _len = _ref.length; _i < _len; _i++) { touch = _ref[_i]; @@ -2473,6 +2559,7 @@ }; drag = function(e) { var bottom, clientX, clientY, left, right, style, top; + clientX = e.clientX, clientY = e.clientY; left = clientX - this.dx; left = left < 10 ? 0 : this.width - left < 10 ? null : left / this.screenWidth * 100 + '%'; @@ -2488,6 +2575,7 @@ }; touchend = function(e) { var touch, _i, _len, _ref; + _ref = e.changedTouches; for (_i = 0, _len = _ref.length; _i < _len; _i++) { touch = _ref[_i]; @@ -2509,6 +2597,7 @@ }; hoverstart = function(_arg) { var asapTest, cb, el, endEvents, latestEvent, o, root; + root = _arg.root, el = _arg.el, latestEvent = _arg.latestEvent, endEvents = _arg.endEvents, asapTest = _arg.asapTest, cb = _arg.cb; o = { root: root, @@ -2537,6 +2626,7 @@ }; hover = function(e) { var clientX, clientY, height, left, right, style, top, _ref; + this.latestEvent = e; height = this.el.offsetHeight; clientX = e.clientX, clientY = e.clientY; @@ -2579,6 +2669,7 @@ }, node: function() { var email, name, tripcode, _ref; + if (this.info.capcode || this.isClone) { return; } @@ -2605,6 +2696,7 @@ filters: {}, init: function() { var boards, err, filter, hl, key, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4; + if (g.VIEW === 'catalog' || !Conf['Filter']) { return; } @@ -2641,6 +2733,7 @@ op = ((_ref2 = filter.match(/[^t]op:(yes|no|only)/)) != null ? _ref2[1] : void 0) || 'yes'; stub = (function() { var _ref3; + switch ((_ref3 = filter.match(/stub:(yes|no)/)) != null ? _ref3[1] : void 0) { case 'yes': return true; @@ -2671,6 +2764,7 @@ }, createFilter: function(regexp, op, stub, hl, top) { var settings, test; + test = typeof regexp === 'string' ? function(value) { return regexp === value; } : function(value) { @@ -2694,6 +2788,7 @@ }, node: function() { var filter, firstThread, key, result, thisThread, value, _i, _len, _ref; + if (this.isClone) { return; } @@ -2805,6 +2900,7 @@ menu: { init: function() { var div, entry, type, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Filter']) { return; } @@ -2830,6 +2926,7 @@ }, createSubEntry: function(text, type) { var el; + el = $.el('a', { href: 'javascript:;', textContent: text @@ -2840,6 +2937,7 @@ el: el, open: function(post) { var value; + value = Filter[type](post); return value !== false; } @@ -2847,6 +2945,7 @@ }, makeFilter: function() { var re, type, value; + type = this.dataset.type; value = Filter[type](Filter.menu.post); re = ['uniqueID', 'MD5'].contains(type) ? value : value.replace(/\/|\\|\^|\$|\n|\.|\(|\)|\{|\}|\[|\]|\?|\*|\+|\|/g, function(c) { @@ -2861,6 +2960,7 @@ re = ['uniqueID', 'MD5'].contains(type) ? "/" + re + "/" : "/^" + re + "$/"; return $.get(type, Conf[type], function(item) { var save, section, select, ta, tl; + save = item[type]; save = save ? "" + save + "\n" + re : re; $.set(type, save); @@ -2894,6 +2994,7 @@ }, node: function() { var data; + if (!this.isReply || this.isClone) { return; } @@ -2917,6 +3018,7 @@ menu: { init: function() { var apply, div, hideStubLink, makeStub, replies, thisPost; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Reply Hiding Link']) { return; } @@ -2987,6 +3089,7 @@ order: 20, open: function(post) { var data; + if (!post.isReply || post.isClone || !post.isHidden) { return false; } @@ -3018,6 +3121,7 @@ order: 15, open: function(post) { var data; + if (!post.isReply || post.isClone || !post.isHidden) { return false; } @@ -3034,6 +3138,7 @@ }, hide: function() { var makeStub, parent, post, replies, thisPost; + parent = this.parentNode; thisPost = $('input[name=thisPost]', parent).checked; replies = $('input[name=replies]', parent).checked; @@ -3052,6 +3157,7 @@ }, show: function() { var data, parent, post, replies, thisPost; + parent = this.parentNode; thisPost = $('input[name=thisPost]', parent).checked; replies = $('input[name=replies]', parent).checked; @@ -3075,6 +3181,7 @@ }, hideStub: function() { var post; + post = PostHiding.menu.post; post.nodes.root.hidden = true; $.event('CloseMenu'); @@ -3082,6 +3189,7 @@ }, makeButton: function(post, type) { var a; + a = $.el('a', { className: "" + type + "-reply-button", innerHTML: " " + (type === 'hide' ? '-' : '+') + " ", @@ -3092,6 +3200,7 @@ }, saveHiddenState: function(post, isHiding, thisPost, makeStub, hideRecursively) { var data; + data = { boardID: post.board.ID, threadID: post.thread.ID, @@ -3110,6 +3219,7 @@ }, toggle: function() { var post; + post = Get.postFromNode(this); if (post.isHidden) { PostHiding.show(post); @@ -3120,6 +3230,7 @@ }, hide: function(post, makeStub, hideRecursively) { var a, postInfo, quotelink, _i, _len, _ref; + if (makeStub == null) { makeStub = Conf['Stubs']; } @@ -3157,6 +3268,7 @@ }, show: function(post, showRecursively) { var quotelink, _i, _len, _ref; + if (showRecursively == null) { showRecursively = Conf['Recursive Hiding']; } @@ -3192,6 +3304,7 @@ }, node: function() { var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1; + if (this.isClone) { return; } @@ -3209,6 +3322,7 @@ }, add: function() { var args, obj, post, recursive, _base, _name; + recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = { recursives: [], @@ -3219,6 +3333,7 @@ }, rm: function(recursive, post) { var i, obj, rec, _i, _len, _ref; + if (!(obj = Recursive.recursives[post.fullID])) { return; } @@ -3233,6 +3348,7 @@ }, apply: function() { var ID, args, fullID, post, recursive, _ref; + recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; fullID = post.fullID; _ref = g.posts; @@ -3259,6 +3375,7 @@ }, node: function() { var data; + if (data = ThreadHiding.db.get({ boardID: this.board.ID, threadID: this.ID @@ -3272,6 +3389,7 @@ }, syncCatalog: function() { var hiddenThreads, hiddenThreadsOnCatalog, threadID; + hiddenThreads = ThreadHiding.db.get({ boardID: g.BOARD.ID, defaultValue: {} @@ -3298,6 +3416,7 @@ cleanCatalog: function(hiddenThreadsOnCatalog) { return $.cache("//api.4chan.org/" + g.BOARD + "/threads.json", function() { var page, thread, threads, _i, _j, _len, _len1, _ref, _ref1; + if (this.status !== 200) { return; } @@ -3323,6 +3442,7 @@ menu: { init: function() { var apply, div, hideStubLink, makeStub; + if (g.VIEW !== 'index' || !Conf['Menu'] || !Conf['Thread Hiding Link']) { return; } @@ -3349,6 +3469,7 @@ order: 20, open: function(_arg) { var isReply, thread; + thread = _arg.thread, isReply = _arg.isReply; if (isReply || thread.isHidden) { return false; @@ -3370,6 +3491,7 @@ order: 15, open: function(_arg) { var isReply, thread; + thread = _arg.thread, isReply = _arg.isReply; if (isReply || !thread.isHidden) { return false; @@ -3380,6 +3502,7 @@ }, hide: function() { var makeStub, thread; + makeStub = $('input', this.parentNode).checked; thread = ThreadHiding.menu.thread; ThreadHiding.hide(thread, makeStub); @@ -3388,6 +3511,7 @@ }, hideStub: function() { var thread; + thread = ThreadHiding.menu.thread; ThreadHiding.hide(thread, false); $.event('CloseMenu'); @@ -3395,6 +3519,7 @@ }, makeButton: function(thread, type) { var a; + a = $.el('a', { className: "" + type + "-thread-button", innerHTML: " " + (type === 'hide' ? '-' : '+') + " ", @@ -3406,6 +3531,7 @@ }, saveHiddenState: function(thread, makeStub) { var hiddenThreadsOnCatalog; + hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {}; if (thread.isHidden) { ThreadHiding.db.set({ @@ -3438,6 +3564,7 @@ }, hide: function(thread, makeStub) { var OP, a, numReplies, opInfo, span, threadRoot; + if (makeStub == null) { makeStub = Conf['Stubs']; } @@ -3468,6 +3595,7 @@ }, show: function(thread) { var threadRoot; + if (thread.stub) { $.rm(thread.stub); delete thread.stub; @@ -3480,6 +3608,7 @@ QuoteBacklink = { init: function() { var format; + if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) { return; } @@ -3497,6 +3626,7 @@ }, firstNode: function() { var a, clone, container, containers, frag, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + if (this.isClone || !this.quotes.length) { return; } @@ -3534,6 +3664,7 @@ }, secondNode: function() { var container; + if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) { this.nodes.backlinkContainer = $('.container', this.nodes.info); return; @@ -3547,6 +3678,7 @@ }, getContainer: function(id) { var _base; + return (_base = this.containers)[id] || (_base[id] = $.el('span', { className: 'container' })); @@ -3569,6 +3701,7 @@ }, node: function() { var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1; + if (this.isClone && this.thread === this.context.thread) { return; } @@ -3604,6 +3737,7 @@ if (Conf['Quote Hash Navigation']) { this.node = function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3616,6 +3750,7 @@ } else { this.node = function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3639,6 +3774,7 @@ }, toggle: function(e) { var boardID, context, postID, threadID, _ref; + if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) { return; } @@ -3664,6 +3800,7 @@ }, add: function(quotelink, boardID, threadID, postID, context) { var inline, isBacklink, post, qroot, root; + isBacklink = $.hasClass(quotelink, 'backlink'); inline = $.el('div', { id: "i" + postID, @@ -3688,6 +3825,7 @@ }, rm: function(quotelink, boardID, threadID, postID, context) { var el, inlined, isBacklink, post, qroot, root, _ref; + isBacklink = $.hasClass(quotelink, 'backlink'); root = QuoteInline.findRoot(quotelink, isBacklink); root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root); @@ -3729,6 +3867,7 @@ }, node: function() { var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref; + if (this.isClone && this.thread === this.context.thread) { return; } @@ -3771,6 +3910,7 @@ }, node: function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3779,6 +3919,7 @@ }, mouseover: function(e) { var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, root, threadID, workaround, _i, _j, _len, _len1, _ref, _ref1; + if ($.hasClass(this, 'inlined')) { return; } @@ -3834,6 +3975,7 @@ }, mouseout: function() { var clone, post, root, _i, _len, _ref; + if (!(root = this.el.firstElementChild)) { return; } @@ -3863,6 +4005,7 @@ }, node: function() { var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2; + if (this.isClone) { return; } @@ -3885,6 +4028,7 @@ QuoteThreading = { init: function() { var input; + if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) { return; } @@ -3907,6 +4051,7 @@ }, setup: function() { var ID, post, posts; + $.off(d, '4chanXInitFinished', QuoteThreading.setup); posts = g.posts; for (ID in posts) { @@ -3919,6 +4064,7 @@ }, node: function() { var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len; + if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) { return; } @@ -3948,6 +4094,7 @@ }, nodeinsert: function() { var bottom, height, posts, qpost, qroot, threadContainer, top, _ref; + posts = g.posts; qpost = posts[this.threaded]; delete this.threaded; @@ -3977,12 +4124,14 @@ }, toggle: function() { var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1; + thread = $('.thread'); replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread); QuoteThreading.enabled = this.checked; if (this.checked) { nodes = (function() { var _i, _len, _results; + _results = []; for (_i = 0, _len = replies.length; _i < _len; _i++) { reply = replies[_i]; @@ -3997,6 +4146,7 @@ } else { replies.sort(function(a, b) { var aID, bID; + aID = Number(a.id.slice(2)); bID = Number(b.id.slice(2)); return aID - bID; @@ -4012,6 +4162,7 @@ }, kb: function() { var control; + control = $.id('threadingControl'); return control.click(); } @@ -4038,6 +4189,7 @@ }, node: function() { var quotelink, _i, _len, _ref; + if (this.isClone) { return; } @@ -4073,6 +4225,7 @@ }, node: function() { var deadlink, _i, _len, _ref; + _ref = $$('.deadlink', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { deadlink = _ref[_i]; @@ -4087,6 +4240,7 @@ }, parseDeadlink: function(deadlink) { var a, boardID, m, post, postID, quote, quoteID, redirect, _ref; + if (deadlink.parentNode.className === 'prettyprint') { $.replace(deadlink, __slice.call(deadlink.childNodes)); return; @@ -4166,6 +4320,7 @@ cypher: $.el('div'), node: function() { var a, child, cypher, cypherText, data, embed, embedder, embeds, i, index, len, link, links, lookahead, name, next, node, nodes, snapshot, spoiler, text, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2; + if (this.isClone && Conf['Embedding']) { _ref = $$('.embedder', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -4250,6 +4405,7 @@ }, toggle: function() { var el, embed, style, type, url; + embed = this.previousElementSibling; if (this.className.contains("embedded")) { el = $.el('a', { @@ -4343,6 +4499,7 @@ style: 'height: auto; width: 500px; display: inline-block;', el: function() { var div; + div = $.el('div', { className: "soundcloud", name: "soundcloud" @@ -4368,6 +4525,7 @@ regExp: /.*(?:pastebin.com\/(?!u\/))([^#\&\?]*).*/, el: function() { var div; + return div = $.el('iframe', { src: "http://pastebin.com/embed_iframe.php?i=" + this.name }); @@ -4377,6 +4535,7 @@ regExp: /.*(?:gist.github.com.*\/)([^\/][^\/]*)$/, el: function() { var div; + return div = $.el('iframe', { src: "http://www.purplegene.com/script?url=https://gist.github.com/" + this.name + ".js" }); @@ -4387,6 +4546,7 @@ }, text: function() { var file, response; + response = JSON.parse(this.responseText).files; for (file in response) { if (response.hasOwnProperty(file)) { @@ -4407,12 +4567,14 @@ }, embedder: function(a) { var callbacks, embed, key, match, service, titles, type, _ref; + if (!Conf['Link Title']) { return [a]; } titles = {}; callbacks = function() { var title; + return a.textContent = (function() { switch (this.status) { case 200: @@ -4454,6 +4616,7 @@ if (Conf['Link Title'] && (service = type.title)) { $.get('CachedTitles', {}, function(item) { var err, title; + titles = item['CachedTitles']; if (title = titles[match[1]]) { a.textContent = title[0]; @@ -4477,6 +4640,7 @@ QR = { init: function() { var sc; + if (!Conf['Quick Reply']) { return; } @@ -4523,6 +4687,7 @@ }, initReady: function() { var link; + QR.postingIsEnabled = !!$.id('postForm'); if (!QR.postingIsEnabled) { return; @@ -4542,11 +4707,13 @@ $.before($.id('postForm'), link); $.on(d, 'QRGetSelectedPost', function(_arg) { var cb; + cb = _arg.detail; return cb(QR.selected); }); $.on(d, 'QRAddPreSubmitHook', function(_arg) { var cb; + cb = _arg.detail; return QR.preSubmitHooks.push(cb); }); @@ -4575,6 +4742,7 @@ }, open: function() { var err; + if (QR.nodes) { QR.nodes.el.hidden = false; QR.unhide(); @@ -4593,6 +4761,7 @@ }, close: function() { var i, _i, _len, _ref; + if (QR.req) { QR.abort(); return; @@ -4639,6 +4808,7 @@ }, error: function(err) { var el; + QR.open(); if (typeof err === 'string') { el = $.tn(err); @@ -4666,6 +4836,7 @@ notifications: [], cleanNotifications: function() { var notification, _i, _len, _ref; + _ref = QR.notifications; for (_i = 0, _len = _ref.length; _i < _len; _i++) { notification = _ref[_i]; @@ -4675,6 +4846,7 @@ }, status: function() { var disabled, status, value; + if (!QR.nodes) { return; } @@ -4695,6 +4867,7 @@ QR.persona.getPassword(); return $.get('QR.personas', Conf['QR.personas'], function(_arg) { var arr, item, personas, type, types, _i, _len, _ref; + personas = _arg['QR.personas']; types = { name: [], @@ -4714,6 +4887,7 @@ }, parseItem: function(item, types) { var boards, match, type, val, _ref, _ref1; + if (item[0] === '#') { return; } @@ -4742,6 +4916,7 @@ }, loadPersonas: function(type, arr) { var list, val, _i, _len; + list = $("#list-" + type, QR.nodes.el); for (_i = 0, _len = arr.length; _i < _len; _i++) { val = arr[_i]; @@ -4755,6 +4930,7 @@ }, getPassword: function() { var input, m; + if (!QR.persona.pwd) { QR.persona.pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : (input = $.id('postPassword')) ? input.value : $.id('delPassword').value; } @@ -4763,6 +4939,7 @@ get: function(cb) { return $.get('QR.persona', {}, function(_arg) { var persona; + persona = _arg['QR.persona']; return cb(persona); }); @@ -4770,6 +4947,7 @@ set: function(post) { return $.get('QR.persona', {}, function(_arg) { var persona; + persona = _arg['QR.persona']; persona = { name: post.name, @@ -4783,6 +4961,7 @@ cooldown: { init: function() { var board; + if (!Conf['Cooldown']) { return; } @@ -4824,6 +5003,7 @@ }, sync: function(cooldowns) { var id; + for (id in cooldowns) { QR.cooldown.cooldowns[id] = cooldowns[id]; } @@ -4831,6 +5011,7 @@ }, set: function(data) { var cooldown, delay, hasFile, isReply, isSage, post, req, start, type, upSpd; + if (!Conf['Cooldown']) { return; } @@ -4870,6 +5051,7 @@ }, count: function() { var cooldown, cooldowns, elapsed, hasFile, isReply, isSage, now, post, seconds, start, type, types, upSpd, upSpdAccuracy, update, _ref; + if (!Object.keys(QR.cooldown.cooldowns).length) { $["delete"]("" + g.BOARD + ".cooldown"); delete QR.cooldown.isCounting; @@ -4923,6 +5105,7 @@ }, quote: function(e) { var OP, caretPos, com, index, post, range, s, sel, selectionRoot, text, thread, _ref; + if (e != null) { e.preventDefault(); } @@ -4962,6 +5145,7 @@ }, characterCount: function() { var count, counter; + counter = QR.nodes.charCount; count = QR.nodes.com.textLength; counter.textContent = count; @@ -4970,6 +5154,7 @@ }, drag: function(e) { var toggle; + toggle = e.type === 'dragstart' ? $.off : $.on; toggle(d, 'dragover', QR.dragOver); return toggle(d, 'drop', QR.dropFile); @@ -4989,6 +5174,7 @@ }, paste: function(e) { var blob, files, item, _i, _len, _ref; + files = []; _ref = e.clipboardData.items; for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -5016,6 +5202,7 @@ }, fileInput: function(files) { var file, length, max, post, _i, _len; + if (this instanceof Element) { files = __slice.call(this.files); QR.nodes.fileInput.value = null; @@ -5064,6 +5251,7 @@ function _Class(select) { var el, event, prev, _i, _len, _ref, _this = this; + el = $.el('a', { className: 'qr-preview', draggable: true, @@ -5117,6 +5305,7 @@ _Class.prototype.rm = function() { var index; + $.rm(this.nodes.el); index = QR.posts.indexOf(this); if (QR.posts.length === 1) { @@ -5134,6 +5323,7 @@ _Class.prototype.lock = function(lock) { var name, _i, _len, _ref; + if (lock == null) { lock = true; } @@ -5158,6 +5348,7 @@ _Class.prototype.select = function() { var rectEl, rectList; + if (QR.selected) { QR.selected.nodes.el.id = null; QR.selected.forceSave(); @@ -5174,6 +5365,7 @@ _Class.prototype.load = function() { var name, _i, _len, _ref; + _ref = ['thread', 'name', 'email', 'sub', 'com']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { name = _ref[_i]; @@ -5185,6 +5377,7 @@ _Class.prototype.save = function(input) { var value, _ref; + if (input.type === 'checkbox') { this.spoiler = input.checked; return; @@ -5203,6 +5396,7 @@ _Class.prototype.forceSave = function() { var name, _i, _len, _ref; + if (this !== QR.selected) { return; } @@ -5234,6 +5428,7 @@ _Class.prototype.setThumbnail = function(fileURL) { var img, reader, _this = this; + if (!window.URL) { if (!fileURL) { reader = new FileReader(); @@ -5249,6 +5444,7 @@ img = $.el('img'); img.onload = function() { var applyBlob, cv, data, height, i, l, s, ui8a, width, _i; + s = 90 * 2; if (_this.file.type === 'image/gif') { s *= 3; @@ -5328,9 +5524,11 @@ _Class.prototype.pasteText = function(file) { var reader, _this = this; + reader = new FileReader(); reader.onload = function(e) { var text; + text = e.target.result; if (_this.com) { _this.com += "\n" + text; @@ -5368,6 +5566,7 @@ _Class.prototype.drop = function() { var el, index, newIndex, oldIndex, post; + el = $('.drag', this.parentNode); $.rmClass(el, 'drag'); $.rmClass(this, 'over'); @@ -5402,6 +5601,7 @@ ready: function() { var imgContainer, input, observer, setLifetime, _this = this; + setLifetime = function(e) { return _this.lifetime = e.detail; }; @@ -5443,6 +5643,7 @@ }); $.get('captchas', [], function(_arg) { var captchas; + captchas = _arg.captchas; return _this.sync(captchas); }); @@ -5457,6 +5658,7 @@ }, getOne: function() { var captcha, challenge, response; + this.clear(); if (captcha = this.captchas.shift()) { challenge = captcha.challenge, response = captcha.response; @@ -5481,6 +5683,7 @@ }, save: function() { var response; + if (!(response = this.nodes.input.value.trim())) { return; } @@ -5495,6 +5698,7 @@ }, clear: function() { var captcha, i, now, _i, _len, _ref; + now = Date.now(); _ref = this.captchas; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { @@ -5512,6 +5716,7 @@ }, load: function() { var challenge; + if (!this.nodes.challenge.firstChild) { return; } @@ -5524,6 +5729,7 @@ }, count: function() { var count; + count = this.captchas.length; this.nodes.input.placeholder = (function() { switch (count) { @@ -5556,6 +5762,7 @@ }, dialog: function() { var dialog, mimeTypes, name, nodes, thread, _i, _len, _ref; + dialog = UI.dialog('qr', 'top:0;right:0;', "
×
No selected file×+
"); QR.nodes = nodes = { el: dialog, @@ -5657,6 +5864,7 @@ preSubmitHooks: [], submit: function(e) { var callbacks, challenge, err, filetag, hook, opts, post, postData, response, textOnly, thread, threadID, _i, _len, _ref, _ref1; + if (e != null) { e.preventDefault(); } @@ -5769,6 +5977,7 @@ }, response: function() { var URL, ban, board, err, h1, isReply, m, post, postID, req, threadID, tmpDoc, _, _ref, _ref1; + QR.req.upload.onload(); req = QR.req; delete QR.req; @@ -5872,6 +6081,7 @@ FappeTyme = { init: function() { var el, input; + if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } @@ -5923,6 +6133,7 @@ }, node: function() { var thumb, _ref; + if (!((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -5947,6 +6158,7 @@ }, toggleAll: function() { var ID, file, func, post, _i, _len, _ref, _ref1; + $.event('CloseMenu'); if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) { ImageExpand.EAI.className = 'contract-all-shortcut'; @@ -5995,6 +6207,7 @@ }, toggle: function(post) { var headRect, node, rect, root, thumb, top; + thumb = post.file.thumb; if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) { ImageExpand.expand(post); @@ -6039,6 +6252,7 @@ }, expand: function(post, src) { var img, thumb; + thumb = post.file.thumb; if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) { return; @@ -6066,6 +6280,7 @@ }, completeExpand: function(post) { var prev, thumb; + thumb = post.file.thumb; if (!$.hasClass(thumb, 'expanding')) { return; @@ -6079,6 +6294,7 @@ prev = post.nodes.root.getBoundingClientRect(); return $.queueTask(function() { var curr, root; + $.addClass(post.nodes.root, 'expanded-image'); $.rmClass(post.file.thumb, 'expanding'); if (!(prev.top + prev.height <= 0)) { @@ -6091,6 +6307,7 @@ }, error: function() { var URL, post, src, timeoutID; + post = Get.postFromNode(this); $.rm(this); delete post.file.fullImage; @@ -6116,6 +6333,7 @@ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", { onload: function() { var postObj, _i, _len, _ref; + if (this.status !== 200) { return; } @@ -6139,6 +6357,7 @@ menu: { init: function() { var conf, createSubEntry, el, key, subEntries, _ref; + if (g.VIEW === 'catalog' || !Conf['Image Expansion']) { return; } @@ -6162,6 +6381,7 @@ }, createSubEntry: function(type, config) { var input, label; + label = $.el('label', { innerHTML: " " + type }); @@ -6197,6 +6417,7 @@ }, node: function() { var _ref; + if (!((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -6204,6 +6425,7 @@ }, mouseover: function(e) { var el, post; + post = Get.postFromNode(this); el = $.el('img', { id: 'ihover', @@ -6225,6 +6447,7 @@ error: function() { var URL, post, src, timeoutID, _this = this; + if (!doc.contains(this)) { return; } @@ -6249,6 +6472,7 @@ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", { onload: function() { var postObj, _i, _len, _ref; + if (this.status !== 200) { return; } @@ -6274,6 +6498,7 @@ ImageLoader = { init: function() { var prefetch; + if (g.VIEW === 'catalog') { return; } @@ -6300,6 +6525,7 @@ }, node: function() { var URL, img, string, style, thumb, type, _ref, _ref1; + if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -6321,6 +6547,7 @@ }, toggle: function() { var enabled, id, post, _ref; + enabled = Conf['prefetch'] = this.checked; if (enabled) { _ref = g.threads["" + g.BOARD.ID + "." + g.THREADID].posts; @@ -6334,16 +6561,17 @@ RevealSpoilers = { init: function() { - if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) { + if (g.VIEW === 'catalog' || !Conf['Reveal Spoiler Thumbnails']) { return; } return Post.prototype.callbacks.push({ - name: 'Reveal Spoilers', + name: 'Reveal Spoiler Thumbnails', cb: this.node }); }, node: function() { var thumb, _ref; + if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) { return; } @@ -6356,6 +6584,7 @@ ArchiveLink = { init: function() { var div, entry, type, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) { return; } @@ -6368,6 +6597,7 @@ order: 90, open: function(_arg) { var ID, board, thread; + ID = _arg.ID, thread = _arg.thread, board = _arg.board; return !!Redirect.to('thread', { postID: ID, @@ -6386,12 +6616,14 @@ }, createSubEntry: function(text, type) { var el, open; + el = $.el('a', { textContent: text, target: '_blank' }); open = type === 'post' ? function(_arg) { var ID, board, thread; + ID = _arg.ID, thread = _arg.thread, board = _arg.board; el.href = Redirect.to('thread', { postID: ID, @@ -6401,6 +6633,7 @@ return true; } : function(post) { var value; + value = Filter[type](post); if (!value) { return false; @@ -6423,6 +6656,7 @@ DeleteLink = { init: function() { var div, fileEl, fileEntry, postEl, postEntry; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) { return; } @@ -6450,6 +6684,7 @@ el: fileEl, open: function(_arg) { var file; + file = _arg.file; if (!file || file.isDead) { return false; @@ -6465,6 +6700,7 @@ order: 40, open: function(post) { var node; + if (post.isDead || post.board.ID === 'q') { return false; } @@ -6479,6 +6715,7 @@ }, "delete": function() { var fileOnly, form, link, post; + post = DeleteLink.post; if (DeleteLink.cooldown.counting === post) { return; @@ -6507,6 +6744,7 @@ }, load: function(link, post, fileOnly, html) { var msg, s, tmpDoc; + tmpDoc = d.implementation.createHTMLDocument(''); tmpDoc.documentElement.innerHTML = html; if (tmpDoc.title === '4chan - Banned') { @@ -6529,6 +6767,7 @@ cooldown: { start: function(post, node) { var length, seconds, _ref; + if (!((_ref = QR.db) != null ? _ref.get({ boardID: post.board.ID, threadID: post.thread.ID, @@ -6562,6 +6801,7 @@ DownloadLink = { init: function() { var a; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) { return; } @@ -6575,6 +6815,7 @@ order: 100, open: function(_arg) { var file; + file = _arg.file; if (!file) { return false; @@ -6600,6 +6841,7 @@ }, node: function() { var button; + button = Menu.makeButton(this); if (this.isClone) { $.replace($('.menu-button', this.nodes.info), button); @@ -6609,9 +6851,11 @@ }, makeButton: (function() { var a; + a = null; return function(post) { var clone; + a || (a = $.el('a', { className: 'menu-button fourchanx-link', innerHTML: '', @@ -6628,6 +6872,7 @@ })(), toggle: function(e) { var post; + post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid]; return Menu.menu.toggle(e, this, post); } @@ -6636,6 +6881,7 @@ ReportLink = { init: function() { var a; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) { return; } @@ -6657,6 +6903,7 @@ }, report: function() { var id, post, set, url; + post = ReportLink.post; url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post; id = Date.now(); @@ -6669,6 +6916,7 @@ init: function() { return $.ready(function() { var href; + Favicon.el = $('link[rel="shortcut icon"]', d.head); Favicon.el.type = 'image/x-icon'; href = Favicon.el.href; @@ -6741,6 +6989,7 @@ init: function() { var sc, _this = this; + if (g.VIEW !== 'thread' || !Conf['Thread Stats']) { return; } @@ -6770,6 +7019,7 @@ }, node: function() { var ID, fileCount, post, postCount, _ref; + postCount = 0; fileCount = 0; _ref = this.posts; @@ -6787,6 +7037,7 @@ }, onUpdate: function(e) { var fileCount, postCount, _ref; + if (e.detail[404]) { return; } @@ -6795,6 +7046,7 @@ }, update: function(postCount, fileCount) { var fileCountEl, postCountEl, thread; + thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl; postCountEl.textContent = postCount; fileCountEl.textContent = fileCount; @@ -6821,6 +7073,7 @@ }, onThreadsLoad: function() { var page, pages, thread, _i, _j, _len, _len1, _ref; + if (!Conf["Page Count in Stats"]) { return; } @@ -6848,6 +7101,7 @@ init: function() { var checked, conf, el, input, name, sc, settings, subEntries, _ref, _this = this; + if (g.VIEW !== 'thread' || !Conf['Thread Updater']) { return; } @@ -6998,6 +7252,7 @@ }, interval: function() { var val; + val = +this.value; if (val < 1) { val = 1; @@ -7007,6 +7262,7 @@ }, load: function() { var klass, req, text, _ref; + req = ThreadUpdater.req; switch (req.status) { case 200: @@ -7050,6 +7306,7 @@ }, getInterval: function() { var i, j; + i = ThreadUpdater.interval; j = Math.min(ThreadUpdater.outdateCount, 10); if (!d.hidden) { @@ -7059,12 +7316,14 @@ }, intervalShortcut: function() { var settings; + Settings.open('Advanced'); settings = $.id('fourchanx-settings'); return $('input[name=Interval]', settings).focus(); }, set: function(name, text, klass) { var el, node; + el = ThreadUpdater[name]; if (node = el.firstChild) { node.data = text; @@ -7077,6 +7336,7 @@ }, timeout: function() { var n; + ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000); if (!(n = --ThreadUpdater.seconds)) { return ThreadUpdater.update(); @@ -7089,6 +7349,7 @@ }, update: function() { var url; + if (!ThreadUpdater.online) { return; } @@ -7113,6 +7374,7 @@ }, updateThreadStatus: function(title, OP) { var icon, message, root, titleLC; + titleLC = title.toLowerCase(); if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) { return; @@ -7139,6 +7401,7 @@ }, parse: function(postObjects) { var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _len, _ref; + OP = postObjects[0]; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; ThreadUpdater.updateThreadStatus('Sticky', OP); @@ -7224,6 +7487,7 @@ } $.queueTask(function() { var length, threadID; + threadID = ThreadUpdater.thread.ID; length = $$('.thread > .postContainer', ThreadUpdater.root).length; return Fourchan.parseThread(threadID, length - count, length); @@ -7244,6 +7508,7 @@ ThreadWatcher = { init: function() { var sc; + if (!Conf['Thread Watcher']) { return; } @@ -7277,6 +7542,7 @@ node: function() { var favicon, _this = this; + favicon = $.el('a', { className: 'watch-thread-link', href: 'javascript:;' @@ -7296,6 +7562,7 @@ }, refresh: function(watched) { var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1; + if (!watched) { $.get('WatchedThreads', {}, function(item) { return ThreadWatcher.refresh(item['WatchedThreads']); @@ -7344,11 +7611,13 @@ }, x: function() { var thread; + thread = this.nextElementSibling.pathname.split('/'); return ThreadWatcher.unwatch(thread[1], thread[3]); }, post: function(e) { var board, postID, threadID, _ref; + _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID; if (postID === threadID) { if (Conf['Auto Watch']) { @@ -7369,6 +7638,7 @@ unwatch: function(board, threadID) { return $.get('WatchedThreads', {}, function(item) { var watched; + watched = item['WatchedThreads']; delete watched[board][threadID]; if (!Object.keys(watched[board]).length) { @@ -7381,6 +7651,7 @@ watch: function(thread) { return $.get('WatchedThreads', {}, function(item) { var watched, _name; + watched = item['WatchedThreads']; watched[_name = thread.board] || (watched[_name] = {}); watched[thread.board][thread] = { @@ -7426,6 +7697,7 @@ }, ready: function() { var ID, post, posts, _ref; + $.off(d, '4chanXInitFinished', Unread.ready); posts = []; _ref = Unread.thread.posts; @@ -7442,6 +7714,7 @@ }, scroll: function() { var checkPosition, hash, onload, post, posts, prevID, root; + if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { return; } @@ -7473,6 +7746,7 @@ } checkPosition = function(target) { var height, top, _ref; + _ref = target.getBoundingClientRect(), top = _ref.top, height = _ref.height; return top + height - doc.clientHeight > 0; }; @@ -7480,6 +7754,7 @@ }, sync: function() { var lastReadPost; + lastReadPost = Unread.db.get({ boardID: Unread.thread.board.ID, threadID: Unread.thread.ID, @@ -7496,6 +7771,7 @@ }, addPosts: function(posts) { var ID, data, post, _i, _len, _ref; + for (_i = 0, _len = posts.length; _i < _len; _i++) { post = posts[_i]; ID = post.ID; @@ -7523,6 +7799,7 @@ }, addPostQuotingYou: function(post) { var quotelink, _i, _len, _ref; + if (!QR.db) { return; } @@ -7543,6 +7820,7 @@ }, readSinglePost: function(post) { var i; + if ((i = Unread.posts.indexOf(post)) === -1) { return; } @@ -7558,6 +7836,7 @@ }, readArray: function(arr) { var i, post, _i, _len; + for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) { post = arr[i]; if (post.ID > Unread.lastReadPost) { @@ -7568,6 +7847,7 @@ }, read: $.debounce(50, function(e) { var ID, bottom, height, i, post, posts, read; + if (d.hidden || !Unread.posts.length) { return; } @@ -7601,6 +7881,7 @@ }), setLine: function(force) { var post, root; + if (!(d.hidden || force === true)) { return; } @@ -7615,6 +7896,7 @@ }, update: function() { var count; + count = Unread.posts.length; if (Conf['Unread Count']) { d.title = "" + (Conf['Quoted Title'] && Unread.postsQuotingYou.length ? '(!) ' : '') + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title); @@ -7633,6 +7915,7 @@ file: {}, init: function() { var archive, arr, boardID, data, id, name, type, _i, _len, _ref, _ref1, _ref2, _ref3; + _ref = Conf['selectedArchives']; for (boardID in _ref) { data = _ref[boardID]; @@ -7759,6 +8042,7 @@ }, to: function(dest, data) { var archive; + archive = (dest === 'search' ? Redirect.thread : Redirect[dest])[data.boardID]; if (!archive) { return ''; @@ -7767,6 +8051,7 @@ }, protocol: function(archive) { var protocol; + protocol = location.protocol; if (!archive[protocol.slice(0, -1)]) { protocol = protocol === 'https:' ? 'http:' : 'https:'; @@ -7775,6 +8060,7 @@ }, thread: function(archive, _arg) { var boardID, path, postID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID; path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID; if (archive.software === 'foolfuuka') { @@ -7787,6 +8073,7 @@ }, post: function(archive, _arg) { var boardID, postID, protocol; + boardID = _arg.boardID, postID = _arg.postID; protocol = Redirect.protocol(archive); if (['Foolz', 'NSFW Foolz'].contains(archive.name)) { @@ -7796,11 +8083,13 @@ }, file: function(archive, _arg) { var boardID, filename; + boardID = _arg.boardID, filename = _arg.filename; return "" + (Redirect.protocol(archive)) + archive.domain + "/" + boardID + "/full_image/" + filename; }, search: function(archive, _arg) { var boardID, path, type, value; + boardID = _arg.boardID, type = _arg.type, value = _arg.value; type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type; value = encodeURIComponent(value); @@ -7819,6 +8108,7 @@ }, setup: function() { var btn, entry, psa; + $.off(d, '4chanXInitFinished', PSAHiding.setup); if (!(psa = $.id('globalMessage'))) { $.rmClass(doc, 'hide-announcement'); @@ -7847,6 +8137,7 @@ $.on(btn, 'click', PSAHiding.toggle); $.get('hiddenPSA', 0, function(_arg) { var hiddenPSA; + hiddenPSA = _arg.hiddenPSA; PSAHiding.sync(hiddenPSA); $.before(psa, btn); @@ -7856,6 +8147,7 @@ }, toggle: function(e) { var UTC; + if ($.hasClass(this, 'hide-announcement')) { UTC = +$.id('globalMessage').dataset.utc; $.set('hiddenPSA', UTC); @@ -7867,6 +8159,7 @@ }, sync: function(UTC) { var hr, psa; + psa = $.id('globalMessage'); psa.hidden = PSAHiding.btn.hidden = UTC && UTC >= +psa.dataset.utc ? true : false; if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') { @@ -7878,6 +8171,7 @@ CatalogLinks = { init: function() { var el, input; + if (!Conf['Catalog Links']) { return; } @@ -7901,12 +8195,14 @@ }, toggle: function() { var useCatalog; + $.event('CloseMenu'); $.set('Header catalog links', useCatalog = this.checked); return CatalogLinks.set(useCatalog); }, set: function(useCatalog) { var a, board, path, _i, _len, _ref; + path = useCatalog ? 'catalog' : ''; _ref = $$("#board-list a[href*=\"boards.4chan.org\"]:not(.catalog),\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]"); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -7940,6 +8236,7 @@ }, node: function(post) { var str, uid; + if (!(uid = $('.hand', this.nodes.uniqueID))) { return; } @@ -7951,6 +8248,7 @@ ids: {}, compute: function(str) { var hash, rgb; + hash = this.hash(str); rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF]; rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125; @@ -7959,11 +8257,13 @@ }, apply: function() { var rgb; + rgb = IDColor.ids[this] || IDColor.compute(this); return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black; border-radius: 3px; padding: 0px 2px;" : "white; border-radius: 3px; padding: 0px 2px;"); }, hash: function(str) { var i, j, msg; + msg = 0; i = 0; j = str.length; @@ -8002,6 +8302,7 @@ Emoji = { init: function() { var css, icon, name, pos, _ref; + if (!Conf['Emoji']) { return; } @@ -8071,6 +8372,7 @@ }, node: function() { var a; + if (a = $('.abbr > a:not([onclick])', this.nodes.comment)) { return $.on(a, 'click', ExpandComment.cb); } @@ -8078,12 +8380,14 @@ callbacks: [], cb: function(e) { var post; + e.preventDefault(); post = Get.postFromNode(this); return ExpandComment.expand(post); }, expand: function(post) { var a; + if (post.nodes.longComment && !post.nodes.longComment.parentNode) { $.replace(post.nodes.shortComment, post.nodes.longComment); post.nodes.comment = post.nodes.longComment; @@ -8099,6 +8403,7 @@ }, contract: function(post) { var a; + if (!post.nodes.shortComment) { return; } @@ -8109,6 +8414,7 @@ }, parse: function(req, a, post) { var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + status = req.status; if (![200, 304].contains(status)) { a.textContent = "Error " + req.statusText + " (" + status + ")"; @@ -8165,6 +8471,7 @@ }, node: function() { var a, span; + if (!(span = $('.summary', this.OP.nodes.root.parentNode))) { return; } @@ -8178,11 +8485,13 @@ }, cbToggle: function() { var op; + op = Get.postFromRoot(this.previousElementSibling); return ExpandThread.toggle(op.thread); }, toggle: function(thread) { var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + threadRoot = thread.OP.nodes.root.parentNode; a = $('.summary', threadRoot); switch (thread.isExpanded) { @@ -8251,6 +8560,7 @@ }, parse: function(req, thread, a) { var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len; + if (a.textContent[0] === '+') { return; } @@ -8308,6 +8618,7 @@ }, createFunc: function(format) { var code; + code = format.replace(/%(.)/g, function(s, c) { if (c in FileInfo.formatters) { return "' + FileInfo.formatters." + c + ".call(post) + '"; @@ -8319,6 +8630,7 @@ }, convertUnit: function(size, unit) { var i; + if (unit === 'B') { return "" + (size.toFixed()) + " Bytes"; } @@ -8349,6 +8661,7 @@ }, n: function() { var fullname, shortname; + fullname = this.file.name; shortname = Build.shortFilename(this.file.name, this.isReply); if (fullname === shortname) { @@ -8392,6 +8705,7 @@ Fourchan = { init: function() { var board; + if (g.VIEW === 'catalog') { return; } @@ -8413,6 +8727,7 @@ }, code: function() { var pre, _i, _len, _ref; + if (this.isClone) { return; } @@ -8442,11 +8757,13 @@ Keybinds = { init: function() { var init; + if (g.VIEW === 'catalog' || !Conf['Keybinds']) { return; } init = function() { var node, _i, _len, _ref; + $.off(d, '4chanXInitFinished', init); $.on(d, 'keydown', Keybinds.keydown); _ref = $$('[accesskey]'); @@ -8459,6 +8776,7 @@ }, keydown: function(e) { var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len; + if (!(key = Keybinds.keyCode(e))) { return; } @@ -8633,6 +8951,7 @@ }, keyCode: function(e) { var kc, key; + key = (function() { switch (kc = e.keyCode) { case 8: @@ -8688,6 +9007,7 @@ }, tags: function(tag, ta) { var range, selEnd, selStart, value; + value = ta.value; selStart = ta.selectionStart; selEnd = ta.selectionEnd; @@ -8698,11 +9018,13 @@ }, sage: function() { var isSage; + isSage = /sage/i.test(QR.nodes.email.value); return QR.nodes.email.value = isSage ? "" : "sage"; }, img: function(thread, all) { var post; + if (all) { return ImageExpand.cb.toggleAll(); } else { @@ -8712,6 +9034,7 @@ }, open: function(thread, tab) { var url; + if (g.VIEW !== 'index') { return; } @@ -8724,6 +9047,7 @@ }, hl: function(delta, thread) { var axe, headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len; + if (!delta) { if (postEl = $('.reply.highlight', thread)) { $.rmClass(postEl, 'highlight'); @@ -8783,6 +9107,7 @@ Nav = { init: function() { var append, next, prev, span; + switch (g.VIEW) { case 'index': if (!Conf['Index Navigation']) { @@ -8833,6 +9158,7 @@ }, getThread: function(full) { var headRect, i, rect, thread, threads, topMargin, _i, _len; + if (Conf['Bottom header'] || !Conf['Fixed Header']) { topMargin = 0; } else { @@ -8858,6 +9184,7 @@ }, scroll: function(delta) { var i, rect, thread, threads, top, topMargin, _ref, _ref1; + _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4]; top = rect.top - topMargin; if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) { @@ -8883,6 +9210,7 @@ }, node: function() { var dateEl; + if (this.isClone) { return; } @@ -8892,6 +9220,7 @@ }, relative: function(diff, now, date) { var days, months, number, rounded, unit, years; + unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second'); rounded = Math.round(number); if (rounded !== 1) { @@ -8902,6 +9231,7 @@ stale: [], flush: function() { var now, update, _i, _len, _ref; + if (d.hidden) { return; } @@ -8917,13 +9247,16 @@ }, setUpdate: function(post) { var markStale, setOwnTimeout, update; + setOwnTimeout = function(diff) { var delay; + delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY; return setTimeout(markStale, delay); }; update = function(now) { var date, diff, relative, singlePost, _i, _len, _ref; + date = post.info.date; diff = now - date; relative = RelativeDates.relative(diff, now, date); @@ -8964,6 +9297,7 @@ }, node: function(post) { var spoiler, spoilers, _i, _len; + spoilers = $$('s', this.nodes.comment); for (_i = 0, _len = spoilers.length; _i < _len; _i++) { spoiler = spoilers[_i]; @@ -8983,6 +9317,7 @@ }, ready: function() { var field; + field = $.id('recaptcha_response_field'); $.on(field, 'keydown', function(e) { if (e.keyCode === 8 && !field.value) { @@ -8991,6 +9326,7 @@ }); return $.on($('form'), 'submit', function(e) { var response; + e.preventDefault(); response = field.value.trim(); if (!/\s/.test(response)) { @@ -9004,6 +9340,7 @@ Sauce = { init: function() { var err, link, links, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Sauce']) { return; } @@ -9035,6 +9372,7 @@ }, createSauceLink: function(link) { var m, text; + link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) { switch (parameter) { case '%TURL': @@ -9055,6 +9393,7 @@ }, node: function() { var link, nodes, _i, _len, _ref; + if (this.isClone || !this.file) { return; } @@ -9087,6 +9426,7 @@ }, createFunc: function(format) { var code; + code = format.replace(/%([A-Za-z])/g, function(s, c) { if (c in Time.formatters) { return "' + Time.formatters." + c + ".call(date) + '"; @@ -9171,6 +9511,7 @@ Settings = { init: function() { var link, settings; + link = $.el('a', { className: 'settings-link', textContent: 'Settings', @@ -9180,6 +9521,7 @@ Header.addShortcut(link); $.get('previousversion', null, function(item) { var changelog, el, previous; + if (previous = item['previousversion']) { if (previous === g.VERSION) { return; @@ -9217,6 +9559,7 @@ }, open: function(openSection) { var dialog, html, link, links, overlay, section, sectionToOpen, _i, _len, _ref; + $.off(d, '4chanXInitFinished', Settings.open); if (Settings.dialog) { return; @@ -9269,6 +9612,7 @@ sections: [], addSection: function(title, open) { var hyphenatedTitle, _ref; + if (typeof title !== 'string') { _ref = title.detail, title = _ref.title, open = _ref.open; } @@ -9281,6 +9625,7 @@ }, openSection: function() { var section, selected; + if (selected = $('.tab-selected', Settings.dialog)) { $.rmClass(selected, 'tab-selected'); } @@ -9294,6 +9639,7 @@ }, main: function(section) { var arr, button, description, div, fs, hiddenNum, input, inputs, items, key, obj, _ref; + items = {}; inputs = {}; _ref = Config.main; @@ -9318,6 +9664,7 @@ } $.get(items, function(items) { var val; + for (key in items) { val = items[key]; inputs[key].checked = val; @@ -9332,6 +9679,7 @@ boards: {} }, function(item) { var ID, board, thread, _ref1; + _ref1 = item.hiddenThreads.boards; for (ID in _ref1) { board = _ref1[ID]; @@ -9346,6 +9694,7 @@ boards: {} }, function(item) { var ID, board, post, thread, _ref1; + _ref1 = item.hiddenPosts.boards; for (ID in _ref1) { board = _ref1[ID]; @@ -9365,6 +9714,7 @@ boards: {} }, function(item) { var boardID; + for (boardID in item.hiddenThreads.boards) { localStorage.removeItem("4chan-hide-t-" + boardID); } @@ -9375,6 +9725,7 @@ }, "export": function(now, data) { var a, db, _i, _len; + if (typeof now !== 'number') { now = Date.now(); data = { @@ -9409,6 +9760,7 @@ }, onImport: function() { var file, output, reader; + if (!(file = this.files[0])) { return; } @@ -9420,6 +9772,7 @@ reader = new FileReader(); reader.onload = function(e) { var data, err; + try { data = JSON.parse(e.target.result); Settings.loadSettings(data); @@ -9436,6 +9789,7 @@ }, loadSettings: function(data) { var key, val, version, _ref; + version = data.version.split('.'); if (version[0] === '2') { data = Settings.convertSettings(data, { @@ -9525,6 +9879,7 @@ }, convertSettings: function(data, map) { var newKey, prevKey; + for (prevKey in map) { newKey = map[prevKey]; if (newKey) { @@ -9536,6 +9891,7 @@ }, filter: function(section) { var select; + section.innerHTML = "
"; select = $('select', section); $.on(select, 'change', Settings.selectFilter); @@ -9543,6 +9899,7 @@ }, selectFilter: function() { var div, name, ta; + div = this.nextElementSibling; if ((name = this.value) !== 'guide') { $.rmAll(div); @@ -9562,6 +9919,7 @@ }, sauce: function(section) { var ta; + section.innerHTML = "
Sauce is disabled.
Lines starting with a # will be ignored.
You can specify a display text by appending ;text:[text] to the URL.
    These parameters will be replaced by their corresponding values:\n
  • %TURL: Thumbnail URL.
  • %URL: Full image URL.
  • %MD5: MD5 hash.
  • %board: Current board.
"; ta = $('textarea', section); $.get('sauces', Conf['sauces'], function(item) { @@ -9571,6 +9929,7 @@ }, advanced: function(section) { var archive, boardID, boardOptions, boardSelect, boards, data, event, input, inputs, item, items, name, row, rows, ta, table, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _ref4; + section.innerHTML = "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Disabled selections indicate that only one archive is available for that board and redirection type.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
Board link: g
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:\"Install Gentoo\"
Index-only link: g-index
Catalog-only link: g-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: g-index-text:\"Technology Index\"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Time Formatting is disabled.
:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

    You can use these settings with each item, separate them with semicolons:\n
  • Possible items are: name, email, subject and password.
  • Wrap values of items with quotes, like this: email:\"sage\".
  • Force values as defaults with the always keyword, for example: email:\"sage\";always.
  • Select specific boards for an item, separated with commas, for example: email:\"sage\";boards:jp;always.
Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; items = {}; inputs = {}; @@ -9590,6 +9949,7 @@ $.on(ta, 'change', $.cb.value); $.get(items, function(items) { var key, val; + for (key in items) { val = items[key]; if (['emojiPos'].contains(key)) { @@ -9660,6 +10020,7 @@ }); $.get('selectedArchives', Conf['selectedArchives'], function(_arg) { var option, selectedArchives, type; + selectedArchives = _arg.selectedArchives; for (boardID in selectedArchives) { data = selectedArchives[boardID]; @@ -9674,6 +10035,7 @@ }, addArchiveCell: function(boardID, data, type) { var archive, i, length, options, select, td; + length = data[type].length; td = $.el('td', { className: 'archive-cell' @@ -9703,8 +10065,10 @@ }, saveSelectedArchive: function() { var _this = this; + return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) { var selectedArchives, _name; + selectedArchives = _arg.selectedArchives; (selectedArchives[_name = _this.dataset.boardid] || (selectedArchives[_name] = {}))[_this.dataset.type] = _this.value; return $.set('selectedArchives', selectedArchives); @@ -9715,6 +10079,7 @@ }, time: function() { var funk; + funk = Time.createFunc(this.value); return this.nextElementSibling.textContent = funk(Time, new Date()); }, @@ -9723,6 +10088,7 @@ }, fileInfo: function() { var data, funk; + data = { isReply: true, file: { @@ -9761,6 +10127,7 @@ }, keybinds: function(section) { var arr, input, inputs, items, key, tbody, tr, _ref; + section.innerHTML = "
Keybinds are disabled.
Allowed keys: a-z, 0-9, Ctrl, Shift, Alt, Meta, Enter, Esc, Up, Down, Right, Left.
Press Backspace to disable a keybind.
ActionsKeybinds
"; tbody = $('tbody', section); items = {}; @@ -9781,6 +10148,7 @@ } return $.get(items, function(items) { var val; + for (key in items) { val = items[key]; inputs[key].value = val; @@ -9789,6 +10157,7 @@ }, keybind: function(e) { var key; + if (e.keyCode === 9) { return; } @@ -9805,8 +10174,10 @@ Main = { init: function(items) { var db, flatten, _i, _len; + flatten = function(parent, obj) { var key, val; + if (obj instanceof Array) { Conf[parent] = obj[0]; } else if (typeof obj === 'object') { @@ -9830,11 +10201,13 @@ $.on(d, '4chanMainInit', Main.initStyle); return $.asap((function() { var _ref; + return d.head && $('link[rel="shortcut icon"]', d.head) || ((_ref = d.readyState) === 'interactive' || _ref === 'complete'); }), Main.initStyle); }, initFeatures: function(items) { var init, pathname, _ref; + Conf = items; pathname = location.pathname.split('/'); g.BOARD = new Board(pathname[1]); @@ -9863,6 +10236,7 @@ case 'images.4chan.org': $.ready(function() { var URL; + if (Conf['404 Redirect'] && d.title === '4chan - 404 Not Found') { Redirect.init(); pathname = location.pathname.split('/'); @@ -9879,6 +10253,7 @@ } init = function(features) { var err, module, name; + for (name in features) { module = features[name]; try { @@ -9954,6 +10329,7 @@ }, initStyle: function() { var mainStyleSheet, observer, setStyle, style, styleSheets, _ref; + $.off(d, '4chanMainInit', Main.initStyle); if (!Main.isThisPageLegit() || $.hasClass(doc, 'fourchan-x')) { return; @@ -9974,6 +10350,7 @@ styleSheets = $$('link[rel="alternate stylesheet"]', d.head); setStyle = function() { var styleSheet, _i, _len; + $.rmClass(doc, style); for (_i = 0, _len = styleSheets.length; _i < _len; _i++) { styleSheet = styleSheets[_i]; @@ -10000,6 +10377,7 @@ }, initReady: function() { var board, boardChild, err, errors, href, passLink, posts, styleSelector, thread, threadChild, threads, _i, _j, _len, _len1, _ref, _ref1; + if (d.title === '4chan - 404 Not Found') { if (Conf['404 Redirect'] && g.VIEW === 'thread') { href = Redirect.to('thread', { @@ -10076,6 +10454,7 @@ }, callbackNodes: function(klass, nodes) { var callback, err, errors, i, len, node, _i, _len, _ref; + len = nodes.length; _ref = klass.prototype.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -10103,9 +10482,11 @@ }, callbackNodesDB: function(klass, nodes, cb) { var errors, func, i, len, node, queue, softTask; + queue = []; softTask = function() { var args, func, task; + task = queue.shift(); func = task[0]; args = Array.prototype.slice.call(task, 1); @@ -10124,6 +10505,7 @@ errors = null; func = function(node, i) { var callback, err, _i, _len, _ref; + _ref = klass.prototype.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { callback = _ref[_i]; @@ -10157,6 +10539,7 @@ }, addCallback: function(e) { var Klass, obj; + obj = e.detail; if (typeof obj.callback.name !== 'string') { throw new Error("Invalid callback name: " + obj.callback.name); @@ -10176,6 +10559,7 @@ }, message: function(e) { var el, version; + version = e.data.version; if (version && version !== g.VERSION) { el = $.el('span', { @@ -10186,12 +10570,14 @@ }, checkUpdate: function() { var now; + if (!(Conf['Check for Updates'] && Main.isThisPageLegit())) { return; } now = Date.now(); return $.get('lastchecked', 0, function(_arg) { var lastchecked; + lastchecked = _arg.lastchecked; if (lastchecked > now - $.DAY) { return; @@ -10207,6 +10593,7 @@ }, handleErrors: function(errors) { var div, error, logs, _i, _len; + if (!(errors instanceof Array)) { error = errors; } else if (errors.length === 1) { @@ -10221,6 +10608,7 @@ }); $.on(div.lastElementChild, 'click', function() { var _ref; + return _ref = this.textContent === 'show' ? ['hide', false] : ['show', true], this.textContent = _ref[0], logs.hidden = _ref[1], _ref; }); logs = $.el('div', { @@ -10234,6 +10622,7 @@ }, parseError: function(data) { var error, message; + Main.logError(data); message = $.el('div', { textContent: data.message @@ -10250,6 +10639,7 @@ }, isThisPageLegit: function() { var _ref; + if (!('thisPageIsLegit' in Main)) { Main.thisPageIsLegit = location.hostname === 'boards.4chan.org' && !$('link[href*="favicon-status.ico"]', d.head) && ((_ref = d.title) !== '4chan - Temporarily Offline' && _ref !== '4chan - Error'); } diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 62356663d..0f2d22a7e 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -19,7 +19,7 @@ // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC // ==/UserScript== /* -* 4chan X - Version 1.2.24 - 2013-07-24 +* 4chan X - Version 1.2.24 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -159,7 +159,7 @@ 'Image Expansion': [true, 'Expand images.'], 'Image Hover': [true, 'Show full image on mouseover.'], 'Sauce': [true, 'Add sauce links to images.'], - 'Reveal Spoilers': [false, 'Reveal spoiler thumbnails.'], + 'Reveal Spoiler Thumbnails': [false, 'Replace spoiler thumbnails with the original image.'], 'Replace GIF': [false, 'Replace thumbnail of gifs with its actual image.'], 'Replace PNG': [false, 'Replace pngs.'], 'Replace JPG': [false, 'Replace jpgs.'], @@ -337,6 +337,7 @@ Array.prototype.add = function(object, position) { var keep; + keep = this.slice(position); this.length = position; this.push(object); @@ -349,6 +350,7 @@ Array.prototype.indexOf = function(object) { var i; + i = this.length; while (i--) { if (this[i] === object) { @@ -360,6 +362,7 @@ Array.prototype.pushArrays = function() { var arg, args, _i, _len; + args = arguments; for (_i = 0, _len = args.length; _i < _len; _i++) { arg = args[_i]; @@ -370,6 +373,7 @@ Array.prototype.remove = function(object) { var index; + if ((index = this.indexOf(object)) > -1) { return this.splice(index, 1); } else { @@ -386,6 +390,7 @@ $.extend = function(object, properties) { var key, val; + for (key in properties) { val = properties[key]; if (!properties.hasOwnProperty(key)) { @@ -403,6 +408,7 @@ $.ready = function(fc) { var cb, _ref; + if ((_ref = d.readyState) === 'interactive' || _ref === 'complete') { $.queueTask(fc); return; @@ -416,6 +422,7 @@ $.formData = function(form) { var fd, key, val; + if (form instanceof HTMLFormElement) { return new FormData(form); } @@ -436,6 +443,7 @@ $.ajax = function(url, callbacks, opts) { var cred, err, form, headers, key, r, sync, type, upCallbacks, val; + if (opts == null) { opts = {}; } @@ -461,9 +469,11 @@ $.cache = (function() { var reqs; + reqs = {}; return function(url, cb) { var err, req, rm; + if (req = reqs[url]) { if (req.readyState === 4) { cb.call(req, req.evt); @@ -479,6 +489,7 @@ req = $.ajax(url, { onload: function(e) { var _i, _len, _ref; + _ref = this.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { cb = _ref[_i]; @@ -520,6 +531,7 @@ $.addStyle = function(css, id) { var style; + style = $.el('style', { id: id, textContent: css @@ -566,6 +578,7 @@ } else { return function(el) { var _ref; + return (_ref = el.parentNode) != null ? _ref.removeChild(el) : void 0; }; } @@ -573,6 +586,7 @@ $.rmAll = function(root) { var node; + while (node = root.firstChild) { root.removeChild(node); } @@ -588,6 +602,7 @@ $.nodes = function(nodes) { var frag, node, _i, _len; + if (!(nodes instanceof Array)) { return nodes; } @@ -621,6 +636,7 @@ $.el = function(tag, properties) { var el; + el = d.createElement(tag); if (properties) { $.extend(el, properties); @@ -630,6 +646,7 @@ $.on = function(el, events, handler) { var event, _i, _len, _ref; + _ref = events.split(' '); for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; @@ -639,6 +656,7 @@ $.off = function(el, events, handler) { var event, _i, _len, _ref; + _ref = events.split(' '); for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; @@ -664,6 +682,7 @@ $.debounce = function(wait, fn) { var args, exec, lastCall, that, timeout; + lastCall = 0; timeout = null; that = null; @@ -685,9 +704,11 @@ $.queueTask = (function() { var execTask, taskChannel, taskQueue; + taskQueue = []; execTask = function() { var args, func, task; + task = taskQueue.shift(); func = task[0]; args = Array.prototype.slice.call(task, 1); @@ -710,6 +731,7 @@ $.globalEval = function(code) { var script; + script = $.el('script', { textContent: code }); @@ -719,6 +741,7 @@ $.bytesToString = function(size) { var unit; + unit = 0; while (size >= 1024) { size /= 1024; @@ -737,6 +760,7 @@ $.sync = (function() { window.addEventListener('storage', function(e) { var cb; + if (cb = $.syncing[e.key]) { return cb(JSON.parse(e.newValue)); } @@ -748,6 +772,7 @@ $.item = function(key, val) { var item; + item = {}; item[key] = val; return item; @@ -755,6 +780,7 @@ $["delete"] = function(keys) { var key, _i, _len; + if (!(keys instanceof Array)) { keys = [keys]; } @@ -768,6 +794,7 @@ $.get = function(key, val, cb) { var items; + if (typeof cb === 'function') { items = $.item(key, val); } else { @@ -786,6 +813,7 @@ $.set = (function() { var set; + set = function(key, val) { key = g.NAMESPACE + key; val = JSON.stringify(val); @@ -796,6 +824,7 @@ }; return function(keys, val) { var key; + if (typeof keys === 'string') { set(keys, val); return; @@ -863,6 +892,7 @@ function Post(root, thread, board, that) { var alt, anchor, capcode, date, email, file, fileInfo, flag, info, name, post, size, subject, thumb, tripcode, uniqueID, unit; + this.thread = thread; this.board = board; if (that == null) { @@ -961,6 +991,7 @@ Post.prototype.parseComment = function() { var bq, data, i, node, nodes, text, _i, _len, _ref; + bq = this.nodes.comment.cloneNode(true); _ref = $$('.abbr, .capcodeReplies, .exif, b', bq); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -978,6 +1009,7 @@ Post.prototype.parseQuotes = function() { var hash, pathname, quotelink, quotes, _i, _len, _ref; + quotes = {}; _ref = $$('.quotelink', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1007,6 +1039,7 @@ Post.prototype.kill = function(file, now) { var clone, quotelink, strong, _i, _j, _len, _len1, _ref, _ref1; + now || (now = new Date()); if (file) { if (this.file.isDead) { @@ -1055,6 +1088,7 @@ Post.prototype.resurrect = function() { var clone, quotelink, strong, _i, _j, _len, _len1, _ref, _ref1; + delete this.isDead; delete this.timeOfDeath; $.rmClass(this.nodes.root, 'deleted-post'); @@ -1088,6 +1122,7 @@ Post.prototype.rmClone = function(index) { var clone, _i, _len, _ref; + this.clones.splice(index, 1); _ref = this.clones.slice(index); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1105,6 +1140,7 @@ function Clone(origin, context) { var file, index, info, inline, inlined, key, nodes, post, root, val, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; + this.origin = origin; this.context = context; _ref = ['ID', 'fullID', 'board', 'thread', 'info', 'quotes', 'isReply']; @@ -1193,6 +1229,7 @@ function DataBoard(key, sync) { var init, _this = this; + this.key = key; this.data = Conf[key]; $.sync(key, this.onSync.bind(this)); @@ -1209,6 +1246,7 @@ DataBoard.prototype["delete"] = function(_arg) { var boardID, postID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID; if (postID) { delete this.data.boards[boardID][threadID][postID]; @@ -1229,6 +1267,7 @@ DataBoard.prototype.deleteIfEmpty = function(_arg) { var boardID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID; if (threadID) { if (!Object.keys(this.data.boards[boardID][threadID]).length) { @@ -1244,6 +1283,7 @@ DataBoard.prototype.set = function(_arg) { var boardID, postID, threadID, val, _base, _base1, _base2; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID, val = _arg.val; if (postID !== void 0) { ((_base = ((_base1 = this.data.boards)[boardID] || (_base1[boardID] = {})))[threadID] || (_base[threadID] = {}))[postID] = val; @@ -1257,6 +1297,7 @@ DataBoard.prototype.get = function(_arg) { var ID, board, boardID, defaultValue, postID, thread, threadID, val, _i, _len; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID, defaultValue = _arg.defaultValue; if (board = this.data.boards[boardID]) { if (!threadID) { @@ -1280,6 +1321,7 @@ DataBoard.prototype.clean = function() { var boardID, now, val, _ref; + _ref = this.data.boards; for (boardID in _ref) { val = _ref[boardID]; @@ -1299,8 +1341,10 @@ DataBoard.prototype.ajaxClean = function(boardID) { var _this = this; + return $.cache("//api.4chan.org/" + boardID + "/threads.json", function(e) { var board, page, thread, threads, _i, _j, _len, _len1, _ref, _ref1; + if (e.target.status === 404) { _this["delete"](boardID); } else if (e.target.status === 200) { @@ -1411,6 +1455,7 @@ init: function() { var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler, linkJustifyToggler, _this = this; + this.menu = new UI.Menu('header'); this.menuButton = $.el('span', { className: 'menu-button', @@ -1494,6 +1539,7 @@ } $.asap((function() { var _ref; + return $.id('boardNavMobile') || ((_ref = d.readyState) === 'interactive' || _ref === 'complete'); }), Header.setBoardList); $.prepend(d.body, _this.bar); @@ -1502,6 +1548,7 @@ }); return $.ready(function() { var a, cs; + _this.footer = $.id('boardNavDesktopFoot'); if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) { a.className = 'current'; @@ -1535,6 +1582,7 @@ }), setBoardList: function() { var a, boardList, btn, fourchannav, fullBoardList; + fourchannav = $.id('boardNavDesktop'); if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) { a.className = 'current'; @@ -1556,6 +1604,7 @@ }, generateBoardList: function(text) { var as, list, nodes; + list = $('#custom-board-list', Header.bar); $.rmAll(list); if (!text) { @@ -1564,6 +1613,7 @@ as = $$('#full-board-list a', Header.bar); nodes = text.match(/[\w@]+((-(all|title|replace|full|index|catalog|url:"[^"]+[^"]"|text:"[^"]+")|\,"[^"]+[^"]"))*|[^\w@]+/g).map(function(t) { var a, board, m, _i, _len; + if (/^[^\w@]/.test(t)) { return $.tn(t); } @@ -1610,6 +1660,7 @@ }, toggleBoardList: function() { var bar, custom, full, showBoardList; + bar = Header.bar; custom = $('#custom-board-list', bar); full = $('#full-board-list', bar); @@ -1645,6 +1696,7 @@ }, toggleLinkJustify: function() { var centered; + $.event('CloseMenu'); centered = this.nodeName === 'INPUT' ? this.checked : void 0; Header.setLinkJustify(centered); @@ -1674,6 +1726,7 @@ }, toggleBarVisibility: function(e) { var hide, message; + if (e.type === 'mousedown' && e.button !== 0) { return; } @@ -1690,6 +1743,7 @@ }, toggleFooterVisibility: function() { var hide, message; + $.event('CloseMenu'); hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden; Header.setFooterVisibility(hide); @@ -1699,6 +1753,7 @@ }, setCustomNav: function(show) { var btn, cust, full, _ref; + Header.customNavToggler.checked = show; cust = $('#custom-board-list', Header.bar); full = $('#full-board-list', Header.bar); @@ -1711,12 +1766,14 @@ }, editCustomNav: function() { var settings; + Settings.open('Advanced'); settings = $.id('fourchanx-settings'); return $('input[name=boardnav]', settings).focus(); }, hashScroll: function() { var hash, post; + if (!((hash = this.location.hash.slice(1)) && (post = $.id(hash)))) { return; } @@ -1727,6 +1784,7 @@ }, scrollToPost: function(post) { var headRect, top; + top = post.getBoundingClientRect().top; if (Conf['Fixed Header'] && !Conf['Bottom Header']) { headRect = Header.bar.getBoundingClientRect(); @@ -1736,6 +1794,7 @@ }, addShortcut: function(el) { var shortcut; + shortcut = $.el('span', { className: 'shortcut fourchanx-link' }); @@ -1747,6 +1806,7 @@ }, createNotification: function(e) { var cb, content, lifetime, notif, type, _ref; + _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb; notif = new Notification(type, content, lifetime); if (cb) { @@ -1759,6 +1819,7 @@ spoilerRange: {}, shortFilename: function(filename, isReply) { var threshold; + threshold = isReply ? 30 : 40; if (filename.length - 4 > threshold) { return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3); @@ -1768,6 +1829,7 @@ }, postFromObject: function(data, boardID) { var o; + o = { postID: data.no, threadID: data.resto || data.no, @@ -1811,6 +1873,7 @@ */ var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref; + postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file; isOP = postID === threadID; staticPath = '//static.4chan.org/image/'; @@ -1906,6 +1969,7 @@ Get = { threadExcerpt: function(thread) { var OP, excerpt, _ref; + OP = thread.OP; excerpt = ((_ref = OP.info.subject) != null ? _ref.trim() : void 0) || OP.info.comment.replace(/\n+/g, ' // ') || Conf['Anonymize'] && 'Anonymous' || $('.nameBlock', OP.nodes.info).textContent.trim(); if (excerpt.length > 70) { @@ -1918,6 +1982,7 @@ }, postFromRoot: function(root) { var boardID, index, link, post, postID; + link = $('a[title="Highlight this post"]', root); boardID = link.pathname.split('/')[1]; postID = link.hash.slice(2); @@ -1937,6 +2002,7 @@ }, postDataFromLink: function(link) { var boardID, path, postID, threadID; + if (link.hostname === 'boards.4chan.org') { path = link.pathname.split('/'); boardID = path[1]; @@ -1955,6 +2021,7 @@ }, allQuotelinksLinkingTo: function(post) { var ID, quote, quotedPost, quotelinks, quoterPost, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; + quotelinks = []; _ref = g.posts; for (ID in _ref) { @@ -1983,12 +2050,14 @@ } return quotelinks.filter(function(quotelink) { var boardID, postID, _ref4; + _ref4 = Get.postDataFromLink(quotelink), boardID = _ref4.boardID, postID = _ref4.postID; return boardID === post.board.ID && postID === post.ID; }); }, postClone: function(boardID, threadID, postID, root, context) { var post, url; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2009,6 +2078,7 @@ }, insert: function(post, root, context) { var clone, nodes; + if (!root.parentNode) { return; } @@ -2022,6 +2092,7 @@ }, fetchedPost: function(req, boardID, threadID, postID, root, context) { var board, post, posts, status, thread, url, _i, _len; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2071,6 +2142,7 @@ }, archivedPost: function(req, boardID, postID, root, context) { var board, bq, comment, data, o, post, thread, threadID, _ref; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2164,8 +2236,10 @@ UI = (function() { var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove; + dialog = function(id, position, html) { var child, el, move, _i, _len, _ref; + el = $.el('div', { className: 'dialog', innerHTML: html, @@ -2205,6 +2279,7 @@ Menu.prototype.makeMenu = function() { var menu; + menu = $.el('div', { className: 'dialog', id: 'menu', @@ -2219,6 +2294,7 @@ Menu.prototype.toggle = function(e, button, data) { var previousButton; + e.preventDefault(); e.stopPropagation(); if (currentMenu) { @@ -2236,6 +2312,7 @@ Menu.prototype.open = function(button, data) { var bLeft, bRect, bTop, bottom, cHeight, cWidth, entry, left, mRect, menu, right, style, top, _i, _len, _ref, _ref1, _ref2; + menu = this.makeMenu(); currentMenu = menu; lastToggledButton = button; @@ -2274,6 +2351,7 @@ Menu.prototype.insertEntry = function(entry, parent, data) { var subEntry, submenu, _i, _len, _ref; + if (typeof entry.open === 'function') { if (!entry.open(data)) { return; @@ -2307,6 +2385,7 @@ Menu.prototype.findNextEntry = function(entry, direction) { var entries; + entries = __slice.call(entry.parentNode.children); entries.sort(function(first, second) { return +(first.style.order || first.style.webkitOrder) - +(second.style.order || second.style.webkitOrder); @@ -2316,6 +2395,7 @@ Menu.prototype.keybinds = function(e) { var entry, next, nextPrev, subEntry, submenu; + entry = $('.focused', currentMenu); while (subEntry = $('.focused', entry)) { entry = subEntry; @@ -2361,6 +2441,7 @@ Menu.prototype.focus = function(entry) { var bottom, cHeight, cWidth, eRect, focused, left, right, sRect, style, submenu, top, _i, _len, _ref, _ref1, _ref2; + while (focused = $.x('parent::*/child::*[contains(@class,"focused")]', entry)) { $.rmClass(focused, 'focused'); } @@ -2388,6 +2469,7 @@ Menu.prototype.addEntry = function(e) { var entry; + entry = e.detail; if (entry.type !== this.type) { return; @@ -2398,6 +2480,7 @@ Menu.prototype.parseEntry = function(entry) { var el, style, subEntries, subEntry, _i, _len; + el = entry.el, subEntries = entry.subEntries; $.addClass(el, 'entry'); $.on(el, 'focus mouseover', (function(e) { @@ -2421,6 +2504,7 @@ })(); dragstart = function(e) { var el, isTouching, o, rect, screenHeight, screenWidth, _ref; + if (e.type === 'mousedown' && e.button !== 0) { return; } @@ -2459,6 +2543,7 @@ }; touchmove = function(e) { var touch, _i, _len, _ref; + _ref = e.changedTouches; for (_i = 0, _len = _ref.length; _i < _len; _i++) { touch = _ref[_i]; @@ -2470,6 +2555,7 @@ }; drag = function(e) { var bottom, clientX, clientY, left, right, style, top; + clientX = e.clientX, clientY = e.clientY; left = clientX - this.dx; left = left < 10 ? 0 : this.width - left < 10 ? null : left / this.screenWidth * 100 + '%'; @@ -2485,6 +2571,7 @@ }; touchend = function(e) { var touch, _i, _len, _ref; + _ref = e.changedTouches; for (_i = 0, _len = _ref.length; _i < _len; _i++) { touch = _ref[_i]; @@ -2506,6 +2593,7 @@ }; hoverstart = function(_arg) { var asapTest, cb, el, endEvents, latestEvent, o, root; + root = _arg.root, el = _arg.el, latestEvent = _arg.latestEvent, endEvents = _arg.endEvents, asapTest = _arg.asapTest, cb = _arg.cb; o = { root: root, @@ -2534,6 +2622,7 @@ }; hover = function(e) { var clientX, clientY, height, left, right, style, top, _ref; + this.latestEvent = e; height = this.el.offsetHeight; clientX = e.clientX, clientY = e.clientY; @@ -2576,6 +2665,7 @@ }, node: function() { var email, name, tripcode, _ref; + if (this.info.capcode || this.isClone) { return; } @@ -2602,6 +2692,7 @@ filters: {}, init: function() { var boards, err, filter, hl, key, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4; + if (g.VIEW === 'catalog' || !Conf['Filter']) { return; } @@ -2638,6 +2729,7 @@ op = ((_ref2 = filter.match(/[^t]op:(yes|no|only)/)) != null ? _ref2[1] : void 0) || 'yes'; stub = (function() { var _ref3; + switch ((_ref3 = filter.match(/stub:(yes|no)/)) != null ? _ref3[1] : void 0) { case 'yes': return true; @@ -2668,6 +2760,7 @@ }, createFilter: function(regexp, op, stub, hl, top) { var settings, test; + test = typeof regexp === 'string' ? function(value) { return regexp === value; } : function(value) { @@ -2691,6 +2784,7 @@ }, node: function() { var filter, firstThread, key, result, thisThread, value, _i, _len, _ref; + if (this.isClone) { return; } @@ -2802,6 +2896,7 @@ menu: { init: function() { var div, entry, type, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Filter']) { return; } @@ -2827,6 +2922,7 @@ }, createSubEntry: function(text, type) { var el; + el = $.el('a', { href: 'javascript:;', textContent: text @@ -2837,6 +2933,7 @@ el: el, open: function(post) { var value; + value = Filter[type](post); return value !== false; } @@ -2844,6 +2941,7 @@ }, makeFilter: function() { var re, type, value; + type = this.dataset.type; value = Filter[type](Filter.menu.post); re = ['uniqueID', 'MD5'].contains(type) ? value : value.replace(/\/|\\|\^|\$|\n|\.|\(|\)|\{|\}|\[|\]|\?|\*|\+|\|/g, function(c) { @@ -2858,6 +2956,7 @@ re = ['uniqueID', 'MD5'].contains(type) ? "/" + re + "/" : "/^" + re + "$/"; return $.get(type, Conf[type], function(item) { var save, section, select, ta, tl; + save = item[type]; save = save ? "" + save + "\n" + re : re; $.set(type, save); @@ -2891,6 +2990,7 @@ }, node: function() { var data; + if (!this.isReply || this.isClone) { return; } @@ -2914,6 +3014,7 @@ menu: { init: function() { var apply, div, hideStubLink, makeStub, replies, thisPost; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Reply Hiding Link']) { return; } @@ -2984,6 +3085,7 @@ order: 20, open: function(post) { var data; + if (!post.isReply || post.isClone || !post.isHidden) { return false; } @@ -3015,6 +3117,7 @@ order: 15, open: function(post) { var data; + if (!post.isReply || post.isClone || !post.isHidden) { return false; } @@ -3031,6 +3134,7 @@ }, hide: function() { var makeStub, parent, post, replies, thisPost; + parent = this.parentNode; thisPost = $('input[name=thisPost]', parent).checked; replies = $('input[name=replies]', parent).checked; @@ -3049,6 +3153,7 @@ }, show: function() { var data, parent, post, replies, thisPost; + parent = this.parentNode; thisPost = $('input[name=thisPost]', parent).checked; replies = $('input[name=replies]', parent).checked; @@ -3072,6 +3177,7 @@ }, hideStub: function() { var post; + post = PostHiding.menu.post; post.nodes.root.hidden = true; $.event('CloseMenu'); @@ -3079,6 +3185,7 @@ }, makeButton: function(post, type) { var a; + a = $.el('a', { className: "" + type + "-reply-button", innerHTML: " " + (type === 'hide' ? '-' : '+') + " ", @@ -3089,6 +3196,7 @@ }, saveHiddenState: function(post, isHiding, thisPost, makeStub, hideRecursively) { var data; + data = { boardID: post.board.ID, threadID: post.thread.ID, @@ -3107,6 +3215,7 @@ }, toggle: function() { var post; + post = Get.postFromNode(this); if (post.isHidden) { PostHiding.show(post); @@ -3117,6 +3226,7 @@ }, hide: function(post, makeStub, hideRecursively) { var a, postInfo, quotelink, _i, _len, _ref; + if (makeStub == null) { makeStub = Conf['Stubs']; } @@ -3154,6 +3264,7 @@ }, show: function(post, showRecursively) { var quotelink, _i, _len, _ref; + if (showRecursively == null) { showRecursively = Conf['Recursive Hiding']; } @@ -3189,6 +3300,7 @@ }, node: function() { var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1; + if (this.isClone) { return; } @@ -3206,6 +3318,7 @@ }, add: function() { var args, obj, post, recursive, _base, _name; + recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = { recursives: [], @@ -3216,6 +3329,7 @@ }, rm: function(recursive, post) { var i, obj, rec, _i, _len, _ref; + if (!(obj = Recursive.recursives[post.fullID])) { return; } @@ -3230,6 +3344,7 @@ }, apply: function() { var ID, args, fullID, post, recursive, _ref; + recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; fullID = post.fullID; _ref = g.posts; @@ -3256,6 +3371,7 @@ }, node: function() { var data; + if (data = ThreadHiding.db.get({ boardID: this.board.ID, threadID: this.ID @@ -3269,6 +3385,7 @@ }, syncCatalog: function() { var hiddenThreads, hiddenThreadsOnCatalog, threadID; + hiddenThreads = ThreadHiding.db.get({ boardID: g.BOARD.ID, defaultValue: {} @@ -3295,6 +3412,7 @@ cleanCatalog: function(hiddenThreadsOnCatalog) { return $.cache("//api.4chan.org/" + g.BOARD + "/threads.json", function() { var page, thread, threads, _i, _j, _len, _len1, _ref, _ref1; + if (this.status !== 200) { return; } @@ -3320,6 +3438,7 @@ menu: { init: function() { var apply, div, hideStubLink, makeStub; + if (g.VIEW !== 'index' || !Conf['Menu'] || !Conf['Thread Hiding Link']) { return; } @@ -3346,6 +3465,7 @@ order: 20, open: function(_arg) { var isReply, thread; + thread = _arg.thread, isReply = _arg.isReply; if (isReply || thread.isHidden) { return false; @@ -3367,6 +3487,7 @@ order: 15, open: function(_arg) { var isReply, thread; + thread = _arg.thread, isReply = _arg.isReply; if (isReply || !thread.isHidden) { return false; @@ -3377,6 +3498,7 @@ }, hide: function() { var makeStub, thread; + makeStub = $('input', this.parentNode).checked; thread = ThreadHiding.menu.thread; ThreadHiding.hide(thread, makeStub); @@ -3385,6 +3507,7 @@ }, hideStub: function() { var thread; + thread = ThreadHiding.menu.thread; ThreadHiding.hide(thread, false); $.event('CloseMenu'); @@ -3392,6 +3515,7 @@ }, makeButton: function(thread, type) { var a; + a = $.el('a', { className: "" + type + "-thread-button", innerHTML: " " + (type === 'hide' ? '-' : '+') + " ", @@ -3403,6 +3527,7 @@ }, saveHiddenState: function(thread, makeStub) { var hiddenThreadsOnCatalog; + hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {}; if (thread.isHidden) { ThreadHiding.db.set({ @@ -3435,6 +3560,7 @@ }, hide: function(thread, makeStub) { var OP, a, numReplies, opInfo, span, threadRoot; + if (makeStub == null) { makeStub = Conf['Stubs']; } @@ -3465,6 +3591,7 @@ }, show: function(thread) { var threadRoot; + if (thread.stub) { $.rm(thread.stub); delete thread.stub; @@ -3477,6 +3604,7 @@ QuoteBacklink = { init: function() { var format; + if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) { return; } @@ -3494,6 +3622,7 @@ }, firstNode: function() { var a, clone, container, containers, frag, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + if (this.isClone || !this.quotes.length) { return; } @@ -3531,6 +3660,7 @@ }, secondNode: function() { var container; + if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) { this.nodes.backlinkContainer = $('.container', this.nodes.info); return; @@ -3544,6 +3674,7 @@ }, getContainer: function(id) { var _base; + return (_base = this.containers)[id] || (_base[id] = $.el('span', { className: 'container' })); @@ -3566,6 +3697,7 @@ }, node: function() { var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1; + if (this.isClone && this.thread === this.context.thread) { return; } @@ -3601,6 +3733,7 @@ if (Conf['Quote Hash Navigation']) { this.node = function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3613,6 +3746,7 @@ } else { this.node = function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3636,6 +3770,7 @@ }, toggle: function(e) { var boardID, context, postID, threadID, _ref; + if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) { return; } @@ -3661,6 +3796,7 @@ }, add: function(quotelink, boardID, threadID, postID, context) { var inline, isBacklink, post, qroot, root; + isBacklink = $.hasClass(quotelink, 'backlink'); inline = $.el('div', { id: "i" + postID, @@ -3685,6 +3821,7 @@ }, rm: function(quotelink, boardID, threadID, postID, context) { var el, inlined, isBacklink, post, qroot, root, _ref; + isBacklink = $.hasClass(quotelink, 'backlink'); root = QuoteInline.findRoot(quotelink, isBacklink); root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root); @@ -3726,6 +3863,7 @@ }, node: function() { var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref; + if (this.isClone && this.thread === this.context.thread) { return; } @@ -3768,6 +3906,7 @@ }, node: function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3776,6 +3915,7 @@ }, mouseover: function(e) { var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1; + if ($.hasClass(this, 'inlined')) { return; } @@ -3819,6 +3959,7 @@ }, mouseout: function() { var clone, post, root, _i, _len, _ref; + if (!(root = this.el.firstElementChild)) { return; } @@ -3848,6 +3989,7 @@ }, node: function() { var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2; + if (this.isClone) { return; } @@ -3870,6 +4012,7 @@ QuoteThreading = { init: function() { var input; + if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) { return; } @@ -3892,6 +4035,7 @@ }, setup: function() { var ID, post, posts; + $.off(d, '4chanXInitFinished', QuoteThreading.setup); posts = g.posts; for (ID in posts) { @@ -3904,6 +4048,7 @@ }, node: function() { var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len; + if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) { return; } @@ -3933,6 +4078,7 @@ }, nodeinsert: function() { var bottom, height, posts, qpost, qroot, threadContainer, top, _ref; + posts = g.posts; qpost = posts[this.threaded]; delete this.threaded; @@ -3962,12 +4108,14 @@ }, toggle: function() { var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1; + thread = $('.thread'); replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread); QuoteThreading.enabled = this.checked; if (this.checked) { nodes = (function() { var _i, _len, _results; + _results = []; for (_i = 0, _len = replies.length; _i < _len; _i++) { reply = replies[_i]; @@ -3982,6 +4130,7 @@ } else { replies.sort(function(a, b) { var aID, bID; + aID = Number(a.id.slice(2)); bID = Number(b.id.slice(2)); return aID - bID; @@ -3997,6 +4146,7 @@ }, kb: function() { var control; + control = $.id('threadingControl'); return control.click(); } @@ -4023,6 +4173,7 @@ }, node: function() { var quotelink, _i, _len, _ref; + if (this.isClone) { return; } @@ -4058,6 +4209,7 @@ }, node: function() { var deadlink, _i, _len, _ref; + _ref = $$('.deadlink', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { deadlink = _ref[_i]; @@ -4072,6 +4224,7 @@ }, parseDeadlink: function(deadlink) { var a, boardID, m, post, postID, quote, quoteID, redirect, _ref; + if (deadlink.parentNode.className === 'prettyprint') { $.replace(deadlink, __slice.call(deadlink.childNodes)); return; @@ -4151,6 +4304,7 @@ cypher: $.el('div'), node: function() { var a, child, cypher, cypherText, data, embed, embedder, embeds, i, index, len, link, links, lookahead, name, next, node, nodes, snapshot, spoiler, text, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2; + if (this.isClone && Conf['Embedding']) { _ref = $$('.embedder', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -4235,6 +4389,7 @@ }, toggle: function() { var el, embed, style, type, url; + embed = this.previousElementSibling; if (this.className.contains("embedded")) { el = $.el('a', { @@ -4328,6 +4483,7 @@ style: 'height: auto; width: 500px; display: inline-block;', el: function() { var div; + div = $.el('div', { className: "soundcloud", name: "soundcloud" @@ -4353,6 +4509,7 @@ regExp: /.*(?:pastebin.com\/(?!u\/))([^#\&\?]*).*/, el: function() { var div; + return div = $.el('iframe', { src: "http://pastebin.com/embed_iframe.php?i=" + this.name }); @@ -4362,6 +4519,7 @@ regExp: /.*(?:gist.github.com.*\/)([^\/][^\/]*)$/, el: function() { var div; + return div = $.el('iframe', { src: "http://www.purplegene.com/script?url=https://gist.github.com/" + this.name + ".js" }); @@ -4372,6 +4530,7 @@ }, text: function() { var file, response; + response = JSON.parse(this.responseText).files; for (file in response) { if (response.hasOwnProperty(file)) { @@ -4392,12 +4551,14 @@ }, embedder: function(a) { var callbacks, embed, key, match, service, titles, type, _ref; + if (!Conf['Link Title']) { return [a]; } titles = {}; callbacks = function() { var title; + return a.textContent = (function() { switch (this.status) { case 200: @@ -4439,6 +4600,7 @@ if (Conf['Link Title'] && (service = type.title)) { $.get('CachedTitles', {}, function(item) { var err, title; + titles = item['CachedTitles']; if (title = titles[match[1]]) { a.textContent = title[0]; @@ -4462,6 +4624,7 @@ QR = { init: function() { var sc; + if (!Conf['Quick Reply']) { return; } @@ -4508,6 +4671,7 @@ }, initReady: function() { var link; + QR.postingIsEnabled = !!$.id('postForm'); if (!QR.postingIsEnabled) { return; @@ -4527,11 +4691,13 @@ $.before($.id('postForm'), link); $.on(d, 'QRGetSelectedPost', function(_arg) { var cb; + cb = _arg.detail; return cb(QR.selected); }); $.on(d, 'QRAddPreSubmitHook', function(_arg) { var cb; + cb = _arg.detail; return QR.preSubmitHooks.push(cb); }); @@ -4560,6 +4726,7 @@ }, open: function() { var err; + if (QR.nodes) { QR.nodes.el.hidden = false; QR.unhide(); @@ -4578,6 +4745,7 @@ }, close: function() { var i, _i, _len, _ref; + if (QR.req) { QR.abort(); return; @@ -4624,6 +4792,7 @@ }, error: function(err) { var el; + QR.open(); if (typeof err === 'string') { el = $.tn(err); @@ -4651,6 +4820,7 @@ notifications: [], cleanNotifications: function() { var notification, _i, _len, _ref; + _ref = QR.notifications; for (_i = 0, _len = _ref.length; _i < _len; _i++) { notification = _ref[_i]; @@ -4660,6 +4830,7 @@ }, status: function() { var disabled, status, value; + if (!QR.nodes) { return; } @@ -4680,6 +4851,7 @@ QR.persona.getPassword(); return $.get('QR.personas', Conf['QR.personas'], function(_arg) { var arr, item, personas, type, types, _i, _len, _ref; + personas = _arg['QR.personas']; types = { name: [], @@ -4699,6 +4871,7 @@ }, parseItem: function(item, types) { var boards, match, type, val, _ref, _ref1; + if (item[0] === '#') { return; } @@ -4727,6 +4900,7 @@ }, loadPersonas: function(type, arr) { var list, val, _i, _len; + list = $("#list-" + type, QR.nodes.el); for (_i = 0, _len = arr.length; _i < _len; _i++) { val = arr[_i]; @@ -4740,6 +4914,7 @@ }, getPassword: function() { var input, m; + if (!QR.persona.pwd) { QR.persona.pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : (input = $.id('postPassword')) ? input.value : $.id('delPassword').value; } @@ -4748,6 +4923,7 @@ get: function(cb) { return $.get('QR.persona', {}, function(_arg) { var persona; + persona = _arg['QR.persona']; return cb(persona); }); @@ -4755,6 +4931,7 @@ set: function(post) { return $.get('QR.persona', {}, function(_arg) { var persona; + persona = _arg['QR.persona']; persona = { name: post.name, @@ -4768,6 +4945,7 @@ cooldown: { init: function() { var board; + if (!Conf['Cooldown']) { return; } @@ -4809,6 +4987,7 @@ }, sync: function(cooldowns) { var id; + for (id in cooldowns) { QR.cooldown.cooldowns[id] = cooldowns[id]; } @@ -4816,6 +4995,7 @@ }, set: function(data) { var cooldown, delay, hasFile, isReply, isSage, post, req, start, type, upSpd; + if (!Conf['Cooldown']) { return; } @@ -4855,6 +5035,7 @@ }, count: function() { var cooldown, cooldowns, elapsed, hasFile, isReply, isSage, now, post, seconds, start, type, types, upSpd, upSpdAccuracy, update, _ref; + if (!Object.keys(QR.cooldown.cooldowns).length) { $["delete"]("" + g.BOARD + ".cooldown"); delete QR.cooldown.isCounting; @@ -4908,6 +5089,7 @@ }, quote: function(e) { var OP, caretPos, com, index, post, range, s, sel, selectionRoot, text, thread, _ref; + if (e != null) { e.preventDefault(); } @@ -4947,6 +5129,7 @@ }, characterCount: function() { var count, counter; + counter = QR.nodes.charCount; count = QR.nodes.com.textLength; counter.textContent = count; @@ -4955,6 +5138,7 @@ }, drag: function(e) { var toggle; + toggle = e.type === 'dragstart' ? $.off : $.on; toggle(d, 'dragover', QR.dragOver); return toggle(d, 'drop', QR.dropFile); @@ -4974,6 +5158,7 @@ }, paste: function(e) { var blob, files, item, _i, _len, _ref; + files = []; _ref = e.clipboardData.items; for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -5001,6 +5186,7 @@ }, fileInput: function(files) { var file, length, max, post, _i, _len; + if (this instanceof Element) { files = __slice.call(this.files); QR.nodes.fileInput.value = null; @@ -5049,6 +5235,7 @@ function _Class(select) { var el, elm, event, prev, _i, _j, _len, _len1, _ref, _ref1, _this = this; + el = $.el('a', { className: 'qr-preview', draggable: true, @@ -5108,6 +5295,7 @@ _Class.prototype.rm = function() { var index; + $.rm(this.nodes.el); index = QR.posts.indexOf(this); if (QR.posts.length === 1) { @@ -5125,6 +5313,7 @@ _Class.prototype.lock = function(lock) { var name, _i, _len, _ref; + if (lock == null) { lock = true; } @@ -5149,6 +5338,7 @@ _Class.prototype.select = function() { var rectEl, rectList; + if (QR.selected) { QR.selected.nodes.el.id = null; QR.selected.forceSave(); @@ -5165,6 +5355,7 @@ _Class.prototype.load = function() { var name, _i, _len, _ref; + _ref = ['thread', 'name', 'email', 'sub', 'com']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { name = _ref[_i]; @@ -5176,6 +5367,7 @@ _Class.prototype.save = function(input) { var value, _ref; + if (input.type === 'checkbox') { this.spoiler = input.checked; return; @@ -5194,6 +5386,7 @@ _Class.prototype.forceSave = function() { var name, _i, _len, _ref; + if (this !== QR.selected) { return; } @@ -5225,6 +5418,7 @@ _Class.prototype.setThumbnail = function(fileURL) { var img, reader, _this = this; + if (!window.URL) { if (!fileURL) { reader = new FileReader(); @@ -5240,6 +5434,7 @@ img = $.el('img'); img.onload = function() { var applyBlob, cv, data, height, i, l, s, ui8a, width, _i; + s = 90 * 2; if (_this.file.type === 'image/gif') { s *= 3; @@ -5319,9 +5514,11 @@ _Class.prototype.pasteText = function(file) { var reader, _this = this; + reader = new FileReader(); reader.onload = function(e) { var text; + text = e.target.result; if (_this.com) { _this.com += "\n" + text; @@ -5359,6 +5556,7 @@ _Class.prototype.drop = function() { var el, index, newIndex, oldIndex, post; + el = $('.drag', this.parentNode); $.rmClass(el, 'drag'); $.rmClass(this, 'over'); @@ -5393,6 +5591,7 @@ ready: function() { var imgContainer, input, observer, setLifetime, _this = this; + setLifetime = function(e) { return _this.lifetime = e.detail; }; @@ -5434,6 +5633,7 @@ }); $.get('captchas', [], function(_arg) { var captchas; + captchas = _arg.captchas; return _this.sync(captchas); }); @@ -5450,6 +5650,7 @@ }, getOne: function() { var captcha, challenge, response; + this.clear(); if (captcha = this.captchas.shift()) { challenge = captcha.challenge, response = captcha.response; @@ -5474,6 +5675,7 @@ }, save: function() { var response; + if (!(response = this.nodes.input.value.trim())) { return; } @@ -5488,6 +5690,7 @@ }, clear: function() { var captcha, i, now, _i, _len, _ref; + now = Date.now(); _ref = this.captchas; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { @@ -5505,6 +5708,7 @@ }, load: function() { var challenge; + if (!this.nodes.challenge.firstChild) { return; } @@ -5517,6 +5721,7 @@ }, count: function() { var count; + count = this.captchas.length; this.nodes.input.placeholder = (function() { switch (count) { @@ -5549,6 +5754,7 @@ }, dialog: function() { var dialog, elm, mimeTypes, name, nodes, thread, _i, _j, _len, _len1, _ref, _ref1; + dialog = UI.dialog('qr', 'top:0;right:0;', "
×
No selected file×+
"); QR.nodes = nodes = { el: dialog, @@ -5668,6 +5874,7 @@ preSubmitHooks: [], submit: function(e) { var callbacks, challenge, err, filetag, hook, opts, post, postData, response, textOnly, thread, threadID, _i, _len, _ref, _ref1; + if (e != null) { e.preventDefault(); } @@ -5780,6 +5987,7 @@ }, response: function() { var URL, ban, board, err, h1, isReply, m, post, postID, req, threadID, tmpDoc, _, _ref, _ref1; + req = QR.req; delete QR.req; post = QR.posts[0]; @@ -5882,6 +6090,7 @@ FappeTyme = { init: function() { var el, input; + if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } @@ -5933,6 +6142,7 @@ }, node: function() { var thumb, _ref; + if (!((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -5957,6 +6167,7 @@ }, toggleAll: function() { var ID, file, func, post, _i, _len, _ref, _ref1; + $.event('CloseMenu'); if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) { ImageExpand.EAI.className = 'contract-all-shortcut'; @@ -5990,6 +6201,7 @@ }, toggle: function(post) { var headRect, node, rect, root, thumb, top; + thumb = post.file.thumb; if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) { ImageExpand.expand(post); @@ -6034,6 +6246,7 @@ }, expand: function(post, src) { var img, thumb; + thumb = post.file.thumb; if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) { return; @@ -6061,6 +6274,7 @@ }, completeExpand: function(post) { var prev, thumb; + thumb = post.file.thumb; if (!$.hasClass(thumb, 'expanding')) { return; @@ -6074,6 +6288,7 @@ prev = post.nodes.root.getBoundingClientRect(); return $.queueTask(function() { var curr, root; + $.addClass(post.nodes.root, 'expanded-image'); $.rmClass(post.file.thumb, 'expanding'); if (!(prev.top + prev.height <= 0)) { @@ -6086,6 +6301,7 @@ }, error: function() { var URL, post, src, timeoutID; + post = Get.postFromNode(this); $.rm(this); delete post.file.fullImage; @@ -6111,6 +6327,7 @@ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", { onload: function() { var postObj, _i, _len, _ref; + if (this.status !== 200) { return; } @@ -6134,6 +6351,7 @@ menu: { init: function() { var conf, createSubEntry, el, key, subEntries, _ref; + if (g.VIEW === 'catalog' || !Conf['Image Expansion']) { return; } @@ -6157,6 +6375,7 @@ }, createSubEntry: function(type, config) { var input, label; + label = $.el('label', { innerHTML: " " + type }); @@ -6192,6 +6411,7 @@ }, node: function() { var _ref; + if (!((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -6199,6 +6419,7 @@ }, mouseover: function(e) { var el, post; + post = Get.postFromNode(this); el = $.el('img', { id: 'ihover', @@ -6220,6 +6441,7 @@ error: function() { var URL, post, src, timeoutID, _this = this; + if (!doc.contains(this)) { return; } @@ -6244,6 +6466,7 @@ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", { onload: function() { var postObj, _i, _len, _ref; + if (this.status !== 200) { return; } @@ -6269,6 +6492,7 @@ ImageLoader = { init: function() { var prefetch; + if (g.VIEW === 'catalog') { return; } @@ -6295,6 +6519,7 @@ }, node: function() { var URL, img, string, style, thumb, type, _ref, _ref1; + if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -6316,6 +6541,7 @@ }, toggle: function() { var enabled, id, post, _ref; + enabled = Conf['prefetch'] = this.checked; if (enabled) { _ref = g.threads["" + g.BOARD.ID + "." + g.THREADID].posts; @@ -6329,16 +6555,17 @@ RevealSpoilers = { init: function() { - if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) { + if (g.VIEW === 'catalog' || !Conf['Reveal Spoiler Thumbnails']) { return; } return Post.prototype.callbacks.push({ - name: 'Reveal Spoilers', + name: 'Reveal Spoiler Thumbnails', cb: this.node }); }, node: function() { var thumb, _ref; + if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) { return; } @@ -6351,6 +6578,7 @@ ArchiveLink = { init: function() { var div, entry, type, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) { return; } @@ -6363,6 +6591,7 @@ order: 90, open: function(_arg) { var ID, board, thread; + ID = _arg.ID, thread = _arg.thread, board = _arg.board; return !!Redirect.to('thread', { postID: ID, @@ -6381,12 +6610,14 @@ }, createSubEntry: function(text, type) { var el, open; + el = $.el('a', { textContent: text, target: '_blank' }); open = type === 'post' ? function(_arg) { var ID, board, thread; + ID = _arg.ID, thread = _arg.thread, board = _arg.board; el.href = Redirect.to('thread', { postID: ID, @@ -6396,6 +6627,7 @@ return true; } : function(post) { var value; + value = Filter[type](post); if (!value) { return false; @@ -6418,6 +6650,7 @@ DeleteLink = { init: function() { var div, fileEl, fileEntry, postEl, postEntry; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) { return; } @@ -6445,6 +6678,7 @@ el: fileEl, open: function(_arg) { var file; + file = _arg.file; if (!file || file.isDead) { return false; @@ -6460,6 +6694,7 @@ order: 40, open: function(post) { var node; + if (post.isDead || post.board.ID === 'q') { return false; } @@ -6474,6 +6709,7 @@ }, "delete": function() { var fileOnly, form, link, post; + post = DeleteLink.post; if (DeleteLink.cooldown.counting === post) { return; @@ -6502,6 +6738,7 @@ }, load: function(link, post, fileOnly, html) { var msg, s, tmpDoc; + tmpDoc = d.implementation.createHTMLDocument(''); tmpDoc.documentElement.innerHTML = html; if (tmpDoc.title === '4chan - Banned') { @@ -6524,6 +6761,7 @@ cooldown: { start: function(post, node) { var length, seconds, _ref; + if (!((_ref = QR.db) != null ? _ref.get({ boardID: post.board.ID, threadID: post.thread.ID, @@ -6557,6 +6795,7 @@ DownloadLink = { init: function() { var a; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) { return; } @@ -6570,6 +6809,7 @@ order: 100, open: function(_arg) { var file; + file = _arg.file; if (!file) { return false; @@ -6595,6 +6835,7 @@ }, node: function() { var button; + button = Menu.makeButton(this); if (this.isClone) { $.replace($('.menu-button', this.nodes.info), button); @@ -6604,9 +6845,11 @@ }, makeButton: (function() { var a; + a = null; return function(post) { var clone; + a || (a = $.el('a', { className: 'menu-button fourchanx-link', innerHTML: '', @@ -6623,6 +6866,7 @@ })(), toggle: function(e) { var post; + post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid]; return Menu.menu.toggle(e, this, post); } @@ -6631,6 +6875,7 @@ ReportLink = { init: function() { var a; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) { return; } @@ -6652,6 +6897,7 @@ }, report: function() { var id, post, set, url; + post = ReportLink.post; url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post; id = Date.now(); @@ -6664,6 +6910,7 @@ init: function() { return $.ready(function() { var href; + Favicon.el = $('link[rel="shortcut icon"]', d.head); Favicon.el.type = 'image/x-icon'; href = Favicon.el.href; @@ -6736,6 +6983,7 @@ init: function() { var sc, _this = this; + if (g.VIEW !== 'thread' || !Conf['Thread Stats']) { return; } @@ -6765,6 +7013,7 @@ }, node: function() { var ID, fileCount, post, postCount, _ref; + postCount = 0; fileCount = 0; _ref = this.posts; @@ -6782,6 +7031,7 @@ }, onUpdate: function(e) { var fileCount, postCount, _ref; + if (e.detail[404]) { return; } @@ -6790,6 +7040,7 @@ }, update: function(postCount, fileCount) { var fileCountEl, postCountEl, thread; + thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl; postCountEl.textContent = postCount; fileCountEl.textContent = fileCount; @@ -6816,6 +7067,7 @@ }, onThreadsLoad: function() { var page, pages, thread, _i, _j, _len, _len1, _ref; + if (!Conf["Page Count in Stats"]) { return; } @@ -6843,6 +7095,7 @@ init: function() { var checked, conf, el, input, name, sc, settings, subEntries, _ref, _this = this; + if (g.VIEW !== 'thread' || !Conf['Thread Updater']) { return; } @@ -6993,6 +7246,7 @@ }, interval: function() { var val; + val = +this.value; if (val < 1) { val = 1; @@ -7002,6 +7256,7 @@ }, load: function() { var klass, req, text, _ref; + req = ThreadUpdater.req; switch (req.status) { case 200: @@ -7045,6 +7300,7 @@ }, getInterval: function() { var i, j; + i = ThreadUpdater.interval; j = Math.min(ThreadUpdater.outdateCount, 10); if (!d.hidden) { @@ -7054,12 +7310,14 @@ }, intervalShortcut: function() { var settings; + Settings.open('Advanced'); settings = $.id('fourchanx-settings'); return $('input[name=Interval]', settings).focus(); }, set: function(name, text, klass) { var el, node; + el = ThreadUpdater[name]; if (node = el.firstChild) { node.data = text; @@ -7072,6 +7330,7 @@ }, timeout: function() { var n; + ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000); if (!(n = --ThreadUpdater.seconds)) { return ThreadUpdater.update(); @@ -7084,6 +7343,7 @@ }, update: function() { var url; + if (!ThreadUpdater.online) { return; } @@ -7108,6 +7368,7 @@ }, updateThreadStatus: function(title, OP) { var icon, message, root, titleLC; + titleLC = title.toLowerCase(); if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) { return; @@ -7134,6 +7395,7 @@ }, parse: function(postObjects) { var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _len, _ref; + OP = postObjects[0]; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; ThreadUpdater.updateThreadStatus('Sticky', OP); @@ -7219,6 +7481,7 @@ } $.queueTask(function() { var length, threadID; + threadID = ThreadUpdater.thread.ID; length = $$('.thread > .postContainer', ThreadUpdater.root).length; return Fourchan.parseThread(threadID, length - count, length); @@ -7239,6 +7502,7 @@ ThreadWatcher = { init: function() { var sc; + if (!Conf['Thread Watcher']) { return; } @@ -7272,6 +7536,7 @@ node: function() { var favicon, _this = this; + favicon = $.el('a', { className: 'watch-thread-link', href: 'javascript:;' @@ -7291,6 +7556,7 @@ }, refresh: function(watched) { var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1; + if (!watched) { $.get('WatchedThreads', {}, function(item) { return ThreadWatcher.refresh(item['WatchedThreads']); @@ -7339,11 +7605,13 @@ }, x: function() { var thread; + thread = this.nextElementSibling.pathname.split('/'); return ThreadWatcher.unwatch(thread[1], thread[3]); }, post: function(e) { var board, postID, threadID, _ref; + _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID; if (postID === threadID) { if (Conf['Auto Watch']) { @@ -7364,6 +7632,7 @@ unwatch: function(board, threadID) { return $.get('WatchedThreads', {}, function(item) { var watched; + watched = item['WatchedThreads']; delete watched[board][threadID]; if (!Object.keys(watched[board]).length) { @@ -7376,6 +7645,7 @@ watch: function(thread) { return $.get('WatchedThreads', {}, function(item) { var watched, _name; + watched = item['WatchedThreads']; watched[_name = thread.board] || (watched[_name] = {}); watched[thread.board][thread] = { @@ -7421,6 +7691,7 @@ }, ready: function() { var ID, post, posts, _ref; + $.off(d, '4chanXInitFinished', Unread.ready); posts = []; _ref = Unread.thread.posts; @@ -7437,6 +7708,7 @@ }, scroll: function() { var checkPosition, hash, onload, post, posts, prevID, root; + if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { return; } @@ -7468,6 +7740,7 @@ } checkPosition = function(target) { var height, top, _ref; + _ref = target.getBoundingClientRect(), top = _ref.top, height = _ref.height; return top + height - doc.clientHeight > 0; }; @@ -7475,6 +7748,7 @@ }, sync: function() { var lastReadPost; + lastReadPost = Unread.db.get({ boardID: Unread.thread.board.ID, threadID: Unread.thread.ID, @@ -7491,6 +7765,7 @@ }, addPosts: function(posts) { var ID, data, post, _i, _len, _ref; + for (_i = 0, _len = posts.length; _i < _len; _i++) { post = posts[_i]; ID = post.ID; @@ -7518,6 +7793,7 @@ }, addPostQuotingYou: function(post) { var quotelink, _i, _len, _ref; + if (!QR.db) { return; } @@ -7538,6 +7814,7 @@ }, readSinglePost: function(post) { var i; + if ((i = Unread.posts.indexOf(post)) === -1) { return; } @@ -7553,6 +7830,7 @@ }, readArray: function(arr) { var i, post, _i, _len; + for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) { post = arr[i]; if (post.ID > Unread.lastReadPost) { @@ -7563,6 +7841,7 @@ }, read: $.debounce(50, function(e) { var ID, bottom, height, i, post, posts, read; + if (d.hidden || !Unread.posts.length) { return; } @@ -7596,6 +7875,7 @@ }), setLine: function(force) { var post, root; + if (!(d.hidden || force === true)) { return; } @@ -7610,6 +7890,7 @@ }, update: function() { var count; + count = Unread.posts.length; if (Conf['Unread Count']) { d.title = "" + (Conf['Quoted Title'] && Unread.postsQuotingYou.length ? '(!) ' : '') + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title); @@ -7628,6 +7909,7 @@ file: {}, init: function() { var archive, arr, boardID, data, id, name, type, _i, _len, _ref, _ref1, _ref2, _ref3; + _ref = Conf['selectedArchives']; for (boardID in _ref) { data = _ref[boardID]; @@ -7754,6 +8036,7 @@ }, to: function(dest, data) { var archive; + archive = (dest === 'search' ? Redirect.thread : Redirect[dest])[data.boardID]; if (!archive) { return ''; @@ -7762,6 +8045,7 @@ }, protocol: function(archive) { var protocol; + protocol = location.protocol; if (!archive[protocol.slice(0, -1)]) { protocol = protocol === 'https:' ? 'http:' : 'https:'; @@ -7770,6 +8054,7 @@ }, thread: function(archive, _arg) { var boardID, path, postID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID; path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID; if (archive.software === 'foolfuuka') { @@ -7782,6 +8067,7 @@ }, post: function(archive, _arg) { var boardID, postID, protocol; + boardID = _arg.boardID, postID = _arg.postID; protocol = Redirect.protocol(archive); if (['Foolz', 'NSFW Foolz'].contains(archive.name)) { @@ -7791,11 +8077,13 @@ }, file: function(archive, _arg) { var boardID, filename; + boardID = _arg.boardID, filename = _arg.filename; return "" + (Redirect.protocol(archive)) + archive.domain + "/" + boardID + "/full_image/" + filename; }, search: function(archive, _arg) { var boardID, path, type, value; + boardID = _arg.boardID, type = _arg.type, value = _arg.value; type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type; value = encodeURIComponent(value); @@ -7814,6 +8102,7 @@ }, setup: function() { var btn, entry, psa; + $.off(d, '4chanXInitFinished', PSAHiding.setup); if (!(psa = $.id('globalMessage'))) { $.rmClass(doc, 'hide-announcement'); @@ -7842,6 +8131,7 @@ $.on(btn, 'click', PSAHiding.toggle); $.get('hiddenPSA', 0, function(_arg) { var hiddenPSA; + hiddenPSA = _arg.hiddenPSA; PSAHiding.sync(hiddenPSA); $.before(psa, btn); @@ -7851,6 +8141,7 @@ }, toggle: function(e) { var UTC; + if ($.hasClass(this, 'hide-announcement')) { UTC = +$.id('globalMessage').dataset.utc; $.set('hiddenPSA', UTC); @@ -7862,6 +8153,7 @@ }, sync: function(UTC) { var hr, psa; + psa = $.id('globalMessage'); psa.hidden = PSAHiding.btn.hidden = UTC && UTC >= +psa.dataset.utc ? true : false; if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') { @@ -7873,6 +8165,7 @@ CatalogLinks = { init: function() { var el, input; + if (!Conf['Catalog Links']) { return; } @@ -7896,12 +8189,14 @@ }, toggle: function() { var useCatalog; + $.event('CloseMenu'); $.set('Header catalog links', useCatalog = this.checked); return CatalogLinks.set(useCatalog); }, set: function(useCatalog) { var a, board, path, _i, _len, _ref; + path = useCatalog ? 'catalog' : ''; _ref = $$("#board-list a[href*=\"boards.4chan.org\"]:not(.catalog),\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]"); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -7935,6 +8230,7 @@ }, node: function(post) { var str, uid; + if (!(uid = $('.hand', this.nodes.uniqueID))) { return; } @@ -7946,6 +8242,7 @@ ids: {}, compute: function(str) { var hash, rgb; + hash = this.hash(str); rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF]; rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125; @@ -7954,11 +8251,13 @@ }, apply: function() { var rgb; + rgb = IDColor.ids[this] || IDColor.compute(this); return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black; border-radius: 3px; padding: 0px 2px;" : "white; border-radius: 3px; padding: 0px 2px;"); }, hash: function(str) { var i, j, msg; + msg = 0; i = 0; j = str.length; @@ -7997,6 +8296,7 @@ Emoji = { init: function() { var css, icon, name, pos, _ref; + if (!Conf['Emoji']) { return; } @@ -8066,6 +8366,7 @@ }, node: function() { var a; + if (a = $('.abbr > a:not([onclick])', this.nodes.comment)) { return $.on(a, 'click', ExpandComment.cb); } @@ -8073,12 +8374,14 @@ callbacks: [], cb: function(e) { var post; + e.preventDefault(); post = Get.postFromNode(this); return ExpandComment.expand(post); }, expand: function(post) { var a; + if (post.nodes.longComment && !post.nodes.longComment.parentNode) { $.replace(post.nodes.shortComment, post.nodes.longComment); post.nodes.comment = post.nodes.longComment; @@ -8094,6 +8397,7 @@ }, contract: function(post) { var a; + if (!post.nodes.shortComment) { return; } @@ -8104,6 +8408,7 @@ }, parse: function(req, a, post) { var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + status = req.status; if (![200, 304].contains(status)) { a.textContent = "Error " + req.statusText + " (" + status + ")"; @@ -8160,6 +8465,7 @@ }, node: function() { var a, span; + if (!(span = $('.summary', this.OP.nodes.root.parentNode))) { return; } @@ -8173,11 +8479,13 @@ }, cbToggle: function() { var op; + op = Get.postFromRoot(this.previousElementSibling); return ExpandThread.toggle(op.thread); }, toggle: function(thread) { var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + threadRoot = thread.OP.nodes.root.parentNode; a = $('.summary', threadRoot); switch (thread.isExpanded) { @@ -8246,6 +8554,7 @@ }, parse: function(req, thread, a) { var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len; + if (a.textContent[0] === '+') { return; } @@ -8303,6 +8612,7 @@ }, createFunc: function(format) { var code; + code = format.replace(/%(.)/g, function(s, c) { if (c in FileInfo.formatters) { return "' + FileInfo.formatters." + c + ".call(post) + '"; @@ -8314,6 +8624,7 @@ }, convertUnit: function(size, unit) { var i; + if (unit === 'B') { return "" + (size.toFixed()) + " Bytes"; } @@ -8344,6 +8655,7 @@ }, n: function() { var fullname, shortname; + fullname = this.file.name; shortname = Build.shortFilename(this.file.name, this.isReply); if (fullname === shortname) { @@ -8387,6 +8699,7 @@ Fourchan = { init: function() { var board; + if (g.VIEW === 'catalog') { return; } @@ -8408,6 +8721,7 @@ }, code: function() { var pre, _i, _len, _ref; + if (this.isClone) { return; } @@ -8437,11 +8751,13 @@ Keybinds = { init: function() { var init; + if (g.VIEW === 'catalog' || !Conf['Keybinds']) { return; } init = function() { var node, _i, _len, _ref; + $.off(d, '4chanXInitFinished', init); $.on(d, 'keydown', Keybinds.keydown); _ref = $$('[accesskey]'); @@ -8454,6 +8770,7 @@ }, keydown: function(e) { var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len; + if (!(key = Keybinds.keyCode(e))) { return; } @@ -8628,6 +8945,7 @@ }, keyCode: function(e) { var kc, key; + key = (function() { switch (kc = e.keyCode) { case 8: @@ -8683,6 +9001,7 @@ }, tags: function(tag, ta) { var range, selEnd, selStart, value; + value = ta.value; selStart = ta.selectionStart; selEnd = ta.selectionEnd; @@ -8693,11 +9012,13 @@ }, sage: function() { var isSage; + isSage = /sage/i.test(QR.nodes.email.value); return QR.nodes.email.value = isSage ? "" : "sage"; }, img: function(thread, all) { var post; + if (all) { return ImageExpand.cb.toggleAll(); } else { @@ -8707,6 +9028,7 @@ }, open: function(thread, tab) { var url; + if (g.VIEW !== 'index') { return; } @@ -8719,6 +9041,7 @@ }, hl: function(delta, thread) { var axe, headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len; + if (!delta) { if (postEl = $('.reply.highlight', thread)) { $.rmClass(postEl, 'highlight'); @@ -8778,6 +9101,7 @@ Nav = { init: function() { var append, next, prev, span; + switch (g.VIEW) { case 'index': if (!Conf['Index Navigation']) { @@ -8828,6 +9152,7 @@ }, getThread: function(full) { var headRect, i, rect, thread, threads, topMargin, _i, _len; + if (Conf['Bottom header'] || !Conf['Fixed Header']) { topMargin = 0; } else { @@ -8853,6 +9178,7 @@ }, scroll: function(delta) { var i, rect, thread, threads, top, topMargin, _ref, _ref1; + _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4]; top = rect.top - topMargin; if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) { @@ -8878,6 +9204,7 @@ }, node: function() { var dateEl; + if (this.isClone) { return; } @@ -8887,6 +9214,7 @@ }, relative: function(diff, now, date) { var days, months, number, rounded, unit, years; + unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second'); rounded = Math.round(number); if (rounded !== 1) { @@ -8897,6 +9225,7 @@ stale: [], flush: function() { var now, update, _i, _len, _ref; + if (d.hidden) { return; } @@ -8912,13 +9241,16 @@ }, setUpdate: function(post) { var markStale, setOwnTimeout, update; + setOwnTimeout = function(diff) { var delay; + delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY; return setTimeout(markStale, delay); }; update = function(now) { var date, diff, relative, singlePost, _i, _len, _ref; + date = post.info.date; diff = now - date; relative = RelativeDates.relative(diff, now, date); @@ -8959,6 +9291,7 @@ }, node: function(post) { var spoiler, spoilers, _i, _len; + spoilers = $$('s', this.nodes.comment); for (_i = 0, _len = spoilers.length; _i < _len; _i++) { spoiler = spoilers[_i]; @@ -8978,6 +9311,7 @@ }, ready: function() { var field; + field = $.id('recaptcha_response_field'); $.on(field, 'keydown', function(e) { if (e.keyCode === 8 && !field.value) { @@ -8986,6 +9320,7 @@ }); return $.on($('form'), 'submit', function(e) { var response; + e.preventDefault(); response = field.value.trim(); if (!/\s/.test(response)) { @@ -8999,6 +9334,7 @@ Sauce = { init: function() { var err, link, links, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Sauce']) { return; } @@ -9030,6 +9366,7 @@ }, createSauceLink: function(link) { var m, text; + link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) { switch (parameter) { case '%TURL': @@ -9050,6 +9387,7 @@ }, node: function() { var link, nodes, _i, _len, _ref; + if (this.isClone || !this.file) { return; } @@ -9082,6 +9420,7 @@ }, createFunc: function(format) { var code; + code = format.replace(/%([A-Za-z])/g, function(s, c) { if (c in Time.formatters) { return "' + Time.formatters." + c + ".call(date) + '"; @@ -9166,6 +9505,7 @@ Settings = { init: function() { var link, settings; + link = $.el('a', { className: 'settings-link', textContent: 'Settings', @@ -9175,6 +9515,7 @@ Header.addShortcut(link); $.get('previousversion', null, function(item) { var changelog, el, previous; + if (previous = item['previousversion']) { if (previous === g.VERSION) { return; @@ -9212,6 +9553,7 @@ }, open: function(openSection) { var dialog, html, link, links, overlay, section, sectionToOpen, _i, _len, _ref; + $.off(d, '4chanXInitFinished', Settings.open); if (Settings.dialog) { return; @@ -9264,6 +9606,7 @@ sections: [], addSection: function(title, open) { var hyphenatedTitle, _ref; + if (typeof title !== 'string') { _ref = title.detail, title = _ref.title, open = _ref.open; } @@ -9276,6 +9619,7 @@ }, openSection: function() { var section, selected; + if (selected = $('.tab-selected', Settings.dialog)) { $.rmClass(selected, 'tab-selected'); } @@ -9289,6 +9633,7 @@ }, main: function(section) { var arr, button, description, div, fs, hiddenNum, input, inputs, items, key, obj, _ref; + items = {}; inputs = {}; _ref = Config.main; @@ -9313,6 +9658,7 @@ } $.get(items, function(items) { var val; + for (key in items) { val = items[key]; inputs[key].checked = val; @@ -9327,6 +9673,7 @@ boards: {} }, function(item) { var ID, board, thread, _ref1; + _ref1 = item.hiddenThreads.boards; for (ID in _ref1) { board = _ref1[ID]; @@ -9341,6 +9688,7 @@ boards: {} }, function(item) { var ID, board, post, thread, _ref1; + _ref1 = item.hiddenPosts.boards; for (ID in _ref1) { board = _ref1[ID]; @@ -9360,6 +9708,7 @@ boards: {} }, function(item) { var boardID; + for (boardID in item.hiddenThreads.boards) { localStorage.removeItem("4chan-hide-t-" + boardID); } @@ -9370,6 +9719,7 @@ }, "export": function(now, data) { var a, db, p, _i, _len; + if (typeof now !== 'number') { now = Date.now(); data = { @@ -9406,6 +9756,7 @@ }, onImport: function() { var file, output, reader; + if (!(file = this.files[0])) { return; } @@ -9417,6 +9768,7 @@ reader = new FileReader(); reader.onload = function(e) { var data, err; + try { data = JSON.parse(e.target.result); Settings.loadSettings(data); @@ -9433,6 +9785,7 @@ }, loadSettings: function(data) { var key, val, version, _ref; + version = data.version.split('.'); if (version[0] === '2') { data = Settings.convertSettings(data, { @@ -9522,6 +9875,7 @@ }, convertSettings: function(data, map) { var newKey, prevKey; + for (prevKey in map) { newKey = map[prevKey]; if (newKey) { @@ -9533,6 +9887,7 @@ }, filter: function(section) { var select; + section.innerHTML = "
"; select = $('select', section); $.on(select, 'change', Settings.selectFilter); @@ -9540,6 +9895,7 @@ }, selectFilter: function() { var div, name, ta; + div = this.nextElementSibling; if ((name = this.value) !== 'guide') { $.rmAll(div); @@ -9559,6 +9915,7 @@ }, sauce: function(section) { var ta; + section.innerHTML = "
Sauce is disabled.
Lines starting with a # will be ignored.
You can specify a display text by appending ;text:[text] to the URL.
    These parameters will be replaced by their corresponding values:\n
  • %TURL: Thumbnail URL.
  • %URL: Full image URL.
  • %MD5: MD5 hash.
  • %board: Current board.
"; ta = $('textarea', section); $.get('sauces', Conf['sauces'], function(item) { @@ -9568,6 +9925,7 @@ }, advanced: function(section) { var archive, boardID, boardOptions, boardSelect, boards, data, event, input, inputs, item, items, name, row, rows, ta, table, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _ref4; + section.innerHTML = "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Disabled selections indicate that only one archive is available for that board and redirection type.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
Board link: g
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:\"Install Gentoo\"
Index-only link: g-index
Catalog-only link: g-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: g-index-text:\"Technology Index\"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Time Formatting is disabled.
:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

    You can use these settings with each item, separate them with semicolons:\n
  • Possible items are: name, email, subject and password.
  • Wrap values of items with quotes, like this: email:\"sage\".
  • Force values as defaults with the always keyword, for example: email:\"sage\";always.
  • Select specific boards for an item, separated with commas, for example: email:\"sage\";boards:jp;always.
Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; items = {}; inputs = {}; @@ -9587,6 +9945,7 @@ $.on(ta, 'change', $.cb.value); $.get(items, function(items) { var key, val; + for (key in items) { val = items[key]; if (['emojiPos'].contains(key)) { @@ -9657,6 +10016,7 @@ }); $.get('selectedArchives', Conf['selectedArchives'], function(_arg) { var option, selectedArchives, type; + selectedArchives = _arg.selectedArchives; for (boardID in selectedArchives) { data = selectedArchives[boardID]; @@ -9671,6 +10031,7 @@ }, addArchiveCell: function(boardID, data, type) { var archive, i, length, options, select, td; + length = data[type].length; td = $.el('td', { className: 'archive-cell' @@ -9700,8 +10061,10 @@ }, saveSelectedArchive: function() { var _this = this; + return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) { var selectedArchives, _name; + selectedArchives = _arg.selectedArchives; (selectedArchives[_name = _this.dataset.boardid] || (selectedArchives[_name] = {}))[_this.dataset.type] = _this.value; return $.set('selectedArchives', selectedArchives); @@ -9712,6 +10075,7 @@ }, time: function() { var funk; + funk = Time.createFunc(this.value); return this.nextElementSibling.textContent = funk(Time, new Date()); }, @@ -9720,6 +10084,7 @@ }, fileInfo: function() { var data, funk; + data = { isReply: true, file: { @@ -9758,6 +10123,7 @@ }, keybinds: function(section) { var arr, input, inputs, items, key, tbody, tr, _ref; + section.innerHTML = "
Keybinds are disabled.
Allowed keys: a-z, 0-9, Ctrl, Shift, Alt, Meta, Enter, Esc, Up, Down, Right, Left.
Press Backspace to disable a keybind.
ActionsKeybinds
"; tbody = $('tbody', section); items = {}; @@ -9778,6 +10144,7 @@ } return $.get(items, function(items) { var val; + for (key in items) { val = items[key]; inputs[key].value = val; @@ -9786,6 +10153,7 @@ }, keybind: function(e) { var key; + if (e.keyCode === 9) { return; } @@ -9802,8 +10170,10 @@ Main = { init: function(items) { var db, flatten, _i, _len; + flatten = function(parent, obj) { var key, val; + if (obj instanceof Array) { Conf[parent] = obj[0]; } else if (typeof obj === 'object') { @@ -9827,11 +10197,13 @@ $.on(d, '4chanMainInit', Main.initStyle); return $.asap((function() { var _ref; + return d.head && $('link[rel="shortcut icon"]', d.head) || ((_ref = d.readyState) === 'interactive' || _ref === 'complete'); }), Main.initStyle); }, initFeatures: function(items) { var init, pathname, _ref; + Conf = items; pathname = location.pathname.split('/'); g.BOARD = new Board(pathname[1]); @@ -9860,6 +10232,7 @@ case 'images.4chan.org': $.ready(function() { var URL; + if (Conf['404 Redirect'] && d.title === '4chan - 404 Not Found') { Redirect.init(); pathname = location.pathname.split('/'); @@ -9876,6 +10249,7 @@ } init = function(features) { var err, module, name; + for (name in features) { module = features[name]; try { @@ -9951,6 +10325,7 @@ }, initStyle: function() { var mainStyleSheet, observer, setStyle, style, styleSheets, _ref; + $.off(d, '4chanMainInit', Main.initStyle); if (!Main.isThisPageLegit() || $.hasClass(doc, 'fourchan-x')) { return; @@ -9971,6 +10346,7 @@ styleSheets = $$('link[rel="alternate stylesheet"]', d.head); setStyle = function() { var styleSheet, _i, _len; + $.rmClass(doc, style); for (_i = 0, _len = styleSheets.length; _i < _len; _i++) { styleSheet = styleSheets[_i]; @@ -9997,6 +10373,7 @@ }, initReady: function() { var board, boardChild, err, errors, href, passLink, posts, styleSelector, thread, threadChild, threads, _i, _j, _len, _len1, _ref, _ref1; + if (d.title === '4chan - 404 Not Found') { if (Conf['404 Redirect'] && g.VIEW === 'thread') { href = Redirect.to('thread', { @@ -10073,6 +10450,7 @@ }, callbackNodes: function(klass, nodes) { var callback, err, errors, i, len, node, _i, _len, _ref; + len = nodes.length; _ref = klass.prototype.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -10100,9 +10478,11 @@ }, callbackNodesDB: function(klass, nodes, cb) { var errors, func, i, len, node, queue, softTask; + queue = []; softTask = function() { var args, func, task; + task = queue.shift(); func = task[0]; args = Array.prototype.slice.call(task, 1); @@ -10121,6 +10501,7 @@ errors = null; func = function(node, i) { var callback, err, _i, _len, _ref; + _ref = klass.prototype.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { callback = _ref[_i]; @@ -10154,6 +10535,7 @@ }, addCallback: function(e) { var Klass, obj; + obj = e.detail; if (typeof obj.callback.name !== 'string') { throw new Error("Invalid callback name: " + obj.callback.name); @@ -10173,6 +10555,7 @@ }, message: function(e) { var el, version; + version = e.data.version; if (version && version !== g.VERSION) { el = $.el('span', { @@ -10183,12 +10566,14 @@ }, checkUpdate: function() { var now; + if (!(Conf['Check for Updates'] && Main.isThisPageLegit())) { return; } now = Date.now(); return $.get('lastchecked', 0, function(_arg) { var lastchecked; + lastchecked = _arg.lastchecked; if (lastchecked > now - $.DAY) { return; @@ -10204,6 +10589,7 @@ }, handleErrors: function(errors) { var div, error, logs, _i, _len; + if (!(errors instanceof Array)) { error = errors; } else if (errors.length === 1) { @@ -10218,6 +10604,7 @@ }); $.on(div.lastElementChild, 'click', function() { var _ref; + return _ref = this.textContent === 'show' ? ['hide', false] : ['show', true], this.textContent = _ref[0], logs.hidden = _ref[1], _ref; }); logs = $.el('div', { @@ -10231,6 +10618,7 @@ }, parseError: function(data) { var error, message; + Main.logError(data); message = $.el('div', { textContent: data.message @@ -10247,6 +10635,7 @@ }, isThisPageLegit: function() { var _ref; + if (!('thisPageIsLegit' in Main)) { Main.thisPageIsLegit = location.hostname === 'boards.4chan.org' && !$('link[href*="favicon-status.ico"]', d.head) && ((_ref = d.title) !== '4chan - Temporarily Offline' && _ref !== '4chan - Error'); } diff --git a/builds/crx/script.js b/builds/crx/script.js index 8244e17f3..d994ff51c 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.2.24 - 2013-07-24 +* 4chan X - Version 1.2.24 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -139,7 +139,7 @@ 'Image Expansion': [true, 'Expand images.'], 'Image Hover': [true, 'Show full image on mouseover.'], 'Sauce': [true, 'Add sauce links to images.'], - 'Reveal Spoilers': [false, 'Reveal spoiler thumbnails.'], + 'Reveal Spoiler Thumbnails': [false, 'Replace spoiler thumbnails with the original image.'], 'Replace GIF': [false, 'Replace thumbnail of gifs with its actual image.'], 'Replace PNG': [false, 'Replace pngs.'], 'Replace JPG': [false, 'Replace jpgs.'], @@ -317,6 +317,7 @@ Array.prototype.add = function(object, position) { var keep; + keep = this.slice(position); this.length = position; this.push(object); @@ -329,6 +330,7 @@ Array.prototype.indexOf = function(object) { var i; + i = this.length; while (i--) { if (this[i] === object) { @@ -340,6 +342,7 @@ Array.prototype.pushArrays = function() { var arg, args, _i, _len; + args = arguments; for (_i = 0, _len = args.length; _i < _len; _i++) { arg = args[_i]; @@ -350,6 +353,7 @@ Array.prototype.remove = function(object) { var index; + if ((index = this.indexOf(object)) > -1) { return this.splice(index, 1); } else { @@ -366,6 +370,7 @@ $.extend = function(object, properties) { var key, val; + for (key in properties) { val = properties[key]; if (!properties.hasOwnProperty(key)) { @@ -383,6 +388,7 @@ $.ready = function(fc) { var cb, _ref; + if ((_ref = d.readyState) === 'interactive' || _ref === 'complete') { $.queueTask(fc); return; @@ -396,6 +402,7 @@ $.formData = function(form) { var fd, key, val; + if (form instanceof HTMLFormElement) { return new FormData(form); } @@ -416,6 +423,7 @@ $.ajax = function(url, callbacks, opts) { var cred, err, form, headers, key, r, sync, type, upCallbacks, val; + if (opts == null) { opts = {}; } @@ -441,9 +449,11 @@ $.cache = (function() { var reqs; + reqs = {}; return function(url, cb) { var err, req, rm; + if (req = reqs[url]) { if (req.readyState === 4) { cb.call(req, req.evt); @@ -459,6 +469,7 @@ req = $.ajax(url, { onload: function(e) { var _i, _len, _ref; + _ref = this.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { cb = _ref[_i]; @@ -500,6 +511,7 @@ $.addStyle = function(css, id) { var style; + style = $.el('style', { id: id, textContent: css @@ -546,6 +558,7 @@ } else { return function(el) { var _ref; + return (_ref = el.parentNode) != null ? _ref.removeChild(el) : void 0; }; } @@ -553,6 +566,7 @@ $.rmAll = function(root) { var node; + while (node = root.firstChild) { root.removeChild(node); } @@ -568,6 +582,7 @@ $.nodes = function(nodes) { var frag, node, _i, _len; + if (!(nodes instanceof Array)) { return nodes; } @@ -601,6 +616,7 @@ $.el = function(tag, properties) { var el; + el = d.createElement(tag); if (properties) { $.extend(el, properties); @@ -610,6 +626,7 @@ $.on = function(el, events, handler) { var event, _i, _len, _ref; + _ref = events.split(' '); for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; @@ -619,6 +636,7 @@ $.off = function(el, events, handler) { var event, _i, _len, _ref; + _ref = events.split(' '); for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; @@ -642,6 +660,7 @@ $.debounce = function(wait, fn) { var args, exec, lastCall, that, timeout; + lastCall = 0; timeout = null; that = null; @@ -663,9 +682,11 @@ $.queueTask = (function() { var execTask, taskChannel, taskQueue; + taskQueue = []; execTask = function() { var args, func, task; + task = taskQueue.shift(); func = task[0]; args = Array.prototype.slice.call(task, 1); @@ -688,6 +709,7 @@ $.globalEval = function(code) { var script; + script = $.el('script', { textContent: code }); @@ -697,6 +719,7 @@ $.bytesToString = function(size) { var unit; + unit = 0; while (size >= 1024) { size /= 1024; @@ -715,6 +738,7 @@ $.sync = (function() { chrome.storage.onChanged.addListener(function(changes) { var cb, key; + for (key in changes) { if (cb = $.syncing[key]) { cb(changes[key].newValue); @@ -728,6 +752,7 @@ $.item = function(key, val) { var item; + item = {}; item[key] = val; return item; @@ -741,6 +766,7 @@ $.get = function(key, val, cb) { var count, done, items, localItems, syncItems; + if (typeof cb === 'function') { items = $.item(key, val); } else { @@ -760,6 +786,7 @@ count = 0; done = function(item) { var lastError; + lastError = chrome.runtime.lastError; if (lastError) { c.error(lastError, lastError.message || 'No message.'); @@ -781,10 +808,12 @@ $.set = (function() { var items, localItems, set; + items = {}; localItems = {}; set = $.debounce($.SECOND, function() { var err, key, _i, _len, _ref; + _ref = $.localKeys; for (_i = 0, _len = _ref.length; _i < _len; _i++) { key = _ref[_i]; @@ -869,6 +898,7 @@ function Post(root, thread, board, that) { var alt, anchor, capcode, date, email, file, fileInfo, flag, info, name, post, size, subject, thumb, tripcode, uniqueID, unit; + this.thread = thread; this.board = board; if (that == null) { @@ -967,6 +997,7 @@ Post.prototype.parseComment = function() { var bq, data, i, node, nodes, text, _i, _len, _ref; + bq = this.nodes.comment.cloneNode(true); _ref = $$('.abbr, .capcodeReplies, .exif, b', bq); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -984,6 +1015,7 @@ Post.prototype.parseQuotes = function() { var hash, pathname, quotelink, quotes, _i, _len, _ref; + quotes = {}; _ref = $$('.quotelink', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1013,6 +1045,7 @@ Post.prototype.kill = function(file, now) { var clone, quotelink, strong, _i, _j, _len, _len1, _ref, _ref1; + now || (now = new Date()); if (file) { if (this.file.isDead) { @@ -1061,6 +1094,7 @@ Post.prototype.resurrect = function() { var clone, quotelink, strong, _i, _j, _len, _len1, _ref, _ref1; + delete this.isDead; delete this.timeOfDeath; $.rmClass(this.nodes.root, 'deleted-post'); @@ -1094,6 +1128,7 @@ Post.prototype.rmClone = function(index) { var clone, _i, _len, _ref; + this.clones.splice(index, 1); _ref = this.clones.slice(index); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1111,6 +1146,7 @@ function Clone(origin, context) { var file, index, info, inline, inlined, key, nodes, post, root, val, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; + this.origin = origin; this.context = context; _ref = ['ID', 'fullID', 'board', 'thread', 'info', 'quotes', 'isReply']; @@ -1199,6 +1235,7 @@ function DataBoard(key, sync) { var init, _this = this; + this.key = key; this.data = Conf[key]; $.sync(key, this.onSync.bind(this)); @@ -1215,6 +1252,7 @@ DataBoard.prototype["delete"] = function(_arg) { var boardID, postID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID; if (postID) { delete this.data.boards[boardID][threadID][postID]; @@ -1235,6 +1273,7 @@ DataBoard.prototype.deleteIfEmpty = function(_arg) { var boardID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID; if (threadID) { if (!Object.keys(this.data.boards[boardID][threadID]).length) { @@ -1250,6 +1289,7 @@ DataBoard.prototype.set = function(_arg) { var boardID, postID, threadID, val, _base, _base1, _base2; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID, val = _arg.val; if (postID !== void 0) { ((_base = ((_base1 = this.data.boards)[boardID] || (_base1[boardID] = {})))[threadID] || (_base[threadID] = {}))[postID] = val; @@ -1263,6 +1303,7 @@ DataBoard.prototype.get = function(_arg) { var ID, board, boardID, defaultValue, postID, thread, threadID, val, _i, _len; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID, defaultValue = _arg.defaultValue; if (board = this.data.boards[boardID]) { if (!threadID) { @@ -1286,6 +1327,7 @@ DataBoard.prototype.clean = function() { var boardID, now, val, _ref; + _ref = this.data.boards; for (boardID in _ref) { val = _ref[boardID]; @@ -1305,8 +1347,10 @@ DataBoard.prototype.ajaxClean = function(boardID) { var _this = this; + return $.cache("//api.4chan.org/" + boardID + "/threads.json", function(e) { var board, page, thread, threads, _i, _j, _len, _len1, _ref, _ref1; + if (e.target.status === 404) { _this["delete"](boardID); } else if (e.target.status === 200) { @@ -1417,6 +1461,7 @@ init: function() { var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler, linkJustifyToggler, _this = this; + this.menu = new UI.Menu('header'); this.menuButton = $.el('span', { className: 'menu-button', @@ -1500,6 +1545,7 @@ } $.asap((function() { var _ref; + return $.id('boardNavMobile') || ((_ref = d.readyState) === 'interactive' || _ref === 'complete'); }), Header.setBoardList); $.prepend(d.body, _this.bar); @@ -1508,6 +1554,7 @@ }); return $.ready(function() { var a, cs; + _this.footer = $.id('boardNavDesktopFoot'); if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) { a.className = 'current'; @@ -1541,6 +1588,7 @@ }), setBoardList: function() { var a, boardList, btn, fourchannav, fullBoardList; + fourchannav = $.id('boardNavDesktop'); if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) { a.className = 'current'; @@ -1562,6 +1610,7 @@ }, generateBoardList: function(text) { var as, list, nodes; + list = $('#custom-board-list', Header.bar); $.rmAll(list); if (!text) { @@ -1570,6 +1619,7 @@ as = $$('#full-board-list a', Header.bar); nodes = text.match(/[\w@]+((-(all|title|replace|full|index|catalog|url:"[^"]+[^"]"|text:"[^"]+")|\,"[^"]+[^"]"))*|[^\w@]+/g).map(function(t) { var a, board, m, _i, _len; + if (/^[^\w@]/.test(t)) { return $.tn(t); } @@ -1616,6 +1666,7 @@ }, toggleBoardList: function() { var bar, custom, full, showBoardList; + bar = Header.bar; custom = $('#custom-board-list', bar); full = $('#full-board-list', bar); @@ -1651,6 +1702,7 @@ }, toggleLinkJustify: function() { var centered; + $.event('CloseMenu'); centered = this.nodeName === 'INPUT' ? this.checked : void 0; Header.setLinkJustify(centered); @@ -1680,6 +1732,7 @@ }, toggleBarVisibility: function(e) { var hide, message; + if (e.type === 'mousedown' && e.button !== 0) { return; } @@ -1696,6 +1749,7 @@ }, toggleFooterVisibility: function() { var hide, message; + $.event('CloseMenu'); hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden; Header.setFooterVisibility(hide); @@ -1705,6 +1759,7 @@ }, setCustomNav: function(show) { var btn, cust, full, _ref; + Header.customNavToggler.checked = show; cust = $('#custom-board-list', Header.bar); full = $('#full-board-list', Header.bar); @@ -1717,12 +1772,14 @@ }, editCustomNav: function() { var settings; + Settings.open('Advanced'); settings = $.id('fourchanx-settings'); return $('input[name=boardnav]', settings).focus(); }, hashScroll: function() { var hash, post; + if (!((hash = this.location.hash.slice(1)) && (post = $.id(hash)))) { return; } @@ -1733,6 +1790,7 @@ }, scrollToPost: function(post) { var headRect, top; + top = post.getBoundingClientRect().top; if (Conf['Fixed Header'] && !Conf['Bottom Header']) { headRect = Header.bar.getBoundingClientRect(); @@ -1742,6 +1800,7 @@ }, addShortcut: function(el) { var shortcut; + shortcut = $.el('span', { className: 'shortcut fourchanx-link' }); @@ -1753,6 +1812,7 @@ }, createNotification: function(e) { var cb, content, lifetime, notif, type, _ref; + _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb; notif = new Notification(type, content, lifetime); if (cb) { @@ -1765,6 +1825,7 @@ spoilerRange: {}, shortFilename: function(filename, isReply) { var threshold; + threshold = isReply ? 30 : 40; if (filename.length - 4 > threshold) { return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3); @@ -1774,6 +1835,7 @@ }, postFromObject: function(data, boardID) { var o; + o = { postID: data.no, threadID: data.resto || data.no, @@ -1817,6 +1879,7 @@ */ var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref; + postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file; isOP = postID === threadID; staticPath = '//static.4chan.org/image/'; @@ -1912,6 +1975,7 @@ Get = { threadExcerpt: function(thread) { var OP, excerpt, _ref; + OP = thread.OP; excerpt = ((_ref = OP.info.subject) != null ? _ref.trim() : void 0) || OP.info.comment.replace(/\n+/g, ' // ') || Conf['Anonymize'] && 'Anonymous' || $('.nameBlock', OP.nodes.info).textContent.trim(); if (excerpt.length > 70) { @@ -1924,6 +1988,7 @@ }, postFromRoot: function(root) { var boardID, index, link, post, postID; + link = $('a[title="Highlight this post"]', root); boardID = link.pathname.split('/')[1]; postID = link.hash.slice(2); @@ -1943,6 +2008,7 @@ }, postDataFromLink: function(link) { var boardID, path, postID, threadID; + if (link.hostname === 'boards.4chan.org') { path = link.pathname.split('/'); boardID = path[1]; @@ -1961,6 +2027,7 @@ }, allQuotelinksLinkingTo: function(post) { var ID, quote, quotedPost, quotelinks, quoterPost, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; + quotelinks = []; _ref = g.posts; for (ID in _ref) { @@ -1989,12 +2056,14 @@ } return quotelinks.filter(function(quotelink) { var boardID, postID, _ref4; + _ref4 = Get.postDataFromLink(quotelink), boardID = _ref4.boardID, postID = _ref4.postID; return boardID === post.board.ID && postID === post.ID; }); }, postClone: function(boardID, threadID, postID, root, context) { var post, url; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2015,6 +2084,7 @@ }, insert: function(post, root, context) { var clone, nodes; + if (!root.parentNode) { return; } @@ -2028,6 +2098,7 @@ }, fetchedPost: function(req, boardID, threadID, postID, root, context) { var board, post, posts, status, thread, url, _i, _len; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2077,6 +2148,7 @@ }, archivedPost: function(req, boardID, postID, root, context) { var board, bq, comment, data, o, post, thread, threadID, _ref; + if (post = g.posts["" + boardID + "." + postID]) { Get.insert(post, root, context); return; @@ -2170,8 +2242,10 @@ UI = (function() { var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove; + dialog = function(id, position, html) { var child, el, move, _i, _len, _ref; + el = $.el('div', { className: 'dialog', innerHTML: html, @@ -2211,6 +2285,7 @@ Menu.prototype.makeMenu = function() { var menu; + menu = $.el('div', { className: 'dialog', id: 'menu', @@ -2225,6 +2300,7 @@ Menu.prototype.toggle = function(e, button, data) { var previousButton; + e.preventDefault(); e.stopPropagation(); if (currentMenu) { @@ -2242,6 +2318,7 @@ Menu.prototype.open = function(button, data) { var bLeft, bRect, bTop, bottom, cHeight, cWidth, entry, left, mRect, menu, right, style, top, _i, _len, _ref, _ref1, _ref2; + menu = this.makeMenu(); currentMenu = menu; lastToggledButton = button; @@ -2280,6 +2357,7 @@ Menu.prototype.insertEntry = function(entry, parent, data) { var subEntry, submenu, _i, _len, _ref; + if (typeof entry.open === 'function') { if (!entry.open(data)) { return; @@ -2313,6 +2391,7 @@ Menu.prototype.findNextEntry = function(entry, direction) { var entries; + entries = __slice.call(entry.parentNode.children); entries.sort(function(first, second) { return +(first.style.order || first.style.webkitOrder) - +(second.style.order || second.style.webkitOrder); @@ -2322,6 +2401,7 @@ Menu.prototype.keybinds = function(e) { var entry, next, nextPrev, subEntry, submenu; + entry = $('.focused', currentMenu); while (subEntry = $('.focused', entry)) { entry = subEntry; @@ -2367,6 +2447,7 @@ Menu.prototype.focus = function(entry) { var bottom, cHeight, cWidth, eRect, focused, left, right, sRect, style, submenu, top, _i, _len, _ref, _ref1, _ref2; + while (focused = $.x('parent::*/child::*[contains(@class,"focused")]', entry)) { $.rmClass(focused, 'focused'); } @@ -2394,6 +2475,7 @@ Menu.prototype.addEntry = function(e) { var entry; + entry = e.detail; if (entry.type !== this.type) { return; @@ -2404,6 +2486,7 @@ Menu.prototype.parseEntry = function(entry) { var el, style, subEntries, subEntry, _i, _len; + el = entry.el, subEntries = entry.subEntries; $.addClass(el, 'entry'); $.on(el, 'focus mouseover', (function(e) { @@ -2427,6 +2510,7 @@ })(); dragstart = function(e) { var el, isTouching, o, rect, screenHeight, screenWidth, _ref; + if (e.type === 'mousedown' && e.button !== 0) { return; } @@ -2465,6 +2549,7 @@ }; touchmove = function(e) { var touch, _i, _len, _ref; + _ref = e.changedTouches; for (_i = 0, _len = _ref.length; _i < _len; _i++) { touch = _ref[_i]; @@ -2476,6 +2561,7 @@ }; drag = function(e) { var bottom, clientX, clientY, left, right, style, top; + clientX = e.clientX, clientY = e.clientY; left = clientX - this.dx; left = left < 10 ? 0 : this.width - left < 10 ? null : left / this.screenWidth * 100 + '%'; @@ -2491,6 +2577,7 @@ }; touchend = function(e) { var touch, _i, _len, _ref; + _ref = e.changedTouches; for (_i = 0, _len = _ref.length; _i < _len; _i++) { touch = _ref[_i]; @@ -2512,6 +2599,7 @@ }; hoverstart = function(_arg) { var asapTest, cb, el, endEvents, latestEvent, o, root; + root = _arg.root, el = _arg.el, latestEvent = _arg.latestEvent, endEvents = _arg.endEvents, asapTest = _arg.asapTest, cb = _arg.cb; o = { root: root, @@ -2540,6 +2628,7 @@ }; hover = function(e) { var clientX, clientY, height, left, right, style, top, _ref; + this.latestEvent = e; height = this.el.offsetHeight; clientX = e.clientX, clientY = e.clientY; @@ -2582,6 +2671,7 @@ }, node: function() { var email, name, tripcode, _ref; + if (this.info.capcode || this.isClone) { return; } @@ -2608,6 +2698,7 @@ filters: {}, init: function() { var boards, err, filter, hl, key, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4; + if (g.VIEW === 'catalog' || !Conf['Filter']) { return; } @@ -2644,6 +2735,7 @@ op = ((_ref2 = filter.match(/[^t]op:(yes|no|only)/)) != null ? _ref2[1] : void 0) || 'yes'; stub = (function() { var _ref3; + switch ((_ref3 = filter.match(/stub:(yes|no)/)) != null ? _ref3[1] : void 0) { case 'yes': return true; @@ -2674,6 +2766,7 @@ }, createFilter: function(regexp, op, stub, hl, top) { var settings, test; + test = typeof regexp === 'string' ? function(value) { return regexp === value; } : function(value) { @@ -2697,6 +2790,7 @@ }, node: function() { var filter, firstThread, key, result, thisThread, value, _i, _len, _ref; + if (this.isClone) { return; } @@ -2808,6 +2902,7 @@ menu: { init: function() { var div, entry, type, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Filter']) { return; } @@ -2833,6 +2928,7 @@ }, createSubEntry: function(text, type) { var el; + el = $.el('a', { href: 'javascript:;', textContent: text @@ -2843,6 +2939,7 @@ el: el, open: function(post) { var value; + value = Filter[type](post); return value !== false; } @@ -2850,6 +2947,7 @@ }, makeFilter: function() { var re, type, value; + type = this.dataset.type; value = Filter[type](Filter.menu.post); re = ['uniqueID', 'MD5'].contains(type) ? value : value.replace(/\/|\\|\^|\$|\n|\.|\(|\)|\{|\}|\[|\]|\?|\*|\+|\|/g, function(c) { @@ -2864,6 +2962,7 @@ re = ['uniqueID', 'MD5'].contains(type) ? "/" + re + "/" : "/^" + re + "$/"; return $.get(type, Conf[type], function(item) { var save, section, select, ta, tl; + save = item[type]; save = save ? "" + save + "\n" + re : re; $.set(type, save); @@ -2897,6 +2996,7 @@ }, node: function() { var data; + if (!this.isReply || this.isClone) { return; } @@ -2920,6 +3020,7 @@ menu: { init: function() { var apply, div, hideStubLink, makeStub, replies, thisPost; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Reply Hiding Link']) { return; } @@ -2990,6 +3091,7 @@ order: 20, open: function(post) { var data; + if (!post.isReply || post.isClone || !post.isHidden) { return false; } @@ -3021,6 +3123,7 @@ order: 15, open: function(post) { var data; + if (!post.isReply || post.isClone || !post.isHidden) { return false; } @@ -3037,6 +3140,7 @@ }, hide: function() { var makeStub, parent, post, replies, thisPost; + parent = this.parentNode; thisPost = $('input[name=thisPost]', parent).checked; replies = $('input[name=replies]', parent).checked; @@ -3055,6 +3159,7 @@ }, show: function() { var data, parent, post, replies, thisPost; + parent = this.parentNode; thisPost = $('input[name=thisPost]', parent).checked; replies = $('input[name=replies]', parent).checked; @@ -3078,6 +3183,7 @@ }, hideStub: function() { var post; + post = PostHiding.menu.post; post.nodes.root.hidden = true; $.event('CloseMenu'); @@ -3085,6 +3191,7 @@ }, makeButton: function(post, type) { var a; + a = $.el('a', { className: "" + type + "-reply-button", innerHTML: " " + (type === 'hide' ? '-' : '+') + " ", @@ -3095,6 +3202,7 @@ }, saveHiddenState: function(post, isHiding, thisPost, makeStub, hideRecursively) { var data; + data = { boardID: post.board.ID, threadID: post.thread.ID, @@ -3113,6 +3221,7 @@ }, toggle: function() { var post; + post = Get.postFromNode(this); if (post.isHidden) { PostHiding.show(post); @@ -3123,6 +3232,7 @@ }, hide: function(post, makeStub, hideRecursively) { var a, postInfo, quotelink, _i, _len, _ref; + if (makeStub == null) { makeStub = Conf['Stubs']; } @@ -3160,6 +3270,7 @@ }, show: function(post, showRecursively) { var quotelink, _i, _len, _ref; + if (showRecursively == null) { showRecursively = Conf['Recursive Hiding']; } @@ -3195,6 +3306,7 @@ }, node: function() { var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1; + if (this.isClone) { return; } @@ -3212,6 +3324,7 @@ }, add: function() { var args, obj, post, recursive, _base, _name; + recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = { recursives: [], @@ -3222,6 +3335,7 @@ }, rm: function(recursive, post) { var i, obj, rec, _i, _len, _ref; + if (!(obj = Recursive.recursives[post.fullID])) { return; } @@ -3236,6 +3350,7 @@ }, apply: function() { var ID, args, fullID, post, recursive, _ref; + recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; fullID = post.fullID; _ref = g.posts; @@ -3262,6 +3377,7 @@ }, node: function() { var data; + if (data = ThreadHiding.db.get({ boardID: this.board.ID, threadID: this.ID @@ -3275,6 +3391,7 @@ }, syncCatalog: function() { var hiddenThreads, hiddenThreadsOnCatalog, threadID; + hiddenThreads = ThreadHiding.db.get({ boardID: g.BOARD.ID, defaultValue: {} @@ -3301,6 +3418,7 @@ cleanCatalog: function(hiddenThreadsOnCatalog) { return $.cache("//api.4chan.org/" + g.BOARD + "/threads.json", function() { var page, thread, threads, _i, _j, _len, _len1, _ref, _ref1; + if (this.status !== 200) { return; } @@ -3326,6 +3444,7 @@ menu: { init: function() { var apply, div, hideStubLink, makeStub; + if (g.VIEW !== 'index' || !Conf['Menu'] || !Conf['Thread Hiding Link']) { return; } @@ -3352,6 +3471,7 @@ order: 20, open: function(_arg) { var isReply, thread; + thread = _arg.thread, isReply = _arg.isReply; if (isReply || thread.isHidden) { return false; @@ -3373,6 +3493,7 @@ order: 15, open: function(_arg) { var isReply, thread; + thread = _arg.thread, isReply = _arg.isReply; if (isReply || !thread.isHidden) { return false; @@ -3383,6 +3504,7 @@ }, hide: function() { var makeStub, thread; + makeStub = $('input', this.parentNode).checked; thread = ThreadHiding.menu.thread; ThreadHiding.hide(thread, makeStub); @@ -3391,6 +3513,7 @@ }, hideStub: function() { var thread; + thread = ThreadHiding.menu.thread; ThreadHiding.hide(thread, false); $.event('CloseMenu'); @@ -3398,6 +3521,7 @@ }, makeButton: function(thread, type) { var a; + a = $.el('a', { className: "" + type + "-thread-button", innerHTML: " " + (type === 'hide' ? '-' : '+') + " ", @@ -3409,6 +3533,7 @@ }, saveHiddenState: function(thread, makeStub) { var hiddenThreadsOnCatalog; + hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {}; if (thread.isHidden) { ThreadHiding.db.set({ @@ -3441,6 +3566,7 @@ }, hide: function(thread, makeStub) { var OP, a, numReplies, opInfo, span, threadRoot; + if (makeStub == null) { makeStub = Conf['Stubs']; } @@ -3471,6 +3597,7 @@ }, show: function(thread) { var threadRoot; + if (thread.stub) { $.rm(thread.stub); delete thread.stub; @@ -3483,6 +3610,7 @@ QuoteBacklink = { init: function() { var format; + if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) { return; } @@ -3500,6 +3628,7 @@ }, firstNode: function() { var a, clone, container, containers, frag, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + if (this.isClone || !this.quotes.length) { return; } @@ -3537,6 +3666,7 @@ }, secondNode: function() { var container; + if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) { this.nodes.backlinkContainer = $('.container', this.nodes.info); return; @@ -3550,6 +3680,7 @@ }, getContainer: function(id) { var _base; + return (_base = this.containers)[id] || (_base[id] = $.el('span', { className: 'container' })); @@ -3572,6 +3703,7 @@ }, node: function() { var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1; + if (this.isClone && this.thread === this.context.thread) { return; } @@ -3607,6 +3739,7 @@ if (Conf['Quote Hash Navigation']) { this.node = function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3619,6 +3752,7 @@ } else { this.node = function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3642,6 +3776,7 @@ }, toggle: function(e) { var boardID, context, postID, threadID, _ref; + if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) { return; } @@ -3667,6 +3802,7 @@ }, add: function(quotelink, boardID, threadID, postID, context) { var inline, isBacklink, post, qroot, root; + isBacklink = $.hasClass(quotelink, 'backlink'); inline = $.el('div', { id: "i" + postID, @@ -3691,6 +3827,7 @@ }, rm: function(quotelink, boardID, threadID, postID, context) { var el, inlined, isBacklink, post, qroot, root, _ref; + isBacklink = $.hasClass(quotelink, 'backlink'); root = QuoteInline.findRoot(quotelink, isBacklink); root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root); @@ -3732,6 +3869,7 @@ }, node: function() { var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref; + if (this.isClone && this.thread === this.context.thread) { return; } @@ -3774,6 +3912,7 @@ }, node: function() { var link, _i, _len, _ref; + _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks)); for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; @@ -3782,6 +3921,7 @@ }, mouseover: function(e) { var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1; + if ($.hasClass(this, 'inlined')) { return; } @@ -3825,6 +3965,7 @@ }, mouseout: function() { var clone, post, root, _i, _len, _ref; + if (!(root = this.el.firstElementChild)) { return; } @@ -3854,6 +3995,7 @@ }, node: function() { var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2; + if (this.isClone) { return; } @@ -3876,6 +4018,7 @@ QuoteThreading = { init: function() { var input; + if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) { return; } @@ -3898,6 +4041,7 @@ }, setup: function() { var ID, post, posts; + $.off(d, '4chanXInitFinished', QuoteThreading.setup); posts = g.posts; for (ID in posts) { @@ -3910,6 +4054,7 @@ }, node: function() { var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len; + if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) { return; } @@ -3939,6 +4084,7 @@ }, nodeinsert: function() { var bottom, height, posts, qpost, qroot, threadContainer, top, _ref; + posts = g.posts; qpost = posts[this.threaded]; delete this.threaded; @@ -3968,12 +4114,14 @@ }, toggle: function() { var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1; + thread = $('.thread'); replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread); QuoteThreading.enabled = this.checked; if (this.checked) { nodes = (function() { var _i, _len, _results; + _results = []; for (_i = 0, _len = replies.length; _i < _len; _i++) { reply = replies[_i]; @@ -3988,6 +4136,7 @@ } else { replies.sort(function(a, b) { var aID, bID; + aID = Number(a.id.slice(2)); bID = Number(b.id.slice(2)); return aID - bID; @@ -4003,6 +4152,7 @@ }, kb: function() { var control; + control = $.id('threadingControl'); return control.click(); } @@ -4029,6 +4179,7 @@ }, node: function() { var quotelink, _i, _len, _ref; + if (this.isClone) { return; } @@ -4064,6 +4215,7 @@ }, node: function() { var deadlink, _i, _len, _ref; + _ref = $$('.deadlink', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { deadlink = _ref[_i]; @@ -4078,6 +4230,7 @@ }, parseDeadlink: function(deadlink) { var a, boardID, m, post, postID, quote, quoteID, redirect, _ref; + if (deadlink.parentNode.className === 'prettyprint') { $.replace(deadlink, __slice.call(deadlink.childNodes)); return; @@ -4157,6 +4310,7 @@ cypher: $.el('div'), node: function() { var a, child, cypher, cypherText, data, embed, embedder, embeds, i, index, len, link, links, lookahead, name, next, node, nodes, snapshot, spoiler, text, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2; + if (this.isClone && Conf['Embedding']) { _ref = $$('.embedder', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -4241,6 +4395,7 @@ }, toggle: function() { var el, embed, style, type, url; + embed = this.previousElementSibling; if (this.className.contains("embedded")) { el = $.el('a', { @@ -4334,6 +4489,7 @@ style: 'height: auto; width: 500px; display: inline-block;', el: function() { var div; + div = $.el('div', { className: "soundcloud", name: "soundcloud" @@ -4359,6 +4515,7 @@ regExp: /.*(?:pastebin.com\/(?!u\/))([^#\&\?]*).*/, el: function() { var div; + return div = $.el('iframe', { src: "http://pastebin.com/embed_iframe.php?i=" + this.name }); @@ -4368,6 +4525,7 @@ regExp: /.*(?:gist.github.com.*\/)([^\/][^\/]*)$/, el: function() { var div; + return div = $.el('iframe', { src: "http://www.purplegene.com/script?url=https://gist.github.com/" + this.name + ".js" }); @@ -4378,6 +4536,7 @@ }, text: function() { var file, response; + response = JSON.parse(this.responseText).files; for (file in response) { if (response.hasOwnProperty(file)) { @@ -4398,12 +4557,14 @@ }, embedder: function(a) { var callbacks, embed, key, match, service, titles, type, _ref; + if (!Conf['Link Title']) { return [a]; } titles = {}; callbacks = function() { var title; + return a.textContent = (function() { switch (this.status) { case 200: @@ -4445,6 +4606,7 @@ if (Conf['Link Title'] && (service = type.title)) { $.get('CachedTitles', {}, function(item) { var err, title; + titles = item['CachedTitles']; if (title = titles[match[1]]) { a.textContent = title[0]; @@ -4468,6 +4630,7 @@ QR = { init: function() { var sc; + if (!Conf['Quick Reply']) { return; } @@ -4514,6 +4677,7 @@ }, initReady: function() { var link; + QR.postingIsEnabled = !!$.id('postForm'); if (!QR.postingIsEnabled) { return; @@ -4533,11 +4697,13 @@ $.before($.id('postForm'), link); $.on(d, 'QRGetSelectedPost', function(_arg) { var cb; + cb = _arg.detail; return cb(QR.selected); }); $.on(d, 'QRAddPreSubmitHook', function(_arg) { var cb; + cb = _arg.detail; return QR.preSubmitHooks.push(cb); }); @@ -4567,6 +4733,7 @@ }, open: function() { var err; + if (QR.nodes) { QR.nodes.el.hidden = false; QR.unhide(); @@ -4585,6 +4752,7 @@ }, close: function() { var i, _i, _len, _ref; + if (QR.req) { QR.abort(); return; @@ -4631,6 +4799,7 @@ }, error: function(err) { var el; + QR.open(); if (typeof err === 'string') { el = $.tn(err); @@ -4658,6 +4827,7 @@ notifications: [], cleanNotifications: function() { var notification, _i, _len, _ref; + _ref = QR.notifications; for (_i = 0, _len = _ref.length; _i < _len; _i++) { notification = _ref[_i]; @@ -4667,6 +4837,7 @@ }, status: function() { var disabled, status, value; + if (!QR.nodes) { return; } @@ -4687,6 +4858,7 @@ QR.persona.getPassword(); return $.get('QR.personas', Conf['QR.personas'], function(_arg) { var arr, item, personas, type, types, _i, _len, _ref; + personas = _arg['QR.personas']; types = { name: [], @@ -4706,6 +4878,7 @@ }, parseItem: function(item, types) { var boards, match, type, val, _ref, _ref1; + if (item[0] === '#') { return; } @@ -4734,6 +4907,7 @@ }, loadPersonas: function(type, arr) { var list, val, _i, _len; + list = $("#list-" + type, QR.nodes.el); for (_i = 0, _len = arr.length; _i < _len; _i++) { val = arr[_i]; @@ -4747,6 +4921,7 @@ }, getPassword: function() { var input, m; + if (!QR.persona.pwd) { QR.persona.pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : (input = $.id('postPassword')) ? input.value : $.id('delPassword').value; } @@ -4755,6 +4930,7 @@ get: function(cb) { return $.get('QR.persona', {}, function(_arg) { var persona; + persona = _arg['QR.persona']; return cb(persona); }); @@ -4762,6 +4938,7 @@ set: function(post) { return $.get('QR.persona', {}, function(_arg) { var persona; + persona = _arg['QR.persona']; persona = { name: post.name, @@ -4775,6 +4952,7 @@ cooldown: { init: function() { var board; + if (!Conf['Cooldown']) { return; } @@ -4816,6 +4994,7 @@ }, sync: function(cooldowns) { var id; + for (id in cooldowns) { QR.cooldown.cooldowns[id] = cooldowns[id]; } @@ -4823,6 +5002,7 @@ }, set: function(data) { var cooldown, delay, hasFile, isReply, isSage, post, req, start, type, upSpd; + if (!Conf['Cooldown']) { return; } @@ -4862,6 +5042,7 @@ }, count: function() { var cooldown, cooldowns, elapsed, hasFile, isReply, isSage, now, post, seconds, start, type, types, upSpd, upSpdAccuracy, update, _ref; + if (!Object.keys(QR.cooldown.cooldowns).length) { $["delete"]("" + g.BOARD + ".cooldown"); delete QR.cooldown.isCounting; @@ -4915,6 +5096,7 @@ }, quote: function(e) { var OP, caretPos, com, index, post, range, s, sel, selectionRoot, text, thread, _ref; + if (e != null) { e.preventDefault(); } @@ -4954,6 +5136,7 @@ }, characterCount: function() { var count, counter; + counter = QR.nodes.charCount; count = QR.nodes.com.textLength; counter.textContent = count; @@ -4962,6 +5145,7 @@ }, drag: function(e) { var toggle; + toggle = e.type === 'dragstart' ? $.off : $.on; toggle(d, 'dragover', QR.dragOver); return toggle(d, 'drop', QR.dropFile); @@ -4981,6 +5165,7 @@ }, paste: function(e) { var blob, files, item, _i, _len, _ref; + files = []; _ref = e.clipboardData.items; for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -5008,6 +5193,7 @@ }, fileInput: function(files) { var file, length, max, post, _i, _len; + if (this instanceof Element) { files = __slice.call(this.files); QR.nodes.fileInput.value = null; @@ -5056,6 +5242,7 @@ function _Class(select) { var el, event, prev, _i, _len, _ref, _this = this; + el = $.el('a', { className: 'qr-preview', draggable: true, @@ -5109,6 +5296,7 @@ _Class.prototype.rm = function() { var index; + $.rm(this.nodes.el); index = QR.posts.indexOf(this); if (QR.posts.length === 1) { @@ -5126,6 +5314,7 @@ _Class.prototype.lock = function(lock) { var name, _i, _len, _ref; + if (lock == null) { lock = true; } @@ -5150,6 +5339,7 @@ _Class.prototype.select = function() { var rectEl, rectList; + if (QR.selected) { QR.selected.nodes.el.id = null; QR.selected.forceSave(); @@ -5166,6 +5356,7 @@ _Class.prototype.load = function() { var name, _i, _len, _ref; + _ref = ['thread', 'name', 'email', 'sub', 'com']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { name = _ref[_i]; @@ -5177,6 +5368,7 @@ _Class.prototype.save = function(input) { var value, _ref; + if (input.type === 'checkbox') { this.spoiler = input.checked; return; @@ -5195,6 +5387,7 @@ _Class.prototype.forceSave = function() { var name, _i, _len, _ref; + if (this !== QR.selected) { return; } @@ -5226,6 +5419,7 @@ _Class.prototype.setThumbnail = function(fileURL) { var img, reader, _this = this; + if (!window.URL) { if (!fileURL) { reader = new FileReader(); @@ -5241,6 +5435,7 @@ img = $.el('img'); img.onload = function() { var applyBlob, cv, data, height, i, l, s, ui8a, width, _i; + s = 90 * 2; if (_this.file.type === 'image/gif') { s *= 3; @@ -5320,9 +5515,11 @@ _Class.prototype.pasteText = function(file) { var reader, _this = this; + reader = new FileReader(); reader.onload = function(e) { var text; + text = e.target.result; if (_this.com) { _this.com += "\n" + text; @@ -5360,6 +5557,7 @@ _Class.prototype.drop = function() { var el, index, newIndex, oldIndex, post; + el = $('.drag', this.parentNode); $.rmClass(el, 'drag'); $.rmClass(this, 'over'); @@ -5394,6 +5592,7 @@ ready: function() { var imgContainer, input, observer, setLifetime, _this = this; + setLifetime = function(e) { return _this.lifetime = e.detail; }; @@ -5435,6 +5634,7 @@ }); $.get('captchas', [], function(_arg) { var captchas; + captchas = _arg.captchas; return _this.sync(captchas); }); @@ -5449,6 +5649,7 @@ }, getOne: function() { var captcha, challenge, response; + this.clear(); if (captcha = this.captchas.shift()) { challenge = captcha.challenge, response = captcha.response; @@ -5473,6 +5674,7 @@ }, save: function() { var response; + if (!(response = this.nodes.input.value.trim())) { return; } @@ -5487,6 +5689,7 @@ }, clear: function() { var captcha, i, now, _i, _len, _ref; + now = Date.now(); _ref = this.captchas; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { @@ -5504,6 +5707,7 @@ }, load: function() { var challenge; + if (!this.nodes.challenge.firstChild) { return; } @@ -5516,6 +5720,7 @@ }, count: function() { var count; + count = this.captchas.length; this.nodes.input.placeholder = (function() { switch (count) { @@ -5548,6 +5753,7 @@ }, dialog: function() { var dialog, mimeTypes, name, nodes, thread, _i, _len, _ref; + dialog = UI.dialog('qr', 'top:0;right:0;', "
×
No selected file×+
"); QR.nodes = nodes = { el: dialog, @@ -5650,6 +5856,7 @@ preSubmitHooks: [], submit: function(e) { var callbacks, challenge, err, filetag, hook, opts, post, postData, response, textOnly, thread, threadID, _i, _len, _ref, _ref1; + if (e != null) { e.preventDefault(); } @@ -5762,6 +5969,7 @@ }, response: function() { var URL, ban, board, err, h1, isReply, m, post, postID, req, threadID, tmpDoc, _, _ref, _ref1; + req = QR.req; delete QR.req; post = QR.posts[0]; @@ -5864,6 +6072,7 @@ FappeTyme = { init: function() { var el, input; + if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } @@ -5915,6 +6124,7 @@ }, node: function() { var thumb, _ref; + if (!((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -5939,6 +6149,7 @@ }, toggleAll: function() { var ID, file, func, post, _i, _len, _ref, _ref1; + $.event('CloseMenu'); if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) { ImageExpand.EAI.className = 'contract-all-shortcut'; @@ -5972,6 +6183,7 @@ }, toggle: function(post) { var headRect, node, rect, root, thumb, top; + thumb = post.file.thumb; if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) { ImageExpand.expand(post); @@ -6016,6 +6228,7 @@ }, expand: function(post, src) { var img, thumb; + thumb = post.file.thumb; if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) { return; @@ -6043,6 +6256,7 @@ }, completeExpand: function(post) { var prev, thumb; + thumb = post.file.thumb; if (!$.hasClass(thumb, 'expanding')) { return; @@ -6056,6 +6270,7 @@ prev = post.nodes.root.getBoundingClientRect(); return $.queueTask(function() { var curr, root; + $.addClass(post.nodes.root, 'expanded-image'); $.rmClass(post.file.thumb, 'expanding'); if (!(prev.top + prev.height <= 0)) { @@ -6068,6 +6283,7 @@ }, error: function() { var URL, post, src, timeoutID; + post = Get.postFromNode(this); $.rm(this); delete post.file.fullImage; @@ -6093,6 +6309,7 @@ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", { onload: function() { var postObj, _i, _len, _ref; + if (this.status !== 200) { return; } @@ -6116,6 +6333,7 @@ menu: { init: function() { var conf, createSubEntry, el, key, subEntries, _ref; + if (g.VIEW === 'catalog' || !Conf['Image Expansion']) { return; } @@ -6139,6 +6357,7 @@ }, createSubEntry: function(type, config) { var input, label; + label = $.el('label', { innerHTML: " " + type }); @@ -6174,6 +6393,7 @@ }, node: function() { var _ref; + if (!((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -6181,6 +6401,7 @@ }, mouseover: function(e) { var el, post; + post = Get.postFromNode(this); el = $.el('img', { id: 'ihover', @@ -6202,6 +6423,7 @@ error: function() { var URL, post, src, timeoutID, _this = this; + if (!doc.contains(this)) { return; } @@ -6226,6 +6448,7 @@ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", { onload: function() { var postObj, _i, _len, _ref; + if (this.status !== 200) { return; } @@ -6251,6 +6474,7 @@ ImageLoader = { init: function() { var prefetch; + if (g.VIEW === 'catalog') { return; } @@ -6277,6 +6501,7 @@ }, node: function() { var URL, img, string, style, thumb, type, _ref, _ref1; + if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) { return; } @@ -6298,6 +6523,7 @@ }, toggle: function() { var enabled, id, post, _ref; + enabled = Conf['prefetch'] = this.checked; if (enabled) { _ref = g.threads["" + g.BOARD.ID + "." + g.THREADID].posts; @@ -6311,16 +6537,17 @@ RevealSpoilers = { init: function() { - if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) { + if (g.VIEW === 'catalog' || !Conf['Reveal Spoiler Thumbnails']) { return; } return Post.prototype.callbacks.push({ - name: 'Reveal Spoilers', + name: 'Reveal Spoiler Thumbnails', cb: this.node }); }, node: function() { var thumb, _ref; + if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) { return; } @@ -6333,6 +6560,7 @@ ArchiveLink = { init: function() { var div, entry, type, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) { return; } @@ -6345,6 +6573,7 @@ order: 90, open: function(_arg) { var ID, board, thread; + ID = _arg.ID, thread = _arg.thread, board = _arg.board; return !!Redirect.to('thread', { postID: ID, @@ -6363,12 +6592,14 @@ }, createSubEntry: function(text, type) { var el, open; + el = $.el('a', { textContent: text, target: '_blank' }); open = type === 'post' ? function(_arg) { var ID, board, thread; + ID = _arg.ID, thread = _arg.thread, board = _arg.board; el.href = Redirect.to('thread', { postID: ID, @@ -6378,6 +6609,7 @@ return true; } : function(post) { var value; + value = Filter[type](post); if (!value) { return false; @@ -6400,6 +6632,7 @@ DeleteLink = { init: function() { var div, fileEl, fileEntry, postEl, postEntry; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) { return; } @@ -6427,6 +6660,7 @@ el: fileEl, open: function(_arg) { var file; + file = _arg.file; if (!file || file.isDead) { return false; @@ -6442,6 +6676,7 @@ order: 40, open: function(post) { var node; + if (post.isDead || post.board.ID === 'q') { return false; } @@ -6456,6 +6691,7 @@ }, "delete": function() { var fileOnly, form, link, post; + post = DeleteLink.post; if (DeleteLink.cooldown.counting === post) { return; @@ -6484,6 +6720,7 @@ }, load: function(link, post, fileOnly, html) { var msg, s, tmpDoc; + tmpDoc = d.implementation.createHTMLDocument(''); tmpDoc.documentElement.innerHTML = html; if (tmpDoc.title === '4chan - Banned') { @@ -6506,6 +6743,7 @@ cooldown: { start: function(post, node) { var length, seconds, _ref; + if (!((_ref = QR.db) != null ? _ref.get({ boardID: post.board.ID, threadID: post.thread.ID, @@ -6539,6 +6777,7 @@ DownloadLink = { init: function() { var a; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) { return; } @@ -6552,6 +6791,7 @@ order: 100, open: function(_arg) { var file; + file = _arg.file; if (!file) { return false; @@ -6577,6 +6817,7 @@ }, node: function() { var button; + button = Menu.makeButton(this); if (this.isClone) { $.replace($('.menu-button', this.nodes.info), button); @@ -6586,9 +6827,11 @@ }, makeButton: (function() { var a; + a = null; return function(post) { var clone; + a || (a = $.el('a', { className: 'menu-button fourchanx-link', innerHTML: '', @@ -6605,6 +6848,7 @@ })(), toggle: function(e) { var post; + post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid]; return Menu.menu.toggle(e, this, post); } @@ -6613,6 +6857,7 @@ ReportLink = { init: function() { var a; + if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) { return; } @@ -6634,6 +6879,7 @@ }, report: function() { var id, post, set, url; + post = ReportLink.post; url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post; id = Date.now(); @@ -6646,6 +6892,7 @@ init: function() { return $.ready(function() { var href; + Favicon.el = $('link[rel="shortcut icon"]', d.head); Favicon.el.type = 'image/x-icon'; href = Favicon.el.href; @@ -6718,6 +6965,7 @@ init: function() { var sc, _this = this; + if (g.VIEW !== 'thread' || !Conf['Thread Stats']) { return; } @@ -6747,6 +6995,7 @@ }, node: function() { var ID, fileCount, post, postCount, _ref; + postCount = 0; fileCount = 0; _ref = this.posts; @@ -6764,6 +7013,7 @@ }, onUpdate: function(e) { var fileCount, postCount, _ref; + if (e.detail[404]) { return; } @@ -6772,6 +7022,7 @@ }, update: function(postCount, fileCount) { var fileCountEl, postCountEl, thread; + thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl; postCountEl.textContent = postCount; fileCountEl.textContent = fileCount; @@ -6798,6 +7049,7 @@ }, onThreadsLoad: function() { var page, pages, thread, _i, _j, _len, _len1, _ref; + if (!Conf["Page Count in Stats"]) { return; } @@ -6825,6 +7077,7 @@ init: function() { var checked, conf, el, input, name, sc, settings, subEntries, _ref, _this = this; + if (g.VIEW !== 'thread' || !Conf['Thread Updater']) { return; } @@ -6975,6 +7228,7 @@ }, interval: function() { var val; + val = +this.value; if (val < 1) { val = 1; @@ -6984,6 +7238,7 @@ }, load: function() { var klass, req, text, _ref; + req = ThreadUpdater.req; switch (req.status) { case 200: @@ -7027,6 +7282,7 @@ }, getInterval: function() { var i, j; + i = ThreadUpdater.interval; j = Math.min(ThreadUpdater.outdateCount, 10); if (!d.hidden) { @@ -7036,12 +7292,14 @@ }, intervalShortcut: function() { var settings; + Settings.open('Advanced'); settings = $.id('fourchanx-settings'); return $('input[name=Interval]', settings).focus(); }, set: function(name, text, klass) { var el, node; + el = ThreadUpdater[name]; if (node = el.firstChild) { node.data = text; @@ -7054,6 +7312,7 @@ }, timeout: function() { var n; + ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000); if (!(n = --ThreadUpdater.seconds)) { return ThreadUpdater.update(); @@ -7066,6 +7325,7 @@ }, update: function() { var url; + if (!ThreadUpdater.online) { return; } @@ -7090,6 +7350,7 @@ }, updateThreadStatus: function(title, OP) { var icon, message, root, titleLC; + titleLC = title.toLowerCase(); if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) { return; @@ -7116,6 +7377,7 @@ }, parse: function(postObjects) { var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _len, _ref; + OP = postObjects[0]; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; ThreadUpdater.updateThreadStatus('Sticky', OP); @@ -7201,6 +7463,7 @@ } $.queueTask(function() { var length, threadID; + threadID = ThreadUpdater.thread.ID; length = $$('.thread > .postContainer', ThreadUpdater.root).length; return Fourchan.parseThread(threadID, length - count, length); @@ -7221,6 +7484,7 @@ ThreadWatcher = { init: function() { var sc; + if (!Conf['Thread Watcher']) { return; } @@ -7254,6 +7518,7 @@ node: function() { var favicon, _this = this; + favicon = $.el('a', { className: 'watch-thread-link', href: 'javascript:;' @@ -7273,6 +7538,7 @@ }, refresh: function(watched) { var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1; + if (!watched) { $.get('WatchedThreads', {}, function(item) { return ThreadWatcher.refresh(item['WatchedThreads']); @@ -7321,11 +7587,13 @@ }, x: function() { var thread; + thread = this.nextElementSibling.pathname.split('/'); return ThreadWatcher.unwatch(thread[1], thread[3]); }, post: function(e) { var board, postID, threadID, _ref; + _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID; if (postID === threadID) { if (Conf['Auto Watch']) { @@ -7346,6 +7614,7 @@ unwatch: function(board, threadID) { return $.get('WatchedThreads', {}, function(item) { var watched; + watched = item['WatchedThreads']; delete watched[board][threadID]; if (!Object.keys(watched[board]).length) { @@ -7358,6 +7627,7 @@ watch: function(thread) { return $.get('WatchedThreads', {}, function(item) { var watched, _name; + watched = item['WatchedThreads']; watched[_name = thread.board] || (watched[_name] = {}); watched[thread.board][thread] = { @@ -7403,6 +7673,7 @@ }, ready: function() { var ID, post, posts, _ref; + $.off(d, '4chanXInitFinished', Unread.ready); posts = []; _ref = Unread.thread.posts; @@ -7419,6 +7690,7 @@ }, scroll: function() { var checkPosition, hash, onload, post, posts, prevID, root; + if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { return; } @@ -7450,6 +7722,7 @@ } checkPosition = function(target) { var height, top, _ref; + _ref = target.getBoundingClientRect(), top = _ref.top, height = _ref.height; return top + height - doc.clientHeight > 0; }; @@ -7457,6 +7730,7 @@ }, sync: function() { var lastReadPost; + lastReadPost = Unread.db.get({ boardID: Unread.thread.board.ID, threadID: Unread.thread.ID, @@ -7473,6 +7747,7 @@ }, addPosts: function(posts) { var ID, data, post, _i, _len, _ref; + for (_i = 0, _len = posts.length; _i < _len; _i++) { post = posts[_i]; ID = post.ID; @@ -7500,6 +7775,7 @@ }, addPostQuotingYou: function(post) { var quotelink, _i, _len, _ref; + if (!QR.db) { return; } @@ -7520,6 +7796,7 @@ }, readSinglePost: function(post) { var i; + if ((i = Unread.posts.indexOf(post)) === -1) { return; } @@ -7535,6 +7812,7 @@ }, readArray: function(arr) { var i, post, _i, _len; + for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) { post = arr[i]; if (post.ID > Unread.lastReadPost) { @@ -7545,6 +7823,7 @@ }, read: $.debounce(50, function(e) { var ID, bottom, height, i, post, posts, read; + if (d.hidden || !Unread.posts.length) { return; } @@ -7578,6 +7857,7 @@ }), setLine: function(force) { var post, root; + if (!(d.hidden || force === true)) { return; } @@ -7592,6 +7872,7 @@ }, update: function(dontrepeat) { var count; + count = Unread.posts.length; if (Conf['Unread Count']) { d.title = "" + (Conf['Quoted Title'] && Unread.postsQuotingYou.length ? '(!) ' : '') + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title); @@ -7615,6 +7896,7 @@ file: {}, init: function() { var archive, arr, boardID, data, id, name, type, _i, _len, _ref, _ref1, _ref2, _ref3; + _ref = Conf['selectedArchives']; for (boardID in _ref) { data = _ref[boardID]; @@ -7741,6 +8023,7 @@ }, to: function(dest, data) { var archive; + archive = (dest === 'search' ? Redirect.thread : Redirect[dest])[data.boardID]; if (!archive) { return ''; @@ -7749,6 +8032,7 @@ }, protocol: function(archive) { var protocol; + protocol = location.protocol; if (!archive[protocol.slice(0, -1)]) { protocol = protocol === 'https:' ? 'http:' : 'https:'; @@ -7757,6 +8041,7 @@ }, thread: function(archive, _arg) { var boardID, path, postID, threadID; + boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID; path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID; if (archive.software === 'foolfuuka') { @@ -7769,6 +8054,7 @@ }, post: function(archive, _arg) { var boardID, postID, protocol; + boardID = _arg.boardID, postID = _arg.postID; protocol = Redirect.protocol(archive); if (['Foolz', 'NSFW Foolz'].contains(archive.name)) { @@ -7778,11 +8064,13 @@ }, file: function(archive, _arg) { var boardID, filename; + boardID = _arg.boardID, filename = _arg.filename; return "" + (Redirect.protocol(archive)) + archive.domain + "/" + boardID + "/full_image/" + filename; }, search: function(archive, _arg) { var boardID, path, type, value; + boardID = _arg.boardID, type = _arg.type, value = _arg.value; type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type; value = encodeURIComponent(value); @@ -7801,6 +8089,7 @@ }, setup: function() { var btn, entry, psa; + $.off(d, '4chanXInitFinished', PSAHiding.setup); if (!(psa = $.id('globalMessage'))) { $.rmClass(doc, 'hide-announcement'); @@ -7829,6 +8118,7 @@ $.on(btn, 'click', PSAHiding.toggle); $.get('hiddenPSA', 0, function(_arg) { var hiddenPSA; + hiddenPSA = _arg.hiddenPSA; PSAHiding.sync(hiddenPSA); $.before(psa, btn); @@ -7838,6 +8128,7 @@ }, toggle: function(e) { var UTC; + if ($.hasClass(this, 'hide-announcement')) { UTC = +$.id('globalMessage').dataset.utc; $.set('hiddenPSA', UTC); @@ -7849,6 +8140,7 @@ }, sync: function(UTC) { var hr, psa; + psa = $.id('globalMessage'); psa.hidden = PSAHiding.btn.hidden = UTC && UTC >= +psa.dataset.utc ? true : false; if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') { @@ -7860,6 +8152,7 @@ CatalogLinks = { init: function() { var el, input; + if (!Conf['Catalog Links']) { return; } @@ -7883,12 +8176,14 @@ }, toggle: function() { var useCatalog; + $.event('CloseMenu'); $.set('Header catalog links', useCatalog = this.checked); return CatalogLinks.set(useCatalog); }, set: function(useCatalog) { var a, board, path, _i, _len, _ref; + path = useCatalog ? 'catalog' : ''; _ref = $$("#board-list a[href*=\"boards.4chan.org\"]:not(.catalog),\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]"); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -7922,6 +8217,7 @@ }, node: function(post) { var str, uid; + if (!(uid = $('.hand', this.nodes.uniqueID))) { return; } @@ -7933,6 +8229,7 @@ ids: {}, compute: function(str) { var hash, rgb; + hash = this.hash(str); rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF]; rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125; @@ -7941,11 +8238,13 @@ }, apply: function() { var rgb; + rgb = IDColor.ids[this] || IDColor.compute(this); return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black; border-radius: 3px; padding: 0px 2px;" : "white; border-radius: 3px; padding: 0px 2px;"); }, hash: function(str) { var i, j, msg; + msg = 0; i = 0; j = str.length; @@ -7984,6 +8283,7 @@ Emoji = { init: function() { var css, icon, name, pos, _ref; + if (!Conf['Emoji']) { return; } @@ -8053,6 +8353,7 @@ }, node: function() { var a; + if (a = $('.abbr > a:not([onclick])', this.nodes.comment)) { return $.on(a, 'click', ExpandComment.cb); } @@ -8060,12 +8361,14 @@ callbacks: [], cb: function(e) { var post; + e.preventDefault(); post = Get.postFromNode(this); return ExpandComment.expand(post); }, expand: function(post) { var a; + if (post.nodes.longComment && !post.nodes.longComment.parentNode) { $.replace(post.nodes.shortComment, post.nodes.longComment); post.nodes.comment = post.nodes.longComment; @@ -8081,6 +8384,7 @@ }, contract: function(post) { var a; + if (!post.nodes.shortComment) { return; } @@ -8091,6 +8395,7 @@ }, parse: function(req, a, post) { var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + status = req.status; if (![200, 304].contains(status)) { a.textContent = "Error " + req.statusText + " (" + status + ")"; @@ -8147,6 +8452,7 @@ }, node: function() { var a, span; + if (!(span = $('.summary', this.OP.nodes.root.parentNode))) { return; } @@ -8160,11 +8466,13 @@ }, cbToggle: function() { var op; + op = Get.postFromRoot(this.previousElementSibling); return ExpandThread.toggle(op.thread); }, toggle: function(thread) { var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + threadRoot = thread.OP.nodes.root.parentNode; a = $('.summary', threadRoot); switch (thread.isExpanded) { @@ -8233,6 +8541,7 @@ }, parse: function(req, thread, a) { var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len; + if (a.textContent[0] === '+') { return; } @@ -8290,6 +8599,7 @@ }, createFunc: function(format) { var code; + code = format.replace(/%(.)/g, function(s, c) { if (c in FileInfo.formatters) { return "' + FileInfo.formatters." + c + ".call(post) + '"; @@ -8301,6 +8611,7 @@ }, convertUnit: function(size, unit) { var i; + if (unit === 'B') { return "" + (size.toFixed()) + " Bytes"; } @@ -8331,6 +8642,7 @@ }, n: function() { var fullname, shortname; + fullname = this.file.name; shortname = Build.shortFilename(this.file.name, this.isReply); if (fullname === shortname) { @@ -8374,6 +8686,7 @@ Fourchan = { init: function() { var board; + if (g.VIEW === 'catalog') { return; } @@ -8395,6 +8708,7 @@ }, code: function() { var pre, _i, _len, _ref; + if (this.isClone) { return; } @@ -8424,11 +8738,13 @@ Keybinds = { init: function() { var init; + if (g.VIEW === 'catalog' || !Conf['Keybinds']) { return; } init = function() { var node, _i, _len, _ref; + $.off(d, '4chanXInitFinished', init); $.on(d, 'keydown', Keybinds.keydown); _ref = $$('[accesskey]'); @@ -8441,6 +8757,7 @@ }, keydown: function(e) { var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len; + if (!(key = Keybinds.keyCode(e))) { return; } @@ -8615,6 +8932,7 @@ }, keyCode: function(e) { var kc, key; + key = (function() { switch (kc = e.keyCode) { case 8: @@ -8670,6 +8988,7 @@ }, tags: function(tag, ta) { var range, selEnd, selStart, value; + value = ta.value; selStart = ta.selectionStart; selEnd = ta.selectionEnd; @@ -8680,11 +8999,13 @@ }, sage: function() { var isSage; + isSage = /sage/i.test(QR.nodes.email.value); return QR.nodes.email.value = isSage ? "" : "sage"; }, img: function(thread, all) { var post; + if (all) { return ImageExpand.cb.toggleAll(); } else { @@ -8694,6 +9015,7 @@ }, open: function(thread, tab) { var url; + if (g.VIEW !== 'index') { return; } @@ -8706,6 +9028,7 @@ }, hl: function(delta, thread) { var axe, headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len; + if (!delta) { if (postEl = $('.reply.highlight', thread)) { $.rmClass(postEl, 'highlight'); @@ -8765,6 +9088,7 @@ Nav = { init: function() { var append, next, prev, span; + switch (g.VIEW) { case 'index': if (!Conf['Index Navigation']) { @@ -8815,6 +9139,7 @@ }, getThread: function(full) { var headRect, i, rect, thread, threads, topMargin, _i, _len; + if (Conf['Bottom header'] || !Conf['Fixed Header']) { topMargin = 0; } else { @@ -8840,6 +9165,7 @@ }, scroll: function(delta) { var i, rect, thread, threads, top, topMargin, _ref, _ref1; + _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4]; top = rect.top - topMargin; if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) { @@ -8865,6 +9191,7 @@ }, node: function() { var dateEl; + if (this.isClone) { return; } @@ -8874,6 +9201,7 @@ }, relative: function(diff, now, date) { var days, months, number, rounded, unit, years; + unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second'); rounded = Math.round(number); if (rounded !== 1) { @@ -8884,6 +9212,7 @@ stale: [], flush: function() { var now, update, _i, _len, _ref; + if (d.hidden) { return; } @@ -8899,13 +9228,16 @@ }, setUpdate: function(post) { var markStale, setOwnTimeout, update; + setOwnTimeout = function(diff) { var delay; + delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY; return setTimeout(markStale, delay); }; update = function(now) { var date, diff, relative, singlePost, _i, _len, _ref; + date = post.info.date; diff = now - date; relative = RelativeDates.relative(diff, now, date); @@ -8946,6 +9278,7 @@ }, node: function(post) { var spoiler, spoilers, _i, _len; + spoilers = $$('s', this.nodes.comment); for (_i = 0, _len = spoilers.length; _i < _len; _i++) { spoiler = spoilers[_i]; @@ -8965,6 +9298,7 @@ }, ready: function() { var field; + field = $.id('recaptcha_response_field'); $.on(field, 'keydown', function(e) { if (e.keyCode === 8 && !field.value) { @@ -8973,6 +9307,7 @@ }); return $.on($('form'), 'submit', function(e) { var response; + e.preventDefault(); response = field.value.trim(); if (!/\s/.test(response)) { @@ -8986,6 +9321,7 @@ Sauce = { init: function() { var err, link, links, _i, _len, _ref; + if (g.VIEW === 'catalog' || !Conf['Sauce']) { return; } @@ -9017,6 +9353,7 @@ }, createSauceLink: function(link) { var m, text; + link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) { switch (parameter) { case '%TURL': @@ -9037,6 +9374,7 @@ }, node: function() { var link, nodes, _i, _len, _ref; + if (this.isClone || !this.file) { return; } @@ -9069,6 +9407,7 @@ }, createFunc: function(format) { var code; + code = format.replace(/%([A-Za-z])/g, function(s, c) { if (c in Time.formatters) { return "' + Time.formatters." + c + ".call(date) + '"; @@ -9153,6 +9492,7 @@ Settings = { init: function() { var link, settings; + link = $.el('a', { className: 'settings-link', textContent: 'Settings', @@ -9162,6 +9502,7 @@ Header.addShortcut(link); $.get('previousversion', null, function(item) { var changelog, el, previous; + if (previous = item['previousversion']) { if (previous === g.VERSION) { return; @@ -9199,6 +9540,7 @@ }, open: function(openSection) { var dialog, html, link, links, overlay, section, sectionToOpen, _i, _len, _ref; + $.off(d, '4chanXInitFinished', Settings.open); if (Settings.dialog) { return; @@ -9251,6 +9593,7 @@ sections: [], addSection: function(title, open) { var hyphenatedTitle, _ref; + if (typeof title !== 'string') { _ref = title.detail, title = _ref.title, open = _ref.open; } @@ -9263,6 +9606,7 @@ }, openSection: function() { var section, selected; + if (selected = $('.tab-selected', Settings.dialog)) { $.rmClass(selected, 'tab-selected'); } @@ -9276,6 +9620,7 @@ }, main: function(section) { var arr, button, description, div, fs, hiddenNum, input, inputs, items, key, obj, _ref; + items = {}; inputs = {}; _ref = Config.main; @@ -9300,6 +9645,7 @@ } $.get(items, function(items) { var val; + for (key in items) { val = items[key]; inputs[key].checked = val; @@ -9314,6 +9660,7 @@ boards: {} }, function(item) { var ID, board, thread, _ref1; + _ref1 = item.hiddenThreads.boards; for (ID in _ref1) { board = _ref1[ID]; @@ -9328,6 +9675,7 @@ boards: {} }, function(item) { var ID, board, post, thread, _ref1; + _ref1 = item.hiddenPosts.boards; for (ID in _ref1) { board = _ref1[ID]; @@ -9347,6 +9695,7 @@ boards: {} }, function(item) { var boardID; + for (boardID in item.hiddenThreads.boards) { localStorage.removeItem("4chan-hide-t-" + boardID); } @@ -9357,6 +9706,7 @@ }, "export": function(now, data) { var a, db, _i, _len; + if (typeof now !== 'number') { now = Date.now(); data = { @@ -9391,6 +9741,7 @@ }, onImport: function() { var file, output, reader; + if (!(file = this.files[0])) { return; } @@ -9402,6 +9753,7 @@ reader = new FileReader(); reader.onload = function(e) { var data, err; + try { data = JSON.parse(e.target.result); Settings.loadSettings(data); @@ -9418,6 +9770,7 @@ }, loadSettings: function(data) { var key, val, version, _ref; + version = data.version.split('.'); if (version[0] === '2') { data = Settings.convertSettings(data, { @@ -9507,6 +9860,7 @@ }, convertSettings: function(data, map) { var newKey, prevKey; + for (prevKey in map) { newKey = map[prevKey]; if (newKey) { @@ -9518,6 +9872,7 @@ }, filter: function(section) { var select; + section.innerHTML = "
"; select = $('select', section); $.on(select, 'change', Settings.selectFilter); @@ -9525,6 +9880,7 @@ }, selectFilter: function() { var div, name, ta; + div = this.nextElementSibling; if ((name = this.value) !== 'guide') { $.rmAll(div); @@ -9544,6 +9900,7 @@ }, sauce: function(section) { var ta; + section.innerHTML = "
Sauce is disabled.
Lines starting with a # will be ignored.
You can specify a display text by appending ;text:[text] to the URL.
    These parameters will be replaced by their corresponding values:\n
  • %TURL: Thumbnail URL.
  • %URL: Full image URL.
  • %MD5: MD5 hash.
  • %board: Current board.
"; ta = $('textarea', section); $.get('sauces', Conf['sauces'], function(item) { @@ -9553,6 +9910,7 @@ }, advanced: function(section) { var archive, boardID, boardOptions, boardSelect, boards, data, event, input, inputs, item, items, name, row, rows, ta, table, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _ref4; + section.innerHTML = "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Disabled selections indicate that only one archive is available for that board and redirection type.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
Board link: g
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:\"Install Gentoo\"
Index-only link: g-index
Catalog-only link: g-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: g-index-text:\"Technology Index\"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Time Formatting is disabled.
:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

    You can use these settings with each item, separate them with semicolons:\n
  • Possible items are: name, email, subject and password.
  • Wrap values of items with quotes, like this: email:\"sage\".
  • Force values as defaults with the always keyword, for example: email:\"sage\";always.
  • Select specific boards for an item, separated with commas, for example: email:\"sage\";boards:jp;always.
Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; items = {}; inputs = {}; @@ -9572,6 +9930,7 @@ $.on(ta, 'change', $.cb.value); $.get(items, function(items) { var key, val; + for (key in items) { val = items[key]; if (['emojiPos'].contains(key)) { @@ -9642,6 +10001,7 @@ }); $.get('selectedArchives', Conf['selectedArchives'], function(_arg) { var option, selectedArchives, type; + selectedArchives = _arg.selectedArchives; for (boardID in selectedArchives) { data = selectedArchives[boardID]; @@ -9656,6 +10016,7 @@ }, addArchiveCell: function(boardID, data, type) { var archive, i, length, options, select, td; + length = data[type].length; td = $.el('td', { className: 'archive-cell' @@ -9685,8 +10046,10 @@ }, saveSelectedArchive: function() { var _this = this; + return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) { var selectedArchives, _name; + selectedArchives = _arg.selectedArchives; (selectedArchives[_name = _this.dataset.boardid] || (selectedArchives[_name] = {}))[_this.dataset.type] = _this.value; return $.set('selectedArchives', selectedArchives); @@ -9697,6 +10060,7 @@ }, time: function() { var funk; + funk = Time.createFunc(this.value); return this.nextElementSibling.textContent = funk(Time, new Date()); }, @@ -9705,6 +10069,7 @@ }, fileInfo: function() { var data, funk; + data = { isReply: true, file: { @@ -9743,6 +10108,7 @@ }, keybinds: function(section) { var arr, input, inputs, items, key, tbody, tr, _ref; + section.innerHTML = "
Keybinds are disabled.
Allowed keys: a-z, 0-9, Ctrl, Shift, Alt, Meta, Enter, Esc, Up, Down, Right, Left.
Press Backspace to disable a keybind.
ActionsKeybinds
"; tbody = $('tbody', section); items = {}; @@ -9763,6 +10129,7 @@ } return $.get(items, function(items) { var val; + for (key in items) { val = items[key]; inputs[key].value = val; @@ -9771,6 +10138,7 @@ }, keybind: function(e) { var key; + if (e.keyCode === 9) { return; } @@ -9787,8 +10155,10 @@ Main = { init: function(items) { var db, flatten, _i, _len; + flatten = function(parent, obj) { var key, val; + if (obj instanceof Array) { Conf[parent] = obj[0]; } else if (typeof obj === 'object') { @@ -9812,11 +10182,13 @@ $.on(d, '4chanMainInit', Main.initStyle); return $.asap((function() { var _ref; + return d.head && $('link[rel="shortcut icon"]', d.head) || ((_ref = d.readyState) === 'interactive' || _ref === 'complete'); }), Main.initStyle); }, initFeatures: function(items) { var init, pathname, _ref; + Conf = items; pathname = location.pathname.split('/'); g.BOARD = new Board(pathname[1]); @@ -9845,6 +10217,7 @@ case 'images.4chan.org': $.ready(function() { var URL; + if (Conf['404 Redirect'] && d.title === '4chan - 404 Not Found') { Redirect.init(); pathname = location.pathname.split('/'); @@ -9861,6 +10234,7 @@ } init = function(features) { var err, module, name; + for (name in features) { module = features[name]; try { @@ -9936,6 +10310,7 @@ }, initStyle: function() { var mainStyleSheet, observer, setStyle, style, styleSheets, _ref; + $.off(d, '4chanMainInit', Main.initStyle); if (!Main.isThisPageLegit() || $.hasClass(doc, 'fourchan-x')) { return; @@ -9957,6 +10332,7 @@ styleSheets = $$('link[rel="alternate stylesheet"]', d.head); setStyle = function() { var styleSheet, _i, _len; + $.rmClass(doc, style); for (_i = 0, _len = styleSheets.length; _i < _len; _i++) { styleSheet = styleSheets[_i]; @@ -9983,6 +10359,7 @@ }, initReady: function() { var board, boardChild, err, errors, href, passLink, posts, styleSelector, thread, threadChild, threads, _i, _j, _len, _len1, _ref, _ref1; + if (d.title === '4chan - 404 Not Found') { if (Conf['404 Redirect'] && g.VIEW === 'thread') { href = Redirect.to('thread', { @@ -10057,6 +10434,7 @@ }, callbackNodes: function(klass, nodes) { var callback, err, errors, i, len, node, _i, _len, _ref; + len = nodes.length; _ref = klass.prototype.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -10084,9 +10462,11 @@ }, callbackNodesDB: function(klass, nodes, cb) { var errors, func, i, len, node, queue, softTask; + queue = []; softTask = function() { var args, func, task; + task = queue.shift(); func = task[0]; args = Array.prototype.slice.call(task, 1); @@ -10105,6 +10485,7 @@ errors = null; func = function(node, i) { var callback, err, _i, _len, _ref; + _ref = klass.prototype.callbacks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { callback = _ref[_i]; @@ -10138,6 +10519,7 @@ }, addCallback: function(e) { var Klass, obj; + obj = e.detail; if (typeof obj.callback.name !== 'string') { throw new Error("Invalid callback name: " + obj.callback.name); @@ -10157,6 +10539,7 @@ }, handleErrors: function(errors) { var div, error, logs, _i, _len; + if (!(errors instanceof Array)) { error = errors; } else if (errors.length === 1) { @@ -10171,6 +10554,7 @@ }); $.on(div.lastElementChild, 'click', function() { var _ref; + return _ref = this.textContent === 'show' ? ['hide', false] : ['show', true], this.textContent = _ref[0], logs.hidden = _ref[1], _ref; }); logs = $.el('div', { @@ -10184,6 +10568,7 @@ }, parseError: function(data) { var error, message; + Main.logError(data); message = $.el('div', { textContent: data.message @@ -10200,6 +10585,7 @@ }, isThisPageLegit: function() { var _ref; + if (!('thisPageIsLegit' in Main)) { Main.thisPageIsLegit = location.hostname === 'boards.4chan.org' && !$('link[href*="favicon-status.ico"]', d.head) && ((_ref = d.title) !== '4chan - Temporarily Offline' && _ref !== '4chan - Error'); } diff --git a/src/General/Config.coffee b/src/General/Config.coffee index 84b210e54..36ae0def2 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -145,9 +145,9 @@ Config = true 'Add sauce links to images.' ] - 'Reveal Spoilers': [ + 'Reveal Spoiler Thumbnails': [ false - 'Reveal spoiler thumbnails.' + 'Replace spoiler thumbnails with the original image.' ] 'Replace GIF': [ false diff --git a/src/Images/RevealSpoilers.coffee b/src/Images/RevealSpoilers.coffee index 99d4fbd21..8a884dd8b 100644 --- a/src/Images/RevealSpoilers.coffee +++ b/src/Images/RevealSpoilers.coffee @@ -1,9 +1,9 @@ RevealSpoilers = init: -> - return if g.VIEW is 'catalog' or !Conf['Reveal Spoilers'] + return if g.VIEW is 'catalog' or !Conf['Reveal Spoiler Thumbnails'] Post::callbacks.push - name: 'Reveal Spoilers' + name: 'Reveal Spoiler Thumbnails' cb: @node node: -> return if @isClone or !@file?.isSpoiler From d0bbe131728f0927e5774da17dfdb39109de7956 Mon Sep 17 00:00:00 2001 From: Jordan Bates Date: Sun, 4 Aug 2013 14:32:25 -0700 Subject: [PATCH 16/20] Release 4chan X v1.2.25. --- CHANGELOG.md | 7 +++++++ LICENSE | 2 +- builds/4chan-X.js | 10 +++++----- builds/4chan-X.meta.js | 2 +- builds/4chan-X.user.js | 10 +++++----- builds/crx/manifest.json | 2 +- builds/crx/script.js | 8 ++++---- latest.js | 2 +- package.json | 2 +- src/Archive/Redirect.coffee | 4 ++-- 10 files changed, 28 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 679962fa7..e26551471 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +### v1.2.25 +*2013-08-04* + +**seaweedchan**: +- Fix issues with having two options called `Reveal Spoilers`. +- Update archive. + ### v1.2.24 *2013-07-24* diff --git a/LICENSE b/LICENSE index 391e259a5..dd8831faf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.2.24 - 2013-08-04 +* 4chan X - Version 1.2.25 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.js b/builds/4chan-X.js index b2fa58069..dd5c3e4fe 100644 --- a/builds/4chan-X.js +++ b/builds/4chan-X.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript // ==UserScript== // @name 4chan X -// @version 1.2.24 +// @version 1.2.25 // @namespace 4chan-X // @description Cross-browser userscript for maximum lurking on 4chan. // @license MIT; https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -19,7 +19,7 @@ // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC // ==/UserScript== /* -* 4chan X - Version 1.2.24 - 2013-08-04 +* 4chan X - Version 1.2.25 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -323,7 +323,7 @@ doc = d.documentElement; g = { - VERSION: '1.2.24', + VERSION: '1.2.25', NAMESPACE: '4chan X.', boards: {}, threads: {}, @@ -8005,8 +8005,8 @@ 'http': true, 'https': false, 'software': 'foolfuuka', - 'boards': ['e', 'h', 'p', 's', 'u'], - 'files': ['e', 'h', 'p', 's', 'u'] + 'boards': ['e', 'h', 'hc', 'p', 's', 'u'], + 'files': ['e', 'h', 'hc', 'p', 's', 'u'] }, 'Install Gentoo': { 'domain': 'archive.installgentoo.net', diff --git a/builds/4chan-X.meta.js b/builds/4chan-X.meta.js index 089dc6421..6729e9eac 100644 --- a/builds/4chan-X.meta.js +++ b/builds/4chan-X.meta.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X -// @version 1.2.24 +// @version 1.2.25 // @namespace 4chan-X // @description Cross-browser userscript for maximum lurking on 4chan. // @license MIT; https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 0f2d22a7e..1580b7d54 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript // ==UserScript== // @name 4chan X -// @version 1.2.24 +// @version 1.2.25 // @namespace 4chan-X // @description Cross-browser userscript for maximum lurking on 4chan. // @license MIT; https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -19,7 +19,7 @@ // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC // ==/UserScript== /* -* 4chan X - Version 1.2.24 - 2013-08-04 +* 4chan X - Version 1.2.25 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -320,7 +320,7 @@ doc = d.documentElement; g = { - VERSION: '1.2.24', + VERSION: '1.2.25', NAMESPACE: '4chan X.', boards: {}, threads: {}, @@ -7999,8 +7999,8 @@ 'http': true, 'https': false, 'software': 'foolfuuka', - 'boards': ['e', 'h', 'p', 's', 'u'], - 'files': ['e', 'h', 'p', 's', 'u'] + 'boards': ['e', 'h', 'hc', 'p', 's', 'u'], + 'files': ['e', 'h', 'hc', 'p', 's', 'u'] }, 'Install Gentoo': { 'domain': 'archive.installgentoo.net', diff --git a/builds/crx/manifest.json b/builds/crx/manifest.json index bb3e2252f..3112aebc5 100644 --- a/builds/crx/manifest.json +++ b/builds/crx/manifest.json @@ -1,6 +1,6 @@ { "name": "4chan X", - "version": "1.2.24", + "version": "1.2.25", "manifest_version": 2, "description": "Cross-browser userscript for maximum lurking on 4chan.", "icons": { diff --git a/builds/crx/script.js b/builds/crx/script.js index d994ff51c..dfc0591c9 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.2.24 - 2013-08-04 +* 4chan X - Version 1.2.25 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -300,7 +300,7 @@ doc = d.documentElement; g = { - VERSION: '1.2.24', + VERSION: '1.2.25', NAMESPACE: '4chan X.', boards: {}, threads: {}, @@ -7986,8 +7986,8 @@ 'http': true, 'https': false, 'software': 'foolfuuka', - 'boards': ['e', 'h', 'p', 's', 'u'], - 'files': ['e', 'h', 'p', 's', 'u'] + 'boards': ['e', 'h', 'hc', 'p', 's', 'u'], + 'files': ['e', 'h', 'hc', 'p', 's', 'u'] }, 'Install Gentoo': { 'domain': 'archive.installgentoo.net', diff --git a/latest.js b/latest.js index f6f20c5f6..45ec3a6f9 100644 --- a/latest.js +++ b/latest.js @@ -1 +1 @@ -postMessage({version:'1.2.24'},'*') +postMessage({version:'1.2.25'},'*') diff --git a/package.json b/package.json index 8d2059af2..d04cf5d48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "4chan-X", - "version": "1.2.24", + "version": "1.2.25", "description": "Cross-browser userscript for maximum lurking on 4chan.", "meta": { "name": "4chan X", diff --git a/src/Archive/Redirect.coffee b/src/Archive/Redirect.coffee index 13b13a6e9..f8b12e959 100644 --- a/src/Archive/Redirect.coffee +++ b/src/Archive/Redirect.coffee @@ -76,8 +76,8 @@ Redirect = 'http': true 'https': false 'software': 'foolfuuka' - 'boards': ['e', 'h', 'p', 's', 'u'] - 'files': ['e', 'h', 'p', 's', 'u'] + 'boards': ['e', 'h', 'hc', 'p', 's', 'u'] + 'files': ['e', 'h', 'hc', 'p', 's', 'u'] 'Install Gentoo': 'domain': 'archive.installgentoo.net' From a6f6f44d580a3c6b243a69b8177dcec8b4c42eef Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Sun, 4 Aug 2013 18:47:04 -0700 Subject: [PATCH 17/20] Linkifier Rewrite --- LICENSE | 2 +- builds/4chan-X.user.js | 365 +++++++++++++++++-------------- builds/crx/script.js | 365 +++++++++++++++++-------------- src/Linkification/Linkify.coffee | 337 +++++++++++++++------------- 4 files changed, 593 insertions(+), 476 deletions(-) diff --git a/LICENSE b/LICENSE index 97bce1cc7..391e259a5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.2.24 - 2013-08-01 +* 4chan X - Version 1.2.24 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 909c75b3f..8eafa30f9 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -19,7 +19,7 @@ // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC // ==/UserScript== /* -* 4chan X - Version 1.2.24 - 2013-08-01 +* 4chan X - Version 1.2.24 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -4300,122 +4300,235 @@ if (g.VIEW === 'catalog' || !Conf['Linkify']) { return; } - this.regString = Conf['Allow False Positives'] ? /(\b([a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]+|[-a-z0-9]+\.[a-z]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-z]{3,}:[a-z0-9?]|[a-z0-9._%+-:]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi; + this.regString = Conf['Allow False Positives'] ? /(\b([a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]|[a-z]{3,}:[a-z0-9?]|[\S]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi; if (Conf['Comment Expansion']) { ExpandComment.callbacks.push(this.node); } + if (Conf['Title Link']) { + $.sync('CachedTitles', Linkify.titleSync); + } return Post.prototype.callbacks.push({ name: 'Linkify', cb: this.node }); }, - cypher: $.el('div'), node: function() { - var a, child, cypher, cypherText, data, embed, embedder, embeds, i, index, len, link, links, lookahead, name, next, node, nodes, snapshot, spoiler, text, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2; + var data, embedder, i, len, node, range, snapshot, _i, _j, _len, _len1, _ref, _ref1; if (this.isClone && Conf['Embedding']) { _ref = $$('.embedder', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { embedder = _ref[_i]; - $.on(embedder, "click", Linkify.toggle); + $.on(embedder, "click", Linkify.cb.toggle); } return; } snapshot = $.X('.//text()', this.nodes.comment); - cypher = Linkify.cypher; i = -1; len = snapshot.snapshotLength; while (++i < len) { - nodes = $.frag(); node = snapshot.snapshotItem(i); data = node.data; - if (!(node.parentNode && Linkify.regString.test(data))) { - continue; + if (Linkify.regString.test(data)) { + Linkify.regString.lastIndex = 0; + Linkify.gatherLinks(node, this); } - Linkify.regString.lastIndex = 0; - cypherText = []; - if (next = node.nextSibling) { - cypher.textContent = node.textContent; - cypherText[0] = cypher.innerHTML; - while ((next.nodeName.toLowerCase() === 'wbr' || next.nodeName.toLowerCase() === 's') && (lookahead = next.nextSibling) && ((name = lookahead.nodeName) === "#text" || name.toLowerCase() === 'br')) { - cypher.textContent = lookahead.textContent; - cypherText.push((spoiler = next.innerHTML) ? "" + (spoiler.replace(/" : ''); - cypherText.push(cypher.innerHTML); - $.rm(next); - next = lookahead.nextSibling; - if (lookahead.nodeName === "#text") { - $.rm(lookahead); - } - if (!next) { - break; - } - } - } - if (cypherText.length) { - data = cypherText.join(''); - } - links = data.match(Linkify.regString); - for (_j = 0, _len1 = links.length; _j < _len1; _j++) { - link = links[_j]; - index = data.indexOf(link); - if (text = data.slice(0, index)) { - cypher.innerHTML = text; - _ref1 = __slice.call(cypher.childNodes); - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - child = _ref1[_k]; - $.add(nodes, child); - } - } - cypher.innerHTML = (link.indexOf(':') < 0 ? (link.indexOf('@') > 0 ? 'mailto:' + link : 'http://' + link) : link).replace(/<(wbr|s|\/s)>/g, ''); - a = $.el('a', { - innerHTML: link, - className: 'linkify', - rel: 'nofollow noreferrer', - target: '_blank', - href: cypher.textContent - }); - $.add(nodes, Linkify.embedder(a)); - data = data.slice(index + link.length); - } - if (data) { - cypher.innerHTML = data; - _ref2 = __slice.call(cypher.childNodes); - for (_l = 0, _len3 = _ref2.length; _l < _len3; _l++) { - child = _ref2[_l]; - $.add(nodes, child); - } - } - $.replace(node, nodes); } - if (Conf['Auto-embed']) { - embeds = $$('.embedder', this.nodes.comment); - for (_m = 0, _len4 = embeds.length; _m < _len4; _m++) { - embed = embeds[_m]; - embed.click(); + if (!(Conf['Embedding'] || Conf['Link Title'])) { + return; + } + _ref1 = this.nodes.links; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + range = _ref1[_j]; + if (data = Linkify.services(range)) { + if (Conf['Embedding']) { + Linkify.embed(data); + } + if (Conf['Link Title']) { + Linkify.title(data); + } } } }, - toggle: function() { - var el, embed, style, type, url; + gatherLinks: function(node, post) { + var data, index, len, len2, link, links, match, range, _i, _len, _ref; + + data = node.data; + len = data.length; + links = []; + while ((match = Linkify.regString.exec(data))) { + index = match.index; + link = match[0]; + len2 = index + link.length; + if (len - len2 === 0) { + break; + } + range = document.createRange(); + range.setStart(node, index); + range.setEnd(node, len2); + links.push(range); + } + if (match) { + Linkify.seek(match, node, post); + } + _ref = links.reverse(); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + range = _ref[_i]; + Linkify.makeLink(range, post); + } + }, + seek: function(match, node, post) { + var data, index, link, next, range, result; + + index = match.index; + link = match[0]; + range = document.createRange(); + range.setStart(node, index); + while ((next = node.nextSibling) && next.nodeName !== 'BR') { + node = next; + data = node.data; + if (result = /[\s'"]/.exec(data)) { + range.setEnd(node, result.index); + } + } + if (range.collapsed) { + if (node.nodeName === 'WBR') { + node = node.previousSibling; + } + range.setEnd(node, node.length); + } + return Linkify.makeLink(range, post); + }, + makeLink: function(range, post) { + var a, link; + + link = range.toString(); + link = link.contains(':') ? link : (link.contains('@') ? 'mailto:' : 'http://') + link; + a = $.el('a', { + className: 'linkify', + rel: 'nofollow noreferrer', + target: '_blank', + href: link + }); + range.surroundContents(a); + post.nodes.links.push(a); + }, + services: function(link) { + var href, key, match, type, _ref; + + href = link.href; + _ref = Linkify.types; + for (key in _ref) { + type = _ref[key]; + if (!(match = type.regExp.exec(href))) { + continue; + } + return [key, match[1], match[2], link]; + } + }, + embed: function(data) { + var embed, key, link, options, uid; + + key = data[0], uid = data[1], options = data[2], link = data[3]; + embed = $.el('a', { + name: uid, + option: options, + className: 'embedder', + href: 'javascript:;', + textContent: '(embed)' + }); + embed.dataset.service = key; + embed.dataset.originalurl = link.href; + $.addClass(link, "" + embed.dataset.service); + $.on(embed, 'click', Linkify.cb.toggle); + return $.after(link, [$.tn(' '), embed]); + }, + title: function(data) { + var err, key, link, options, service, title, titles, uid; + + key = data[0], uid = data[1], options = data[2], link = data[3]; + if (!(service = Linkify.types[key].title)) { + return; + } + titles = Conf['CachedTitles']; + if (title = titles[uid]) { + link.textContent = title[0]; + if (Conf['Embedding']) { + return link.nextElementSibling.dataset.title = title[0]; + } + } else { + try { + $.cache(service.api(uid), function() { + return title = Linkify.cb.title.apply(this, [data]); + }); + } catch (_error) { + err = _error; + link.innerHTML = "[" + key + "] Title Link Blocked (are you using NoScript?)"; + return; + } + if (title) { + titles[uid] = [title, Date.now()]; + return $.set('CachedTitles', titles); + } + } + }, + titleSync: function(value) { + return Conf['CachedTitles'] = value; + }, + cb: { + toggle: function() { + var el, embed; + + embed = this.previousElementSibling; + el = !this.className.contains("embedded") ? Linkify.cb.embed(this) : Linkify.cb.unembed(this); + $.replace(embed, el); + return $.toggleClass(this, 'embedded'); + }, + embed: function(a) { + var el, style, type; + + el = (type = Linkify.types[a.dataset.service]).el.call(a); + el.style.cssText = (style = type.style) ? style : "border: 0; width: 640px; height: 390px"; + a.textContent = '(unembed)'; + return el; + }, + unembed: function(a) { + var el, url; - embed = this.previousElementSibling; - if (this.className.contains("embedded")) { el = $.el('a', { rel: 'nofollow noreferrer', target: 'blank', className: 'linkify', - href: url = this.getAttribute("data-originalURL"), - textContent: this.getAttribute("data-title") || url + href: url = a.dataset.originalurl, + textContent: a.dataset.title || url }); - this.textContent = '(embed)'; - $.addClass(el, "" + (this.getAttribute('data-service'))); - } else { - el = (type = Linkify.types[this.getAttribute("data-service")]).el.call(this); - el.style.cssText = (style = type.style) ? style : "border: 0; width: 640px; height: 390px"; - this.textContent = '(unembed)'; + a.textContent = '(embed)'; + $.addClass(el, "" + a.dataset.service); + return el; + }, + title: function(data) { + var key, link, options, service, text, uid; + + key = data[0], uid = data[1], options = data[2], link = data[3]; + service = Linkify.types[key].title; + return link.textContent = (function() { + switch (this.status) { + case 200: + case 304: + text = "" + (service.text.call(this)); + if (Conf['Embedding']) { + link.nextElementSibling.dataset.title = text; + } + return text; + case 404: + return "[" + key + "] Not Found"; + case 403: + return "[" + key + "] Forbidden or Private"; + default: + return "[" + key + "] " + this.status + "'d"; + } + }).call(this); } - $.replace(embed, el); - return $.toggleClass(this, 'embedded'); }, types: { YouTube: { @@ -4426,8 +4539,8 @@ }); }, title: { - api: function() { - return "https://gdata.youtube.com/feeds/api/videos/" + this.name + "?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode"; + api: function(uid) { + return "https://gdata.youtube.com/feeds/api/videos/" + uid + "?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode"; }, text: function() { return JSON.parse(this.responseText).entry.title.$t; @@ -4451,8 +4564,8 @@ }); }, title: { - api: function() { - return "https://vimeo.com/api/oembed.json?url=http://vimeo.com/" + this.name; + api: function(uid) { + return "https://vimeo.com/api/oembed.json?url=http://vimeo.com/" + uid; }, text: function() { return JSON.parse(this.responseText).title; @@ -4482,7 +4595,7 @@ style: 'border: 0; width: auto; height: auto;', el: function() { return $.el('div', { - innerHTML: "" + innerHTML: "" }); } }, @@ -4505,8 +4618,8 @@ return div; }, title: { - api: function() { - return "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + this.name; + api: function(uid) { + return "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + uid; }, text: function() { return JSON.parse(this.responseText).title; @@ -4533,8 +4646,8 @@ }); }, title: { - api: function() { - return "https://api.github.com/gists/" + this.name; + api: function(uid) { + return "https://api.github.com/gists/" + uid; }, text: function() { var file, response; @@ -4556,76 +4669,6 @@ }); } } - }, - embedder: function(a) { - var callbacks, embed, key, match, service, titles, type, _ref; - - if (!Conf['Link Title']) { - return [a]; - } - titles = {}; - callbacks = function() { - var title; - - return a.textContent = (function() { - switch (this.status) { - case 200: - case 304: - title = "" + (service.text.call(this)); - embed.setAttribute('data-title', title); - titles[embed.name] = [title, Date.now()]; - $.set('CachedTitles', titles); - return title; - case 404: - return "[" + key + "] Not Found"; - case 403: - return "[" + key + "] Forbidden or Private"; - default: - return "[" + key + "] " + this.status + "'d"; - } - }).call(this); - }; - _ref = Linkify.types; - for (key in _ref) { - type = _ref[key]; - if (!(match = a.href.match(type.regExp))) { - continue; - } - embed = $.el('a', { - name: (a.name = match[1]), - option: match[2], - className: 'embedder', - href: 'javascript:;', - textContent: '(embed)' - }); - embed.setAttribute('data-service', key); - embed.setAttribute('data-originalURL', a.href); - $.addClass(a, "" + (embed.getAttribute('data-service'))); - $.on(embed, 'click', Linkify.toggle); - if (!Conf['Embedding']) { - embed.hidden = true; - } - if (Conf['Link Title'] && (service = type.title)) { - $.get('CachedTitles', {}, function(item) { - var err, title; - - titles = item['CachedTitles']; - if (title = titles[match[1]]) { - a.textContent = title[0]; - return embed.setAttribute('data-title', title[0]); - } else { - try { - return $.cache(service.api.call(a), callbacks); - } catch (_error) { - err = _error; - return a.innerHTML = "[" + key + "] Title Link Blocked (are you using NoScript?)"; - } - } - }); - } - return [a, $.tn(' '), embed]; - } - return [a]; } }; diff --git a/builds/crx/script.js b/builds/crx/script.js index b56ccc5f4..77e9eb973 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.2.24 - 2013-08-01 +* 4chan X - Version 1.2.24 - 2013-08-04 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -4302,122 +4302,235 @@ if (g.VIEW === 'catalog' || !Conf['Linkify']) { return; } - this.regString = Conf['Allow False Positives'] ? /(\b([a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]+|[-a-z0-9]+\.[a-z]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-z]{3,}:[a-z0-9?]|[a-z0-9._%+-:]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi; + this.regString = Conf['Allow False Positives'] ? /(\b([a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]|[a-z]{3,}:[a-z0-9?]|[\S]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi; if (Conf['Comment Expansion']) { ExpandComment.callbacks.push(this.node); } + if (Conf['Title Link']) { + $.sync('CachedTitles', Linkify.titleSync); + } return Post.prototype.callbacks.push({ name: 'Linkify', cb: this.node }); }, - cypher: $.el('div'), node: function() { - var a, child, cypher, cypherText, data, embed, embedder, embeds, i, index, len, link, links, lookahead, name, next, node, nodes, snapshot, spoiler, text, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2; + var data, embedder, i, len, node, range, snapshot, _i, _j, _len, _len1, _ref, _ref1; if (this.isClone && Conf['Embedding']) { _ref = $$('.embedder', this.nodes.comment); for (_i = 0, _len = _ref.length; _i < _len; _i++) { embedder = _ref[_i]; - $.on(embedder, "click", Linkify.toggle); + $.on(embedder, "click", Linkify.cb.toggle); } return; } snapshot = $.X('.//text()', this.nodes.comment); - cypher = Linkify.cypher; i = -1; len = snapshot.snapshotLength; while (++i < len) { - nodes = $.frag(); node = snapshot.snapshotItem(i); data = node.data; - if (!(node.parentNode && Linkify.regString.test(data))) { - continue; + if (Linkify.regString.test(data)) { + Linkify.regString.lastIndex = 0; + Linkify.gatherLinks(node, this); } - Linkify.regString.lastIndex = 0; - cypherText = []; - if (next = node.nextSibling) { - cypher.textContent = node.textContent; - cypherText[0] = cypher.innerHTML; - while ((next.nodeName.toLowerCase() === 'wbr' || next.nodeName.toLowerCase() === 's') && (lookahead = next.nextSibling) && ((name = lookahead.nodeName) === "#text" || name.toLowerCase() === 'br')) { - cypher.textContent = lookahead.textContent; - cypherText.push((spoiler = next.innerHTML) ? "" + (spoiler.replace(/" : ''); - cypherText.push(cypher.innerHTML); - $.rm(next); - next = lookahead.nextSibling; - if (lookahead.nodeName === "#text") { - $.rm(lookahead); - } - if (!next) { - break; - } - } - } - if (cypherText.length) { - data = cypherText.join(''); - } - links = data.match(Linkify.regString); - for (_j = 0, _len1 = links.length; _j < _len1; _j++) { - link = links[_j]; - index = data.indexOf(link); - if (text = data.slice(0, index)) { - cypher.innerHTML = text; - _ref1 = __slice.call(cypher.childNodes); - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - child = _ref1[_k]; - $.add(nodes, child); - } - } - cypher.innerHTML = (link.indexOf(':') < 0 ? (link.indexOf('@') > 0 ? 'mailto:' + link : 'http://' + link) : link).replace(/<(wbr|s|\/s)>/g, ''); - a = $.el('a', { - innerHTML: link, - className: 'linkify', - rel: 'nofollow noreferrer', - target: '_blank', - href: cypher.textContent - }); - $.add(nodes, Linkify.embedder(a)); - data = data.slice(index + link.length); - } - if (data) { - cypher.innerHTML = data; - _ref2 = __slice.call(cypher.childNodes); - for (_l = 0, _len3 = _ref2.length; _l < _len3; _l++) { - child = _ref2[_l]; - $.add(nodes, child); - } - } - $.replace(node, nodes); } - if (Conf['Auto-embed']) { - embeds = $$('.embedder', this.nodes.comment); - for (_m = 0, _len4 = embeds.length; _m < _len4; _m++) { - embed = embeds[_m]; - embed.click(); + if (!(Conf['Embedding'] || Conf['Link Title'])) { + return; + } + _ref1 = this.nodes.links; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + range = _ref1[_j]; + if (data = Linkify.services(range)) { + if (Conf['Embedding']) { + Linkify.embed(data); + } + if (Conf['Link Title']) { + Linkify.title(data); + } } } }, - toggle: function() { - var el, embed, style, type, url; + gatherLinks: function(node, post) { + var data, index, len, len2, link, links, match, range, _i, _len, _ref; + + data = node.data; + len = data.length; + links = []; + while ((match = Linkify.regString.exec(data))) { + index = match.index; + link = match[0]; + len2 = index + link.length; + if (len - len2 === 0) { + break; + } + range = document.createRange(); + range.setStart(node, index); + range.setEnd(node, len2); + links.push(range); + } + if (match) { + Linkify.seek(match, node, post); + } + _ref = links.reverse(); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + range = _ref[_i]; + Linkify.makeLink(range, post); + } + }, + seek: function(match, node, post) { + var data, index, link, next, range, result; + + index = match.index; + link = match[0]; + range = document.createRange(); + range.setStart(node, index); + while ((next = node.nextSibling) && next.nodeName !== 'BR') { + node = next; + data = node.data; + if (result = /[\s'"]/.exec(data)) { + range.setEnd(node, result.index); + } + } + if (range.collapsed) { + if (node.nodeName === 'WBR') { + node = node.previousSibling; + } + range.setEnd(node, node.length); + } + return Linkify.makeLink(range, post); + }, + makeLink: function(range, post) { + var a, link; + + link = range.toString(); + link = link.contains(':') ? link : (link.contains('@') ? 'mailto:' : 'http://') + link; + a = $.el('a', { + className: 'linkify', + rel: 'nofollow noreferrer', + target: '_blank', + href: link + }); + range.surroundContents(a); + post.nodes.links.push(a); + }, + services: function(link) { + var href, key, match, type, _ref; + + href = link.href; + _ref = Linkify.types; + for (key in _ref) { + type = _ref[key]; + if (!(match = type.regExp.exec(href))) { + continue; + } + return [key, match[1], match[2], link]; + } + }, + embed: function(data) { + var embed, key, link, options, uid; + + key = data[0], uid = data[1], options = data[2], link = data[3]; + embed = $.el('a', { + name: uid, + option: options, + className: 'embedder', + href: 'javascript:;', + textContent: '(embed)' + }); + embed.dataset.service = key; + embed.dataset.originalurl = link.href; + $.addClass(link, "" + embed.dataset.service); + $.on(embed, 'click', Linkify.cb.toggle); + return $.after(link, [$.tn(' '), embed]); + }, + title: function(data) { + var err, key, link, options, service, title, titles, uid; + + key = data[0], uid = data[1], options = data[2], link = data[3]; + if (!(service = Linkify.types[key].title)) { + return; + } + titles = Conf['CachedTitles']; + if (title = titles[uid]) { + link.textContent = title[0]; + if (Conf['Embedding']) { + return link.nextElementSibling.dataset.title = title[0]; + } + } else { + try { + $.cache(service.api(uid), function() { + return title = Linkify.cb.title.apply(this, [data]); + }); + } catch (_error) { + err = _error; + link.innerHTML = "[" + key + "] Title Link Blocked (are you using NoScript?)"; + return; + } + if (title) { + titles[uid] = [title, Date.now()]; + return $.set('CachedTitles', titles); + } + } + }, + titleSync: function(value) { + return Conf['CachedTitles'] = value; + }, + cb: { + toggle: function() { + var el, embed; + + embed = this.previousElementSibling; + el = !this.className.contains("embedded") ? Linkify.cb.embed(this) : Linkify.cb.unembed(this); + $.replace(embed, el); + return $.toggleClass(this, 'embedded'); + }, + embed: function(a) { + var el, style, type; + + el = (type = Linkify.types[a.dataset.service]).el.call(a); + el.style.cssText = (style = type.style) ? style : "border: 0; width: 640px; height: 390px"; + a.textContent = '(unembed)'; + return el; + }, + unembed: function(a) { + var el, url; - embed = this.previousElementSibling; - if (this.className.contains("embedded")) { el = $.el('a', { rel: 'nofollow noreferrer', target: 'blank', className: 'linkify', - href: url = this.getAttribute("data-originalURL"), - textContent: this.getAttribute("data-title") || url + href: url = a.dataset.originalurl, + textContent: a.dataset.title || url }); - this.textContent = '(embed)'; - $.addClass(el, "" + (this.getAttribute('data-service'))); - } else { - el = (type = Linkify.types[this.getAttribute("data-service")]).el.call(this); - el.style.cssText = (style = type.style) ? style : "border: 0; width: 640px; height: 390px"; - this.textContent = '(unembed)'; + a.textContent = '(embed)'; + $.addClass(el, "" + a.dataset.service); + return el; + }, + title: function(data) { + var key, link, options, service, text, uid; + + key = data[0], uid = data[1], options = data[2], link = data[3]; + service = Linkify.types[key].title; + return link.textContent = (function() { + switch (this.status) { + case 200: + case 304: + text = "" + (service.text.call(this)); + if (Conf['Embedding']) { + link.nextElementSibling.dataset.title = text; + } + return text; + case 404: + return "[" + key + "] Not Found"; + case 403: + return "[" + key + "] Forbidden or Private"; + default: + return "[" + key + "] " + this.status + "'d"; + } + }).call(this); } - $.replace(embed, el); - return $.toggleClass(this, 'embedded'); }, types: { YouTube: { @@ -4428,8 +4541,8 @@ }); }, title: { - api: function() { - return "https://gdata.youtube.com/feeds/api/videos/" + this.name + "?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode"; + api: function(uid) { + return "https://gdata.youtube.com/feeds/api/videos/" + uid + "?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode"; }, text: function() { return JSON.parse(this.responseText).entry.title.$t; @@ -4453,8 +4566,8 @@ }); }, title: { - api: function() { - return "https://vimeo.com/api/oembed.json?url=http://vimeo.com/" + this.name; + api: function(uid) { + return "https://vimeo.com/api/oembed.json?url=http://vimeo.com/" + uid; }, text: function() { return JSON.parse(this.responseText).title; @@ -4484,7 +4597,7 @@ style: 'border: 0; width: auto; height: auto;', el: function() { return $.el('div', { - innerHTML: "" + innerHTML: "" }); } }, @@ -4507,8 +4620,8 @@ return div; }, title: { - api: function() { - return "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + this.name; + api: function(uid) { + return "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + uid; }, text: function() { return JSON.parse(this.responseText).title; @@ -4535,8 +4648,8 @@ }); }, title: { - api: function() { - return "https://api.github.com/gists/" + this.name; + api: function(uid) { + return "https://api.github.com/gists/" + uid; }, text: function() { var file, response; @@ -4558,76 +4671,6 @@ }); } } - }, - embedder: function(a) { - var callbacks, embed, key, match, service, titles, type, _ref; - - if (!Conf['Link Title']) { - return [a]; - } - titles = {}; - callbacks = function() { - var title; - - return a.textContent = (function() { - switch (this.status) { - case 200: - case 304: - title = "" + (service.text.call(this)); - embed.setAttribute('data-title', title); - titles[embed.name] = [title, Date.now()]; - $.set('CachedTitles', titles); - return title; - case 404: - return "[" + key + "] Not Found"; - case 403: - return "[" + key + "] Forbidden or Private"; - default: - return "[" + key + "] " + this.status + "'d"; - } - }).call(this); - }; - _ref = Linkify.types; - for (key in _ref) { - type = _ref[key]; - if (!(match = a.href.match(type.regExp))) { - continue; - } - embed = $.el('a', { - name: (a.name = match[1]), - option: match[2], - className: 'embedder', - href: 'javascript:;', - textContent: '(embed)' - }); - embed.setAttribute('data-service', key); - embed.setAttribute('data-originalURL', a.href); - $.addClass(a, "" + (embed.getAttribute('data-service'))); - $.on(embed, 'click', Linkify.toggle); - if (!Conf['Embedding']) { - embed.hidden = true; - } - if (Conf['Link Title'] && (service = type.title)) { - $.get('CachedTitles', {}, function(item) { - var err, title; - - titles = item['CachedTitles']; - if (title = titles[match[1]]) { - a.textContent = title[0]; - return embed.setAttribute('data-title', title[0]); - } else { - try { - return $.cache(service.api.call(a), callbacks); - } catch (_error) { - err = _error; - return a.innerHTML = "[" + key + "] Title Link Blocked (are you using NoScript?)"; - } - } - }); - } - return [a, $.tn(' '), embed]; - } - return [a]; } }; diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 776cb059e..4938a532c 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -2,20 +2,20 @@ Linkify = init: -> return if g.VIEW is 'catalog' or not Conf['Linkify'] - @regString = if Conf['Allow False Positives'] + @regString = if Conf['Allow False Positives'] ///( \b( [a-z]+:// | - [a-z]{3,}\.[-a-z0-9]+\.[a-z]+ + [a-z]{3,}\.[-a-z0-9]+\.[a-z] | [-a-z0-9]+\.[a-z] | - [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ + [0-9]+\.[0-9]+\.[0-9]+\.[0-9] | [a-z]{3,}:[a-z0-9?] | - [a-z0-9._%+-:]+@[a-z0-9.-]+\.[a-z0-9] + [\S]+@[a-z0-9.-]+\.[a-z0-9] ) [^\s'"]+ )///gi @@ -25,115 +25,170 @@ Linkify = if Conf['Comment Expansion'] ExpandComment.callbacks.push @node + if Conf['Title Link'] + $.sync 'CachedTitles', Linkify.titleSync + Post::callbacks.push name: 'Linkify' cb: @node - cypher: $.el 'div' - node: -> if @isClone and Conf['Embedding'] for embedder in $$ '.embedder', @nodes.comment - $.on embedder, "click", Linkify.toggle + $.on embedder, "click", Linkify.cb.toggle return + snapshot = $.X './/text()', @nodes.comment - cypher = Linkify.cypher - i = -1 - len = snapshot.snapshotLength + i = -1 + len = snapshot.snapshotLength while ++i < len - nodes = $.frag() - node = snapshot.snapshotItem i - data = node.data + node = snapshot.snapshotItem i + data = node.data - # Test for valid links + if Linkify.regString.test data + Linkify.regString.lastIndex = 0 + Linkify.gatherLinks node, @ - continue unless node.parentNode and Linkify.regString.test data + return unless Conf['Embedding'] or Conf['Link Title'] - Linkify.regString.lastIndex = 0 + for range in @nodes.links + if data = Linkify.services range + Linkify.embed data if Conf['Embedding'] + Linkify.title data if Conf['Link Title'] - cypherText = [] - - if next = node.nextSibling - cypher.textContent = node.textContent - cypherText[0] = cypher.innerHTML - - while (next.nodeName.toLowerCase() is 'wbr' or next.nodeName.toLowerCase() is 's') and (lookahead = next.nextSibling) and ((name = lookahead.nodeName) is "#text" or name.toLowerCase() is 'br') - cypher.textContent = lookahead.textContent - - cypherText.push if spoiler = next.innerHTML then "#{spoiler.replace /" else '' - cypherText.push cypher.innerHTML - - $.rm next - next = lookahead.nextSibling - $.rm lookahead if lookahead.nodeName is "#text" - - unless next - break - - if cypherText.length - data = cypherText.join '' - - links = data.match Linkify.regString - - for link in links - index = data.indexOf link - - if text = data[...index] - # press button get bacon - cypher.innerHTML = text - for child in [cypher.childNodes...] - $.add nodes, child - - cypher.innerHTML = (if link.indexOf(':') < 0 then (if link.indexOf('@') > 0 then 'mailto:' + link else 'http://' + link) else link).replace /<(wbr|s|\/s)>/g, '' - - a = $.el 'a', - innerHTML: link - className: 'linkify' - rel: 'nofollow noreferrer' - target: '_blank' - href: cypher.textContent - - $.add nodes, Linkify.embedder a - - data = data[index + link.length..] - - if data - # Potential text after the last valid link. - cypher.innerHTML = data - - # Convert into elements - for child in [cypher.childNodes...] - $.add nodes, child - - $.replace node, nodes - - if Conf['Auto-embed'] - embeds = $$ '.embedder', @nodes.comment - for embed in embeds - embed.click() return - toggle: -> - # We setup the link to be replaced by the embedded video - embed = @previousElementSibling + gatherLinks: (node, post) -> + {data} = node + len = data.length + links = [] - # Unembed. - if @className.contains "embedded" - # Recreate the original link. - el = $.el 'a', - rel: 'nofollow noreferrer' - target: 'blank' - className: 'linkify' - href: url = @getAttribute("data-originalURL") - textContent: @getAttribute("data-title") or url + while (match = Linkify.regString.exec data) + {index} = match + link = match[0] + len2 = index + link.length - @textContent = '(embed)' - $.addClass el, "#{@getAttribute 'data-service'}" + break if len - len2 is 0 + range = document.createRange(); + range.setStart node, index + range.setEnd node, len2 + links.push range + + if match + Linkify.seek match, node, post + + for range in links.reverse() + Linkify.makeLink range, post + + return + + seek: (match, node, post) -> + {index} = match + link = match[0] + range = document.createRange() + range.setStart node, index + + while (next = node.nextSibling) and next.nodeName isnt 'BR' + node = next + data = node.data + if result = /[\s'"]/.exec data + range.setEnd node, result.index + + if range.collapsed + if node.nodeName is 'WBR' + node = node.previousSibling + range.setEnd node, node.length + + Linkify.makeLink range, post + + makeLink: (range, post) -> + link = range.toString() + link = + if link.contains ':' + link + else ( + if link.contains '@' + 'mailto:' + else + 'http://' + ) + link + + a = $.el 'a', + className: 'linkify' + rel: 'nofollow noreferrer' + target: '_blank' + href: link + range.surroundContents a + post.nodes.links.push a + return + + services: (link) -> + href = link.href + + for key, type of Linkify.types + continue unless match = type.regExp.exec href + return [key, match[1], match[2], link] + + return + + embed: (data) -> + [key, uid, options, link] = data + embed = $.el 'a', + name: uid + option: options + className: 'embedder' + href: 'javascript:;' + textContent: '(embed)' + + embed.dataset.service = key + embed.dataset.originalurl = link.href + + $.addClass link, "#{embed.dataset.service}" + + $.on embed, 'click', Linkify.cb.toggle + $.after link, [$.tn(' '), embed] + + title: (data) -> + [key, uid, options, link] = data + return unless service = Linkify.types[key].title + titles = Conf['CachedTitles'] + if title = titles[uid] + link.textContent = title[0] + if Conf['Embedding'] + link.nextElementSibling.dataset.title = title[0] else + try + $.cache service.api(uid), -> + title = Linkify.cb.title.apply @, [data] + catch err + link.innerHTML = "[#{key}] Title Link Blocked (are you using NoScript?)" + return + if title + titles[uid] = [title, Date.now()] + $.set 'CachedTitles', titles + + titleSync: (value) -> + Conf['CachedTitles'] = value + + cb: + toggle: -> + # We setup the link to be replaced by the embedded video + embed = @previousElementSibling + + # Unembed. + el = unless @className.contains "embedded" + Linkify.cb.embed @ + else + Linkify.cb.unembed @ + + $.replace embed, el + $.toggleClass @, 'embedded' + + embed: (a) -> # We create an element to embed - el = (type = Linkify.types[@getAttribute("data-service")]).el.call @ + el = (type = Linkify.types[a.dataset.service]).el.call a # Set style values. el.style.cssText = if style = type.style @@ -141,10 +196,39 @@ Linkify = else "border: 0; width: 640px; height: 390px" - @textContent = '(unembed)' + a.textContent = '(unembed)' - $.replace embed, el - $.toggleClass @, 'embedded' + return el + + unembed: (a) -> + # Recreate the original link. + el = $.el 'a', + rel: 'nofollow noreferrer' + target: 'blank' + className: 'linkify' + href: url = a.dataset.originalurl + textContent: a.dataset.title or url + + a.textContent = '(embed)' + $.addClass el, "#{a.dataset.service}" + + return el + + title: (data) -> + [key, uid, options, link] = data + service = Linkify.types[key].title + link.textContent = switch @status + when 200, 304 + text = "#{service.text.call @}" + if Conf['Embedding'] + link.nextElementSibling.dataset.title = text + text + when 404 + "[#{key}] Not Found" + when 403 + "[#{key}] Forbidden or Private" + else + "[#{key}] #{@status}'d" types: YouTube: @@ -153,7 +237,7 @@ Linkify = $.el 'iframe', src: "//www.youtube.com/embed/#{@name}#{if @option then '#' + @option else ''}?wmode=opaque" title: - api: -> "https://gdata.youtube.com/feeds/api/videos/#{@name}?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode" + api: (uid) -> "https://gdata.youtube.com/feeds/api/videos/#{uid}?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode" text: -> JSON.parse(@responseText).entry.title.$t Vocaroo: @@ -169,7 +253,7 @@ Linkify = $.el 'iframe', src: "//player.vimeo.com/video/#{@name}?wmode=opaque" title: - api: -> "https://vimeo.com/api/oembed.json?url=http://vimeo.com/#{@name}" + api: (uid) -> "https://vimeo.com/api/oembed.json?url=http://vimeo.com/#{uid}" text: -> JSON.parse(@responseText).title LiveLeak: @@ -191,7 +275,7 @@ Linkify = style: 'border: 0; width: auto; height: auto;' el: -> $.el 'div', - innerHTML: "" + innerHTML: "" SoundCloud: regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/ @@ -208,7 +292,7 @@ Linkify = false) div title: - api: -> "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/#{@name}" + api: (uid) -> "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/#{uid}" text: -> JSON.parse(@responseText).title pastebin: @@ -224,7 +308,7 @@ Linkify = # Github doesn't allow embedding straight from the site, so we use an external site to bypass that. src: "http://www.purplegene.com/script?url=https://gist.github.com/#{@name}.js" title: - api: -> "https://api.github.com/gists/#{@name}" + api: (uid) -> "https://api.github.com/gists/#{uid}" text: -> response = JSON.parse(@responseText).files return file for file of response when response.hasOwnProperty file @@ -233,57 +317,4 @@ Linkify = regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/ el: -> $.el 'iframe', - src: "http://paste.installgentoo.com/view/embed/#{@name}" - - embedder: (a) -> - return [a] unless Conf['Link Title'] - titles = {} - - callbacks = -> - a.textContent = switch @status - when 200, 304 - title = "#{service.text.call @}" - embed.setAttribute 'data-title', title - titles[embed.name] = [title, Date.now()] - $.set 'CachedTitles', titles - title - when 404 - "[#{key}] Not Found" - when 403 - "[#{key}] Forbidden or Private" - else - "[#{key}] #{@status}'d" - - for key, type of Linkify.types - continue unless match = a.href.match type.regExp - - embed = $.el 'a', - name: (a.name = match[1]) - option: match[2] - className: 'embedder' - href: 'javascript:;' - textContent: '(embed)' - - embed.setAttribute 'data-service', key - embed.setAttribute 'data-originalURL', a.href - $.addClass a, "#{embed.getAttribute 'data-service'}" - - $.on embed, 'click', Linkify.toggle - - unless Conf['Embedding'] - embed.hidden = true - - if Conf['Link Title'] and (service = type.title) - $.get 'CachedTitles', {}, (item) -> - titles = item['CachedTitles'] - if title = titles[match[1]] - a.textContent = title[0] - embed.setAttribute 'data-title', title[0] - else - try - $.cache service.api.call(a), callbacks - catch err - a.innerHTML = "[#{key}] Title Link Blocked (are you using NoScript?)" - - return [a, $.tn(' '), embed] - return [a] \ No newline at end of file + src: "http://paste.installgentoo.com/view/embed/#{@name}" \ No newline at end of file From b60ddfe9075b1c1c379f3785e399b2f5f2854fa8 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Sun, 4 Aug 2013 18:55:10 -0700 Subject: [PATCH 18/20] I think this is safer. --- builds/4chan-X.user.js | 2 +- builds/crx/script.js | 2 +- src/Linkification/Linkify.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 8eafa30f9..2be937096 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -4300,7 +4300,7 @@ if (g.VIEW === 'catalog' || !Conf['Linkify']) { return; } - this.regString = Conf['Allow False Positives'] ? /(\b([a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]|[a-z]{3,}:[a-z0-9?]|[\S]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi; + this.regString = Conf['Allow False Positives'] ? /(\b([a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]|[a-z]{3,}:[a-z0-9?]|[^\s@]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi; if (Conf['Comment Expansion']) { ExpandComment.callbacks.push(this.node); } diff --git a/builds/crx/script.js b/builds/crx/script.js index 77e9eb973..c2be42ede 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -4302,7 +4302,7 @@ if (g.VIEW === 'catalog' || !Conf['Linkify']) { return; } - this.regString = Conf['Allow False Positives'] ? /(\b([a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]|[a-z]{3,}:[a-z0-9?]|[\S]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi; + this.regString = Conf['Allow False Positives'] ? /(\b([a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]|[a-z]{3,}:[a-z0-9?]|[^\s@]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi; if (Conf['Comment Expansion']) { ExpandComment.callbacks.push(this.node); } diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 4938a532c..599a11245 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -15,7 +15,7 @@ Linkify = | [a-z]{3,}:[a-z0-9?] | - [\S]+@[a-z0-9.-]+\.[a-z0-9] + [^\s@]+@[a-z0-9.-]+\.[a-z0-9] ) [^\s'"]+ )///gi From f41a40c1ad564beee56f6d53857bd70eb7eb2c61 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Sun, 4 Aug 2013 19:47:07 -0700 Subject: [PATCH 19/20] Forgot to add links to the post datatype --- builds/4chan-X.user.js | 1 + builds/crx/script.js | 1 + src/General/lib/post.class | 1 + 3 files changed, 3 insertions(+) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index d82d9b6d6..04d7f5e66 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -904,6 +904,7 @@ post: post, info: info, comment: $('.postMessage', post), + links: [], quotelinks: [], backlinks: info.getElementsByClassName('backlink') }; diff --git a/builds/crx/script.js b/builds/crx/script.js index fbb0c45b9..4f2213b40 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -915,6 +915,7 @@ post: post, info: info, comment: $('.postMessage', post), + links: [], quotelinks: [], backlinks: info.getElementsByClassName('backlink') }; diff --git a/src/General/lib/post.class b/src/General/lib/post.class index 57fdddcf2..2b5c26aa4 100644 --- a/src/General/lib/post.class +++ b/src/General/lib/post.class @@ -13,6 +13,7 @@ class Post post: post info: info comment: $ '.postMessage', post + links: [] quotelinks: [] backlinks: info.getElementsByClassName 'backlink' From 37cf68f43d6244b2647c088c091a06c1f668d368 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Sun, 4 Aug 2013 19:54:56 -0700 Subject: [PATCH 20/20] Update changelog --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1f993ec..0a3c64220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,18 @@ **MayhemYDG**: - 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. +- Minor optimizations. +- Minor fixes. + +**aeosynth**: +- Update Gruntfile.coffee. ### v1.2.25 *2013-08-04*