Merge branch 'v3' into Av2
Conflicts: appchan-x.meta.js appchan-x.user.js css/style.css package.json src/features.coffee src/globals.coffee
@ -3,10 +3,10 @@
|
||||
1. Make sure both your **browser** and **4chan X** are up to date.
|
||||
2. Disable your other extensions & scripts to identify conflicts.
|
||||
3. If your issue persists, open a [new issue](https://github.com/MayhemYDG/4chan-x/issues) with the following information:
|
||||
1. Report precise steps to reproduce the problem.
|
||||
2. Report console errors, if any.
|
||||
3. Report browser version.
|
||||
4. Include your exported settings.
|
||||
1. Precise steps to reproduce the problem.
|
||||
2. Console errors, if any.
|
||||
3. Browser version.
|
||||
4. Your exported settings.
|
||||
|
||||
Open your console with:
|
||||
- `Ctrl + Shift + J` on Chrome.
|
||||
|
||||
124
Gruntfile.coffee
@ -24,31 +24,18 @@ module.exports = (grunt) ->
|
||||
]
|
||||
dest: 'tmp/script.coffee'
|
||||
|
||||
manifest:
|
||||
options:
|
||||
process:
|
||||
data: pkg
|
||||
src: 'src/manifest.json',
|
||||
dest: 'builds/crx/manifest.json'
|
||||
|
||||
metadata:
|
||||
options:
|
||||
process:
|
||||
data: pkg
|
||||
src: 'src/metadata.js',
|
||||
dest: '<%= pkg.name %>.meta.js'
|
||||
|
||||
crx:
|
||||
options:
|
||||
process:
|
||||
data: pkg
|
||||
src: [
|
||||
'src/banner.js'
|
||||
'tmp/script.js'
|
||||
]
|
||||
dest: 'builds/crx/script.js'
|
||||
files:
|
||||
'builds/crx/manifest.json': 'src/manifest.json'
|
||||
'builds/crx/script.js': [
|
||||
'src/banner.js'
|
||||
'tmp/script.js'
|
||||
]
|
||||
|
||||
userscript:
|
||||
userjs:
|
||||
options:
|
||||
process:
|
||||
data: pkg
|
||||
@ -57,13 +44,27 @@ module.exports = (grunt) ->
|
||||
'src/banner.js'
|
||||
'tmp/script.js'
|
||||
]
|
||||
dest: '<%= pkg.name %>.user.js'
|
||||
|
||||
userjs:
|
||||
# Lazily copy the userscript
|
||||
src: '<%= pkg.name %>.user.js'
|
||||
dest: 'builds/<%= pkg.name %>.js'
|
||||
|
||||
userscript:
|
||||
options:
|
||||
process:
|
||||
data: pkg
|
||||
files:
|
||||
'<%= pkg.name %>.meta.js': 'src/metadata.js'
|
||||
'<%= pkg.name %>.user.js': [
|
||||
'src/metadata.js'
|
||||
'src/banner.js'
|
||||
'tmp/script.js'
|
||||
]
|
||||
|
||||
copy:
|
||||
crx:
|
||||
src: 'img/*.png'
|
||||
dest: 'builds/crx/'
|
||||
expand: true
|
||||
flatten: true
|
||||
|
||||
coffee:
|
||||
script:
|
||||
src: 'tmp/script.coffee'
|
||||
@ -90,35 +91,73 @@ module.exports = (grunt) ->
|
||||
options:
|
||||
interrupt: true
|
||||
files: [
|
||||
'Gruntfile.js'
|
||||
'Gruntfile.coffee'
|
||||
'package.json'
|
||||
'lib/**/*.coffee'
|
||||
'src/**/*.coffee'
|
||||
'src/**/*.js'
|
||||
'css/**/*.css'
|
||||
'img/*'
|
||||
'lib/**/*'
|
||||
'src/**/*'
|
||||
'css/**/*'
|
||||
'img/**/*'
|
||||
]
|
||||
tasks: 'default'
|
||||
tasks: 'build'
|
||||
|
||||
compress:
|
||||
crx:
|
||||
options:
|
||||
archive: 'builds/4chan-X.zip'
|
||||
level: 9
|
||||
pretty: true
|
||||
expand: true
|
||||
cwd: 'builds/crx/'
|
||||
src: '**'
|
||||
|
||||
clean:
|
||||
tmp: 'tmp'
|
||||
builds: 'builds'
|
||||
tmp: 'tmp'
|
||||
|
||||
grunt.loadNpmTasks 'grunt-bump'
|
||||
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-exec'
|
||||
|
||||
grunt.registerTask 'default', [
|
||||
'concat:coffee',
|
||||
'coffee:script',
|
||||
'concat:manifest',
|
||||
'concat:crx',
|
||||
'concat:userscript',
|
||||
'concat:userjs',
|
||||
'concat:metadata',
|
||||
'clean'
|
||||
grunt.registerTask 'default', ['build']
|
||||
|
||||
grunt.registerTask 'set-build', 'Set the build type variable', (type) ->
|
||||
pkg.type = type;
|
||||
grunt.log.ok 'pkg.type = %s', type
|
||||
|
||||
grunt.registerTask 'build', [
|
||||
'build-crx'
|
||||
'build-userjs'
|
||||
'build-userscript'
|
||||
]
|
||||
|
||||
grunt.registerTask 'build-crx', [
|
||||
'set-build:crx'
|
||||
'concat:coffee'
|
||||
'coffee:script'
|
||||
'concat:crx'
|
||||
'copy:crx'
|
||||
'clean:tmp'
|
||||
]
|
||||
|
||||
grunt.registerTask 'build-userjs', [
|
||||
'set-build:userjs'
|
||||
'concat:coffee'
|
||||
'coffee:script'
|
||||
'concat:userjs'
|
||||
'clean:tmp'
|
||||
]
|
||||
|
||||
grunt.registerTask 'build-userscript', [
|
||||
'set-build:userscript'
|
||||
'concat:coffee'
|
||||
'coffee:script'
|
||||
'concat:userscript'
|
||||
'clean:tmp'
|
||||
]
|
||||
|
||||
grunt.registerTask 'release', [
|
||||
@ -141,6 +180,7 @@ module.exports = (grunt) ->
|
||||
'bump:major'
|
||||
'updcl:1'
|
||||
]
|
||||
|
||||
grunt.registerTask 'updcl', 'Update the changelog', (i) ->
|
||||
# Update the `pkg` object with the new version.
|
||||
pkg = grunt.file.readJSON('package.json');
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# 4chan X
|
||||
|
||||
Get it [here](http://mayhemydg.github.com/4chan-x/).
|
||||
Get it [here](https://4chan-x.just-believe.in/).
|
||||
|
||||
***
|
||||
|
||||
### [MIT License](/4chan-x/blob/master/LICENSE)
|
||||
### [Contribute](/4chan-x/blob/master/CONTRIBUTING.md)
|
||||
### [MIT License](/LICENSE)
|
||||
### [Contribute](/CONTRIBUTING.md)
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
// @grant GM_deleteValue
|
||||
// @grant GM_openInTab
|
||||
// @run-at document-start
|
||||
// @updateURL https://github.com/zixaphir/appchan-x/raw/Av2/appchan-x.meta.js
|
||||
// @downloadURL https://github.com/zixaphir/appchan-x/raw/Av2/appchan-x.user.js
|
||||
// @icon data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAIALAAAAAAQABAAAAIxlI+pq+D9DAgUoFkPDlbs7lGiI2bSVnKglnJMOL6omczxVZK3dH/41AG6Lh7i6qUoAAA7
|
||||
// @updateURL http://zixaphir.github.com/appchan-x/builds/appchan-x.meta.js
|
||||
// @downloadURL http://zixaphir.github.com/appchan-x/builds/appchan-x.user.js
|
||||
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC
|
||||
// ==/UserScript==
|
||||
|
||||
@ -15,12 +15,12 @@
|
||||
// @grant GM_deleteValue
|
||||
// @grant GM_openInTab
|
||||
// @run-at document-start
|
||||
// @updateURL https://github.com/zixaphir/appchan-x/raw/Av2/appchan-x.meta.js
|
||||
// @downloadURL https://github.com/zixaphir/appchan-x/raw/Av2/appchan-x.user.js
|
||||
// @icon data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAIALAAAAAAQABAAAAIxlI+pq+D9DAgUoFkPDlbs7lGiI2bSVnKglnJMOL6omczxVZK3dH/41AG6Lh7i6qUoAAA7
|
||||
// @updateURL http://zixaphir.github.com/appchan-x/builds/appchan-x.meta.js
|
||||
// @downloadURL http://zixaphir.github.com/appchan-x/builds/appchan-x.user.js
|
||||
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC
|
||||
// ==/UserScript==
|
||||
|
||||
/* appchan x - Version 2.0.0 - 2013-03-20
|
||||
/* appchan x - Version 2.0.0 - 2013-03-28
|
||||
* http://zixaphir.github.com/appchan-x/
|
||||
*
|
||||
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
@ -54,16 +54,15 @@
|
||||
'Catalog Links': [true, 'Turn Navigation links into links to each board\'s catalog.'],
|
||||
'External Catalog': [false, 'Link to external catalog instead of the internal one.'],
|
||||
'Enable 4chan\'s Extension': [false, 'Compatibility between appchan x and 4chan\'s inline extension is NOT guaranteed.'],
|
||||
'Custom Board Navigation': [true, 'Disable this to always display the full board list.'],
|
||||
'Custom Board Navigation': [true, 'Show custom links instead of the full board list.'],
|
||||
'404 Redirect': [true, 'Redirect dead threads and images.'],
|
||||
'Keybinds': [true, 'Bind actions to keyboard shortcuts.'],
|
||||
'Time Formatting': [true, 'Localize and format timestamps arbitrarily.'],
|
||||
'Time Formatting': [true, 'Localize and format timestamps.'],
|
||||
'Relative Post Dates': [false, 'Display dates like "3 minutes ago". Tooltip shows the timestamp.'],
|
||||
'File Info Formatting': [true, 'Reformat the file information.'],
|
||||
'Comment Expansion': [true, 'Can expand too long comments.'],
|
||||
'Thread Expansion': [true, 'Can expand threads to view all replies.'],
|
||||
'Index Navigation': [false, 'Navigate to previous / next thread.'],
|
||||
'Custom CSS': [false, 'Apply custom CSS to 4chan.'],
|
||||
'Comment Expansion': [true, 'Add buttons to expand long comments.'],
|
||||
'Thread Expansion': [true, 'Add buttons to expand threads.'],
|
||||
'Index Navigation': [false, 'Add buttons to navigate between threads.'],
|
||||
'Check for Updates': [true, 'Check for updated versions of appchan x.']
|
||||
},
|
||||
'Linkification': {
|
||||
@ -72,13 +71,13 @@
|
||||
'Link Title': [true, 'Replace the link of a supported site with its actual title. Currently Supported: YouTube, Vimeo, SoundCloud']
|
||||
},
|
||||
'Filtering': {
|
||||
'Anonymize': [false, 'Turn everyone Anonymous.'],
|
||||
'Anonymize': [false, 'Make everyone Anonymous.'],
|
||||
'Filter': [true, 'Self-moderation placebo.'],
|
||||
'Recursive Hiding': [true, 'Hide replies of hidden posts, recursively.'],
|
||||
'Thread Hiding': [true, 'Hide entire threads.'],
|
||||
'Reply Hiding': [true, 'Hide single replies.'],
|
||||
'Hiding Buttons': [true, 'Make buttons to hide threads / replies, in addition to menu links.'],
|
||||
'Stubs': [true, 'Make stubs of hidden threads / replies.']
|
||||
'Thread Hiding': [true, 'Add buttons to hide entire threads.'],
|
||||
'Reply Hiding': [true, 'Add buttons to hide single replies.'],
|
||||
'Hiding Buttons': [true, 'Add buttons to hide threads / replies, in addition to menu links.'],
|
||||
'Stubs': [true, 'Show stubs of hidden threads / replies.']
|
||||
},
|
||||
'Images': {
|
||||
'Image Expansion': [true, 'Expand images.'],
|
||||
@ -90,7 +89,9 @@
|
||||
'Replace JPG': [false, 'Replace jpgs.']
|
||||
},
|
||||
'Menu': {
|
||||
'Menu': [true, 'Add a drop-down menu in posts.'],
|
||||
'Menu': [true, 'Add a drop-down menu to posts.'],
|
||||
'Thread Hiding Link': [true, 'Add a link to hide entire threads.'],
|
||||
'Reply Hiding Link': [true, 'Add a link to hide single replies.'],
|
||||
'Report Link': [true, 'Add a report link to the menu.'],
|
||||
'Delete Link': [true, 'Add post and image deletion links to the menu.'],
|
||||
'Download Link': [true, 'Add a download with original filename link to the menu. Chrome-only currently.'],
|
||||
@ -116,7 +117,7 @@
|
||||
'Remember Spoiler': [false, 'Remember the spoiler state, instead of resetting after posting.'],
|
||||
'Hide Original Post Form': [true, 'Hide the normal post form.']
|
||||
},
|
||||
'Quote links': {
|
||||
'Quote Links': {
|
||||
'Quote Backlinks': [true, 'Add quote backlinks.'],
|
||||
'OP Backlinks': [false, 'Add backlinks to the OP.'],
|
||||
'Quote Inlining': [true, 'Inline quoted post on click.'],
|
||||
@ -238,7 +239,8 @@
|
||||
filesize: '',
|
||||
MD5: ''
|
||||
},
|
||||
sauces: "http://iqdb.org/?url=%turl\nhttp://www.google.com/searchbyimage?image_url=%turl\n#http://tineye.com/search?url=%turl\n#http://saucenao.com/search.php?db=999&url=%turl\n#http://3d.iqdb.org/?url=%turl\n#http://regex.info/exif.cgi?imgurl=%url\n# uploaders:\n#http://imgur.com/upload?url=%url;text:Upload to imgur\n#http://omploader.org/upload?url1=%url;text:Upload to omploader\n# \"View Same\" in archives:\n#//archive.foolz.us/_/search/image/%MD5/;text:View same on foolz\n#//archive.foolz.us/%board/search/image/%MD5/;text:View same on foolz /%board/\n#//archive.installgentoo.net/%board/image/%MD5;text:View same on installgentoo /%board/",
|
||||
sauces: "http://iqdb.org/?url=%TURL\nhttps://www.google.com/searchbyimage?image_url=%TURL\n#//tineye.com/search?url=%TURL\n#http://saucenao.com/search.php?url=%TURL\n#http://3d.iqdb.org/?url=%TURL\n#http://regex.info/exif.cgi?imgurl=%URL\n# uploaders:\n#http://imgur.com/upload?url=%URL;text:Upload to imgur\n#http://ompldr.org/upload?url1=%URL;text:Upload to ompldr\n# \"View Same\" in archives:\n#//archive.foolz.us/_/search/image/%MD5/;text:View same on foolz\n#//archive.foolz.us/%board/search/image/%MD5/;text:View same on foolz /%board/\n#//archive.installgentoo.net/%board/image/%MD5;text:View same on installgentoo /%board/",
|
||||
'Custom CSS': false,
|
||||
'Header auto-hide': false,
|
||||
'Header catalog links': false,
|
||||
boardnav: '[ toggle-all ] [current-title]',
|
||||
@ -292,10 +294,6 @@
|
||||
mascot: ''
|
||||
};
|
||||
|
||||
if (!/^[a-z]+\.4chan\.org$/.test(location.hostname)) {
|
||||
return;
|
||||
}
|
||||
|
||||
editTheme = {};
|
||||
|
||||
editMascot = {};
|
||||
@ -308,7 +306,7 @@
|
||||
|
||||
d = document;
|
||||
|
||||
doc = null;
|
||||
doc = d.documentElement;
|
||||
|
||||
g = {
|
||||
VERSION: '2.0.0',
|
||||
@ -2913,7 +2911,7 @@
|
||||
$.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000)));
|
||||
|
||||
$.extend($, {
|
||||
engine: /WebKit|Presto|Gecko/.exec(navigator.userAgent)[0].toLowerCase(),
|
||||
engine: 'gecko',
|
||||
id: function(id) {
|
||||
return d.getElementById(id);
|
||||
},
|
||||
@ -3208,16 +3206,9 @@
|
||||
script = $.el('script', {
|
||||
textContent: code
|
||||
});
|
||||
$.add(d.head, script);
|
||||
$.add(d.head || doc, script);
|
||||
return $.rm(script);
|
||||
},
|
||||
unsafeWindow: window.opera ? window : typeof unsafeWindow !== "undefined" && unsafeWindow !== null ? unsafeWindow : (function() {
|
||||
var p;
|
||||
|
||||
p = d.createElement('p');
|
||||
p.setAttribute('onclick', 'return window');
|
||||
return p.onclick();
|
||||
})(),
|
||||
bytesToString: function(size) {
|
||||
var unit;
|
||||
|
||||
@ -3228,70 +3219,37 @@
|
||||
}
|
||||
size = unit > 1 ? Math.round(size * 100) / 100 : Math.round(size);
|
||||
return "" + size + " " + ['B', 'KB', 'MB', 'GB'][unit];
|
||||
},
|
||||
"delete": function(key) {
|
||||
var keys, _i, _len;
|
||||
|
||||
if (!(keys instanceof Array)) {
|
||||
keys = [keys];
|
||||
}
|
||||
for (_i = 0, _len = keys.length; _i < _len; _i++) {
|
||||
key = keys[_i];
|
||||
key = g.NAMESPACE + key;
|
||||
localStorage.removeItem(key);
|
||||
GM_deleteValue(key);
|
||||
}
|
||||
},
|
||||
get: function(key, defaultVal) {
|
||||
var val;
|
||||
|
||||
if (val = GM_getValue(g.NAMESPACE + key)) {
|
||||
return JSON.parse(val);
|
||||
} else {
|
||||
return defaultVal;
|
||||
}
|
||||
},
|
||||
set: function(key, val) {
|
||||
key = g.NAMESPACE + key;
|
||||
val = JSON.stringify(val);
|
||||
localStorage.setItem(key, val);
|
||||
return GM_setValue(key, val);
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof GM_deleteValue !== "undefined" && GM_deleteValue !== null) {
|
||||
$["delete"] = function(name) {
|
||||
return GM_deleteValue(g.NAMESPACE + name);
|
||||
};
|
||||
$.get = function(name, defaultValue) {
|
||||
var value;
|
||||
|
||||
if (value = GM_getValue(g.NAMESPACE + name)) {
|
||||
return JSON.parse(value);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
$.set = function(name, value) {
|
||||
name = g.NAMESPACE + name;
|
||||
value = JSON.stringify(value);
|
||||
localStorage.setItem(name, value);
|
||||
return GM_setValue(name, value);
|
||||
};
|
||||
} else if (window.opera) {
|
||||
(function() {
|
||||
var scriptStorage;
|
||||
|
||||
scriptStorage = opera.scriptStorage;
|
||||
$["delete"] = function(name) {
|
||||
return delete scriptStorage[g.NAMESPACE + name];
|
||||
};
|
||||
$.get = function(name, defaultValue) {
|
||||
var value;
|
||||
|
||||
if (value = scriptStorage[g.NAMESPACE + name]) {
|
||||
return JSON.parse(value);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
return $.set = function(name, value) {
|
||||
name = g.NAMESPACE + name;
|
||||
value = JSON.stringify(value);
|
||||
localStorage.setItem(name, value);
|
||||
return scriptStorage[name] = value;
|
||||
};
|
||||
})();
|
||||
} else {
|
||||
$["delete"] = function(name) {
|
||||
return localStorage.removeItem(g.NAMESPACE + name);
|
||||
};
|
||||
$.get = function(name, defaultValue) {
|
||||
var value;
|
||||
|
||||
if (value = localStorage.getItem(g.NAMESPACE + name)) {
|
||||
return JSON.parse(value);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
$.set = function(name, value) {
|
||||
return localStorage.setItem(g.NAMESPACE + name, JSON.stringify(value));
|
||||
};
|
||||
}
|
||||
|
||||
Polyfill = {
|
||||
init: function() {
|
||||
return Polyfill.visibility();
|
||||
@ -3882,7 +3840,7 @@
|
||||
};
|
||||
|
||||
/*
|
||||
JSColor
|
||||
JSColor
|
||||
http://github.com/hotchpotch/jscolor/tree/master
|
||||
|
||||
JSColor is color library for JavaScript.
|
||||
@ -4919,7 +4877,7 @@
|
||||
innerHTML: '[<a href=javascript:;> - </a>]\u00A0'
|
||||
});
|
||||
$.on(btn, 'click', Header.toggleBoardList);
|
||||
return $.prepend(fullBoardList, btn);
|
||||
return $.add(fullBoardList, btn);
|
||||
} else {
|
||||
$.rm($('#custom-board-list', nav));
|
||||
return fullBoardList.hidden = false;
|
||||
@ -4933,8 +4891,8 @@
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
as = $$('#full-board-list a', Header.nav);
|
||||
nodes = text.match(/[\w@]+(-(all|title|full|text:"[^"]+"))?|[^\w@]+/g).map(function(t) {
|
||||
as = $$('#full-board-list a', Header.nav).slice(0, -2);
|
||||
nodes = text.match(/[\w@]+(-(all|title|full|index|catalog|text:"[^"]+"))*|[^\w@]+/g).map(function(t) {
|
||||
var a, board, m, _i, _len;
|
||||
|
||||
if (/^[^\w@]/.test(t)) {
|
||||
@ -4954,12 +4912,21 @@
|
||||
a = as[_i];
|
||||
if (a.textContent === board) {
|
||||
a = a.cloneNode(true);
|
||||
if (/-title$/.test(t)) {
|
||||
if (/-title/.test(t)) {
|
||||
a.textContent = a.title;
|
||||
} else if (/-full$/.test(t)) {
|
||||
} else if (/-full/.test(t)) {
|
||||
a.textContent = "/" + board + "/ - " + a.title;
|
||||
} else if (m = t.match(/-text:"(.+)"$/)) {
|
||||
a.textContent = m[1];
|
||||
} else if (/-(index|catalog|text)/.test(t)) {
|
||||
if (m = t.match(/-(index|catalog)/)) {
|
||||
a.setAttribute('data-only', m[1]);
|
||||
a.href = "//boards.4chan.org/" + board + "/";
|
||||
if (m[1] === 'catalog') {
|
||||
a.href += 'catalog';
|
||||
}
|
||||
}
|
||||
if (m = t.match(/-text:"(.+)"/)) {
|
||||
a.textContent = m[1];
|
||||
}
|
||||
} else if (board === '@') {
|
||||
$.addClass(a, 'navSmall');
|
||||
}
|
||||
@ -5107,7 +5074,7 @@
|
||||
|
||||
Settings = {
|
||||
init: function() {
|
||||
var link, settings;
|
||||
var link, prevVersion, settings;
|
||||
|
||||
link = $.el('a', {
|
||||
id: 'appchanOptions',
|
||||
@ -5127,9 +5094,12 @@
|
||||
return $.prepend($.id('navtopright'), [$.tn(' ['), link, $.tn('] ')]);
|
||||
});
|
||||
});
|
||||
if (!$.get('previousversion')) {
|
||||
if ((prevVersion = $.get('previousversion', null)) !== g.VERSION) {
|
||||
$.set('lastupdate', Date.now());
|
||||
$.set('previousversion', g.VERSION);
|
||||
$.on(d, '4chanXInitFinished', Settings.open);
|
||||
if (!prevVersion) {
|
||||
$.on(d, '4chanXInitFinished', Settings.open);
|
||||
}
|
||||
}
|
||||
Settings.addSection('Main', Settings.main);
|
||||
Settings.addSection('Filter', Settings.filter);
|
||||
@ -5167,6 +5137,7 @@
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
section = _ref[_i];
|
||||
link = $.el('a', {
|
||||
className: "tab-" + section.hyphenatedTitle,
|
||||
textContent: section.title,
|
||||
href: 'javascript:;'
|
||||
});
|
||||
@ -5177,12 +5148,8 @@
|
||||
}
|
||||
}
|
||||
links.pop();
|
||||
if (sectionToOpen) {
|
||||
sectionToOpen.click();
|
||||
} else {
|
||||
links[0].click();
|
||||
}
|
||||
$.add($('.sections-list', overlay), links);
|
||||
(sectionToOpen ? sectionToOpen : links[0]).click();
|
||||
$.on($('.close', overlay), 'click', Settings.close);
|
||||
$.on(overlay, 'click', Settings.close);
|
||||
$.on(overlay.firstElementChild, 'click', function(e) {
|
||||
@ -5203,22 +5170,28 @@
|
||||
},
|
||||
sections: [],
|
||||
addSection: function(title, open) {
|
||||
var _ref;
|
||||
var hyphenatedTitle, _ref;
|
||||
|
||||
if (typeof title !== 'string') {
|
||||
_ref = title.detail, title = _ref.title, open = _ref.open;
|
||||
}
|
||||
hyphenatedTitle = title.toLowerCase().replace(/\s+/g, '-');
|
||||
return Settings.sections.push({
|
||||
title: title,
|
||||
hyphenatedTitle: hyphenatedTitle,
|
||||
open: open
|
||||
});
|
||||
},
|
||||
openSection: function() {
|
||||
var section;
|
||||
var section, selected;
|
||||
|
||||
if (selected = $('.tab-selected', Settings.dialog)) {
|
||||
$.rmClass(selected, 'tab-selected');
|
||||
}
|
||||
$.addClass($(".tab-" + this.hyphenatedTitle, Settings.dialog), 'tab-selected');
|
||||
section = $('section', Settings.dialog);
|
||||
section.innerHTML = null;
|
||||
section.className = "section-" + (this.title.toLowerCase().replace(/\s+/g, '-'));
|
||||
section.className = "section-" + this.hyphenatedTitle;
|
||||
this.open(section, g);
|
||||
return section.scrollTop = 0;
|
||||
},
|
||||
@ -5242,7 +5215,7 @@
|
||||
div = $.el('div', {
|
||||
innerHTML: "<label><input type=checkbox name=\"" + key + "\" " + checked + ">" + key + "</label><span class=description>: " + description + "</span>"
|
||||
});
|
||||
$.on($('input', div), 'click', $.cb.checked);
|
||||
$.on($('input', div), 'change', $.cb.checked);
|
||||
$.add(fs, div);
|
||||
}
|
||||
$.add(section, fs);
|
||||
@ -5266,8 +5239,7 @@
|
||||
});
|
||||
$.on($('button', div), 'click', function() {
|
||||
this.textContent = 'Hidden: 0';
|
||||
$["delete"]("hiddenThreads." + g.BOARD);
|
||||
return $["delete"]("hiddenPosts." + g.BOARD);
|
||||
return $["delete"](["hiddenThreads." + g.BOARD, "hiddenPosts." + g.BOARD]);
|
||||
});
|
||||
return $.after($('input[name="Stubs"]', section).parentNode.parentNode, div);
|
||||
},
|
||||
@ -5285,7 +5257,7 @@
|
||||
className: 'warning',
|
||||
textContent: 'Save me!',
|
||||
download: "appchan x v" + g.VERSION + "-" + now + ".json",
|
||||
href: "data:application/json;base64," + (btoa(unescape(encodeURIComponent(JSON.stringify(data))))),
|
||||
href: "data:application/json;base64," + (btoa(unescape(encodeURIComponent(JSON.stringify(data, null, 2))))),
|
||||
target: '_blank'
|
||||
});
|
||||
if ($.engine !== 'gecko') {
|
||||
@ -5449,7 +5421,7 @@
|
||||
$.add(div, ta);
|
||||
return;
|
||||
}
|
||||
return div.innerHTML = "<div class=warning " + (Conf['Sauce'] ? 'hidden' : '') + "><code>Filter</code> is disabled.</div>\n<p>\n Use <a href=https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions>regular expressions</a>, one per line.<br>\n Lines starting with a <code>#</code> will be ignored.<br>\n For example, <code>/weeaboo/i</code> will filter posts containing the string `<code>weeaboo</code>`, case-insensitive.<br>\n MD5 filtering uses exact string matching, not regular expressions.\n</p>\n<ul>You can use these settings with each regular expression, separate them with semicolons:\n <li>\n Per boards, separate them with commas. It is global if not specified.<br>\n For example: <code>boards:a,jp;</code>.\n </li>\n <li>\n Filter OPs only along with their threads (`only`), replies only (`no`), or both (`yes`, this is default).<br>\n For example: <code>op:only;</code>, <code>op:no;</code> or <code>op:yes;</code>.\n </li>\n <li>\n Overrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`).<br>\n For example: <code>stub:yes;</code> or <code>stub:no;</code>.\n </li>\n <li>\n Highlight instead of hiding. You can specify a class name to use with a userstyle.<br>\n For example: <code>highlight;</code> or <code>highlight:wallpaper;</code>.\n </li>\n <li>\n Highlighted OPs will have their threads put on top of board pages by default.<br>\n For example: <code>top:yes;</code> or <code>top:no;</code>.\n </li>\n</ul>";
|
||||
return div.innerHTML = "<div class=warning " + (Conf['Filter'] ? 'hidden' : '') + "><code>Filter</code> is disabled.</div>\n<p>\n Use <a href=https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions>regular expressions</a>, one per line.<br>\n Lines starting with a <code>#</code> will be ignored.<br>\n For example, <code>/weeaboo/i</code> will filter posts containing the string `<code>weeaboo</code>`, case-insensitive.<br>\n MD5 filtering uses exact string matching, not regular expressions.\n</p>\n<ul>You can use these settings with each regular expression, separate them with semicolons:\n <li>\n Per boards, separate them with commas. It is global if not specified.<br>\n For example: <code>boards:a,jp;</code>.\n </li>\n <li>\n Filter OPs only along with their threads (`only`), replies only (`no`), or both (`yes`, this is default).<br>\n For example: <code>op:only;</code>, <code>op:no;</code> or <code>op:yes;</code>.\n </li>\n <li>\n Overrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`).<br>\n For example: <code>stub:yes;</code> or <code>stub:no;</code>.\n </li>\n <li>\n Highlight instead of hiding. You can specify a class name to use with a userstyle.<br>\n For example: <code>highlight;</code> or <code>highlight:wallpaper;</code>.\n </li>\n <li>\n Highlighted OPs will have their threads put on top of board pages by default.<br>\n For example: <code>top:yes;</code> or <code>top:no;</code>.\n </li>\n</ul>";
|
||||
},
|
||||
sauce: function(section) {
|
||||
var sauce;
|
||||
@ -5462,7 +5434,7 @@
|
||||
rice: function(section) {
|
||||
var event, input, name, _i, _len, _ref;
|
||||
|
||||
section.innerHTML = "<fieldset>\n <legend>Custom Board Navigation <span class=warning " + (Conf['Custom Board Navigation'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <div><input name=boardnav class=field spellcheck=false></div>\n <div>In the following, <code>board</code> can translate to a board ID (<code>a</code>, <code>b</code>, etc...), the current board (<code>current</code>), or the Status/Twitter link (<code>status</code>, <code>@</code>).</div>\n <div>Board link: <code>board</code></div>\n <div>Title link: <code>board-title</code></div>\n <div>Full text link: <code>board-full</code></div>\n <div>Custom text link: <code>board-text:\"VIP Board\"</code></div>\n <div>Full board list toggle: <code>toggle-all</code></div>\n</fieldset>\n\n<fieldset>\n <legend>Time Formatting <span class=warning " + (Conf['Time Formatting'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <div><input name=time class=field spellcheck=false>: <span class=time-preview></span></div>\n <div>Supported <a href=//en.wikipedia.org/wiki/Date_%28Unix%29#Formatting>format specifiers</a>:</div>\n <div>Day: <code>%a</code>, <code>%A</code>, <code>%d</code>, <code>%e</code></div>\n <div>Month: <code>%m</code>, <code>%b</code>, <code>%B</code></div>\n <div>Year: <code>%y</code></div>\n <div>Hour: <code>%k</code>, <code>%H</code>, <code>%l</code>, <code>%I</code>, <code>%p</code>, <code>%P</code></div>\n <div>Minute: <code>%M</code></div>\n <div>Second: <code>%S</code></div>\n</fieldset>\n\n<fieldset>\n <legend>Quote Backlinks formatting <span class=warning " + (Conf['Quote Backlinks'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <div><input name=backlink class=field spellcheck=false>: <span class=backlink-preview></span></div>\n</fieldset>\n\n<fieldset>\n <legend>File Info Formatting <span class=warning " + (Conf['File Info Formatting'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <div><input name=fileInfo class=field spellcheck=false>: <span class='fileText file-info-preview'></span></div>\n <div>Link: <code>%l</code> (truncated), <code>%L</code> (untruncated), <code>%T</code> (Unix timestamp)</div>\n <div>Original file name: <code>%n</code> (truncated), <code>%N</code> (untruncated), <code>%t</code> (Unix timestamp)</div>\n <div>Spoiler indicator: <code>%p</code></div>\n <div>Size: <code>%B</code> (Bytes), <code>%K</code> (KB), <code>%M</code> (MB), <code>%s</code> (4chan default)</div>\n <div>Resolution: <code>%r</code> (Displays 'PDF' for PDF files)</div>\n</fieldset>\n\n<fieldset>\n <legend>Unread Tab Icon <span class=warning " + (Conf['Unread Tab Icon'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <select name=favicon>\n <option value=ferongr>ferongr</option>\n <option value=xat->xat-</option>\n <option value=Mayhem>Mayhem</option>\n <option value=Original>Original</option>\n </select>\n <span class=favicon-preview></span>\n</fieldset>\n\n<fieldset>\n <legend>Custom CSS <span class=warning " + (Conf['Custom CSS'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <button id=apply-css>Apply CSS</button>\n <textarea name=usercss class=field spellcheck=false></textarea>\n</fieldset>";
|
||||
section.innerHTML = "<fieldset>\n <legend>Custom Board Navigation <span class=warning " + (Conf['Custom Board Navigation'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <div><input name=boardnav class=field spellcheck=false></div>\n <div>In the following, <code>board</code> can translate to a board ID (<code>a</code>, <code>b</code>, etc...), the current board (<code>current</code>), or the Status/Twitter link (<code>status</code>, <code>@</code>).</div>\n <div>Board link: <code>board</code></div>\n <div>Title link: <code>board-title</code></div>\n <div>Full text link: <code>board-full</code></div>\n <div>Custom text link: <code>board-text:\"VIP Board\"</code></div>\n <div>Index-only link: <code>board-index</code></div>\n <div>Catalog-only link: <code>board-catalog</code></div>\n <div>Combinations are possible: <code>board-index-text:\"VIP Index\"</code></div>\n <div>Full board list toggle: <code>toggle-all</code></div>\n</fieldset>\n\n<fieldset>\n <legend>Time Formatting <span class=warning " + (Conf['Time Formatting'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <div><input name=time class=field spellcheck=false>: <span class=time-preview></span></div>\n <div>Supported <a href=//en.wikipedia.org/wiki/Date_%28Unix%29#Formatting>format specifiers</a>:</div>\n <div>Day: <code>%a</code>, <code>%A</code>, <code>%d</code>, <code>%e</code></div>\n <div>Month: <code>%m</code>, <code>%b</code>, <code>%B</code></div>\n <div>Year: <code>%y</code></div>\n <div>Hour: <code>%k</code>, <code>%H</code>, <code>%l</code>, <code>%I</code>, <code>%p</code>, <code>%P</code></div>\n <div>Minute: <code>%M</code></div>\n <div>Second: <code>%S</code></div>\n</fieldset>\n\n<fieldset>\n <legend>Quote Backlinks formatting <span class=warning " + (Conf['Quote Backlinks'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <div><input name=backlink class=field spellcheck=false>: <span class=backlink-preview></span></div>\n</fieldset>\n\n<fieldset>\n <legend>File Info Formatting <span class=warning " + (Conf['File Info Formatting'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <div><input name=fileInfo class=field spellcheck=false>: <span class='fileText file-info-preview'></span></div>\n <div>Link: <code>%l</code> (truncated), <code>%L</code> (untruncated), <code>%T</code> (Unix timestamp)</div>\n <div>Original file name: <code>%n</code> (truncated), <code>%N</code> (untruncated), <code>%t</code> (Unix timestamp)</div>\n <div>Spoiler indicator: <code>%p</code></div>\n <div>Size: <code>%B</code> (Bytes), <code>%K</code> (KB), <code>%M</code> (MB), <code>%s</code> (4chan default)</div>\n <div>Resolution: <code>%r</code> (Displays 'PDF' for PDF files)</div>\n</fieldset>\n\n<fieldset>\n <legend>Unread Tab Icon <span class=warning " + (Conf['Unread Tab Icon'] ? 'hidden' : '') + ">is disabled.</span></legend>\n <select name=favicon>\n <option value=ferongr>ferongr</option>\n <option value=xat->xat-</option>\n <option value=Mayhem>Mayhem</option>\n <option value=Original>Original</option>\n </select>\n <span class=favicon-preview></span>\n</fieldset>\n\n<fieldset>\n <legend><input type=checkbox name='Custom CSS' " + (Conf['Custom CSS'] ? 'checked' : '') + "> Custom CSS</legend>\n <button id=apply-css>Apply CSS</button>\n <textarea name=usercss class=field spellcheck=false " + (Conf['Custom CSS'] ? '' : 'disabled') + "></textarea>\n</fieldset>";
|
||||
_ref = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
name = _ref[_i];
|
||||
@ -5475,6 +5447,7 @@
|
||||
Settings[name].call(input);
|
||||
}
|
||||
}
|
||||
$.on($('input[name="Custom CSS"]', section), 'change', Settings.togglecss);
|
||||
return $.on($.id('apply-css'), 'click', Settings.usercss);
|
||||
},
|
||||
boardnav: function() {
|
||||
@ -5512,14 +5485,18 @@
|
||||
if (g.VIEW === 'thread' && Conf['Unread Tab Icon']) {
|
||||
Unread.update();
|
||||
}
|
||||
return this.nextElementSibling.innerHTML = "<img src=" + Favicon.unreadSFW + "> <img src=" + Favicon.unreadNSFW + "> <img src=" + Favicon.unreadDead + ">";
|
||||
return this.nextElementSibling.innerHTML = "<img src=" + Favicon["default"] + ">\n<img src=" + Favicon.unreadSFW + ">\n<img src=" + Favicon.unreadNSFW + ">\n<img src=" + Favicon.unreadDead + ">";
|
||||
},
|
||||
togglecss: function() {
|
||||
if ($('textarea', this.parentNode.parentNode).disabled = !this.checked) {
|
||||
CustomCSS.rmStyle();
|
||||
} else {
|
||||
CustomCSS.addStyle();
|
||||
}
|
||||
return $.cb.checked.call(this);
|
||||
},
|
||||
usercss: function() {
|
||||
if (Conf['Custom CSS']) {
|
||||
return CustomCSS.update();
|
||||
} else {
|
||||
return CustomCSS.rmStyle();
|
||||
}
|
||||
return CustomCSS.update();
|
||||
},
|
||||
keybinds: function(section) {
|
||||
var arr, input, key, tbody, tr, _ref;
|
||||
@ -5565,12 +5542,14 @@
|
||||
}
|
||||
board = g.BOARD.ID;
|
||||
if (board === 'g') {
|
||||
$.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
|
||||
Post.prototype.callbacks.push({
|
||||
name: 'Parse /g/ code',
|
||||
cb: this.code
|
||||
});
|
||||
}
|
||||
if (board === 'sci') {
|
||||
$.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
|
||||
return Post.prototype.callbacks.push({
|
||||
name: 'Parse /sci/ math',
|
||||
cb: this.math
|
||||
@ -5586,23 +5565,14 @@
|
||||
_ref = $$('.prettyprint', this.nodes.comment);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
pre = _ref[_i];
|
||||
pre.innerHTML = $.unsafeWindow.prettyPrintOne(pre.innerHTML);
|
||||
$.event('prettyprint', pre, window);
|
||||
}
|
||||
},
|
||||
math: function() {
|
||||
var jsMath;
|
||||
|
||||
if (this.isClone || !$('.math', this.nodes.comment)) {
|
||||
return;
|
||||
}
|
||||
jsMath = $.unsafeWindow.jsMath;
|
||||
if (jsMath) {
|
||||
if (jsMath.loaded) {
|
||||
return jsMath.ProcessBeforeShowing(this.nodes.post);
|
||||
} else {
|
||||
return $.globalEval("jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\njsMath.Autoload.LoadJsMath();");
|
||||
}
|
||||
}
|
||||
return $.event('jsmath', this.nodes.post, window);
|
||||
},
|
||||
parseThread: function(threadID, offset, limit) {
|
||||
return $.event('4chanParsingDone', {
|
||||
@ -5921,7 +5891,7 @@
|
||||
|
||||
ThreadHiding = {
|
||||
init: function() {
|
||||
if (g.VIEW !== 'index' || !Conf['Thread Hiding']) {
|
||||
if (g.VIEW !== 'index' || !Conf['Thread Hiding'] && !Conf['Thread Hiding Link']) {
|
||||
return;
|
||||
}
|
||||
Misc.clearThreads("hiddenThreads." + g.BOARD);
|
||||
@ -5938,7 +5908,7 @@
|
||||
if (data = ThreadHiding.hiddenThreads.threads[this]) {
|
||||
ThreadHiding.hide(this, data.makeStub);
|
||||
}
|
||||
if (!Conf['Hiding Buttons']) {
|
||||
if (!Conf['Thread Hiding']) {
|
||||
return;
|
||||
}
|
||||
return $.prepend(this.OP.nodes.root, ThreadHiding.makeButton(this, 'hide'));
|
||||
@ -5975,7 +5945,7 @@
|
||||
init: function() {
|
||||
var apply, div, makeStub;
|
||||
|
||||
if (g.VIEW !== 'index' || !Conf['Menu'] || !Conf['Thread Hiding']) {
|
||||
if (g.VIEW !== 'index' || !Conf['Menu'] || !Conf['Thread Hiding Link']) {
|
||||
return;
|
||||
}
|
||||
div = $.el('div', {
|
||||
@ -6111,7 +6081,7 @@
|
||||
|
||||
ReplyHiding = {
|
||||
init: function() {
|
||||
if (g.VIEW === 'catalog' || !Conf['Reply Hiding']) {
|
||||
if (g.VIEW === 'catalog' || !Conf['Reply Hiding'] && !Conf['Reply Hiding Link']) {
|
||||
return;
|
||||
}
|
||||
Misc.clearThreads("hiddenPosts." + g.BOARD);
|
||||
@ -6137,7 +6107,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Conf['Hiding Buttons']) {
|
||||
if (!Conf['Reply Hiding']) {
|
||||
return;
|
||||
}
|
||||
return $.add($('.postInfo', this.nodes.post), ReplyHiding.makeButton(this, 'hide'));
|
||||
@ -6151,7 +6121,7 @@
|
||||
init: function() {
|
||||
var apply, div, makeStub, replies, thisPost;
|
||||
|
||||
if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Reply Hiding']) {
|
||||
if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Reply Hiding Link']) {
|
||||
return;
|
||||
}
|
||||
div = $.el('div', {
|
||||
@ -6461,7 +6431,7 @@
|
||||
|
||||
QuoteStrikeThrough = {
|
||||
init: function() {
|
||||
if (g.VIEW === 'catalog' || !Conf['Reply Hiding'] && !Conf['Filter']) {
|
||||
if (g.VIEW === 'catalog' || !Conf['Reply Hiding'] && !Conf['Reply Hiding Link'] && !Conf['Filter']) {
|
||||
return;
|
||||
}
|
||||
return Post.prototype.callbacks.push({
|
||||
@ -6874,7 +6844,7 @@
|
||||
Settings.open();
|
||||
break;
|
||||
case Conf['Close']:
|
||||
if ($.id('settings')) {
|
||||
if ($.id('fourchanx-settings')) {
|
||||
Settings.close();
|
||||
} else if ((notifications = $$('.notification')).length) {
|
||||
for (_i = 0, _len = notifications.length; _i < _len; _i++) {
|
||||
@ -7111,8 +7081,7 @@
|
||||
}
|
||||
},
|
||||
focus: function(post) {
|
||||
$.addClass(post, 'highlight');
|
||||
return $('a[title="Highlight this post"]', post).focus();
|
||||
return $.addClass(post, 'highlight');
|
||||
}
|
||||
};
|
||||
|
||||
@ -7741,15 +7710,15 @@
|
||||
if (data.lastChecked > Date.now() - 12 * $.HOUR) {
|
||||
return;
|
||||
}
|
||||
return $.ajax("//api.4chan.org/" + g.BOARD + "/catalog.json", {
|
||||
return $.ajax("//api.4chan.org/" + g.BOARD + "/threads.json", {
|
||||
onload: function() {
|
||||
var obj, thread, threads, _i, _j, _len, _len1, _ref, _ref1;
|
||||
var page, thread, threads, _i, _j, _len, _len1, _ref, _ref1;
|
||||
|
||||
threads = {};
|
||||
_ref = JSON.parse(this.response);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
obj = _ref[_i];
|
||||
_ref1 = obj.threads;
|
||||
page = _ref[_i];
|
||||
_ref1 = page.threads;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
thread = _ref1[_j];
|
||||
if (thread.no in data.threads) {
|
||||
@ -8008,7 +7977,7 @@
|
||||
posts.pop();
|
||||
for (_i = 0, _len = posts.length; _i < _len; _i++) {
|
||||
post = posts[_i];
|
||||
$.addClass(post.nodes.post, 'qphl');
|
||||
$.addClass(post.nodes.root, 'qphl');
|
||||
}
|
||||
}
|
||||
quoterID = $.x('ancestor::*[@id][1]', this).id.match(/\d+$/)[0];
|
||||
@ -8043,7 +8012,7 @@
|
||||
_ref = [post].concat(post.clones);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
post = _ref[_i];
|
||||
$.rmClass(post.nodes.post, 'qphl');
|
||||
$.rmClass(post.nodes.root, 'qphl');
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -8590,16 +8559,13 @@
|
||||
link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) {
|
||||
switch (parameter) {
|
||||
case '%TURL':
|
||||
case '%turl':
|
||||
return "' + post.file.thumbURL + '";
|
||||
return "' + encodeURIComponent(post.file.thumbURL) + '";
|
||||
case '%URL':
|
||||
case '%url':
|
||||
return "' + post.file.URL + '";
|
||||
return "' + encodeURIComponent(post.file.URL) + '";
|
||||
case '%MD5':
|
||||
case '%md5':
|
||||
return "' + encodeURIComponent(post.file.MD5) + '";
|
||||
case '%board':
|
||||
return "' + post.board + '";
|
||||
return "' + encodeURIComponent(post.board) + '";
|
||||
default:
|
||||
return parameter;
|
||||
}
|
||||
@ -8747,7 +8713,7 @@
|
||||
rect = thumb.parentNode.getBoundingClientRect();
|
||||
if (rect.bottom > 0) {
|
||||
postRect = post.nodes.root.getBoundingClientRect();
|
||||
headRect = Header.bar.getBoundingClientRect();
|
||||
headRect = Header.toggle.getBoundingClientRect();
|
||||
top = postRect.top - headRect.top - headRect.height - 2;
|
||||
root = $.engine === 'webkit' ? d.body : doc;
|
||||
if (rect.top < 0) {
|
||||
@ -8814,7 +8780,7 @@
|
||||
post = Get.postFromNode(this);
|
||||
$.rm(this);
|
||||
delete post.file.fullImage;
|
||||
if (!$.hasClass(post.file.thumb, 'expanding')) {
|
||||
if (!($.hasClass(post.file.thumb, 'expanding') || $.hasClass(post.nodes.root, 'expanded-image'))) {
|
||||
return;
|
||||
}
|
||||
ImageExpand.contract(post);
|
||||
@ -9166,7 +9132,7 @@
|
||||
if (thread.isSticky) {
|
||||
return 1;
|
||||
} else {
|
||||
switch (g.BOARD) {
|
||||
switch (g.BOARD.ID) {
|
||||
case 'b':
|
||||
case 'vg':
|
||||
case 'q':
|
||||
@ -9232,7 +9198,7 @@
|
||||
Main.callbackNodes(Post, posts);
|
||||
$.after(a, nodes);
|
||||
if (Conf['Enable 4chan\'s Extension']) {
|
||||
return $.unsafeWindow.Parser.parseThread(thread.ID, 1, nodes.length);
|
||||
return $.globalEval("Parser.parseThread(" + thread.ID + ", 1, " + nodes.length + ")");
|
||||
} else {
|
||||
return Fourchan.parseThread(thread.ID, 1, nodes.length);
|
||||
}
|
||||
@ -9250,7 +9216,9 @@
|
||||
});
|
||||
},
|
||||
node: function() {
|
||||
return d.title = Get.threadExcerpt(this);
|
||||
var excerpt;
|
||||
|
||||
return d.title = (excerpt = Get.threadExcerpt(this)).length > 80 ? "" + excerpt.slice(0, 77) + "..." : excerpt;
|
||||
}
|
||||
};
|
||||
|
||||
@ -9438,35 +9406,35 @@
|
||||
switch (Conf['favicon']) {
|
||||
case 'ferongr':
|
||||
Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAOMHAOgLAnMFAL8AAOgLAukMA/+AgP+rq////////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
|
||||
Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABEklEQVQ4y6VSu07DQBCcXftQhFNQpEC0UEQpLfEXNFTQ8g0WFY0lyuRPUqRJT8kf5BucCFFhiiAyFNZad+aOFJy0utXN7HMO+OcRc5pCaf55e5AYOcbJDZjvDwFxmCTJaQpl5UDWNblcknXNyoF+taMcI2zHGbfjLCD4wYZHg1/Q2ZA0TG48wyU2HwA8nmi/qGN434lvQwVWI2GpYKngaiRM6ppKUCpoB8CrvecpqXwpm0I5a4MRzqKVK4dfMtn7dDLpO7gSMOjAKi+eauwe7qOjFe9vvd96HapP2i2ek7u5zQWn0tnU+6PBDjYf31g74OYLgAsTrPfEJ7vOL1WQ3IF/+9hdBl4reCF/yGhBMRlT2A8kHPXzaYhj2AAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAAJAAASAAAZAQAaAQAiAQAkAQAoFBQyAgAzAgA1AgA4AABBAgBXAwBzBQCEBgGvCAG/AADoCwLpDAP/gID/q6v///9zILr8AAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTqnbE70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUkB/VJW57kHU7fUcHStm8FkncGE/mwP6CGzq/eauHwvT7sWQt3gZLW+AAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAADX8QBwfgC2zADX8QDY8nnl8qLp8v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
|
||||
Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4y6WTv0rDUBTGf7d0aREUNwcHK1UEoQgFwQdwEZw617FrQB2yZHXqA3TNIyh0KN19hJQM2Tq4KEmhHY9Dktub9F47+MEll/N9554/H4F/QulblIq+Xx0qq9qiaWpiMq4K6484NVEqeIH4y0zCr0z8ZSZ4gVSq7dUUAhaZsKgJjOSSN5MburX7R0hiAN5Wu+PrWBLn2skYolSUdT6A0fN2mft4LTJPHeFU6PXzE07FbazrgV5fSgCfZbjptMq0MkqFu46pPLJX9oJdm4r48Xl328FZV6odFJX91xeGP/bJvg+Mopu17rBhtcqGhwGq1Ua12nB5jX0HSQyz99znOuYfyGad/0CdC5w7qHxNbvAk3NwKJ6d/2Fgm2Wx0cL8YR/0BY2szrwAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAASFBMVEUAAAAAAAAAAAAACAkAERMAGBsAGR0AISUALzQALzUAMTcANjwAP0cAVF8AcH4AeokAorYAtswA1/EA2PISIyV55fKi6fL////l+pZqAAAAA3RSTlMAx9dmesIgAAAAcklEQVQY02VPARLCIAxjsjnUWdcg6/9/ukIr00nvIMldEhrC/wHwA0BE3wBUtnICOStQnrNx5oqqzmzKx9vDPH1Nae3F9U4ig3OzjCIX51treYvMxou13EQmBPtHE14xLiawjgoPtfgOaKHP+9VrEXA8O1v7CmSPE3u0AAAAAElFTkSuQmCC';
|
||||
Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAFT+ACh5AEncAFT+AFX/Acz/su7/5v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
|
||||
Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4y6VSPWvCUBQ9L2Qp0iLWLSB1Mkh3oYs/oUscxNGhvyF1rtD/0bGD5Be4dXGra6CLHTvYZKrkdAg3773kpQ698OBy7rlf71zgn6bEiQpQ/FdP46a5OL4E9iubWC/SyokKMIzBHRN+8ZM7Jgxj0Ox2liOEGRVnVBbBTJa4mezJaMMlkKVlwWfcN/YXLEuJ4RLYr8rGyrUfANw+6Y86F6/WMF99gukW7E3KN902441Cdbw3AcUAvAnut0llShkVYNK36nWdncMYDZkEvwmDaoLLkZ7QOqSXdYIHBM7Vjt1D5f986wk9l1QuG8wBv6PgdxSuxhq3CmQp8f7I6h5MO2yAU06cciL/aPl92dt1yoMFeH0HXgR/yChJLhnbYr91gPOcGoNvnQAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAADCgAGEgAIGgAJGwALJAANJwASNwASOAATOgAVQQAWRAAeWwAgKBsoeQAwkQA/wABJ3ABU/gBV/wHM/7Lu/+b////r+K2AAAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTonbk70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUmB/VJW0byDqfvqGBp20mB5J3Bi3zYH1BD38/eauHwvT7sEAt1Fb320QAAAABJRU5ErkJggg==';
|
||||
break;
|
||||
case 'xat-':
|
||||
Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA2ElEQVQ4y61TQQrCMBDMQ8WDIEV6LbT2A4og2Hq0veo7fIAH04dY9N4xmyYlpGmI2MCQTWYy3Wy2DAD7B2wWAzWgcTgVeZKlZRxHNYFi2jM18oBh0IcKtC6ixf22WT4IFLs0owxswXu9egm0Ls6bwfCFfNsJYJKfqoEkd3vgUgFVLWObtzNgVKyruC+ljSzr5OEnBzjvjcQecaQhbZgBb4CmGQw+PoMkTUtdbd8VSEPakcGxPOcsoIgUKy0LecY29BmdBrqRfjIwZ93KLs5loHvBnL3cLH/jF+C/+z5dgUysAAAAAElFTkSuQmCC';
|
||||
Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABa0lEQVQ4y8WTv0vDUBDHv6/EoaQ/AsZYHJ06SpUiCP0L/AcsToXSoUPFQdo6iyIIVicpdPJfcIkIrXSwguA/4FpK0yHUhiKkOYfkhTR5Ogne8g7e3efuvvce8N/GAj5x5/K6dToeDTPzT1MGgHhSsbTMxujkqHYWzuUAotBNq3L4rMViCQAYO86sdndfoGhlttRBOGBaLpkAWKrdSYuSAUASJXNLrq2nQ2P6szLvEGoAAHR+AaiqG2IYYI26UD/eAarVSmfPmW/t29JmclVLQ1UZ8nk3bPCKbrFIx7q+mNDiK7ud6+n6E5YA4h0xf4B6t8veDEMCICmKssNDfEA8oViGac1S7Y7ijzAYuJDJBC/Doc+1bXslUuzq5rbpiUnk6kHUbDjUbBAAygLETZblsahhP5kDpuWS6a2SdgOAoOC/avAg2R+emzsAILPIRqMAFsD3Y/F3DngEYHmvhQlA4bdAP9z1vbPwZ7/xG/NNlMkOsFNNAAAAAElFTkSuQmCC';
|
||||
Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACKkJGNkpN0d3d0eHdra2dGRkORZ1wAAACmaV6naV4PDw8LCwsLCwvyZWLyZWIeExEyFBTAWlr/eHj/enkAAAAKAAAoAAA4AAA4GhpMAACRAAD/AAD/enn/h4j/m5z/nJ3/0dL/0tL/0tP/09P///9VK8WFAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4y2P4//8/AyWYgSoGQMF/GJ7Y11VVUVoyKTM9ey4Ig9ggMWQ1YA1IBvzXm34YjkH8mPyJB+Nqlp8FYRAbmxoMF6ArSNrw6T0Qf8Amh9cFMEWVR/7/A+L/uORxhgEIt5/+/3/2lf//5wAxiI0uj+4CBlBgxVUvOwtydgXQZpDmi2/+/7/0GmIQSAwkB1IDUkuUAZeABlx+g2zAZ9wGlAOjChba+LwAUgNSi2HA5Am9VciBhSsQQWyoWgZiovEDsdGI1QBYQiLJAGQalpSxyWEzAJYWkGm8clTJjQCZ1hkoVG0CygAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjklEQVQ4y8VTv0tCURT+rtkPU997w8sfFA1NLUWEtlROjQ3O0dQSEvLEIJJmkRoiIXBz6g9oaTECK4ckAwmCIFrzx3Monw9Nnt4G3xN9PpuCznLPPfc7H+d+5xzgv430+FRz4qcnR4VC2fVVrVsBgGUsstvtKArhg6g+VyOgi4n77stzYB3bQvzOZHfYAKAtlWsXccGnxwAgfRXoATuX1U8AJOlnWKNkADAZJWvm5O2sk7ez+riKpUM1AIDYIwVv6QDEOhDxEkP9zNotsLuXlPnVJbN3c87B21neArLiAggFsiVg6zxNU2fhVqta+fYszN9e36TQRzCsRZpK6cQhEd+ezADMHMd5NEyXgGEsslQTa0k/w2lfyBY7JJU68PHy0CVWFGV0gGBm2l08DglBTcyIlyCSoRQAia0RjDtne4tTBgiCof2ovhOlilRVXXZk0taNy7I8NUBgZEru6l11lznPBkxjEwMYkz6gDgkAwCpm8lYxkwcA6TWHdrOBdrPx625Qo5noiWXU0/dn2/gDsiiJvxnPWcEAAAAASUVORK5CYII=';
|
||||
Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRjoqTkI13dXR4dXRpZ2tFQ0Zcb5EAAABee6ZefKcPDw8LCwsLCwtisPJisPIRFh4UJDJalMB4xP95xP8AAAABBQcHFx4KISoNLToaKzgaVW4ul8N5xP+Hy/+b1P+c1P/R7P/S6//S7P/T7P////9P0rk0AAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uUrk6MFOxRGRkwdbBNGHSE7jWmPwFMEEtEZdlgPonRmvoYNA4Z49Nguv/gEE3A2/sQ7iRgAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA4ElEQVQ4y2P4//8/AyWYgSoGQMF/GJ7YNbGqrKRiUnp21lwQBrFBYshqwBqQDPifdsYYjkH8mInxB+OWx58FYRAbmxoMF6ArKPmU9B6IP2CTw+sCmKKe/5X/gPg/LnmcYQDCs/63/1/9fzYQzwGz0eXRXcAACqy4ZfFnQc7u+V/xD6T55v+LQHwJbBBIDCQHUgNSS5QBt4Cab/2/jDDgMx4DykrKJ8FCG58XQGpAajEMmNw7uQo5sHAFIogNVctATDR+IDYasRoAS0gkGYBMw5IyNjlsBsDSAjKNV44quREAx58Mr9vt5wQAAAAASUVORK5CYII=';
|
||||
Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABi0lEQVQ4y8WTzysEYRjHP7M/MI3dGVp2RXJwohysOIhyEGdnpRxWkTaRLGeU1mFzcyAl/4Gbg7QHisIdJSy7CsO0B7tel5mJ2eGkPJf3eZ/3+3zf5yf8t0hfdGEpqZXUwm02E3nJ6wqAKgeN+tq6+/hsfNHpaxGI2HHUflnvOGE4NXLgqaUS4CPL23Z8q9eJAaRvETgBM/roMyAlgxuqmzOAx83ZkkggrEYCYdVpN7HixxoArItlqggBEk/kiEkJ1/p5rdvYxHhj61SL6N+MykNLA+URGqQ2OgnTgM4Tob6AuDnPFP3+8nx3V8/e1cXlDoDv9xZJdpC7c/tS5iTnA3yapnVYGJtAlQOGkTPeksENzUrhjCMzhUeuD+9s4kKh4C/5bW11bd4spogdRwUgkiLxkRQJAQitqUJYoihKtiSCyenJRWcn7l8fdCvAskq7XBiGUVNC4CbZ3eKFqbY3D1bjl70lGI/TYA4JAHJaOZXTyinAzaHOe77Ie774624It5n4YkubZ++fbeMnwHeVVSmTml8AAAAASUVORK5CYII=';
|
||||
Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRipGTjZN2dHd2dHhna2pDRkVckV8AAABepl9ep18PDw8LCwsLCwt08mJ08mIRHhEYMhRpwFqM/3iM/3kAAAAECAIQIAgWLAseOBoePA86dB1mzDOM/3ma/4er/5ur/5zZ/9HZ/9La/9La/9P///85Jx7jAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
|
||||
break;
|
||||
case 'Mayhem':
|
||||
Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4jZ2ScWuDMBDFgw4pIkU0WsoQkWAYIkXZH4N9/+/V3dmfXSrKYIFHwt17j8vdGWNMIkgFuaDgzgQnwRs4EQs5KdolUQtagRN0givEDBTEOjgtGs0Zq8F7cKqqusVxrMQLaDUWcjBSrXkn8gs51tpJSWLk9b3HUa0aNIL5gPBR1/V4kJvR7lTwl8GmAm1Gf9+c3S+89qBHa8502AsmSrtBaEBPbIbj0ah2madlNAPEccdgJDfAtWifBjqWKShRBT6KoiH8QlEUn/qt0CCjnNdmPUwmFWzj9Oe6LpKuZXcwqq88z78Pch3aZU3dPwwc2sWlfZKCW5tWluV8kGvXClLm6dYN4/aUqfCbnEOzNDGhGZbNargvxCzvMGfRJD8UaDVvgkzo6QAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABj0lEQVQ4y42TQUorQRCGv+oekpj43pOhOyIiKoHBxTMkuAnEtWcwx/AY3sUbBIRcwCw8gCfIMkaTOOUiNdgGRRuKoav+v2qq/i4BakBmXweUwDoxLF5ZhVkC64rYBHYMUAIvwKuBMEwdaFiCNbAAngEC0NHkxBi73vsOsG92HGPsphigY1wOzfNhqhpC6AEd730RQuh9hQEOAY6A/jeAs3a7/f+bWB84ckCpqg+I8Osjgqo+AKUDViJS8LkGMcY+sJrNZssYY387LiIFsBLgL9AC/pgaArzZlF+sZgO4BG7sfgvcA3MxUtOStBIpX7cS3Klqd9OBTIEr4DlLOsuAmqpODXQOiHMuy/O8FkLoJth/6Uh2gQPg87Q3k+7leX6hqnpmPvM/GWfXWeWGqj5+oUS9LMs6wF7iHAwGJ9ZW5uxpup+UGwEtEVoijEYjKl66PJujmvIW3vsFwBiYqzJXZTweY5wSU6Bd7UP1KoECODUrJpOJAtPhcKjAtXGaYptWs57qWyv9Zn/it1a5knj5Dm3v4q8APeACAAAAAElFTkSuQmCC';
|
||||
Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCElEQVQ4jZ2S4crCMAxF+0OGDJEPKYrIGKOsiJSx/fJRfSAfTJNyKqXfiuDg0C25N2RJjTGmEVrhTzhw7oStsIEtsVzT4o2Jo9ALThiEM8IdHIgNaHo8mjNWg6/ske8bohPo+63QOLzmooHp8fyAICBSQkVz0QKdsFQEV6WSW/D+7+BbgbIDHcb4Kp61XyjyI16zZ8JemGltQtDBSGxB4/GoN+7TpkkjDCsFArm0IYv3U0BbnYtf8BCy+JytsE0X6VyuKhPPK/GAJ14kvZZDZVV3pZIb8MZr6n4o4PDGKn0S5SdDmyq5PnXQsk+Xbhinp03FFzmHJw6xYRiWm9VxnohZ3vOcxdO8ARmXRvbWdtzQAAAAAElFTkSuQmCC';
|
||||
Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABlklEQVQ4y4WTTWobQRCFv2qNRiP5J1mJLAzBJMiCYBubLATy0uQM1jYrb30M38CHyA20EngZPAhhCEaXMIkjWUjzvKkWzWzcUPRM13vVXfWqDMiBzPcAVMA6MdwfLWJWwDoSO0DbARWwBF4dhGNaQOEB1sAC+J/54Z6kuYMxs2/AiwfCMTuSHhPMV6DKgJak+endffQh6dHMjv1FAG1JsxpmbmYHAQhmdj69vtg6T+/ukTQDmkCzTp5eX2Bm50AIQCXpIQW8t/yCB6AyoAt8kPSUgjyFRZpCzd8DnjMvVMPMjlwNAzY1FYKZ/QRu/P8W+AcszUkdYMctSvlaU+GXpBO/vQR+RBlJmiWXVCYpWOyDfr9/kmD3U1LwarcllbGYkmZmdubfZfHpc1qCyAnBgxR1qXy13Gh0dreHg8Hg0NPKgkcL70n38fslIS8IecFoNIqvCOnwbJskWYso5d8/v6lWS6rVkvF4jHMqXIEu8EWSgDPfe8ChW28ymQgoh8OhgCvndMwnLfecWrWR3vhLGrVRjhKv3gDhOKP2kgPZ3gAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OztMTEyRkZHBwcH///9dzWZ0AAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIrhVbv/3Y4Ydj9Ic030ogqpY3mDdGGi1EVsYuSvGE2Pkl0TFYAdLGuY1eMWGowzzN6kX41DYVpNbvdKlO4Jx5gSbi2VO+Vcq2jrc/jNLQhtM+n05PfkrKxG/oFHIEXqwqQsVRy7n+AtwLYL3sYR3wA755Jp3Vvv8cn8Js0GXmA7/P5TwzpiLn8MOALuEZNygkm5JTy/+vl4BRVbJvQ1NbWRSxXN64PGOBlhG0qAAAAAElFTkSuQmCC';
|
||||
Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCklEQVQ4jZ2S0WrDMAxF/TBCCKWMYhZKCSGYmFJMSNjD/mhf239qJXNcjBdTWODgRLpXKJKNMaYROuFTOHEehFb4gJZYrunwxsSXMApOmIQzwgOciE1oRjyaM1aDj+yR7xuiHvT9VmgcXnPRwO/9+wWCgEgJFc1FCwzCVhFclUpuw/u3g3cFyg50GPOjePZ+ocjPeM2RCXthpbUFwQAzsQ2Nx6PeuE+bJo0w7BQI5NKGLN5XAW11LX7BQ8jia7bCLl2kc7mqTLzuxAOeeJH0Wk6VVf0oldyEN15T948CDm+sMiZRfjK0pZIbUwcd+3TphnF62lR8kXN44hAbhmG5WQNnT8zynucsnuYJhFpBfkMzqD4AAAAASUVORK5CYII=';
|
||||
Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABlklEQVQ4y4WTv04bQRDGf7N3/nMmCSIFVRoLZCxFQQJTWHKP8gi4paHOY/AIvANv4ModBXCFRRO5zAskSnL8se+jmbVW13il0d7tfN/sznwzBrSB3PcA1MAqMdwfLWJegVUk9oDCATXwDLw4CMd0gK4HWAEV8D/3w4+Slg7GzL4C/zwQjtmR9JRgDoE6BzqSllcPZ9GHpCcz++YvAigkLRqYpZl9CUAws9Ob0f3GefVwhqQF0AJaTfLN6B4zOwVCAGpJjylg2/ILHoHagH1gV9LPFOQpVGkKDf8A+J17oTIzO3I1DFg3VAhmdgn88P9r4C/wbE7qATtuUcqXhgq3ko799hI4jzKSNEtbUpmkYLEPhsPhcYL9lJKCV7uQVMZiSlqY2Yl/l3v9Ii1B5ITgQbpNqXx13Gh/yDaH4/G472nlwaOFbdIdfv9Mq8hoFRnT6TS+IqTDs2mSZFVRyl93f3ir1rxVa2azGc6pcQX2gQNJAk58HwB9t8F8PhdQTiYTARfO6ZlPWttz6jRGeu0vyRqjHCV+fQf4OaM8g/XFLAAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztMTExmzDORkZHBwcH///92I3mvAAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIT0ur93w4nDLs/pPlGGlGltNG8IdpwMaoidlGSN8zGJ4mOyQqALtZ17IoRSw3meUYv0q+moTCtZrdbZQr3xAMsCdeW6r1SrnW09XmchjaE9vl0evJbUjZ2Q7+AI/BiVQEylkrO/TfwVgD7ZQ/jiA/g3TPptO7t9/gEfpImIw/wez7/iSEdMZcfBnwB16hJOcGEnFL+f70cnKKKbROa2tq6iOXqBuMXGTe4CAUbAAAAAElFTkSuQmCC';
|
||||
break;
|
||||
case 'Original':
|
||||
Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
|
||||
Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAsUlEQVQ4y6VTPQ6DIQh9NG5degyPQOJJetZOTj1R5/ctYggVbVISEoTHPwJ/kphAklMpIitwihmGyR54wghJiggYyiI5s2wxJ8AoN01wWzmfiBbUMsT+4hxO9gnyFLP23qmqVFX23vOCswCq6oO/TV+is613yBL1gx7ZkZCDfVcAWN271sqt8yqAhre1WX5d3RPAfXHhZfU5ViN+Afi4w8pnEEr0ttYaAeRrNKfNZ/qyXeAkApbmVGieAAAAAElFTkSuQmCC';
|
||||
Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAKAAAoAAAoKCg4AAA4ODg7OztMAACRAADBwcH/AAD///+WCcPSAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQmAUAxEb4Isk0rwp3EPR3ECcRQrh7C3/nAasPwzmCgYuPBy5AH/NALSImqAK+H1oJRqyJVHNAnZqDITVhj7/PrAciJ9il0BHs/jjU+fnB9sQ0IxX6OBO6Xr0xKAxANLZzUanCWzZQAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAC6Xw////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
|
||||
Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA3UlEQVQ4y6VTMQ6DMAw8U9RWVQe2bp0zdepgCbH1M7yI90QMXTox5R9dEAPuQqIoxKVST0KKzueL8QHwJ8gfREQCSUQ5sapZCuGJhVuaUkSEiHDrekTuWHjyzapGEwxtAz+IViMiKnLNW7h1fZgg+37pHrbqQRQjvdVaK8wszCzWWlHH0wyYOTZ/er5Mm328uRQiVCuDdJnxkogIh8s1dBtjjHMOAFBoMabYnc7h7JwL5uWv0VX3B4r9ccUXKTG0Tdbg7V6YpxHzNOrbj/LNfgd1XQsAPUbf9OVnWtU+UtzonSagmcwAAAAASUVORK5CYII=';
|
||||
Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWoftRGvdwBEewchM7d9BFbE6pbP4Mgj+R5MjjwgP+qQSkRtQAV8K3lVI2Q648oknIRpWZsMI4988HjgvpU+wO8HgeHzR9cjZYhoRiPkcDd0rXpyUAiRd5YjKC7MvNRgAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
|
||||
Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4y6VTMQ6CQBCcBTSaWBBfYGFBD8UmfMCX8Ch+c5UW0N8DfIGNBSFrw10ux62YOAnJZXZ2btkB4E+QO4iIeJKIUmJVsxT8Ewq3NIWICBGhG2oE7lh4cs2qRhP0zQg3iFYjIspSzVvohtpPkHy/eA9bdS8KEd9qjBFmFmYWY4yo42kGzBya3x1fxM0u3lQKAcqVQbzMcElEhPJy8N1VVVXWWgBApsUYY3/K/dla682LX6O73s7YHfMVn8VE34xJg+fjhek9Y3rP+vaDfJPfQdu2AkCP0TV9+ZlWtQ9lu+fiaucJAgAAAABJRU5ErkJggg==';
|
||||
Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWofRL4x6O4AhuopWb2P4F7E5prP4MgiaSHHlceMA/jYC0iBrgSnjdKaUacuURTUI2qsyEFcaxvD6wnkifYleAx/N449Mn5wfbkFDM52jgTun6tAQg8QAEvjQg42KY2AAAAABJRU5ErkJggg==';
|
||||
}
|
||||
if (Favicon.SFW) {
|
||||
Favicon.unread = Favicon.unreadSFW;
|
||||
@ -9859,9 +9827,9 @@
|
||||
var length, threadID;
|
||||
|
||||
threadID = ThreadUpdater.thread.ID;
|
||||
length = ThreadUpdater.root.children.length;
|
||||
length = $$('.thread > .postContainer', ThreadUpdater.root).length;
|
||||
if (Conf['Enable 4chan\'s Extension']) {
|
||||
return $.unsafeWindow.Parser.parseThread(threadID, -count);
|
||||
return $.globalEval("Parser.parseThread(" + threadID + ", " + (-count) + ")");
|
||||
} else {
|
||||
return Fourchan.parseThread(threadID, length - count, length);
|
||||
}
|
||||
@ -9909,6 +9877,9 @@
|
||||
}
|
||||
},
|
||||
ready: function() {
|
||||
if (!Main.isThisPageLegit()) {
|
||||
return;
|
||||
}
|
||||
ThreadWatcher.refresh();
|
||||
return $.add(d.body, ThreadWatcher.dialog);
|
||||
},
|
||||
@ -10899,6 +10870,9 @@
|
||||
var applyBlob, cv, data, height, i, l, s, ui8a, width, _i;
|
||||
|
||||
s = 90 * 2;
|
||||
if (_this.file.type === 'image/gif') {
|
||||
s *= 3;
|
||||
}
|
||||
height = img.height, width = img.width;
|
||||
if (height < s || width < s) {
|
||||
if (window.URL) {
|
||||
@ -11051,8 +11025,16 @@
|
||||
}), this.ready.bind(this));
|
||||
},
|
||||
ready: function() {
|
||||
var MutationObserver, imgContainer, input, observer;
|
||||
var MutationObserver, imgContainer, input, observer, setLifetime,
|
||||
_this = this;
|
||||
|
||||
setLifetime = function(e) {
|
||||
return _this.lifetime = e.detail;
|
||||
};
|
||||
$.on(window, 'captcha:timeout', setLifetime);
|
||||
$.globalEval('window.dispatchEvent(new CustomEvent("captcha:timeout", {detail: RecaptchaState.timeout}))');
|
||||
$.off(window, 'captcha:timeout', setLifetime);
|
||||
c.log(this.lifetime);
|
||||
imgContainer = $.el('div', {
|
||||
className: 'captcha-img',
|
||||
title: 'Reload',
|
||||
@ -11153,7 +11135,7 @@
|
||||
if (!this.nodes.challenge.firstChild) {
|
||||
return;
|
||||
}
|
||||
this.timeout = Date.now() + $.unsafeWindow.RecaptchaState.timeout * $.SECOND - $.MINUTE;
|
||||
this.timeout = Date.now() + this.lifetime * $.SECOND - $.MINUTE;
|
||||
challenge = this.nodes.challenge.firstChild.value;
|
||||
this.nodes.img.alt = challenge;
|
||||
this.nodes.img.src = "//www.google.com/recaptcha/api/image?c=" + challenge;
|
||||
@ -11177,7 +11159,7 @@
|
||||
return this.nodes.input.alt = count;
|
||||
},
|
||||
reload: function(focus) {
|
||||
$.unsafeWindow.Recaptcha.reload('t');
|
||||
$.globalEval('Recaptcha.reload("t")');
|
||||
if (focus) {
|
||||
return this.nodes.input.focus();
|
||||
}
|
||||
@ -11196,7 +11178,7 @@
|
||||
dialog: function() {
|
||||
var dialog, mimeTypes, name, node, nodes, thread, _i, _j, _len, _len1, _ref, _ref1;
|
||||
|
||||
dialog = UI.dialog('qr', 'top:0;right:0;', "<div id=qrtab>\n <input type=checkbox id=autohide title=Auto-hide>\n <span class=move></span>\n <a href=javascript:; class=close title=Close>×</a>\n</div>\n<form>\n <div class=persona>\n <input id=dump-button type=button title='Dump list' value=+>\n <input name=name data-name=name title=Name placeholder=Name class=field size=1>\n <input name=email data-name=email title=E-mail placeholder=E-mail class=field size=1>\n <input name=sub data-name=sub title=Subject placeholder=Subject class=field size=1>\n </div>\n <div class=textarea>\n <textarea data-name=com title=Comment placeholder=Comment class=field></textarea>\n <span id=char-count></span>\n </div>\n <div id=dump-list-container>\n <div id=dump-list></div>\n <a id=add-post href=javascript:; title=\"Add a post\">+</a>\n </div>\n <div id=file-n-submit>\n <input id=qr-file-button type=button value='Choose files'>\n <span id=qr-filename-container>\n <span id=qr-no-file>No selected file</span>\n <span id=qr-filename></span>\n </span>\n <a id=qr-filerm href=javascript:; title='Remove file' tabindex=-1>×</a>\n <input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=-1>\n <input type=submit>\n </div>\n <input type=file multiple>\n</form>\n<select title='Create a new thread / Reply'>\n <option value=new>New thread</option>\n</select>".replace(/>\s+</g, '><'));
|
||||
dialog = UI.dialog('qr', 'top:0;right:0;', "<div id=qrtab>\n <input type=checkbox id=autohide title=Auto-hide>\n <span class=move></span>\n <a href=javascript:; class=close title=Close>×</a>\n</div>\n<form>\n <div class=persona>\n <input id=dump-button type=button title='Dump list' value=+>\n <input name=name data-name=name title=Name placeholder=Name class=field size=1>\n <input name=email data-name=email title=E-mail placeholder=E-mail class=field size=1>\n <input name=sub data-name=sub title=Subject placeholder=Subject class=field size=1>\n </div>\n <div class=textarea>\n <textarea data-name=com title=Comment placeholder=Comment class=field></textarea>\n <span id=char-count></span>\n </div>\n <div id=dump-list-container>\n <div id=dump-list></div>\n <a id=add-post href=javascript:; title=\"Add a post\">+</a>\n </div>\n <div id=file-n-submit>\n <input type=submit>\n <input id=qr-file-button type=button value='Choose files'>\n <span id=qr-filename-container>\n <span id=qr-no-file>No selected file</span>\n <span id=qr-filename></span>\n </span>\n <a id=qr-filerm href=javascript:; title='Remove file'>×</a>\n <input type=checkbox id=qr-file-spoiler title='Spoiler image'>\n </div>\n <input type=file multiple>\n</form>\n<select title='Create a new thread / Reply'>\n <option value=new>New thread</option>\n</select>".replace(/>\s+</g, '><'));
|
||||
QR.nodes = nodes = {
|
||||
el: dialog,
|
||||
move: $('.move', dialog),
|
||||
@ -11366,7 +11348,9 @@
|
||||
post.unlock();
|
||||
QR.cooldown.auto = false;
|
||||
QR.status();
|
||||
return QR.error('Network error.');
|
||||
return QR.error($.el('span', {
|
||||
innerHTML: 'Connection error. You may have been <a href=//www.4chan.org/banned target=_blank>banned</a>.'
|
||||
}));
|
||||
}
|
||||
};
|
||||
opts = {
|
||||
@ -11390,7 +11374,7 @@
|
||||
return QR.status();
|
||||
},
|
||||
response: function() {
|
||||
var URL, ban, board, err, h1, persona, post, postID, req, threadID, tmpDoc, _, _base, _ref, _ref1;
|
||||
var URL, ban, board, err, h1, isReply, persona, post, postID, req, threadID, tmpDoc, _, _base, _ref, _ref1;
|
||||
|
||||
req = QR.req;
|
||||
delete QR.req;
|
||||
@ -11441,6 +11425,7 @@
|
||||
_ref1 = h1.nextSibling.textContent.match(/thread:(\d+),no:(\d+)/), _ = _ref1[0], threadID = _ref1[1], postID = _ref1[2];
|
||||
postID = +postID;
|
||||
threadID = +threadID || postID;
|
||||
isReply = threadID !== postID;
|
||||
((_base = QR.yourPosts.threads)[threadID] || (_base[threadID] = [])).push(postID);
|
||||
$.set("yourPosts." + g.BOARD, QR.yourPosts);
|
||||
ThreadUpdater.postID = postID;
|
||||
@ -11449,16 +11434,16 @@
|
||||
threadID: threadID,
|
||||
postID: postID
|
||||
}, QR.nodes.el);
|
||||
QR.cooldown.auto = QR.posts.length > 1;
|
||||
QR.cooldown.auto = QR.posts.length > 1 && isReply;
|
||||
post.rm();
|
||||
QR.cooldown.set({
|
||||
req: req,
|
||||
post: post,
|
||||
isReply: !!threadID
|
||||
isReply: isReply
|
||||
});
|
||||
if (threadID === postID) {
|
||||
URL = "/" + g.BOARD + "/res/" + threadID;
|
||||
} else if (g.VIEW === 'index' && !QR.cooldown.auto) {
|
||||
} else if (g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab']) {
|
||||
URL = "/" + g.BOARD + "/res/" + threadID + "#p" + postID;
|
||||
}
|
||||
if (URL) {
|
||||
@ -11498,7 +11483,7 @@
|
||||
field = $.id('recaptcha_response_field');
|
||||
$.on(field, 'keydown', function(e) {
|
||||
if (e.keyCode === 8 && !field.value) {
|
||||
return $.unsafeWindow.Recaptcha.reload('t');
|
||||
return $.globalEval('Recaptcha.reload("t")');
|
||||
}
|
||||
});
|
||||
return $.on(form, 'submit', function(e) {
|
||||
@ -11602,9 +11587,9 @@
|
||||
this.nodes.uniqueID = uniqueID;
|
||||
this.info.uniqueID = uniqueID.firstElementChild.textContent;
|
||||
}
|
||||
if (capcode = $('.capcode', info)) {
|
||||
if (capcode = $('.capcode.hand', info)) {
|
||||
this.nodes.capcode = capcode;
|
||||
this.info.capcode = capcode.textContent;
|
||||
this.info.capcode = capcode.textContent.replace('## ', '');
|
||||
}
|
||||
if (flag = $('.countryFlag', info)) {
|
||||
this.nodes.flag = flag;
|
||||
@ -11887,11 +11872,6 @@
|
||||
init: function() {
|
||||
var flatten, initFeatures, key, pathname, val;
|
||||
|
||||
$.asap((function() {
|
||||
return d.documentElement;
|
||||
}), function() {
|
||||
return doc = d.documentElement;
|
||||
});
|
||||
flatten = function(parent, obj) {
|
||||
var key, val;
|
||||
|
||||
@ -12079,7 +12059,8 @@
|
||||
Main.callbackNodes(Thread, threads);
|
||||
Main.callbackNodes(Post, posts);
|
||||
}
|
||||
return $.event('4chanXInitFinished');
|
||||
$.event('4chanXInitFinished');
|
||||
return Main.checkUpdate();
|
||||
},
|
||||
callbackNodes: function(klass, nodes) {
|
||||
var callback, err, errors, i, len, node, _i, _j, _len, _ref;
|
||||
@ -12112,10 +12093,56 @@
|
||||
var Klass, obj;
|
||||
|
||||
obj = e.detail;
|
||||
Klass = obj.type === 'Post' ? Post : Thread;
|
||||
if (typeof obj.callback.name !== 'string') {
|
||||
throw new Error("Invalid callback name: " + obj.callback.name);
|
||||
}
|
||||
switch (obj.type) {
|
||||
case 'Post':
|
||||
Klass = Post;
|
||||
break;
|
||||
case 'Thread':
|
||||
Klass = Thread;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
obj.callback.isAddon = true;
|
||||
return Klass.prototype.callbacks.push(obj.callback);
|
||||
},
|
||||
checkUpdate: function() {
|
||||
var freq, now;
|
||||
|
||||
if (!Main.isThisPageLegit()) {
|
||||
return;
|
||||
}
|
||||
now = Date.now();
|
||||
freq = 7 * $.DAY;
|
||||
if ($.get('lastupdate', 0) > now - freq || $.get('lastchecked', 0) > now - $.DAY) {
|
||||
return;
|
||||
}
|
||||
return $.ajax('http://zixaphir.github.com/appchan-x/builds/version', {
|
||||
onload: function() {
|
||||
var el, version;
|
||||
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
version = this.response;
|
||||
if (!/^\d\.\d+\.\d+$/.test(version)) {
|
||||
return;
|
||||
}
|
||||
if (g.VERSION === version) {
|
||||
$.set('lastupdate', now);
|
||||
return;
|
||||
}
|
||||
$.set('lastchecked', now);
|
||||
el = $.el('span', {
|
||||
innerHTML: "Update: appchan x v" + version + " is out, get it <a href=http://zixaphir.github.com/appchan-x/ target=_blank>here</a>."
|
||||
});
|
||||
return new Notification('info', el, 2 * $.MINUTE);
|
||||
}
|
||||
});
|
||||
},
|
||||
handleErrors: function(errors) {
|
||||
var div, error, logs, _i, _len;
|
||||
|
||||
@ -12129,7 +12156,7 @@
|
||||
return;
|
||||
}
|
||||
div = $.el('div', {
|
||||
innerHTML: "" + errors.length + " errors occured. [<a href=javascript:;>show</a>]"
|
||||
innerHTML: "" + errors.length + " errors occurred. [<a href=javascript:;>show</a>]"
|
||||
});
|
||||
$.on(div.lastElementChild, 'click', function() {
|
||||
if (this.textContent === 'show') {
|
||||
@ -12164,8 +12191,10 @@
|
||||
return [message, error];
|
||||
},
|
||||
isThisPageLegit: function() {
|
||||
var _ref;
|
||||
|
||||
if (!('thisPageIsLegit' in Main)) {
|
||||
Main.thisPageIsLegit = !$('link[href*="favicon-status.ico"]', d.head) && d.title !== '4chan - Temporarily Offline';
|
||||
Main.thisPageIsLegit = location.hostname === 'boards.4chan.org' && !$('link[href*="favicon-status.ico"]', d.head) && ((_ref = d.title) !== '4chan - Temporarily Offline' && _ref !== '4chan - Error');
|
||||
}
|
||||
return Main.thisPageIsLegit;
|
||||
}
|
||||
|
||||
816
css/style.css
Normal file
@ -0,0 +1,816 @@
|
||||
/* General */
|
||||
.dialog {
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .15);
|
||||
border: 1px solid;
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
.field {
|
||||
border: 1px solid #CCC;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #333;
|
||||
font: 13px sans-serif;
|
||||
margin: 0;
|
||||
padding: 2px 4px 3px;
|
||||
outline: none;
|
||||
-webkit-transition: color .25s, border-color .25s, -webkit-flex .25s;
|
||||
transition: color .25s, border-color .25s, flex .25s;
|
||||
}
|
||||
.field::-moz-placeholder,
|
||||
.field:hover::-moz-placeholder {
|
||||
color: #AAA !important;
|
||||
}
|
||||
.field:hover {
|
||||
border-color: #999;
|
||||
}
|
||||
.field:hover, .field:focus {
|
||||
color: #000;
|
||||
}
|
||||
.field[disabled] {
|
||||
background-color: #F2F2F2;
|
||||
color: #888;
|
||||
}
|
||||
.move {
|
||||
cursor: move;
|
||||
}
|
||||
label, .favicon {
|
||||
cursor: pointer;
|
||||
}
|
||||
a[href="javascript:;"] {
|
||||
text-decoration: none;
|
||||
}
|
||||
.warning {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* 4chan style fixes */
|
||||
.opContainer, .op {
|
||||
display: block !important;
|
||||
}
|
||||
.post {
|
||||
overflow: visible !important;
|
||||
}
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* fixed, z-index */
|
||||
#overlay,
|
||||
#qp, #ihover,
|
||||
#updater, #thread-stats,
|
||||
#navlinks, #header,
|
||||
#qr {
|
||||
position: fixed;
|
||||
}
|
||||
#overlay {
|
||||
z-index: 999;
|
||||
}
|
||||
#notifications {
|
||||
z-index: 70;
|
||||
}
|
||||
#qp, #ihover {
|
||||
z-index: 60;
|
||||
}
|
||||
#menu {
|
||||
z-index: 50;
|
||||
}
|
||||
#navlinks, #updater, #thread-stats {
|
||||
z-index: 40;
|
||||
}
|
||||
#qr {
|
||||
z-index: 30;
|
||||
}
|
||||
#watcher:hover {
|
||||
z-index: 20;
|
||||
}
|
||||
#header {
|
||||
z-index: 10;
|
||||
}
|
||||
#watcher {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.fourchan-x body {
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#header {
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
#header-bar {
|
||||
border-width: 0 0 1px;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
padding: 3px 4px 4px;
|
||||
position: relative;
|
||||
-webkit-transition: all .1s .05s ease-in-out;
|
||||
transition: all .1s .05s ease-in-out;
|
||||
}
|
||||
#board-list {
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
#header-bar.autohide:not(:hover) {
|
||||
box-shadow: none;
|
||||
margin-bottom: -1em;
|
||||
-webkit-transform: translateY(-100%);
|
||||
transform: translateY(-100%);
|
||||
-webkit-transition: all .8s .6s cubic-bezier(.55, .055, .675, .19);
|
||||
transition: all .8s .6s cubic-bezier(.55, .055, .675, .19);
|
||||
}
|
||||
#toggle-header-bar {
|
||||
cursor: n-resize;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -8px;
|
||||
height: 10px;
|
||||
position: absolute;
|
||||
}
|
||||
#header-bar.autohide:not(:hover) #toggle-header-bar, #toggle-header-bar:hover {
|
||||
bottom: -16px;
|
||||
height: 18px;
|
||||
}
|
||||
#header-bar.autohide #toggle-header-bar {
|
||||
cursor: s-resize;
|
||||
}
|
||||
#header-bar a:not(.entry) {
|
||||
text-decoration: none;
|
||||
padding: 1px;
|
||||
}
|
||||
#shortcuts:empty {
|
||||
display: none;
|
||||
}
|
||||
.brackets-wrap::before {
|
||||
content: "\\00a0[";
|
||||
}
|
||||
.brackets-wrap::after {
|
||||
content: "]\\00a0";
|
||||
}
|
||||
.disabled,
|
||||
.expand-all-shortcut {
|
||||
opacity: .45;
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
#notifications {
|
||||
height: 0;
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
.notification {
|
||||
color: #FFF;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .15);
|
||||
border-radius: 2px;
|
||||
margin: 1px auto;
|
||||
width: 500px;
|
||||
max-width: 100%;
|
||||
position: relative;
|
||||
-webkit-transition: all .25s ease-in-out;
|
||||
transition: all .25s ease-in-out;
|
||||
}
|
||||
.notification.error {
|
||||
background-color: hsla(0, 100%, 38%, .9);
|
||||
}
|
||||
.notification.warning {
|
||||
background-color: hsla(36, 100%, 38%, .9);
|
||||
}
|
||||
.notification.info {
|
||||
background-color: hsla(200, 100%, 38%, .9);
|
||||
}
|
||||
.notification.success {
|
||||
background-color: hsla(104, 100%, 38%, .9);
|
||||
}
|
||||
.notification a {
|
||||
color: white;
|
||||
}
|
||||
.notification > .close {
|
||||
padding: 6px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
.message {
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 6px 20px;
|
||||
max-height: 200px;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Settings */
|
||||
#overlay {
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
#fourchanx-settings {
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 15px rgba(0, 0, 0, .15);
|
||||
height: 600px;
|
||||
min-height: 0;
|
||||
max-height: 100%;
|
||||
width: 900px;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
padding: 3px;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
#fourchanx-settings > nav {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
padding: 2px 2px 0;
|
||||
}
|
||||
#fourchanx-settings > nav a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
#fourchanx-settings > nav a.close {
|
||||
text-decoration: none;
|
||||
padding: 2px;
|
||||
}
|
||||
.sections-list {
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
.tab-selected {
|
||||
font-weight: 700;
|
||||
}
|
||||
.section-container {
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
.section-container > section {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.section-sauce ul,
|
||||
.section-rice ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
}
|
||||
.section-sauce li,
|
||||
.section-rice li {
|
||||
padding-left: 4px;
|
||||
}
|
||||
.section-main label {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.section-filter ul {
|
||||
padding: 0;
|
||||
}
|
||||
.section-filter li {
|
||||
margin: 10px 40px;
|
||||
}
|
||||
.section-filter textarea {
|
||||
height: 500px;
|
||||
}
|
||||
.section-sauce textarea {
|
||||
height: 350px;
|
||||
}
|
||||
.section-rice .field[name="boardnav"] {
|
||||
width: 100%;
|
||||
}
|
||||
.section-rice textarea {
|
||||
height: 150px;
|
||||
}
|
||||
#fourchanx-settings fieldset {
|
||||
border: 1px solid;
|
||||
border-radius: 3px;
|
||||
}
|
||||
#fourchanx-settings legend {
|
||||
font-weight: 700;
|
||||
}
|
||||
#fourchanx-settings textarea {
|
||||
font-family: monospace;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
#fourchanx-settings code {
|
||||
color: #000;
|
||||
background-color: #FFF;
|
||||
padding: 0 2px;
|
||||
}
|
||||
.unscroll {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Unread */
|
||||
#unread-line {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Thread Updater */
|
||||
#updater:not(:hover) {
|
||||
background: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
#updater > .move {
|
||||
padding: 0 3px;
|
||||
}
|
||||
#updater > div:last-child {
|
||||
text-align: center;
|
||||
}
|
||||
#updater input[type=number] {
|
||||
width: 4em;
|
||||
}
|
||||
#updater:not(:hover) > div:not(.move) {
|
||||
display: none;
|
||||
}
|
||||
.new {
|
||||
color: limegreen;
|
||||
}
|
||||
|
||||
/* Thread Watcher */
|
||||
#watcher {
|
||||
padding-bottom: 3px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#watcher:not(:hover) {
|
||||
max-height: 220px;
|
||||
}
|
||||
#watcher > .move {
|
||||
padding-top: 3px;
|
||||
}
|
||||
#watcher > div {
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
#watcher a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Thread Stats */
|
||||
#thread-stats {
|
||||
background: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Quote */
|
||||
.deadlink {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.backlink.deadlink:not(.forwardlink), .quotelink.deadlink:not(.forwardlink) {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
.inlined {
|
||||
opacity: .5;
|
||||
}
|
||||
#qp input, .forwarded {
|
||||
display: none;
|
||||
}
|
||||
.quotelink.forwardlink,
|
||||
.backlink.forwardlink {
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dashed;
|
||||
}
|
||||
.filtered {
|
||||
text-decoration: underline line-through;
|
||||
}
|
||||
.inline {
|
||||
border: 1px solid;
|
||||
display: table;
|
||||
margin: 2px 0;
|
||||
}
|
||||
.inline .post {
|
||||
border: 0 !important;
|
||||
background-color: transparent !important;
|
||||
display: table !important;
|
||||
margin: 0 !important;
|
||||
padding: 1px 2px !important;
|
||||
}
|
||||
#qp > .opContainer::after {
|
||||
content: '';
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
#qp .post {
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 2px 2px 5px;
|
||||
}
|
||||
#qp img {
|
||||
max-height: 300px;
|
||||
max-width: 500px;
|
||||
}
|
||||
.qphl > .post {
|
||||
outline: 2px solid rgba(216, 94, 49, .7);
|
||||
}
|
||||
|
||||
/* File */
|
||||
.fileText:hover .fntrunc,
|
||||
.fileText:not(:hover) .fnfull,
|
||||
.expanded-image > .post > .file > .fileThumb > img[data-md5],
|
||||
:not(.expanded-image) > .post > .file > .fileThumb > .full-image {
|
||||
display: none;
|
||||
}
|
||||
.expanding {
|
||||
opacity: .5;
|
||||
}
|
||||
.expanded-image {
|
||||
clear: both;
|
||||
}
|
||||
.expanded-image > .op > .file::after {
|
||||
content: '';
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
:root.fit-width .full-image {
|
||||
max-width: 100%;
|
||||
}
|
||||
:root.gecko.fit-width .full-image,
|
||||
:root.presto.fit-width .full-image {
|
||||
width: 100%;
|
||||
}
|
||||
#ihover {
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
max-height: 100%;
|
||||
max-width: 75%;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
/* Index/Reply Navigation */
|
||||
#navlinks {
|
||||
font-size: 16px;
|
||||
top: 25px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
/* Filter */
|
||||
.opContainer.filter-highlight {
|
||||
box-shadow: inset 5px 0 rgba(255, 0, 0, .5);
|
||||
}
|
||||
.filter-highlight > .reply {
|
||||
box-shadow: -5px 0 rgba(255, 0, 0, .5);
|
||||
}
|
||||
|
||||
/* Thread & Reply Hiding */
|
||||
.hide-thread-button,
|
||||
.hide-reply-button {
|
||||
float: left;
|
||||
margin-right: 2px;
|
||||
}
|
||||
.stub ~ .sideArrows,
|
||||
.stub ~ .hide-reply-button,
|
||||
.stub ~ .post {
|
||||
display: none !important;
|
||||
}
|
||||
.stub input {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* QR */
|
||||
.hide-original-post-form #postForm,
|
||||
.hide-original-post-form .postingMode,
|
||||
#qr.autohide:not(:hover) > form {
|
||||
display: none;
|
||||
}
|
||||
#qr select, #dump-button, .remove, .captcha-img {
|
||||
cursor: pointer;
|
||||
}
|
||||
#qr > div {
|
||||
min-width: 300px;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
#qr .move {
|
||||
-webkit-align-self: stretch;
|
||||
align-self: stretch;
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
#qr select {
|
||||
margin: 0;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
.presto #qr select {
|
||||
height: 1em;
|
||||
}
|
||||
#qr .close {
|
||||
padding: 0 3px;
|
||||
}
|
||||
#qr > form {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
.persona {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
}
|
||||
.persona .field {
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
.persona .field:focus {
|
||||
-webkit-flex: 4;
|
||||
flex: 4;
|
||||
}
|
||||
#dump-button {
|
||||
background: -webkit-linear-gradient(#EEE, #CCC);
|
||||
background: linear-gradient(#EEE, #CCC);
|
||||
border: 1px solid #CCC;
|
||||
margin: 0;
|
||||
padding: 2px 4px 3px;
|
||||
outline: none;
|
||||
width: 30px;
|
||||
}
|
||||
#dump-button:hover, #dump-button:focus {
|
||||
background: -webkit-linear-gradient(#FFF, #DDD);
|
||||
background: linear-gradient(#FFF, #DDD);
|
||||
}
|
||||
#dump-button:active, .dump #dump-button:not(:hover):not(:focus) {
|
||||
background: -webkit-linear-gradient(#CCC, #DDD);
|
||||
background: linear-gradient(#CCC, #DDD);
|
||||
}
|
||||
.gecko #dump-button {
|
||||
padding: 0;
|
||||
}
|
||||
#qr:not(.dump) #dump-list-container {
|
||||
display: none;
|
||||
}
|
||||
#dump-list-container {
|
||||
height: 100px;
|
||||
position: relative;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
#dump-list {
|
||||
counter-reset: qrpreviews;
|
||||
top: 0; right: 0; bottom: 0; left: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#dump-list:hover {
|
||||
bottom: -12px;
|
||||
overflow-x: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
#dump-list::-webkit-scrollbar {
|
||||
height: 12px;
|
||||
}
|
||||
#dump-list::-webkit-scrollbar-thumb {
|
||||
border: 1px solid;
|
||||
}
|
||||
.qr-preview {
|
||||
background-position: 50% 20%;
|
||||
background-size: cover;
|
||||
border: 1px solid #808080;
|
||||
color: #FFF !important;
|
||||
font-size: 12px;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
cursor: move;
|
||||
display: inline-block;
|
||||
height: 92px; width: 92px;
|
||||
margin: 4px; padding: 2px;
|
||||
opacity: .6;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
text-shadow: 0 1px 1px #000;
|
||||
-webkit-transition: opacity .25s ease-in-out;
|
||||
transition: opacity .25s ease-in-out;
|
||||
vertical-align: top;
|
||||
white-space: pre;
|
||||
}
|
||||
.qr-preview:hover, .qr-preview:focus {
|
||||
opacity: .9;
|
||||
color: #FFF !important;
|
||||
}
|
||||
.qr-preview#selected {
|
||||
opacity: 1;
|
||||
}
|
||||
.qr-preview::before {
|
||||
counter-increment: qrpreviews;
|
||||
content: counter(qrpreviews);
|
||||
font-weight: 700;
|
||||
text-shadow: 0 0 3px #000, 0 0 5px #000;
|
||||
position: absolute;
|
||||
top: 3px; right: 3px;
|
||||
}
|
||||
.qr-preview.drag {
|
||||
border-color: red;
|
||||
border-style: dashed;
|
||||
}
|
||||
.qr-preview.over {
|
||||
border-color: #FFF;
|
||||
border-style: dashed;
|
||||
}
|
||||
.remove {
|
||||
color: #E00 !important;
|
||||
font-weight: 700;
|
||||
padding: 3px;
|
||||
}
|
||||
.remove:hover::after {
|
||||
content: ' Remove';
|
||||
}
|
||||
.qr-preview > label {
|
||||
background: rgba(0, 0, 0, .5);
|
||||
right: 0; bottom: 0; left: 0;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
}
|
||||
.qr-preview > label > input {
|
||||
margin: 1px 0;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
#add-post {
|
||||
display: inline-block;
|
||||
font-size: 30px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
right: 0; bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
#qr textarea {
|
||||
min-height: 160px;
|
||||
min-width: 100%;
|
||||
display: block;
|
||||
}
|
||||
#qr.has-captcha textarea {
|
||||
min-height: 120px;
|
||||
}
|
||||
.textarea {
|
||||
position: relative;
|
||||
}
|
||||
#char-count {
|
||||
color: #000;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
font-size: 8pt;
|
||||
position: absolute;
|
||||
bottom: 1px;
|
||||
right: 1px;
|
||||
pointer-events: none;
|
||||
}
|
||||
#char-count.warning {
|
||||
color: red;
|
||||
}
|
||||
.captcha-img {
|
||||
background: #FFF;
|
||||
outline: 1px solid #CCC;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
.captcha-img > img {
|
||||
display: block;
|
||||
height: 57px;
|
||||
width: 300px;
|
||||
}
|
||||
#file-n-submit > input {
|
||||
margin: 0;
|
||||
}
|
||||
#file-n-submit.has-file #qr-no-file {
|
||||
visibility: hidden;
|
||||
}
|
||||
#file-n-submit:not(.has-file) #qr-filename,
|
||||
#file-n-submit:not(.has-file) #qr-file-spoiler,
|
||||
#file-n-submit:not(.has-file) #qr-filerm {
|
||||
display: none;
|
||||
}
|
||||
#file-n-submit {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
#qr-no-file, #qr-filename-container {
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
#qr-filename-container {
|
||||
cursor: default;
|
||||
position: relative;
|
||||
margin-left: 2px;
|
||||
}
|
||||
#qr-filename {
|
||||
position: absolute;
|
||||
top: 0; right: 0; bottom: 0; left: 0;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#qr-filerm {
|
||||
padding: 0 2px;
|
||||
}
|
||||
#file-n-submit > #qr-file-spoiler {
|
||||
margin: 0 2px;
|
||||
}
|
||||
#file-n-submit input[type='submit'] {
|
||||
min-width: 40px;
|
||||
-webkit-order: 1;
|
||||
order: 1;
|
||||
}
|
||||
#qr input[type='file'] {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* Menu */
|
||||
.menu-button {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
.menu-button i {
|
||||
border-top: 6px solid;
|
||||
border-right: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
display: inline-block;
|
||||
margin: 2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#menu {
|
||||
border-bottom: 0;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
margin: 2px 0;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
outline: none;
|
||||
}
|
||||
.entry {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
padding: 3px 7px;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.entry.has-submenu {
|
||||
padding-right: 20px;
|
||||
}
|
||||
.has-submenu::after {
|
||||
content: '';
|
||||
border-left: 6px solid;
|
||||
border-top: 4px solid transparent;
|
||||
border-bottom: 4px solid transparent;
|
||||
display: inline-block;
|
||||
margin: 4px;
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
}
|
||||
.has-submenu:not(.focused) > .submenu {
|
||||
display: none;
|
||||
}
|
||||
.submenu {
|
||||
border-bottom: 0;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
margin: -1px 0;
|
||||
}
|
||||
.entry input {
|
||||
margin: 0;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 232 B |
|
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 232 B |
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 232 B |
|
Before Width: | Height: | Size: 331 B After Width: | Height: | Size: 274 B |
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 274 B |
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 270 B |
|
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 349 B |
|
Before Width: | Height: | Size: 452 B After Width: | Height: | Size: 349 B |
|
Before Width: | Height: | Size: 455 B After Width: | Height: | Size: 349 B |
BIN
img/icon128.png
Normal file
|
After Width: | Height: | Size: 196 B |
BIN
img/icon16.png
Normal file
|
After Width: | Height: | Size: 157 B |
BIN
img/icon48.png
Normal file
|
After Width: | Height: | Size: 204 B |
118
lib/$.coffee
@ -51,7 +51,7 @@ $.extend String::,
|
||||
$.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000)))
|
||||
|
||||
$.extend $,
|
||||
engine: /WebKit|Presto|Gecko/.exec(navigator.userAgent)[0].toLowerCase()
|
||||
engine: '<% if (type === 'crx') { %>webkit<% } else if (type === 'userjs') { %>presto<% } else { %>gecko<% } %>'
|
||||
id: (id) ->
|
||||
d.getElementById id
|
||||
ready: (fc) ->
|
||||
@ -227,19 +227,8 @@ $.extend $,
|
||||
globalEval: (code) ->
|
||||
script = $.el 'script',
|
||||
textContent: code
|
||||
$.add d.head, script
|
||||
$.add (d.head or doc), script
|
||||
$.rm script
|
||||
# http://mths.be/unsafewindow
|
||||
unsafeWindow:
|
||||
if window.opera # Opera
|
||||
window
|
||||
else if unsafeWindow? # Firefox
|
||||
unsafeWindow
|
||||
else # Chrome
|
||||
do ->
|
||||
p = d.createElement 'p'
|
||||
p.setAttribute 'onclick', 'return window'
|
||||
p.onclick()
|
||||
bytesToString: (size) ->
|
||||
unit = 0 # Bytes
|
||||
while size >= 1024
|
||||
@ -256,50 +245,65 @@ $.extend $,
|
||||
Math.round size
|
||||
"#{size} #{['B', 'KB', 'MB', 'GB'][unit]}"
|
||||
|
||||
if GM_deleteValue?
|
||||
$.delete = (name) ->
|
||||
GM_deleteValue g.NAMESPACE + name
|
||||
$.get = (name, defaultValue) ->
|
||||
if value = GM_getValue g.NAMESPACE + name
|
||||
JSON.parse value
|
||||
<% if (type === 'crx') { %>
|
||||
delete: (keys) ->
|
||||
chrome.storage.sync.remove keys
|
||||
get: (key, defaultVal) ->
|
||||
if val = localStorage.getItem g.NAMESPACE + key
|
||||
JSON.parse val
|
||||
else
|
||||
defaultValue
|
||||
$.set = (name, value) ->
|
||||
name = g.NAMESPACE + name
|
||||
value = JSON.stringify value
|
||||
defaultVal
|
||||
set: (key, val) ->
|
||||
item = {}
|
||||
item[key] = val
|
||||
chrome.storage.sync.set item
|
||||
<% } else if (type === 'userjs') { %>
|
||||
do ->
|
||||
# http://www.opera.com/docs/userjs/specs/#scriptstorage
|
||||
# http://www.opera.com/docs/userjs/using/#securepages
|
||||
# The scriptStorage object is available only during
|
||||
# the main User JavaScript thread, being therefore
|
||||
# accessible only in the main body of the user script.
|
||||
# To access the storage object later, keep a reference
|
||||
# to the object.
|
||||
{scriptStorage} = opera
|
||||
$.delete = (keys) ->
|
||||
unless keys instanceof Array
|
||||
keys = [keys]
|
||||
for key in keys
|
||||
key = g.NAMESPACE + key
|
||||
localStorage.removeItem key
|
||||
delete scriptStorage[key]
|
||||
return
|
||||
$.get = (key, defaultVal) ->
|
||||
if val = scriptStorage[g.NAMESPACE + key]
|
||||
JSON.parse val
|
||||
else
|
||||
defaultVal
|
||||
$.set = (key, val) ->
|
||||
key = g.NAMESPACE + key
|
||||
val = JSON.stringify val
|
||||
# for `storage` events
|
||||
localStorage.setItem name, value
|
||||
GM_setValue name, value
|
||||
else if window.opera
|
||||
do ->
|
||||
# http://www.opera.com/docs/userjs/specs/#scriptstorage
|
||||
# http://www.opera.com/docs/userjs/using/#securepages
|
||||
# >The scriptStorage object is available only during
|
||||
# the main User JavaScript thread, being therefore
|
||||
# accessible only in the main body of the user script.
|
||||
# To access the storage object later, keep a reference
|
||||
# to the object.
|
||||
{scriptStorage} = opera
|
||||
$.delete = (name) ->
|
||||
delete scriptStorage[g.NAMESPACE + name]
|
||||
$.get = (name, defaultValue) ->
|
||||
if value = scriptStorage[g.NAMESPACE + name]
|
||||
JSON.parse value
|
||||
else
|
||||
defaultValue
|
||||
$.set = (name, value) ->
|
||||
name = g.NAMESPACE + name
|
||||
value = JSON.stringify value
|
||||
# for `storage` events
|
||||
localStorage.setItem name, value
|
||||
scriptStorage[name] = value
|
||||
else
|
||||
$.delete = (name) ->
|
||||
localStorage.removeItem g.NAMESPACE + name
|
||||
$.get = (name, defaultValue) ->
|
||||
if value = localStorage.getItem g.NAMESPACE + name
|
||||
JSON.parse value
|
||||
localStorage.setItem key, val
|
||||
scriptStorage[key] = val
|
||||
<% } else { %>
|
||||
delete: (key) ->
|
||||
unless keys instanceof Array
|
||||
keys = [keys]
|
||||
for key in keys
|
||||
key = g.NAMESPACE + key
|
||||
localStorage.removeItem key
|
||||
GM_deleteValue key
|
||||
return
|
||||
get: (key, defaultVal) ->
|
||||
if val = GM_getValue g.NAMESPACE + key
|
||||
JSON.parse val
|
||||
else
|
||||
defaultValue
|
||||
$.set = (name, value) ->
|
||||
localStorage.setItem g.NAMESPACE + name, JSON.stringify value
|
||||
defaultVal
|
||||
set: (key, val) ->
|
||||
key = g.NAMESPACE + key
|
||||
val = JSON.stringify val
|
||||
# for `storage` events
|
||||
localStorage.setItem key, val
|
||||
GM_setValue key, val
|
||||
<% } %>
|
||||
|
||||
11
package.json
@ -7,6 +7,7 @@
|
||||
"namespace": "zixaphir",
|
||||
"repo": "https://github.com/zixaphir/appchan-x/",
|
||||
"page": "http://zixaphir.github.com/appchan-x/",
|
||||
"buildsPath": "builds/",
|
||||
"mainBranch": "Av2",
|
||||
"matches": [
|
||||
"*://api.4chan.org/*",
|
||||
@ -16,12 +17,14 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-bump": "~0.0.0",
|
||||
"grunt-contrib-clean": "~0.4.0",
|
||||
"grunt-contrib-coffee": "~0.6.2",
|
||||
"grunt-contrib-concat": "~0.1.0",
|
||||
"grunt-contrib-watch": "~0.3.0",
|
||||
"grunt-contrib-coffee": "~0.6.4",
|
||||
"grunt-contrib-compress": "~0.4.5",
|
||||
"grunt-contrib-concat": "~0.1.3",
|
||||
"grunt-contrib-copy": "~0.4.0",
|
||||
"grunt-contrib-watch": "~0.3.1",
|
||||
"grunt-exec": "~0.4.0"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@ -15,7 +15,7 @@ Config =
|
||||
]
|
||||
'Custom Board Navigation': [
|
||||
true
|
||||
'Disable this to always display the full board list.'
|
||||
'Show custom links instead of the full board list.'
|
||||
]
|
||||
'404 Redirect': [
|
||||
true
|
||||
@ -27,7 +27,7 @@ Config =
|
||||
]
|
||||
'Time Formatting': [
|
||||
true
|
||||
'Localize and format timestamps arbitrarily.'
|
||||
'Localize and format timestamps.'
|
||||
]
|
||||
'Relative Post Dates': [
|
||||
false
|
||||
@ -39,19 +39,15 @@ Config =
|
||||
]
|
||||
'Comment Expansion': [
|
||||
true
|
||||
'Can expand too long comments.'
|
||||
'Add buttons to expand long comments.'
|
||||
]
|
||||
'Thread Expansion': [
|
||||
true
|
||||
'Can expand threads to view all replies.'
|
||||
'Add buttons to expand threads.'
|
||||
]
|
||||
'Index Navigation': [
|
||||
false
|
||||
'Navigate to previous / next thread.'
|
||||
]
|
||||
'Custom CSS': [
|
||||
false
|
||||
'Apply custom CSS to 4chan.'
|
||||
'Add buttons to navigate between threads.'
|
||||
]
|
||||
'Check for Updates': [
|
||||
true
|
||||
@ -75,7 +71,7 @@ Config =
|
||||
'Filtering':
|
||||
'Anonymize': [
|
||||
false
|
||||
'Turn everyone Anonymous.'
|
||||
'Make everyone Anonymous.'
|
||||
]
|
||||
'Filter': [
|
||||
true
|
||||
@ -87,19 +83,19 @@ Config =
|
||||
]
|
||||
'Thread Hiding': [
|
||||
true
|
||||
'Hide entire threads.'
|
||||
'Add buttons to hide entire threads.'
|
||||
]
|
||||
'Reply Hiding': [
|
||||
true
|
||||
'Hide single replies.'
|
||||
'Add buttons to hide single replies.'
|
||||
]
|
||||
'Hiding Buttons': [
|
||||
true
|
||||
'Make buttons to hide threads / replies, in addition to menu links.'
|
||||
'Add buttons to hide threads / replies, in addition to menu links.'
|
||||
]
|
||||
'Stubs': [
|
||||
true
|
||||
'Make stubs of hidden threads / replies.'
|
||||
'Show stubs of hidden threads / replies.'
|
||||
]
|
||||
|
||||
'Images':
|
||||
@ -135,8 +131,16 @@ Config =
|
||||
'Menu':
|
||||
'Menu': [
|
||||
true
|
||||
'Add a drop-down menu in posts.'
|
||||
'Add a drop-down menu to posts.'
|
||||
]
|
||||
'Thread Hiding Link': [
|
||||
true
|
||||
'Add a link to hide entire threads.'
|
||||
]
|
||||
'Reply Hiding Link': [
|
||||
true
|
||||
'Add a link to hide single replies.'
|
||||
]
|
||||
'Report Link': [
|
||||
true
|
||||
'Add a report link to the menu.'
|
||||
@ -222,7 +226,7 @@ Config =
|
||||
'Hide the normal post form.'
|
||||
]
|
||||
|
||||
'Quote links':
|
||||
'Quote Links':
|
||||
'Quote Backlinks': [
|
||||
true
|
||||
'Add quote backlinks.'
|
||||
@ -681,21 +685,23 @@ Config =
|
||||
MD5: ''
|
||||
|
||||
sauces: """
|
||||
http://iqdb.org/?url=%turl
|
||||
http://www.google.com/searchbyimage?image_url=%turl
|
||||
#http://tineye.com/search?url=%turl
|
||||
#http://saucenao.com/search.php?db=999&url=%turl
|
||||
#http://3d.iqdb.org/?url=%turl
|
||||
#http://regex.info/exif.cgi?imgurl=%url
|
||||
http://iqdb.org/?url=%TURL
|
||||
https://www.google.com/searchbyimage?image_url=%TURL
|
||||
#//tineye.com/search?url=%TURL
|
||||
#http://saucenao.com/search.php?url=%TURL
|
||||
#http://3d.iqdb.org/?url=%TURL
|
||||
#http://regex.info/exif.cgi?imgurl=%URL
|
||||
# uploaders:
|
||||
#http://imgur.com/upload?url=%url;text:Upload to imgur
|
||||
#http://omploader.org/upload?url1=%url;text:Upload to omploader
|
||||
#http://imgur.com/upload?url=%URL;text:Upload to imgur
|
||||
#http://ompldr.org/upload?url1=%URL;text:Upload to ompldr
|
||||
# "View Same" in archives:
|
||||
#//archive.foolz.us/_/search/image/%MD5/;text:View same on foolz
|
||||
#//archive.foolz.us/%board/search/image/%MD5/;text:View same on foolz /%board/
|
||||
#//archive.installgentoo.net/%board/image/%MD5;text:View same on installgentoo /%board/
|
||||
"""
|
||||
|
||||
'Custom CSS': false
|
||||
|
||||
'Header auto-hide': false
|
||||
|
||||
'Header catalog links': false
|
||||
|
||||
@ -31,7 +31,7 @@ Header =
|
||||
className: 'hide-board-list-button'
|
||||
innerHTML: '[<a href=javascript:;> - </a>]\u00A0'
|
||||
$.on btn, 'click', Header.toggleBoardList
|
||||
$.prepend fullBoardList, btn
|
||||
$.add fullBoardList, btn
|
||||
else
|
||||
$.rm $ '#custom-board-list', nav
|
||||
fullBoardList.hidden = false
|
||||
@ -40,8 +40,8 @@ Header =
|
||||
list = $ '#custom-board-list', Header.nav
|
||||
list.innerHTML = null
|
||||
return unless text
|
||||
as = $$('#full-board-list a', Header.nav)
|
||||
nodes = text.match(/[\w@]+(-(all|title|full|text:"[^"]+"))?|[^\w@]+/g).map (t) ->
|
||||
as = $$('#full-board-list a', Header.nav)[0...-2] # ignore the Settings and Home links
|
||||
nodes = text.match(/[\w@]+(-(all|title|full|index|catalog|text:"[^"]+"))*|[^\w@]+/g).map (t) ->
|
||||
if /^[^\w@]/.test t
|
||||
return $.tn t
|
||||
if t is 'toggle-all'
|
||||
@ -58,12 +58,17 @@ Header =
|
||||
for a in as
|
||||
if a.textContent is board
|
||||
a = a.cloneNode true
|
||||
if /-title$/.test t
|
||||
if /-title/.test t
|
||||
a.textContent = a.title
|
||||
else if /-full$/.test t
|
||||
else if /-full/.test t
|
||||
a.textContent = "/#{board}/ - #{a.title}"
|
||||
else if m = t.match /-text:"(.+)"$/
|
||||
a.textContent = m[1]
|
||||
else if /-(index|catalog|text)/.test t
|
||||
if m = t.match /-(index|catalog)/
|
||||
a.setAttribute 'data-only', m[1]
|
||||
a.href = "//boards.4chan.org/#{board}/"
|
||||
a.href += 'catalog' if m[1] is 'catalog'
|
||||
if m = t.match /-text:"(.+)"/
|
||||
a.textContent = m[1]
|
||||
else if board is '@'
|
||||
$.addClass a, 'navSmall'
|
||||
return a
|
||||
@ -186,9 +191,10 @@ Settings =
|
||||
$.asap (-> $.id 'boardNavMobile'), ->
|
||||
$.prepend $.id('navtopright'), [$.tn(' ['), link, $.tn('] ')]
|
||||
|
||||
unless $.get 'previousversion'
|
||||
if (prevVersion = $.get 'previousversion', null) isnt g.VERSION
|
||||
$.set 'lastupdate', Date.now()
|
||||
$.set 'previousversion', g.VERSION
|
||||
$.on d, '4chanXInitFinished', Settings.open
|
||||
$.on d, '4chanXInitFinished', Settings.open unless prevVersion
|
||||
|
||||
Settings.addSection 'Main', Settings.main
|
||||
Settings.addSection 'Filter', Settings.filter
|
||||
@ -231,17 +237,15 @@ Settings =
|
||||
links = []
|
||||
for section in Settings.sections
|
||||
link = $.el 'a',
|
||||
className: "tab-#{section.hyphenatedTitle}"
|
||||
textContent: section.title
|
||||
href: 'javascript:;'
|
||||
$.on link, 'click', Settings.openSection.bind section
|
||||
links.push link, $.tn ' | '
|
||||
sectionToOpen = link if section.title is openSection
|
||||
links.pop()
|
||||
if sectionToOpen
|
||||
sectionToOpen.click()
|
||||
else
|
||||
links[0].click()
|
||||
$.add $('.sections-list', overlay), links
|
||||
(if sectionToOpen then sectionToOpen else links[0]).click()
|
||||
|
||||
$.on $('.close', overlay), 'click', Settings.close
|
||||
$.on overlay, 'click', Settings.close
|
||||
@ -261,11 +265,15 @@ Settings =
|
||||
addSection: (title, open) ->
|
||||
if typeof title isnt 'string'
|
||||
{title, open} = title.detail
|
||||
Settings.sections.push {title, open}
|
||||
hyphenatedTitle = title.toLowerCase().replace /\s+/g, '-'
|
||||
Settings.sections.push {title, hyphenatedTitle, open}
|
||||
openSection: ->
|
||||
if selected = $ '.tab-selected', Settings.dialog
|
||||
$.rmClass selected, 'tab-selected'
|
||||
$.addClass $(".tab-#{@hyphenatedTitle}", Settings.dialog), 'tab-selected'
|
||||
section = $ 'section', Settings.dialog
|
||||
section.innerHTML = null
|
||||
section.className = "section-#{@title.toLowerCase().replace /\s+/g, '-'}"
|
||||
section.className = "section-#{@hyphenatedTitle}"
|
||||
@open section, g
|
||||
section.scrollTop = 0
|
||||
|
||||
@ -290,7 +298,7 @@ Settings =
|
||||
description = arr[1]
|
||||
div = $.el 'div',
|
||||
innerHTML: "<label><input type=checkbox name=\"#{key}\" #{checked}>#{key}</label><span class=description>: #{description}</span>"
|
||||
$.on $('input', div), 'click', $.cb.checked
|
||||
$.on $('input', div), 'change', $.cb.checked
|
||||
$.add fs, div
|
||||
$.add section, fs
|
||||
|
||||
@ -304,8 +312,7 @@ Settings =
|
||||
innerHTML: "<button>Hidden: #{hiddenNum}</button><span class=description>: Clear manually hidden threads and posts on /#{g.BOARD}/."
|
||||
$.on $('button', div), 'click', ->
|
||||
@textContent = 'Hidden: 0'
|
||||
$.delete "hiddenThreads.#{g.BOARD}"
|
||||
$.delete "hiddenPosts.#{g.BOARD}"
|
||||
$.delete ["hiddenThreads.#{g.BOARD}", "hiddenPosts.#{g.BOARD}"]
|
||||
$.after $('input[name="Stubs"]', section).parentNode.parentNode, div
|
||||
export: ->
|
||||
now = Date.now()
|
||||
@ -318,7 +325,7 @@ Settings =
|
||||
className: 'warning'
|
||||
textContent: 'Save me!'
|
||||
download: "<%= meta.name %> v#{g.VERSION}-#{now}.json"
|
||||
href: "data:application/json;base64,#{btoa unescape encodeURIComponent JSON.stringify data}"
|
||||
href: "data:application/json;base64,#{btoa unescape encodeURIComponent JSON.stringify data, null, 2}"
|
||||
target: '_blank'
|
||||
if $.engine isnt 'gecko'
|
||||
a.click()
|
||||
@ -458,7 +465,7 @@ Settings =
|
||||
$.add div, ta
|
||||
return
|
||||
div.innerHTML = """
|
||||
<div class=warning #{if Conf['Sauce'] then 'hidden' else ''}><code>Filter</code> is disabled.</div>
|
||||
<div class=warning #{if Conf['Filter'] then 'hidden' else ''}><code>Filter</code> is disabled.</div>
|
||||
<p>
|
||||
Use <a href=https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions>regular expressions</a>, one per line.<br>
|
||||
Lines starting with a <code>#</code> will be ignored.<br>
|
||||
@ -516,6 +523,9 @@ Settings =
|
||||
<div>Title link: <code>board-title</code></div>
|
||||
<div>Full text link: <code>board-full</code></div>
|
||||
<div>Custom text link: <code>board-text:"VIP Board"</code></div>
|
||||
<div>Index-only link: <code>board-index</code></div>
|
||||
<div>Catalog-only link: <code>board-catalog</code></div>
|
||||
<div>Combinations are possible: <code>board-index-text:"VIP Index"</code></div>
|
||||
<div>Full board list toggle: <code>toggle-all</code></div>
|
||||
</fieldset>
|
||||
|
||||
@ -558,9 +568,9 @@ Settings =
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Custom CSS <span class=warning #{if Conf['Custom CSS'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||
<legend><input type=checkbox name='Custom CSS' #{if Conf['Custom CSS'] then 'checked' else ''}> Custom CSS</legend>
|
||||
<button id=apply-css>Apply CSS</button>
|
||||
<textarea name=usercss class=field spellcheck=false></textarea>
|
||||
<textarea name=usercss class=field spellcheck=false #{if Conf['Custom CSS'] then '' else 'disabled'}></textarea>
|
||||
</fieldset>
|
||||
"""
|
||||
for name in ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss']
|
||||
@ -574,6 +584,7 @@ Settings =
|
||||
unless 'usercss' is name
|
||||
$.on input, event, Settings[name]
|
||||
Settings[name].call input
|
||||
$.on $('input[name="Custom CSS"]', section), 'change', Settings.togglecss
|
||||
$.on $.id('apply-css'), 'click', Settings.usercss
|
||||
boardnav: ->
|
||||
Header.generateBoardList @value
|
||||
@ -598,12 +609,20 @@ Settings =
|
||||
favicon: ->
|
||||
Favicon.switch()
|
||||
Unread.update() if g.VIEW is 'thread' and Conf['Unread Tab Icon']
|
||||
@nextElementSibling.innerHTML = "<img src=#{Favicon.unreadSFW}> <img src=#{Favicon.unreadNSFW}> <img src=#{Favicon.unreadDead}>"
|
||||
usercss: ->
|
||||
if Conf['Custom CSS']
|
||||
CustomCSS.update()
|
||||
else
|
||||
@nextElementSibling.innerHTML = """
|
||||
<img src=#{Favicon.default}>
|
||||
<img src=#{Favicon.unreadSFW}>
|
||||
<img src=#{Favicon.unreadNSFW}>
|
||||
<img src=#{Favicon.unreadDead}>
|
||||
"""
|
||||
togglecss: ->
|
||||
if $('textarea', @parentNode.parentNode).disabled = !@checked
|
||||
CustomCSS.rmStyle()
|
||||
else
|
||||
CustomCSS.addStyle()
|
||||
$.cb.checked.call @
|
||||
usercss: ->
|
||||
CustomCSS.update()
|
||||
|
||||
keybinds: (section) ->
|
||||
section.innerHTML = """
|
||||
@ -639,33 +658,40 @@ Fourchan =
|
||||
|
||||
board = g.BOARD.ID
|
||||
if board is 'g'
|
||||
$.globalEval """
|
||||
window.addEventListener('prettyprint', function(e) {
|
||||
var pre = e.detail;
|
||||
pre.innerHTML = prettyPrintOne(pre.innerHTML);
|
||||
}, false);
|
||||
"""
|
||||
Post::callbacks.push
|
||||
name: 'Parse /g/ code'
|
||||
cb: @code
|
||||
if board is 'sci'
|
||||
# https://github.com/MayhemYDG/4chan-x/issues/645#issuecomment-13704562
|
||||
$.globalEval """
|
||||
window.addEventListener('jsmath', function(e) {
|
||||
if (jsMath.loaded) {
|
||||
// process one post
|
||||
jsMath.ProcessBeforeShowing(e.detail);
|
||||
} else {
|
||||
// load jsMath and process whole document
|
||||
jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);
|
||||
jsMath.Autoload.LoadJsMath();
|
||||
}
|
||||
}, false);
|
||||
"""
|
||||
Post::callbacks.push
|
||||
name: 'Parse /sci/ math'
|
||||
cb: @math
|
||||
code: ->
|
||||
return if @isClone
|
||||
for pre in $$ '.prettyprint', @nodes.comment
|
||||
pre.innerHTML = $.unsafeWindow.prettyPrintOne pre.innerHTML
|
||||
$.event 'prettyprint', pre, window
|
||||
return
|
||||
math: ->
|
||||
return if @isClone or !$ '.math', @nodes.comment
|
||||
# https://github.com/MayhemYDG/4chan-x/issues/645#issuecomment-13704562
|
||||
{jsMath} = $.unsafeWindow
|
||||
if jsMath
|
||||
if jsMath.loaded
|
||||
# process one post
|
||||
jsMath.ProcessBeforeShowing @nodes.post
|
||||
else
|
||||
# load jsMath and process whole document
|
||||
# Yes this requires to be globalEval'd, don't ask me why.
|
||||
$.globalEval """
|
||||
jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);
|
||||
jsMath.Autoload.LoadJsMath();
|
||||
"""
|
||||
$.event 'jsmath', @nodes.post, window
|
||||
parseThread: (threadID, offset, limit) ->
|
||||
# Fix /sci/
|
||||
# Fix /g/
|
||||
@ -966,7 +992,7 @@ Filter =
|
||||
|
||||
ThreadHiding =
|
||||
init: ->
|
||||
return if g.VIEW isnt 'index' or !Conf['Thread Hiding']
|
||||
return if g.VIEW isnt 'index' or !Conf['Thread Hiding'] and !Conf['Thread Hiding Link']
|
||||
|
||||
Misc.clearThreads "hiddenThreads.#{g.BOARD}"
|
||||
@getHiddenThreads()
|
||||
@ -978,7 +1004,7 @@ ThreadHiding =
|
||||
node: ->
|
||||
if data = ThreadHiding.hiddenThreads.threads[@]
|
||||
ThreadHiding.hide @, data.makeStub
|
||||
return unless Conf['Hiding Buttons']
|
||||
return unless Conf['Thread Hiding']
|
||||
$.prepend @OP.nodes.root, ThreadHiding.makeButton @, 'hide'
|
||||
|
||||
getHiddenThreads: ->
|
||||
@ -1006,7 +1032,7 @@ ThreadHiding =
|
||||
|
||||
menu:
|
||||
init: ->
|
||||
return if g.VIEW isnt 'index' or !Conf['Menu'] or !Conf['Thread Hiding']
|
||||
return if g.VIEW isnt 'index' or !Conf['Menu'] or !Conf['Thread Hiding Link']
|
||||
|
||||
div = $.el 'div',
|
||||
className: 'hide-thread-link'
|
||||
@ -1108,7 +1134,7 @@ ThreadHiding =
|
||||
|
||||
ReplyHiding =
|
||||
init: ->
|
||||
return if g.VIEW is 'catalog' or !Conf['Reply Hiding']
|
||||
return if g.VIEW is 'catalog' or !Conf['Reply Hiding'] and !Conf['Reply Hiding Link']
|
||||
|
||||
Misc.clearThreads "hiddenPosts.#{g.BOARD}"
|
||||
@getHiddenPosts()
|
||||
@ -1125,7 +1151,7 @@ ReplyHiding =
|
||||
else
|
||||
Recursive.apply ReplyHiding.hide, @, data.makeStub, true
|
||||
Recursive.add ReplyHiding.hide, @, data.makeStub, true
|
||||
return unless Conf['Hiding Buttons']
|
||||
return unless Conf['Reply Hiding']
|
||||
$.add $('.postInfo', @nodes.post), ReplyHiding.makeButton @, 'hide'
|
||||
|
||||
getHiddenPosts: ->
|
||||
@ -1133,7 +1159,7 @@ ReplyHiding =
|
||||
|
||||
menu:
|
||||
init: ->
|
||||
return if g.VIEW is 'catalog' or !Conf['Menu'] or !Conf['Reply Hiding']
|
||||
return if g.VIEW is 'catalog' or !Conf['Menu'] or !Conf['Reply Hiding Link']
|
||||
|
||||
# Hide
|
||||
div = $.el 'div',
|
||||
@ -1343,7 +1369,7 @@ Recursive =
|
||||
|
||||
QuoteStrikeThrough =
|
||||
init: ->
|
||||
return if g.VIEW is 'catalog' or !Conf['Reply Hiding'] and !Conf['Filter']
|
||||
return if g.VIEW is 'catalog' or !Conf['Reply Hiding'] and !Conf['Reply Hiding Link'] and !Conf['Filter']
|
||||
|
||||
Post::callbacks.push
|
||||
name: 'Strike-through Quotes'
|
||||
@ -1631,7 +1657,7 @@ Keybinds =
|
||||
when Conf['Open settings']
|
||||
Settings.open()
|
||||
when Conf['Close']
|
||||
if $.id 'settings'
|
||||
if $.id 'fourchanx-settings'
|
||||
Settings.close()
|
||||
else if (notifications = $$ '.notification').length
|
||||
for notification in notifications
|
||||
@ -1798,7 +1824,6 @@ Keybinds =
|
||||
|
||||
focus: (post) ->
|
||||
$.addClass post, 'highlight'
|
||||
$('a[title="Highlight this post"]', post).focus()
|
||||
|
||||
Nav =
|
||||
init: ->
|
||||
@ -2426,10 +2451,10 @@ Misc = # super semantic
|
||||
|
||||
return if data.lastChecked > Date.now() - 12 * $.HOUR
|
||||
|
||||
$.ajax "//api.4chan.org/#{g.BOARD}/catalog.json", onload: ->
|
||||
$.ajax "//api.4chan.org/#{g.BOARD}/threads.json", onload: ->
|
||||
threads = {}
|
||||
for obj in JSON.parse @response
|
||||
for thread in obj.threads
|
||||
for page in JSON.parse @response
|
||||
for thread in page.threads
|
||||
if thread.no of data.threads
|
||||
threads[thread.no] = data.threads[thread.no]
|
||||
unless Object.keys(threads).length
|
||||
@ -2637,7 +2662,7 @@ QuotePreview =
|
||||
# Remove the clone that's in the qp from the array.
|
||||
posts.pop()
|
||||
for post in posts
|
||||
$.addClass post.nodes.post, 'qphl'
|
||||
$.addClass post.nodes.root, 'qphl'
|
||||
|
||||
quoterID = $.x('ancestor::*[@id][1]', @).id.match(/\d+$/)[0]
|
||||
clone = Get.postFromRoot qp.firstChild
|
||||
@ -2658,7 +2683,7 @@ QuotePreview =
|
||||
|
||||
return unless Conf['Quote Highlighting']
|
||||
for post in [post].concat post.clones
|
||||
$.rmClass post.nodes.post, 'qphl'
|
||||
$.rmClass post.nodes.root, 'qphl'
|
||||
return
|
||||
|
||||
QuoteBacklink =
|
||||
@ -3062,14 +3087,15 @@ Sauce =
|
||||
createSauceLink: (link) ->
|
||||
link = link.replace /%(T?URL|MD5|board)/ig, (parameter) ->
|
||||
switch parameter
|
||||
when '%TURL', '%turl'
|
||||
"' + post.file.thumbURL + '"
|
||||
when '%URL', '%url'
|
||||
"' + post.file.URL + '"
|
||||
when '%MD5', '%md5'
|
||||
|
||||
when '%TURL'
|
||||
"' + encodeURIComponent(post.file.thumbURL) + '"
|
||||
when '%URL'
|
||||
"' + encodeURIComponent(post.file.URL) + '"
|
||||
when '%MD5'
|
||||
"' + encodeURIComponent(post.file.MD5) + '"
|
||||
when '%board'
|
||||
"' + post.board + '"
|
||||
"' + encodeURIComponent(post.board) + '"
|
||||
else
|
||||
parameter
|
||||
text = if m = link.match(/;text:(.+)$/) then m[1] else link.match(/(\w+)\.\w+\//)[1]
|
||||
@ -3178,7 +3204,7 @@ ImageExpand =
|
||||
# Scroll back to the thumbnail when contracting the image
|
||||
# to avoid being left miles away from the relevant post.
|
||||
postRect = post.nodes.root.getBoundingClientRect()
|
||||
headRect = Header.bar.getBoundingClientRect()
|
||||
headRect = Header.toggle.getBoundingClientRect()
|
||||
top = postRect.top - headRect.top - headRect.height - 2
|
||||
root = if $.engine is 'webkit'
|
||||
d.body
|
||||
@ -3229,7 +3255,10 @@ ImageExpand =
|
||||
post = Get.postFromNode @
|
||||
$.rm @
|
||||
delete post.file.fullImage
|
||||
unless $.hasClass post.file.thumb, 'expanding'
|
||||
# Images can error:
|
||||
# - before the image started loading.
|
||||
# - after the image started loading.
|
||||
unless $.hasClass(post.file.thumb, 'expanding') or $.hasClass post.nodes.root, 'expanded-image'
|
||||
# Don't try to re-expend if it was already contracted.
|
||||
return
|
||||
ImageExpand.contract post
|
||||
@ -3452,7 +3481,7 @@ ExpandThread =
|
||||
#goddamit moot
|
||||
num = if thread.isSticky
|
||||
1
|
||||
else switch g.BOARD
|
||||
else switch g.BOARD.ID
|
||||
# XXX boards config
|
||||
when 'b', 'vg', 'q' then 3
|
||||
when 't' then 1
|
||||
@ -3500,7 +3529,7 @@ ExpandThread =
|
||||
|
||||
# Enable 4chan features.
|
||||
if Conf['Enable 4chan\'s Extension']
|
||||
$.unsafeWindow.Parser.parseThread thread.ID, 1, nodes.length
|
||||
$.globalEval "Parser.parseThread(#{thread.ID}, 1, #{nodes.length})"
|
||||
else
|
||||
Fourchan.parseThread thread.ID, 1, nodes.length
|
||||
|
||||
@ -3512,7 +3541,10 @@ ThreadExcerpt =
|
||||
name: 'Thread Excerpt'
|
||||
cb: @node
|
||||
node: ->
|
||||
d.title = Get.threadExcerpt @
|
||||
d.title = if (excerpt = Get.threadExcerpt @).length > 80
|
||||
"#{excerpt[...77]}..."
|
||||
else
|
||||
excerpt
|
||||
|
||||
Unread =
|
||||
init: ->
|
||||
@ -3634,10 +3666,12 @@ Unread =
|
||||
else
|
||||
Favicon.default
|
||||
|
||||
<% if (type !== 'crx') { %>
|
||||
# `favicon.href = href` doesn't work on Firefox.
|
||||
# `favicon.href = href` isn't enough on Opera.
|
||||
# Opera won't always update the favicon if the href didn't change.
|
||||
$.add d.head, Favicon.el
|
||||
<% } %>
|
||||
|
||||
Favicon =
|
||||
init: ->
|
||||
@ -4004,9 +4038,9 @@ ThreadUpdater =
|
||||
$.queueTask ->
|
||||
# Enable 4chan features.
|
||||
threadID = ThreadUpdater.thread.ID
|
||||
{length} = ThreadUpdater.root.children
|
||||
{length} = $$ '.thread > .postContainer', ThreadUpdater.root
|
||||
if Conf['Enable 4chan\'s Extension']
|
||||
$.unsafeWindow.Parser.parseThread threadID, -count
|
||||
$.globalEval "Parser.parseThread(#{threadID}, #{-count})"
|
||||
else
|
||||
Fourchan.parseThread threadID, length - count, length
|
||||
|
||||
@ -4045,6 +4079,7 @@ ThreadWatcher =
|
||||
$.delete 'AutoWatch'
|
||||
|
||||
ready: ->
|
||||
return unless Main.isThisPageLegit()
|
||||
ThreadWatcher.refresh()
|
||||
$.add d.body, ThreadWatcher.dialog
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
<% if (type === 'userjs') { %>
|
||||
# Opera doesn't support the @match metadata key,
|
||||
# return 4chan X here if we're not on 4chan.
|
||||
return unless /^[a-z]+\.4chan\.org$/.test location.hostname
|
||||
<% } %>
|
||||
|
||||
editTheme = {} # Currently editted theme.
|
||||
editMascot = {} # Which mascot we're editting.
|
||||
@ -8,8 +10,8 @@ userNavigation = {} # ...
|
||||
Conf = {}
|
||||
c = console
|
||||
d = document
|
||||
doc = null
|
||||
g =
|
||||
doc = d.documentElement
|
||||
g =
|
||||
VERSION: '<%= version %>'
|
||||
NAMESPACE: '<%= meta.name %>.'.replace ' ', '_'
|
||||
TYPE: 'sfw'
|
||||
@ -2759,4 +2761,4 @@ Icons =
|
||||
png: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA'
|
||||
themes:
|
||||
oneechan: 'A8AAACWBAMAAADzkc/yAAAAMFBMVEVoaGhsbGxsbGxsbGxsbGxsbGxsbGxsbGxqampsbGxsbGxsbGxlZWVsbGxsbGxsbGzdpWE1AAAAD3RSTlMAfEDYHcNYkhP0pz8MJYTrg0d+AAACwElEQVR4Xp3RT2gTaRjH8W9r/rVJNTl42UvHvYinVGLR7SoZ6+JBD0kpsafVgJale4m67r/DkgEp7EEMsqy2KEwEUdjt0kBZqovY3oQedEBE8GA9iV42TQaTVm0f33lfCAgLZfuDgc/85n2f5zDAonnYIQ5LIwCykrj5hyqc5dWlz35QaMr7c3eKEBGReVVASaRZBOCxiKfRJ7KuMV4x1eGvE7pKjHo8bvwDXXsh0Xqu4AGP/mKT7DRgwTc4IgaXRSSTeQ2i0zbNv2UBjonP9gDMGQC7DQAiGbacbwpjRYB7rsh0DSLN+pnSqxbk7reIfEjb7Iyvwvtw0jSrC7Y6Uy6WzreAPVl1y+rM2STjmaGa3uX/+PNbB+JrHqSnoDJAfy3mQ92hbJG2GFS26KnSIHjtHaClUCM6wBA8RX0KDtf14coUp73YdDDQgvRb4ImMnRJxgPnRsXFZwaTbAl4UTnoASzKYbTsQy14gVD4AvS0g0oblsxCvztrUbUKztVySUSi12ZanQEg+EM6rpleK9OTptxd+AnUmV/0TULeies5GMPmWun8AeCS/uxsOwOHCiM0nOV4zWBp5Y2ncJnYIIJSHeYB4EsIaL2ESgH3wSmPOutzQCH1/ov8gJmF/0SCWXTfgYtuAvl/4jyyLzzYRj5xcJ+6KrfBucbsEcKVaF9dm8oH48u5vB6iLzJhN4qMzIWtF4OFR95p79dkilS+kOLGWdajIVSKuBDhEKKuQkzZRUUj8ekk/MPy5io2qg7Qhd8GGr8o2aRsgZ5EeloZB9zqwQ6PrxkkN8QanTEMpaRD7TTfDsnFwv7rVmdOZ3NnV2a6KZL/Iyv9DKpWydqVSSTrpNFsbCN9mpk8ATIrKWWA2QAsiEqQBYY0Z6FG4cheIytBEC4AE4TUP0GXeoEvaBnG1xSgrTYOS+Hz6M2PffclH1wyYp51t8R8AAAAASUVORK5CYII='
|
||||
"4chan SS": 'A8AAACWBAMAAADzkc/yAAAAMFBMVEVmZmZnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2djY2NkZGRnZ2dnZ2dnZ2eHsc5jAAAAD3RSTlMAgEDLkve+G+dSqwcRdCZzKH/3AAACz0lEQVR4Xp2PQWhTdxzHP0vTliQvMaE4NjdoutMOA6NrpeghQaazp4R1XkL15VDR4UbeKiJ4UXCuzG7kgd2lONLbGNmWgKwqGyMQN0QRqruIuKYXi9iDtkmeaaD97Z9/2nfy0n0u+fDl//3+XnA5E+XIoA30bPDnVceC0EfgkynAl6AyulICHhjDi/kYEHx7Ab8NhPpW0bxfbRQAfEcfSasEVGv3RTIQlMlAVlagv7lIRcSi+An05hy4awN3f+a1TKNhqbFvfAG4LW1+BVNLI0pRNDE8cS0p8F364bEpF4FbkJdZAIxs0wIIvSU/AuAdPci2GRj6ooz+jpp8A4RyzvKSFOCZrB46KLUyWUmZKVMybuK+cVvAwAm1s12MXUP73wXYKSKNMHhF0iJ1qIpMqWyebEcymCJjSi4SFzmuk6p+LPP8JXKs0zI3dx7eePOyWn4900ODNsD5xmC8ZUHv5Se/B81J8Lf6xkdOpSE/kmvtWq7aJK0Xze/KNxN8iNeZpyfGpwT+vYc3xT4I/GP7YxwqQTL9W4J8GO6sqJb/OHSPpNvL7/C8OKlvjZ9Qt9zrEDx1Rf+G4iKtMtAlIzOSAKprUF0FsgmV1oGcDW84W9ICirNwfQ3IrxNIvgL8sqdPVgAjKYow4Dn805c6AujXEaq/JURg/BpgTGdINhbhqSTI10pQEZs78dMY8eEyvXNOqeLcAALZkyoEmGs4JS295hiaik5Qlc+zpwFPxSnNqRZncwVVVDt6+brYFJubt36Jbl5n4j2FBV5pU4cLH1twLmmx2wK4EGX3hKx3xLMB7NASHBvUIstff9tJyM93xLg0tkO36lNfqZa74y67t9zrKgj3i7zcnkQikehAJBLGxU3+3yDMDB/9DOBvUSSAYlvWwSeb0qWlAN1Kjn0AeOXK9+sA/EFXYxHQ4QE0QamjCakraOKyiqYqNTQ9W2Ic2ct/3c/SAwz13v8AAAAASUVORK5CYII='
|
||||
"4chan SS": 'A8AAACWBAMAAADzkc/yAAAAMFBMVEVmZmZnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2djY2NkZGRnZ2dnZ2dnZ2eHsc5jAAAAD3RSTlMAgEDLkve+G+dSqwcRdCZzKH/3AAACz0lEQVR4Xp2PQWhTdxzHP0vTliQvMaE4NjdoutMOA6NrpeghQaazp4R1XkL15VDR4UbeKiJ4UXCuzG7kgd2lONLbGNmWgKwqGyMQN0QRqruIuKYXi9iDtkmeaaD97Z9/2nfy0n0u+fDl//3+XnA5E+XIoA30bPDnVceC0EfgkynAl6AyulICHhjDi/kYEHx7Ab8NhPpW0bxfbRQAfEcfSasEVGv3RTIQlMlAVlagv7lIRcSi+An05hy4awN3f+a1TKNhqbFvfAG4LW1+BVNLI0pRNDE8cS0p8F364bEpF4FbkJdZAIxs0wIIvSU/AuAdPci2GRj6ooz+jpp8A4RyzvKSFOCZrB46KLUyWUmZKVMybuK+cVvAwAm1s12MXUP73wXYKSKNMHhF0iJ1qIpMqWyebEcymCJjSi4SFzmuk6p+LPP8JXKs0zI3dx7eePOyWn4900ODNsD5xmC8ZUHv5Se/B81J8Lf6xkdOpSE/kmvtWq7aJK0Xze/KNxN8iNeZpyfGpwT+vYc3xT4I/GP7YxwqQTL9W4J8GO6sqJb/OHSPpNvL7/C8OKlvjZ9Qt9zrEDx1Rf+G4iKtMtAlIzOSAKprUF0FsgmV1oGcDW84W9ICirNwfQ3IrxNIvgL8sqdPVgAjKYow4Dn805c6AujXEaq/JURg/BpgTGdINhbhqSTI10pQEZs78dMY8eEyvXNOqeLcAALZkyoEmGs4JS295hiaik5Qlc+zpwFPxSnNqRZncwVVVDt6+brYFJubt36Jbl5n4j2FBV5pU4cLH1twLmmx2wK4EGX3hKx3xLMB7NASHBvUIstff9tJyM93xLg0tkO36lNfqZa74y67t9zrKgj3i7zcnkQikehAJBLGxU3+3yDMDB/9DOBvUSSAYlvWwSeb0qWlAN1Kjn0AeOXK9+sA/EFXYxHQ4QE0QamjCakraOKyiqYqNTQ9W2Ic2ct/3c/SAwz13v8AAAAASUVORK5CYII='
|
||||
|
||||
@ -41,28 +41,28 @@ class Post
|
||||
backlinks: info.getElementsByClassName 'backlink'
|
||||
|
||||
@info = {}
|
||||
if subject = $ '.subject', info
|
||||
if subject = $ '.subject', info
|
||||
@nodes.subject = subject
|
||||
@info.subject = subject.textContent
|
||||
if name = $ '.name', info
|
||||
if name = $ '.name', info
|
||||
@nodes.name = name
|
||||
@info.name = name.textContent
|
||||
if email = $ '.useremail', info
|
||||
if email = $ '.useremail', info
|
||||
@nodes.email = email
|
||||
@info.email = decodeURIComponent email.href[7..]
|
||||
if tripcode = $ '.postertrip', info
|
||||
if tripcode = $ '.postertrip', info
|
||||
@nodes.tripcode = tripcode
|
||||
@info.tripcode = tripcode.textContent
|
||||
if uniqueID = $ '.posteruid', info
|
||||
if uniqueID = $ '.posteruid', info
|
||||
@nodes.uniqueID = uniqueID
|
||||
@info.uniqueID = uniqueID.firstElementChild.textContent
|
||||
if capcode = $ '.capcode', info
|
||||
if capcode = $ '.capcode.hand', info
|
||||
@nodes.capcode = capcode
|
||||
@info.capcode = capcode.textContent
|
||||
if flag = $ '.countryFlag', info
|
||||
@info.capcode = capcode.textContent.replace '## ', ''
|
||||
if flag = $ '.countryFlag', info
|
||||
@nodes.flag = flag
|
||||
@info.flag = flag.title
|
||||
if date = $ '.dateTime', info
|
||||
if date = $ '.dateTime', info
|
||||
@nodes.date = date
|
||||
@info.date = new Date date.dataset.utc * 1000
|
||||
if Conf['Quick Reply']
|
||||
@ -284,9 +284,6 @@ class Clone extends Post
|
||||
|
||||
Main =
|
||||
init: ->
|
||||
$.asap (-> d.documentElement), ->
|
||||
doc = d.documentElement
|
||||
|
||||
# flatten Config into Conf
|
||||
# and get saved or default values
|
||||
flatten = (parent, obj) ->
|
||||
@ -344,7 +341,7 @@ Main =
|
||||
for name, module of features
|
||||
# c.time "#{name} initialization"
|
||||
try
|
||||
module.init()
|
||||
do module.init
|
||||
catch err
|
||||
Main.handleErrors
|
||||
message: "\"#{name}\" initialization crashed."
|
||||
@ -447,6 +444,7 @@ Main =
|
||||
Main.callbackNodes Post, posts
|
||||
|
||||
$.event '4chanXInitFinished'
|
||||
Main.checkUpdate()
|
||||
|
||||
callbackNodes: (klass, nodes) ->
|
||||
# get the nodes' length only once
|
||||
@ -467,14 +465,42 @@ Main =
|
||||
Main.handleErrors errors if errors
|
||||
|
||||
addCallback: (e) ->
|
||||
obj = e.detail
|
||||
Klass = if obj.type is 'Post'
|
||||
Post
|
||||
else
|
||||
Thread
|
||||
obj = e.detail
|
||||
unless typeof obj.callback.name is 'string'
|
||||
throw new Error "Invalid callback name: #{obj.callback.name}"
|
||||
switch obj.type
|
||||
when 'Post'
|
||||
Klass = Post
|
||||
when 'Thread'
|
||||
Klass = Thread
|
||||
else
|
||||
return
|
||||
obj.callback.isAddon = true
|
||||
Klass::callbacks.push obj.callback
|
||||
|
||||
checkUpdate: ->
|
||||
return unless Main.isThisPageLegit()
|
||||
# Check for updates after:
|
||||
# - 6 hours since the last update on Opera because it lacks auto-updating.
|
||||
# - 7 days since the last update on Chrome/Firefox.
|
||||
# After that, check for updates every day if we still haven't updated.
|
||||
now = Date.now()
|
||||
freq = <% if (type === 'userjs') { %>6 * $.HOUR<% } else { %>7 * $.DAY<% } %>
|
||||
if $.get('lastupdate', 0) > now - freq or $.get('lastchecked', 0) > now - $.DAY
|
||||
return
|
||||
$.ajax '<%= meta.page %><%= meta.buildsPath %>version', onload: ->
|
||||
return unless @status is 200
|
||||
version = @response
|
||||
return unless /^\d\.\d+\.\d+$/.test version
|
||||
if g.VERSION is version
|
||||
# Don't check for updates too frequently if there wasn't one in a 'long' time.
|
||||
$.set 'lastupdate', now
|
||||
return
|
||||
$.set 'lastchecked', now
|
||||
el = $.el 'span',
|
||||
innerHTML: "Update: <%= meta.name %> v#{version} is out, get it <a href=<%= meta.page %> target=_blank>here</a>."
|
||||
new Notification 'info', el, 2 * $.MINUTE
|
||||
|
||||
handleErrors: (errors) ->
|
||||
unless 'length' of errors
|
||||
error = errors
|
||||
@ -485,7 +511,7 @@ Main =
|
||||
return
|
||||
|
||||
div = $.el 'div',
|
||||
innerHTML: "#{errors.length} errors occured. [<a href=javascript:;>show</a>]"
|
||||
innerHTML: "#{errors.length} errors occurred. [<a href=javascript:;>show</a>]"
|
||||
$.on div.lastElementChild, 'click', ->
|
||||
if @textContent is 'show'
|
||||
@textContent = 'hide'
|
||||
@ -514,7 +540,9 @@ Main =
|
||||
isThisPageLegit: ->
|
||||
# 404 error page or similar.
|
||||
unless 'thisPageIsLegit' of Main
|
||||
Main.thisPageIsLegit = !$('link[href*="favicon-status.ico"]', d.head) and d.title isnt '4chan - Temporarily Offline'
|
||||
Main.thisPageIsLegit = location.hostname is 'boards.4chan.org' and
|
||||
!$('link[href*="favicon-status.ico"]', d.head) and
|
||||
d.title not in ['4chan - Temporarily Offline', '4chan - Error']
|
||||
Main.thisPageIsLegit
|
||||
|
||||
|
||||
|
||||
@ -3,12 +3,19 @@
|
||||
"version": "<%= version %>",
|
||||
"manifest_version": 2,
|
||||
"description": "<%= description %>",
|
||||
"icons": {
|
||||
"16": "icon16.png",
|
||||
"48": "icon48.png",
|
||||
"128": "icon128.png"
|
||||
},
|
||||
"content_scripts": [{
|
||||
"js": ["script.js"],
|
||||
"matches": <%= JSON.stringify(meta.matches) %>,
|
||||
"run_at": "document_start"
|
||||
}],
|
||||
"homepage_url": "<%= meta.page %>",
|
||||
"incognito": "spanning",
|
||||
"minimum_chrome_version": "25"
|
||||
"minimum_chrome_version": "25",
|
||||
"permissions": [
|
||||
"storage"
|
||||
]
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
// @grant GM_deleteValue
|
||||
// @grant GM_openInTab
|
||||
// @run-at document-start
|
||||
// @updateURL <%= meta.repo %>raw/<%= meta.mainBranch %>/<%= name %>.meta.js
|
||||
// @downloadURL <%= meta.repo %>raw/<%= meta.mainBranch %>/<%= name %>.user.js
|
||||
// @icon data:image/gif;base64,<%= grunt.file.read('img/icon.gif', {encoding: 'base64'}) %>
|
||||
// @updateURL <%= meta.page %><%= meta.buildsPath %><%= name %>.meta.js
|
||||
// @downloadURL <%= meta.page %><%= meta.buildsPath %><%= name %>.user.js
|
||||
// @icon data:image/png;base64,<%= grunt.file.read('img/icon48.png', {encoding: 'base64'}) %>
|
||||
// ==/UserScript==
|
||||
|
||||
@ -486,6 +486,7 @@ QR =
|
||||
# so we generate thumbnails `s` times bigger then expected
|
||||
# to avoid crappy resized quality.
|
||||
s = 90*2
|
||||
s *= 3 if @file.type is 'image/gif' # let them animate
|
||||
{height, width} = img
|
||||
if height < s or width < s
|
||||
@URL = fileURL if window.URL
|
||||
@ -581,6 +582,12 @@ QR =
|
||||
return unless @isEnabled = !!$.id 'captchaFormPart'
|
||||
$.asap (-> $.id 'recaptcha_challenge_field_holder'), @ready.bind @
|
||||
ready: ->
|
||||
setLifetime = (e) => @lifetime = e.detail
|
||||
$.on window, 'captcha:timeout', setLifetime
|
||||
$.globalEval 'window.dispatchEvent(new CustomEvent("captcha:timeout", {detail: RecaptchaState.timeout}))'
|
||||
$.off window, 'captcha:timeout', setLifetime
|
||||
c.log @lifetime
|
||||
|
||||
imgContainer = $.el 'div',
|
||||
className: 'captcha-img'
|
||||
title: 'Reload'
|
||||
@ -648,7 +655,7 @@ QR =
|
||||
load: ->
|
||||
return unless @nodes.challenge.firstChild
|
||||
# -1 minute to give upload some time.
|
||||
@timeout = Date.now() + $.unsafeWindow.RecaptchaState.timeout * $.SECOND - $.MINUTE
|
||||
@timeout = Date.now() + @lifetime * $.SECOND - $.MINUTE
|
||||
challenge = @nodes.challenge.firstChild.value
|
||||
@nodes.img.alt = challenge
|
||||
@nodes.img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}"
|
||||
@ -666,7 +673,7 @@ QR =
|
||||
@nodes.input.alt = count # For XTRM RICE.
|
||||
reload: (focus) ->
|
||||
# the 't' argument prevents the input from being focused
|
||||
$.unsafeWindow.Recaptcha.reload 't'
|
||||
$.globalEval 'Recaptcha.reload("t")'
|
||||
# Focus if we meant to.
|
||||
@nodes.input.focus() if focus
|
||||
keydown: (e) ->
|
||||
@ -701,14 +708,14 @@ QR =
|
||||
<a id=add-post href=javascript:; title="Add a post">+</a>
|
||||
</div>
|
||||
<div id=file-n-submit>
|
||||
<input type=submit>
|
||||
<input id=qr-file-button type=button value='Choose files'>
|
||||
<span id=qr-filename-container>
|
||||
<span id=qr-no-file>No selected file</span>
|
||||
<span id=qr-filename></span>
|
||||
</span>
|
||||
<a id=qr-filerm href=javascript:; title='Remove file' tabindex=-1>×</a>
|
||||
<input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=-1>
|
||||
<input type=submit>
|
||||
<a id=qr-filerm href=javascript:; title='Remove file'>×</a>
|
||||
<input type=checkbox id=qr-file-spoiler title='Spoiler image'>
|
||||
</div>
|
||||
<input type=file multiple>
|
||||
</form>
|
||||
@ -877,12 +884,14 @@ QR =
|
||||
callbacks =
|
||||
onload: QR.response
|
||||
onerror: ->
|
||||
# Connection error, or
|
||||
# www.4chan.org/banned
|
||||
delete QR.req
|
||||
post.unlock()
|
||||
QR.cooldown.auto = false
|
||||
QR.status()
|
||||
# Connection error.
|
||||
QR.error 'Network error.'
|
||||
QR.error $.el 'span',
|
||||
innerHTML: 'Connection error. You may have been <a href=//www.4chan.org/banned target=_blank>banned</a>.'
|
||||
opts =
|
||||
form: $.formData postData
|
||||
upCallbacks:
|
||||
@ -966,6 +975,7 @@ QR =
|
||||
[_, threadID, postID] = h1.nextSibling.textContent.match /thread:(\d+),no:(\d+)/
|
||||
postID = +postID
|
||||
threadID = +threadID or postID
|
||||
isReply = threadID isnt postID
|
||||
|
||||
(QR.yourPosts.threads[threadID] or= []).push postID
|
||||
$.set "yourPosts.#{g.BOARD}", QR.yourPosts
|
||||
@ -980,18 +990,15 @@ QR =
|
||||
}, QR.nodes.el
|
||||
|
||||
# Enable auto-posting if we have stuff to post, disable it otherwise.
|
||||
QR.cooldown.auto = QR.posts.length > 1
|
||||
QR.cooldown.auto = QR.posts.length > 1 and isReply
|
||||
|
||||
post.rm()
|
||||
|
||||
QR.cooldown.set
|
||||
req: req
|
||||
post: post
|
||||
isReply: !!threadID
|
||||
QR.cooldown.set {req, post, isReply}
|
||||
|
||||
if threadID is postID # new thread
|
||||
URL = "/#{g.BOARD}/res/#{threadID}"
|
||||
else if g.VIEW is 'index' and !QR.cooldown.auto # posting from the index
|
||||
else if g.VIEW is 'index' and !QR.cooldown.auto and Conf['Open Post in New Tab'] # replying from the index
|
||||
URL = "/#{g.BOARD}/res/#{threadID}#p#{postID}"
|
||||
if URL
|
||||
if Conf['Open Post in New Tab']
|
||||
|
||||
@ -6,7 +6,7 @@ Report =
|
||||
form = $ 'form'
|
||||
field = $.id 'recaptcha_response_field'
|
||||
$.on field, 'keydown', (e) ->
|
||||
$.unsafeWindow.Recaptcha.reload 't' if e.keyCode is 8 and not field.value
|
||||
$.globalEval 'Recaptcha.reload("t")' if e.keyCode is 8 and not field.value
|
||||
$.on form, 'submit', (e) ->
|
||||
e.preventDefault()
|
||||
response = field.value.trim()
|
||||
|
||||