Tag:
%gLiteral %: %%
Quick Reply Personas One item per line. Items will be added in the relevant input's auto-completion list. Password items will always be used, since there is no password input. Lines starting with a # will be ignored.
You can use these settings with each item, separate them with semicolons:Possible items are: name, options (or equivalently email), subject and password. Wrap values of items with quotes, like this: options:"sage". Force values as defaults with the always keyword, for example: options:"sage";always. Select specific boards for an item, separated with commas, for example: options:"sage";boards:jp;always. Unread Favicon is disabled. ferongr xat- 4chanJS Mayhem Original Metro Thread Updater is disabled. Interval: seconds
Custom Cooldown Time Seconds:
Custom CSSFor more information about customizing 4chan X's CSS, see the
styling guide .
Apply CSS Javascript Whitelist Sources from which Javascript is allowed to be loaded by
Content Security Policy .
Lines starting with a
# will be ignored.
Known Banners List of known banners, used for click-to-change feature.
"});
ref = $$('.warning', section);
for (j = 0, len = ref.length; j < len; j++) {
warning = ref[j];
@@ -13607,9 +13538,7 @@ Settings = (function() {
textContent: archive[1]
}));
}
- $.extend(td, {
- innerHTML: "
"
- });
+ $.extend(td, {innerHTML: "
"});
select = td.firstElementChild;
if (!(select.disabled = length === 1)) {
select.setAttribute('data-boardid', boardID);
@@ -13731,9 +13660,7 @@ Settings = (function() {
},
keybinds: function(section) {
var arr, input, inputs, items, key, ref, tbody, tr;
- $.extend(section, {
- innerHTML: "
Keybinds are disabled.
Allowed keys: a-z , 0-9 , Ctrl , Shift , Alt , Meta , Enter , Esc , Up , Down , Right , Left .
Press Backspace to disable a keybind.
"
- });
+ $.extend(section, {innerHTML: "
Keybinds are disabled.
Allowed keys: a-z , 0-9 , Ctrl , Shift , Alt , Meta , Enter , Esc , Up , Down , Right , Left .
Press Backspace to disable a keybind.
"});
$('.warning', section).hidden = Conf['Keybinds'];
tbody = $('tbody', section);
items = $.dict();
@@ -13741,9 +13668,7 @@ Settings = (function() {
ref = Config.hotkeys;
for (key in ref) {
arr = ref[key];
- tr = $.el('tr', {
- innerHTML: "
" + E(arr[1]) + " "
- });
+ tr = $.el('tr', {innerHTML: "
" + E(arr[1]) + " "});
input = $('input', tr);
input.name = key;
input.spellcheck = false;
@@ -14424,9 +14349,7 @@ Gallery = (function() {
nodes.el = dialog = $.el('div', {
id: 'a-gallery'
});
- $.extend(dialog, {
- innerHTML: "
"
- });
+ $.extend(dialog, {innerHTML: "
"});
ref = {
buttons: '.gal-buttons',
frame: '.gal-image',
@@ -14875,9 +14798,7 @@ Gallery = (function() {
}
return results;
})();
- delayLabel = $.el('label', {
- innerHTML: "Slide Delay:
"
- });
+ delayLabel = $.el('label', {innerHTML: "Slide Delay:
"});
delayInput = delayLabel.firstElementChild;
delayInput.value = Gallery.delay;
$.on(delayInput, 'change', Gallery.cb.setDelay);
@@ -14991,7 +14912,7 @@ ImageCommon = (function() {
onloadend: function() {
var i, len, postObj, ref, ref1;
if (this.status === 404) {
- post.kill(!post.isClone);
+ post.kill(!post.isClone, fileObj.index);
}
if (this.status !== 200) {
return redirect();
@@ -15083,9 +15004,7 @@ ImageExpand = (function() {
this.videoControls = $.el('span', {
className: 'video-controls'
});
- $.extend(this.videoControls, {
- innerHTML: "
contract "
- });
+ $.extend(this.videoControls, {innerHTML: "
contract "});
return Callbacks.Post.push({
name: 'Image Expansion',
cb: this.node
@@ -15693,9 +15612,7 @@ ImageLoader = (function() {
if (!(Conf['Image Prefetching'] && ((ref1 = g.VIEW) === 'index' || ref1 === 'thread'))) {
return;
}
- prefetch = $.el('label', {
- innerHTML: "
Prefetch Images"
- });
+ prefetch = $.el('label', {innerHTML: "
Prefetch Images"});
this.el = prefetch.firstElementChild;
$.on(this.el, 'change', this.toggle);
return Header.menu.addEntry({
@@ -15741,12 +15658,19 @@ ImageLoader = (function() {
return file.videoThumb = true;
},
prefetch: function(post, file) {
- var clone, el, i, isImage, isVideo, len, match, ref, replace, thumb, type, url;
+ var clone, el, i, isImage, isVideo, len, ref, ref1, replace, thumb, type, url;
isImage = file.isImage, isVideo = file.isVideo, thumb = file.thumb, url = file.url;
if (file.isPrefetched || !(isImage || isVideo) || post.isHidden || post.thread.isHidden) {
return;
}
- type = (match = url.match(/\.([^.]+)$/)[1].toUpperCase()) === 'JPEG' ? 'JPG' : match;
+ if (isVideo) {
+ type = 'WEBM';
+ } else {
+ type = (ref = url.match(/\.([^.]+)$/)) != null ? ref[1].toUpperCase() : void 0;
+ if (type === 'JPEG') {
+ type = 'JPG';
+ }
+ }
replace = Conf["Replace " + type] && !/spoiler/.test(thumb.src || thumb.dataset.src);
if (!(replace || Conf['prefetch'])) {
return;
@@ -15761,9 +15685,9 @@ ImageLoader = (function() {
}
file.isPrefetched = true;
if (file.videoThumb) {
- ref = post.clones;
- for (i = 0, len = ref.length; i < len; i++) {
- clone = ref[i];
+ ref1 = post.clones;
+ for (i = 0, len = ref1.length; i < len; i++) {
+ clone = ref1[i];
clone.file.thumb.preload = 'auto';
}
thumb.preload = 'auto';
@@ -15777,10 +15701,10 @@ ImageLoader = (function() {
el = $.el(isImage ? 'img' : 'video');
if (replace && isImage) {
$.on(el, 'load', function() {
- var j, len1, ref1;
- ref1 = post.clones;
- for (j = 0, len1 = ref1.length; j < len1; j++) {
- clone = ref1[j];
+ var j, len1, ref2;
+ ref2 = post.clones;
+ for (j = 0, len1 = ref2.length; j < len1; j++) {
+ clone = ref2[j];
clone.file.thumb.src = url;
}
return thumb.src = url;
@@ -15860,9 +15784,7 @@ Metadata = (function() {
className: 'webm-title'
});
el.dataset.index = i;
- $.extend(el, {
- innerHTML: "
"
- });
+ $.extend(el, {innerHTML: "
"});
$.add(file.text, [$.tn(' '), el]);
}
if (el.children.length === 1) {
@@ -16249,9 +16171,7 @@ Volume = (function() {
volumeEntry = $.el('label', {
title: 'Default volume for videos.'
});
- $.extend(volumeEntry, {
- innerHTML: "
Volume"
- });
+ $.extend(volumeEntry, {innerHTML: "
Volume"});
this.inputs = {
unmute: unmuteEntry.firstElementChild,
volume: volumeEntry.firstElementChild
@@ -16361,20 +16281,18 @@ Embedding = (function() {
this.types[type.key] = type;
}
if (Conf['Embedding'] && g.VIEW !== 'archive') {
- this.dialog = UI.dialog('embedding', {
- innerHTML: "
"
- });
+ this.dialog = UI.dialog('embedding', {innerHTML: "
"});
this.media = $('#media-embed', this.dialog);
$.one(d, '4chanXInitFinished', this.ready);
$.on(d, 'IndexRefreshInternal', function() {
return g.posts.forEach(function(post) {
- var embed, k, l, len1, len2, ref2, ref3;
+ var embed, l, len1, len2, n, ref2, ref3;
ref2 = [post].concat(slice.call(post.clones));
- for (k = 0, len1 = ref2.length; k < len1; k++) {
- post = ref2[k];
+ for (l = 0, len1 = ref2.length; l < len1; l++) {
+ post = ref2[l];
ref3 = post.nodes.embedlinks;
- for (l = 0, len2 = ref3.length; l < len2; l++) {
- embed = ref3[l];
+ for (n = 0, len2 = ref3.length; n < len2; n++) {
+ embed = ref3[n];
Embedding.cb.catalogRemove.call(embed);
}
}
@@ -16382,7 +16300,7 @@ Embedding = (function() {
});
}
if (Conf['Link Title']) {
- return $.on(d, '4chanXInitFinished PostsInserted', function() {
+ $.on(d, '4chanXInitFinished PostsInserted', function() {
var key, ref2, ref3, service;
ref2 = Embedding.types;
for (key in ref2) {
@@ -16392,6 +16310,8 @@ Embedding = (function() {
}
}
});
+ this.cache.init(Conf['cachedTitles']);
+ return $.sync('cachedTitles', this.cache.sync);
}
},
events: function(post) {
@@ -16464,9 +16384,7 @@ Embedding = (function() {
embed = $.el('a', {
className: 'embedder',
href: 'javascript:;'
- }, {
- innerHTML: "(
un embed)"
- });
+ }, {innerHTML: "(
un embed)"});
ref = {
key: key,
uid: uid,
@@ -16521,13 +16439,15 @@ Embedding = (function() {
return style.pointerEvents = 'none';
},
title: function(data) {
- var key, link, options, post, service, uid;
+ var key, link, options, post, service, text, uid;
key = data.key, uid = data.uid, options = data.options, link = data.link, post = data.post;
if (!(service = Embedding.types[key].title)) {
return;
}
$.addClass(link, key.toLowerCase());
- if (service.batchSize) {
+ if ((text = Embedding.cache.get(data))) {
+ return Embedding.cb.titleText(text, data);
+ } else if (service.batchSize) {
(service.queue || (service.queue = [])).push(data);
if (service.queue.length >= service.batchSize) {
return Embedding.flushTitles(service);
@@ -16562,6 +16482,70 @@ Embedding = (function() {
return results;
})()), cb);
},
+ cache: (function() {
+ var get, init, newEntries, save, set, sync, titles;
+ titles = $.dict();
+ newEntries = [];
+ init = function(data) {
+ var j, key, len, ref, text, uid;
+ try {
+ for (j = 0, len = data.length; j < len; j++) {
+ ref = data[j], key = ref.key, uid = ref.uid, text = ref.text;
+ titles[key + "." + uid] = text;
+ }
+ } catch (error) {}
+ };
+ sync = function(data) {
+ var j, k, key, len, ref, text, uid;
+ try {
+ for (j = 0, len = data.length; j < len; j++) {
+ ref = data[j], key = ref.key, uid = ref.uid, text = ref.text;
+ k = key + "." + uid;
+ if (k in titles) {
+ break;
+ }
+ titles[k] = text;
+ }
+ } catch (error) {}
+ };
+ get = function(arg) {
+ var key, uid;
+ key = arg.key, uid = arg.uid;
+ return titles[key + "." + uid];
+ };
+ set = function(arg, text) {
+ var key, uid;
+ key = arg.key, uid = arg.uid;
+ titles[key + "." + uid] = text;
+ newEntries.push({
+ key: key,
+ uid: uid,
+ text: text
+ });
+ return save();
+ };
+ save = $.debounce(2 * $.SECOND, function() {
+ return $.get('cachedTitles', Conf['cachedTitles'], function(arg) {
+ var cachedTitles;
+ cachedTitles = arg.cachedTitles;
+ sync(cachedTitles);
+ try {
+ cachedTitles = newEntries.concat(cachedTitles).slice(-100);
+ } catch (error) {
+ cachedTitles = newEntries;
+ }
+ newEntries = [];
+ return $.set('cachedTitles', cachedTitles);
+ });
+ });
+ return {
+ init: init,
+ sync: sync,
+ get: get,
+ set: set,
+ save: save
+ };
+ })(),
preview: function(data) {
var key, link, service, uid;
key = data.key, uid = data.uid, link = data.link;
@@ -16627,34 +16611,42 @@ Embedding = (function() {
}
},
title: function(req, data) {
- var base1, j, k, key, len, len1, link, link2, options, post, post2, ref, ref1, service, status, text, uid;
+ var key, service, status, text, uid;
if (!req.status) {
return;
}
- key = data.key, uid = data.uid, options = data.options, link = data.link, post = data.post;
+ key = data.key, uid = data.uid;
status = req.status;
service = Embedding.types[key].title;
- text = "[" + key + "] " + ((function() {
- switch (status) {
- case 200:
- case 304:
- return service.text(req.response, uid);
- case 404:
- return "Not Found";
- case 403:
- return "Forbidden or Private";
- default:
- return status + "'d";
- }
- })());
+ switch (status) {
+ case 200:
+ case 304:
+ text = service.text(req.response, uid);
+ Embedding.cache.set(data, text);
+ break;
+ case 404:
+ text = "Not Found";
+ break;
+ case 403:
+ text = "Forbidden or Private";
+ break;
+ default:
+ text = status + "'d";
+ }
+ return Embedding.cb.titleText(text, data);
+ },
+ titleText: function(text, data) {
+ var base1, j, key, l, len, len1, link, link2, post, post2, ref, ref1;
+ key = data.key, link = data.link, post = data.post;
+ text = "[" + key + "] " + text;
link.dataset.original = link.textContent;
link.textContent = text;
ref = post.clones;
for (j = 0, len = ref.length; j < len; j++) {
post2 = ref[j];
ref1 = $$('a.linkify', post2.nodes.comment);
- for (k = 0, len1 = ref1.length; k < len1; k++) {
- link2 = ref1[k];
+ for (l = 0, len1 = ref1.length; l < len1; l++) {
+ link2 = ref1[l];
if (!(link2.href === link.href)) {
continue;
}
@@ -16683,9 +16675,7 @@ Embedding = (function() {
regExp: /^[^?#]+\.(?:gif|png|jpg|jpeg|bmp)(?::\w+)?(?:[?#]|$)/i,
style: '',
el: function(a) {
- return $.el('div', {
- innerHTML: "
"
- });
+ return $.el('div', {innerHTML: "
"});
}
}, {
key: 'video',
@@ -16845,10 +16835,10 @@ Embedding = (function() {
}
}, {
key: 'Loopvid',
- regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\/#?((?:pf|kd|lv|gd|gh|db|dx|nn|cp|wu|ig|ky|mf|m2|pc|1c|pi|ni|wl|ko|gc)\/[\w\-\/]+(?:,[\w\-\/]+)*|fc\/\w+\/\d+|https?:\/\/.+)/,
+ regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\/#?((?:pf|kd|lv|gd|gh|db|dx|nn|cp|wu|ig|ky|mf|m2|pc|1c|pi|ni|wl|ko|mm|ic|gc)\/[\w\-\/]+(?:,[\w\-\/]+)*|fc\/\w+\/\d+|https?:\/\/.+)/,
style: 'max-width: 80vw; max-height: 80vh;',
el: function(a) {
- var _, base, el, host, j, k, l, len, len1, len2, name, names, ref, ref1, type, types, url, urls;
+ var _, base, el, host, j, l, len, len1, len2, n, name, names, ref, ref1, type, types, url, urls;
el = $.el('video', {
controls: true,
preload: 'auto',
@@ -16876,8 +16866,8 @@ Embedding = (function() {
ref1 = names.split(',');
for (j = 0, len = ref1.length; j < len; j++) {
name = ref1[j];
- for (k = 0, len1 = types.length; k < len1; k++) {
- type = types[k];
+ for (l = 0, len1 = types.length; l < len1; l++) {
+ type = types[l];
base = "" + name + type;
urls = (function() {
switch (host) {
@@ -16910,25 +16900,29 @@ Embedding = (function() {
case 'm2':
return ["https://kastden.org/_loopvid_media/m2/" + base];
case 'pc':
- return ["http://a.pomf.cat/" + base];
+ return ["https://kastden.org/_loopvid_media/pc/" + base, "https://web.archive.org/web/2/http://a.pomf.cat/" + base];
case '1c':
return ["http://b.1339.cf/" + base];
case 'pi':
- return ["https://u.pomf.is/" + base];
+ return ["https://kastden.org/_loopvid_media/pi/" + base, "https://web.archive.org/web/2/https://u.pomf.is/" + base];
case 'ni':
- return ["https://u.nya.is/" + base];
+ return ["https://kastden.org/_loopvid_media/ni/" + base, "https://web.archive.org/web/2/https://u.nya.is/" + base];
case 'wl':
return ["http://webm.land/media/" + base];
case 'ko':
return ["https://kordy.kastden.org/loopvid/" + base];
+ case 'mm':
+ return ["https://kastden.org/_loopvid_media/mm/" + base, "https://web.archive.org/web/2/https://my.mixtape.moe/" + base];
+ case 'ic':
+ return ["https://media.8ch.net/file_store/" + base];
case 'fc':
return ["//" + (ImageHost.host()) + "/" + base + ".webm"];
case 'gc':
return ["https://" + type + ".gfycat.com/" + name + ".webm"];
}
})();
- for (l = 0, len2 = urls.length; l < len2; l++) {
- url = urls[l];
+ for (n = 0, len2 = urls.length; n < len2; n++) {
+ url = urls[n];
$.add(el, $.el('source', {
src: url
}));
@@ -17567,9 +17561,7 @@ DeleteLink = (function() {
}
link.textContent = DeleteLink.linkText(fileOnly);
if (resDoc.title === '4chan - Banned') {
- el = $.el('span', {
- innerHTML: "You can't delete posts because you are
banned ."
- });
+ el = $.el('span', {innerHTML: "You can't delete posts because you are
banned ."});
return new Notice('warning', el, 20);
} else if (msg = resDoc.getElementById('errmsg')) {
new Notice('warning', msg.textContent, 20);
@@ -17681,9 +17673,7 @@ Menu = (function() {
className: 'menu-button',
href: 'javascript:;'
});
- $.extend(this.button, {
- innerHTML: "
"
- });
+ $.extend(this.button, {innerHTML: "
"});
this.menu = new UI.Menu('post');
Callbacks.Post.push({
name: 'Menu',
@@ -18542,14 +18532,10 @@ FileInfo = (function() {
var a, i, j, len, len1, output, ref, ref1;
output = [];
formatString.replace(/%(.)|[^%]+/g, function(s, c) {
- output.push($.hasOwn(FileInfo.formatters, c) ? FileInfo.formatters[c].call(post) : {
- innerHTML: E(s)
- });
+ output.push($.hasOwn(FileInfo.formatters, c) ? FileInfo.formatters[c].call(post) : {innerHTML: E(s)});
return '';
});
- $.extend(outputNode, {
- innerHTML: E.cat(output)
- });
+ $.extend(outputNode, {innerHTML: E.cat(output)});
ref = $$('.download-button', outputNode);
for (i = 0, len = ref.length; i < len; i++) {
a = ref[i];
@@ -18563,93 +18549,59 @@ FileInfo = (function() {
},
formatters: {
t: function() {
- return {
- innerHTML: E(this.file.url.match(/[^/]*$/)[0])
- };
+ return {innerHTML: E(this.file.url.match(/[^/]*$/)[0])};
},
T: function() {
- return {
- innerHTML: "
" + (FileInfo.formatters.t.call(this)).innerHTML + " "
- };
+ return {innerHTML: "
" + (FileInfo.formatters.t.call(this)).innerHTML + " "};
},
l: function() {
- return {
- innerHTML: "
" + (FileInfo.formatters.n.call(this)).innerHTML + " "
- };
+ return {innerHTML: "
" + (FileInfo.formatters.n.call(this)).innerHTML + " "};
},
L: function() {
- return {
- innerHTML: "
" + (FileInfo.formatters.N.call(this)).innerHTML + " "
- };
+ return {innerHTML: "
" + (FileInfo.formatters.N.call(this)).innerHTML + " "};
},
n: function() {
var fullname, shortname;
fullname = this.file.name;
shortname = g.SITE.Build.shortFilename(this.file.name, this.isReply);
if (fullname === shortname) {
- return {
- innerHTML: E(fullname)
- };
+ return {innerHTML: E(fullname)};
} else {
- return {
- innerHTML: "
" + E(shortname) + " " + E(fullname) + " "
- };
+ return {innerHTML: "
" + E(shortname) + " " + E(fullname) + " "};
}
},
N: function() {
- return {
- innerHTML: E(this.file.name)
- };
+ return {innerHTML: E(this.file.name)};
},
d: function() {
- return {
- innerHTML: "
"
- };
+ return {innerHTML: "
"};
},
f: function() {
- return {
- innerHTML: "
"
- };
+ return {innerHTML: "
"};
},
p: function() {
- return {
- innerHTML: ((this.file.isSpoiler) ? "Spoiler, " : "")
- };
+ return {innerHTML: ((this.file.isSpoiler) ? "Spoiler, " : "")};
},
s: function() {
- return {
- innerHTML: E(this.file.size)
- };
+ return {innerHTML: E(this.file.size)};
},
B: function() {
- return {
- innerHTML: E(Math.round(this.file.sizeInBytes)) + " Bytes"
- };
+ return {innerHTML: E(Math.round(this.file.sizeInBytes)) + " Bytes"};
},
K: function() {
- return {
- innerHTML: E(Math.round(this.file.sizeInBytes/1024)) + " KB"
- };
+ return {innerHTML: E(Math.round(this.file.sizeInBytes/1024)) + " KB"};
},
M: function() {
- return {
- innerHTML: E(Math.round(this.file.sizeInBytes/1048576*100)/100) + " MB"
- };
+ return {innerHTML: E(Math.round(this.file.sizeInBytes/1048576*100)/100) + " MB"};
},
r: function() {
- return {
- innerHTML: E(this.file.dimensions || "PDF")
- };
+ return {innerHTML: E(this.file.dimensions || "PDF")};
},
g: function() {
- return {
- innerHTML: ((this.file.tag) ? ", " + E(this.file.tag) : "")
- };
+ return {innerHTML: ((this.file.tag) ? ", " + E(this.file.tag) : "")};
},
'%': function() {
- return {
- innerHTML: "%"
- };
+ return {innerHTML: "%"};
}
}
};
@@ -18718,7 +18670,17 @@ Fourchan = (function() {
return $.addClass(pre, 'prettyprinted');
}
});
- $.globalEval('window.addEventListener(\'prettyprint\', function(e) {\n window.dispatchEvent(new CustomEvent(\'prettyprint:cb\', {\n detail: {\n ID: e.detail.ID,\n i: e.detail.i,\n html: prettyPrintOne(e.detail.html)\n }\n }));\n}, false);');
+ $.global(function() {
+ return window.addEventListener('prettyprint', function(e) {
+ return window.dispatchEvent(new CustomEvent('prettyprint:cb', {
+ detail: {
+ ID: e.detail.ID,
+ i: e.detail.i,
+ html: window.prettyPrintOne(e.detail.html)
+ }
+ }));
+ }, false);
+ });
Callbacks.Post.push({
name: 'Parse [code] tags',
cb: Fourchan.code
@@ -19317,7 +19279,7 @@ Keybinds = (function() {
}
post = Keybinds.post(threadRoot);
Keybinds.hl(+1, threadRoot);
- Filter.quickFilterMD5.call(post);
+ Filter.quickFilterMD5.call(post, e);
break;
case Conf['Previous Post Quoting You']:
if (!(threadRoot && QuoteYou.db)) {
@@ -19531,34 +19493,24 @@ ModContact = (function() {
}
},
template: function(capcode) {
- return {
- innerHTML: "
feedback " + (ModContact.specific[capcode]()).innerHTML
- };
+ return {innerHTML: "
feedback " + (ModContact.specific[capcode]()).innerHTML};
},
specific: {
Mod: function() {
- return {
- innerHTML: "
IRC "
- };
+ return {innerHTML: "
IRC "};
},
Manager: function() {
return ModContact.specific.Mod();
},
Developer: function() {
- return {
- innerHTML: "
github "
- };
+ return {innerHTML: "
github "};
},
Admin: function() {
- return {
- innerHTML: "
twitter "
- };
+ return {innerHTML: "
twitter "};
}
},
moveNote: {
- qa: {
- innerHTML: "Moving a thread to /qa/ does not imply mods will read it. If you wish to contact mods, use
feedback (https://www.4chan.org/feedback) or
IRC (https://www.4chan-x.net/4chan-irc.html) ."
- }
+ qa: {innerHTML: "Moving a thread to /qa/ does not imply mods will read it. If you wish to contact mods, use
feedback (https://www.4chan.org/feedback) or
IRC (https://www.4chan-x.net/4chan-irc.html) ."}
}
};
@@ -19889,9 +19841,7 @@ PostJumper = (function() {
span = $.el('span', {
className: 'postJumper'
});
- $.extend(span, {
- innerHTML: "
" + E(charPrev) + " " + E(charNext) + " "
- });
+ $.extend(span, {innerHTML: "
" + E(charPrev) + " " + E(charNext) + " "});
return span;
},
scroll: function(fromJumper, toJumper) {
@@ -20121,9 +20071,7 @@ Report = (function() {
fieldset = $.el('fieldset', {
id: 'archive-report',
hidden: true
- }, {
- innerHTML: "
Report illegal content to archivesDetails Submit "
- });
+ }, {innerHTML: "
Report illegal content to archivesDetails Submit "});
enabled = $('#archive-report-enabled', fieldset);
reason = $('#archive-report-reason', fieldset);
submit = $('#archive-report-submit', fieldset);
@@ -20590,9 +20538,7 @@ ReplyPruning = (function() {
label = UI.checkbox('Prune Replies', 'Show Last', Conf['Prune All Threads']);
el = $.el('span', {
title: 'Maximum number of replies to show.'
- }, {
- innerHTML: "
"
- });
+ }, {innerHTML: "
"});
$.prepend(el, label);
this.inputs = {
enabled: label.firstElementChild,
@@ -20736,9 +20682,7 @@ ThreadStats = (function() {
if (Conf['Page Count in Stats']) {
this[(typeof (base = g.SITE).isPrunedByAge === "function" ? base.isPrunedByAge(g.BOARD) : void 0) ? 'showPurgePos' : 'showPage'] = true;
}
- statsHTML = {
- innerHTML: "
? /
? " + ((Conf["IP Count in Stats"] && g.SITE.hasIPCount) ? " /
? " : "") + ((Conf["Page Count in Stats"]) ? " /
? " : "")
- };
+ statsHTML = {innerHTML: "
? /
? " + ((Conf["IP Count in Stats"] && g.SITE.hasIPCount) ? " /
? " : "") + ((Conf["Page Count in Stats"]) ? " /
? " : "")};
statsTitle = 'Posts / Files';
if (Conf['IP Count in Stats'] && g.SITE.hasIPCount) {
statsTitle += ' / IPs';
@@ -20754,9 +20698,7 @@ ThreadStats = (function() {
$.extend(sc, statsHTML);
Header.addShortcut('stats', sc, 200);
} else {
- this.dialog = sc = UI.dialog('thread-stats', {
- innerHTML: "
" + (statsHTML).innerHTML + "
"
- });
+ this.dialog = sc = UI.dialog('thread-stats', {innerHTML: "
" + (statsHTML).innerHTML + "
"});
$.addClass(doc, 'float');
$.ready(function() {
return $.add(d.body, sc);
@@ -20925,14 +20867,10 @@ ThreadUpdater = (function() {
this.dialog = sc = $.el('span', {
id: 'updater'
});
- $.extend(sc, {
- innerHTML: "
"
- });
+ $.extend(sc, {innerHTML: "
"});
Header.addShortcut('updater', sc, 100);
} else {
- this.dialog = sc = UI.dialog('updater', {
- innerHTML: "
"
- });
+ this.dialog = sc = UI.dialog('updater', {innerHTML: "
"});
$.addClass(doc, 'float');
$.ready(function() {
return $.add(d.body, sc);
@@ -20946,9 +20884,7 @@ ThreadUpdater = (function() {
updateLink = $.el('span', {
className: 'brackets-wrap updatelink'
});
- $.extend(updateLink, {
- innerHTML: "
Update "
- });
+ $.extend(updateLink, {innerHTML: "
Update "});
Main.ready(function() {
var navLinksBot;
if ((navLinksBot = $('.navLinksBot'))) {
@@ -20974,9 +20910,7 @@ ThreadUpdater = (function() {
el: el
});
}
- this.settings = $.el('span', {
- innerHTML: "
Interval "
- });
+ this.settings = $.el('span', {innerHTML: "
Interval "});
$.on(this.settings, 'click', this.intervalShortcut);
subEntries.push({
el: this.settings
@@ -21359,9 +21293,7 @@ ThreadWatcher = (function() {
});
this.db = new DataBoard('watchedThreads', this.refresh, true);
this.dbLM = new DataBoard('watcherLastModified', null, true);
- this.dialog = UI.dialog('thread-watcher', {
- innerHTML: "
"
- });
+ this.dialog = UI.dialog('thread-watcher', {innerHTML: "
"});
this.status = $('#watcher-status', this.dialog);
this.list = this.dialog.lastElementChild;
this.refreshButton = $('.refresh', this.dialog);
@@ -21399,9 +21331,7 @@ ThreadWatcher = (function() {
el: $.el('a', {
href: 'javascript:;',
className: 'has-shortcut-text'
- }, {
- innerHTML: "
Alt+click "
- }),
+ }, {innerHTML: "
Alt+click "}),
order: 6,
open: function(arg) {
var thread;
@@ -23486,9 +23416,7 @@ Captcha = {};
root = $.el('div', {
className: 'captcha-root'
});
- $.extend(root, {
- innerHTML: "
"
- });
+ $.extend(root, {innerHTML: "
"});
counter = $('.captcha-counter > a', root);
this.nodes = {
root: root,
@@ -23767,9 +23695,7 @@ PassLink = (function() {
passLink = $.el('span', {
className: 'brackets-wrap pass-link-container'
});
- $.extend(passLink, {
- innerHTML: "
4chan Pass "
- });
+ $.extend(passLink, {innerHTML: "
4chan Pass "});
$.on(passLink.firstElementChild, 'click', function() {
return window.open("//sys." + (location.hostname.split('.')[1]) + ".org/auth", Date.now(), 'width=500,height=280,toolbar=0');
});
@@ -23940,9 +23866,7 @@ QR = (function() {
link = $.el('h1', {
className: "qr-link-container"
});
- $.extend(link, {
- innerHTML: "
" + ((g.VIEW === "thread") ? "Reply to Thread" : "Start a Thread") + " "
- });
+ $.extend(link, {innerHTML: "
" + ((g.VIEW === "thread") ? "Reply to Thread" : "Start a Thread") + " "});
QR.link = link.firstElementChild;
$.on(link.firstChild, 'click', function() {
QR.open();
@@ -23955,9 +23879,7 @@ QR = (function() {
linkBot = $.el('div', {
className: "brackets-wrap qr-link-container-bottom"
});
- $.extend(linkBot, {
- innerHTML: "
Reply to Thread "
- });
+ $.extend(linkBot, {innerHTML: "
Reply to Thread "});
$.on(linkBot.firstElementChild, 'click', function() {
QR.open();
return QR.nodes.com.focus();
@@ -24156,9 +24078,7 @@ QR = (function() {
}
},
connectionError: function() {
- return $.el('span', {
- innerHTML: "Connection error while posting. [
More info ]"
- });
+ return $.el('span', {innerHTML: "Connection error while posting. [
More info ]"});
},
notifications: [],
cleanNotifications: function() {
@@ -24306,9 +24226,7 @@ QR = (function() {
openError: function() {
var div;
div = $.el('div');
- $.extend(div, {
- innerHTML: "Could not open file. [
More info ]"
- });
+ $.extend(div, {innerHTML: "Could not open file. [
More info ]"});
return QR.error(div);
},
setFile: function(e) {
@@ -24486,9 +24404,7 @@ QR = (function() {
dialog: function() {
var classList, config, dialog, event, i, items, name, node, nodes, save, setNode;
QR.nodes = nodes = {
- el: dialog = UI.dialog('qr', {
- innerHTML: "
"
- })
+ el: dialog = UI.dialog('qr', {innerHTML: "
∀ TE X
Width: Height:
Hentai Porn Japanese Anime Game Loop Other "})
};
setNode = function(name, query) {
return nodes[name] = $(query, dialog);
@@ -24544,6 +24460,7 @@ QR = (function() {
QR.flagsInput();
$.on(nodes.autohide, 'change', QR.toggleHide);
$.on(nodes.close, 'click', QR.close);
+ $.on(nodes.status, 'click', QR.submit);
$.on(nodes.form, 'submit', QR.submit);
$.on(nodes.sjisToggle, 'click', QR.toggleSJIS);
$.on(nodes.texButton, 'mousedown', QR.texPreviewShow);
@@ -24657,19 +24574,24 @@ QR = (function() {
}
},
submit: function(e) {
- var captcha, cb, err, filetag, formData, options, post, ref, thread, threadID;
+ var captcha, cb, err, filetag, force, formData, options, post, ref, thread, threadID;
if (e != null) {
e.preventDefault();
}
+ force = e != null ? e.shiftKey : void 0;
if (QR.req) {
QR.abort();
return;
}
$.forceSync('cooldowns');
if (QR.cooldown.seconds) {
- QR.cooldown.auto = !QR.cooldown.auto;
- QR.status();
- return;
+ if (force) {
+ QR.cooldown.clear();
+ } else {
+ QR.cooldown.auto = !QR.cooldown.auto;
+ QR.status();
+ return;
+ }
}
post = QR.posts[0];
post.forceSave();
@@ -24703,7 +24625,7 @@ QR = (function() {
}
}
QR.cleanNotifications();
- if (err) {
+ if (err && !force) {
QR.cooldown.auto = false;
QR.status();
QR.error(err);
@@ -24789,7 +24711,7 @@ QR = (function() {
return QR.status();
},
response: function() {
- var URL, _, connErr, err, h1, isReply, lastPostToThread, m, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
+ var URL, _, connErr, err, h1, isReply, j, lastPostToThread, len, m, mi, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
if (this !== QR.req) {
return;
}
@@ -24823,9 +24745,13 @@ QR = (function() {
QR.cooldown.auto = QR.captcha.isEnabled || connErr;
QR.cooldown.addDelay(post, 2);
}
- } else if (err.textContent && (m = err.textContent.match(/(?:(\d+)\s+minutes?\s+)?(\d+)\s+second/i)) && !/duplicate|hour/i.test(err.textContent)) {
+ } else if (err.textContent && (m = err.textContent.match(/\d+\s+(?:minute|second)/gi)) && !/duplicate|hour/i.test(err.textContent)) {
QR.cooldown.auto = !/have\s+been\s+muted/i.test(err.textContent);
- seconds = 60 * (+(m[1] || 0)) + (+m[2]);
+ seconds = 0;
+ for (j = 0, len = m.length; j < len; j++) {
+ mi = m[j];
+ seconds += (/minute/i.test(mi) ? 60 : 1) * (+mi.match(/\d+/)[0]);
+ }
if (/muted/i.test(err.textContent)) {
QR.cooldown.addMute(seconds);
} else {
@@ -24858,10 +24784,10 @@ QR = (function() {
postsCount = QR.posts.length - 1;
QR.cooldown.auto = postsCount && isReply;
lastPostToThread = !((function() {
- var j, len, p, ref4;
+ var k, len1, p, ref4;
ref4 = QR.posts.slice(1);
- for (j = 0, len = ref4.length; j < len; j++) {
- p = ref4[j];
+ for (k = 0, len1 = ref4.length; k < len1; k++) {
+ p = ref4[k];
if (p.thread === post.thread) {
return true;
}
@@ -25102,6 +25028,13 @@ QR = (function() {
});
});
},
+ clear: function() {
+ QR.cooldown.data = $.dict();
+ QR.cooldown.changes = $.dict();
+ QR.cooldown.auto = false;
+ QR.cooldown.update();
+ return $.queueTask($["delete"], 'cooldowns');
+ },
update: function() {
var base, cooldown, cooldowns, elapsed, i, len, maxDelay, nCooldowns, now, ref, ref1, save, scope, seconds, start, suffix, threadID, type, update;
if (!QR.cooldown.isCounting) {
@@ -25524,9 +25457,7 @@ QR = (function() {
draggable: true,
href: 'javascript:;'
});
- $.extend(el, {
- innerHTML: "
Spoiler"
- });
+ $.extend(el, {innerHTML: "
Spoiler"});
this.nodes = {
el: el,
rm: el.firstChild,
@@ -25763,9 +25694,7 @@ QR = (function() {
div = $.el('div', {
className: className
});
- $.extend(div, {
- innerHTML: E(message) + ((link) ? " [
More info ]" : "") + "
[
delete post ] [
delete all ]"
- });
+ $.extend(div, {innerHTML: E(message) + ((link) ? " [
More info ]" : "") + "
[
delete post ] [
delete all ]"});
(this.errors || (this.errors = [])).push(div);
ref = $$('a', div), rm = ref[0], rmAll = ref[1];
$.on(div, 'click', (function(_this) {
@@ -26568,16 +26497,12 @@ QuoteThreading =
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
- this.controls = $.el('label', {
- innerHTML: "
Threading"
- });
+ this.controls = $.el('label', {innerHTML: "
Threading"});
this.threadNewLink = $.el('span', {
className: 'brackets-wrap threadnewlink',
hidden: true
});
- $.extend(this.threadNewLink, {
- innerHTML: "
Thread New Posts "
- });
+ $.extend(this.threadNewLink, {innerHTML: "
Thread New Posts "});
this.input = $('input', this.controls);
this.input.checked = Conf['Thread Quotes'];
$.on(this.input, 'change', this.setEnabled);
@@ -26872,9 +26797,7 @@ QuoteYou = (function() {
var input, label, ref;
label = $.el('label', {
className: 'toggle-you'
- }, {
- innerHTML: "
You"
- });
+ }, {innerHTML: "
You"});
input = $('input', label);
$.on(input, 'change', QuoteYou.menu.toggle);
return (ref = Menu.menu) != null ? ref.addEntry({
@@ -27276,6 +27199,7 @@ Main = (function() {
if ($.cantSet) {
} else if (items.previousversion == null) {
+ Main.isFirstRun = true;
Main.ready(function() {
$.set('previousversion', g.VERSION);
return Settings.open();
@@ -27299,9 +27223,7 @@ Main = (function() {
return $.set(changes, function() {
var el, ref;
if ((ref = items['Show Updated Notifications']) != null ? ref : true) {
- el = $.el('span', {
- innerHTML: "4chan X has been updated to
version " + E(g.VERSION) + " ."
- });
+ el = $.el('span', {innerHTML: "4chan X has been updated to
version " + E(g.VERSION) + " ."});
return new Notice('info', el, 15);
}
});
@@ -27541,9 +27463,7 @@ Main = (function() {
return;
}
if (typeof (base1 = g.SITE).isIncomplete === "function" ? base1.isIncomplete() : void 0) {
- msg = $.el('div', {
- innerHTML: "The page didn't load completely.
Some features may not work unless you
reload ."
- });
+ msg = $.el('div', {innerHTML: "The page didn't load completely.
Some features may not work unless you
reload ."});
$.on($('a', msg), 'click', function() {
return location.reload();
});
@@ -27627,7 +27547,8 @@ Main = (function() {
err = error1;
errors.push({
message: "Parsing of Post No." + (postRoot.id.match(/\d+/)) + " failed. Post will be skipped.",
- error: err
+ error: err,
+ html: postRoot.outerHTML
});
}
}
@@ -27746,7 +27667,8 @@ Main = (function() {
err = error1;
errors.push({
message: "Parsing of Catalog Thread No." + ((threadRoot.dataset.id || threadRoot.id).match(/\d+/)) + " failed. Thread will be skipped.",
- error: err
+ error: err,
+ html: threadRoot.outerHTML
});
}
}
@@ -27810,11 +27732,21 @@ Main = (function() {
return softTask();
},
handleErrors: function(errors) {
- var div, error, j, len, logs;
+ var div, enabled, error, j, len, logs, msg;
if (d.body && $.hasClass(d.body, 'fourchan_x') && !$.hasClass(doc, 'tainted')) {
new Notice('error', 'Error: Multiple copies of 4chan X are enabled.');
$.addClass(doc, 'tainted');
}
+ if (g.SITE.testNativeExtension && !$.hasClass(doc, 'tainted')) {
+ enabled = g.SITE.testNativeExtension().enabled;
+ if (enabled) {
+ $.addClass(doc, 'tainted');
+ if (Conf['Disable Native Extension'] && !Main.isFirstRun) {
+ msg = $.el('div', {innerHTML: "Failed to disable the native extension. You may need to
block it ."});
+ new Notice('error', msg);
+ }
+ }
+ }
if (!(errors instanceof Array)) {
error = errors;
} else if (errors.length === 1) {
@@ -27824,9 +27756,7 @@ Main = (function() {
new Notice('error', Main.parseError(error, Main.reportLink([error])), 15);
return;
}
- div = $.el('div', {
- innerHTML: E(errors.length) + " errors occurred." + (Main.reportLink(errors)).innerHTML + " [
show ]"
- });
+ div = $.el('div', {innerHTML: E(errors.length) + " errors occurred." + (Main.reportLink(errors)).innerHTML + " [
show ]"});
$.on(div.lastElementChild, 'click', function() {
var ref;
return ref = this.textContent === 'show' ? ['hide', false] : ['show', true], this.textContent = ref[0], logs.hidden = ref[1], ref;
@@ -27843,9 +27773,7 @@ Main = (function() {
parseError: function(data, reportLink) {
var context, error, lines, message, ref, ref1;
c.error(data.message, data.error.stack);
- message = $.el('div', {
- innerHTML: E(data.message) + ((reportLink) ? (reportLink).innerHTML : "")
- });
+ message = $.el('div', {innerHTML: E(data.message) + ((reportLink) ? (reportLink).innerHTML : "")});
error = $.el('div', {
textContent: (data.error.name || 'Error') + ": " + (data.error.message || 'see console for details')
});
@@ -27856,7 +27784,7 @@ Main = (function() {
return [message, error, context];
},
reportLink: function(errors) {
- var addDetails, data, details, title, url;
+ var addDetails, data, details, info, title, url;
data = errors[0];
title = data.message;
if (errors.length > 1) {
@@ -27868,7 +27796,10 @@ Main = (function() {
return details += text + '\n';
}
};
- addDetails("[Please describe the steps needed to reproduce this error.]\n\nScript: 4chan X ccd0 v" + g.VERSION + " " + $.platform + "\nUser agent: " + navigator.userAgent + "\nURL: " + location.href);
+ addDetails("[Please describe the steps needed to reproduce this error.]\n\nScript: 4chan X ccd0 v" + g.VERSION + " " + $.platform + "\nURL: " + location.href + "\nUser agent: " + navigator.userAgent);
+ if ($.platform === 'userscript' && (info = typeof GM !== "undefined" && GM !== null ? GM.info : (typeof GM_info !== "undefined" && GM_info !== null ? GM_info : void 0))) {
+ addDetails("Userscript manager: " + info.scriptHandler + " " + info.version);
+ }
addDetails('\n' + data.error);
if (data.error.stack) {
addDetails(data.error.stack.replace(data.error.toString(), '').trim());
@@ -27877,10 +27808,8 @@ Main = (function() {
addDetails('\n`' + data.html + '`');
}
details = details.replace(/file:\/{3}.+\//g, '');
- url = "https://gitreports.com/issue/ccd0/4chan-x?issue_title=" + (encodeURIComponent(title)) + "&details=" + (encodeURIComponent(details));
- return {
- innerHTML: "
[report ] "
- };
+ url = 'https://gitreports.com/issue/ccd0/4chan-x?issue_title=%title&details=%details'.replace('%title', encodeURIComponent(title)).replace('%details', encodeURIComponent(details));
+ return {innerHTML: "
[report ] "};
},
isThisPageLegit: function() {
if (!('thisPageIsLegit' in Main)) {
diff --git a/builds/4chan-X.crx b/builds/4chan-X.crx
index 28a046201..0bb29dedd 100644
Binary files a/builds/4chan-X.crx and b/builds/4chan-X.crx differ
diff --git a/builds/4chan-X.meta.js b/builds/4chan-X.meta.js
index dd50574b9..5f76c94b5 100644
--- a/builds/4chan-X.meta.js
+++ b/builds/4chan-X.meta.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
-// @version 1.14.11.1
+// @version 1.14.12.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js
index 5b6e4f0fb..84faca6aa 100644
--- a/builds/4chan-X.user.js
+++ b/builds/4chan-X.user.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
-// @version 1.14.11.1
+// @version 1.14.12.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@@ -199,7 +199,7 @@ docSet = function() {
};
g = {
- VERSION: '1.14.11.1',
+ VERSION: '1.14.12.0',
NAMESPACE: '4chan X.',
sites: Object.create(null),
boards: Object.create(null)
@@ -575,7 +575,8 @@ Config = (function() {
],
fourchanImageHost: 'i.4cdn.org',
hiddenPSAList: [{}],
- knownBanners: '0.jpg,1.jpg,2.jpg,4.jpg,6.jpg,7.jpg,8.jpg,9.jpg,10.jpg,11.jpg,12.jpg,13.jpg,14.jpg,16.jpg,17.jpg,18.jpg,19.jpg,20.jpg,21.jpg,22.jpg,24.jpg,25.jpg,26.jpg,28.jpg,29.jpg,33.jpg,38.jpg,39.jpg,43.jpg,44.jpg,45.jpg,46.jpg,47.jpg,52.jpg,54.jpg,57.jpg,59.jpg,60.jpg,61.jpg,64.jpg,66.jpg,67.jpg,69.jpg,71.jpg,72.jpg,76.jpg,77.jpg,81.jpg,82.jpg,83.jpg,84.jpg,88.jpg,90.jpg,91.jpg,96.jpg,98.jpg,99.jpg,100.jpg,104.jpg,106.jpg,116.jpg,119.jpg,137.jpg,140.jpg,148.jpg,149.jpg,150.jpg,154.jpg,156.jpg,157.jpg,158.jpg,159.jpg,161.jpg,162.jpg,164.jpg,165.jpg,166.jpg,167.jpg,168.jpg,169.jpg,170.jpg,171.jpg,172.jpg,173.jpg,174.jpg,175.jpg,176.jpg,178.jpg,179.jpg,180.jpg,181.jpg,182.jpg,183.jpg,186.jpg,189.jpg,190.jpg,192.jpg,193.jpg,194.jpg,197.jpg,198.jpg,200.jpg,201.jpg,202.jpg,203.jpg,205.jpg,206.jpg,207.jpg,208.jpg,210.jpg,213.jpg,214.jpg,215.jpg,216.jpg,218.jpg,219.jpg,220.jpg,221.jpg,222.jpg,223.jpg,224.jpg,227.jpg,0.png,1.png,2.png,3.png,5.png,6.png,9.png,10.png,11.png,12.png,14.png,16.png,19.png,20.png,21.png,22.png,23.png,24.png,26.png,27.png,28.png,29.png,30.png,31.png,32.png,33.png,34.png,37.png,39.png,40.png,41.png,42.png,43.png,44.png,45.png,48.png,49.png,50.png,51.png,52.png,53.png,57.png,58.png,59.png,64.png,66.png,67.png,68.png,69.png,70.png,71.png,72.png,76.png,78.png,79.png,81.png,82.png,85.png,86.png,87.png,89.png,95.png,98.png,100.png,101.png,102.png,105.png,106.png,107.png,109.png,110.png,111.png,112.png,113.png,114.png,115.png,116.png,118.png,119.png,120.png,121.png,122.png,123.png,126.png,128.png,130.png,134.png,136.png,138.png,139.png,140.png,142.png,145.png,146.png,149.png,150.png,151.png,152.png,153.png,154.png,155.png,156.png,157.png,158.png,159.png,160.png,163.png,164.png,165.png,166.png,167.png,168.png,169.png,170.png,171.png,172.png,173.png,174.png,178.png,179.png,180.png,181.png,182.png,184.png,186.png,188.png,190.png,192.png,193.png,194.png,195.png,196.png,197.png,198.png,200.png,202.png,203.png,205.png,206.png,207.png,209.png,212.png,213.png,214.png,216.png,217.png,218.png,219.png,220.png,221.png,222.png,223.png,224.png,225.png,226.png,229.png,231.png,232.png,233.png,234.png,235.png,237.png,238.png,239.png,240.png,241.png,242.png,244.png,245.png,246.png,247.png,248.png,249.png,250.png,253.png,254.png,255.png,256.png,257.png,258.png,259.png,260.png,262.png,268.png,0.gif,1.gif,2.gif,3.gif,4.gif,5.gif,6.gif,7.gif,8.gif,9.gif,10.gif,12.gif,13.gif,14.gif,15.gif,16.gif,18.gif,19.gif,20.gif,21.gif,22.gif,23.gif,24.gif,28.gif,29.gif,30.gif,33.gif,34.gif,35.gif,36.gif,37.gif,39.gif,40.gif,42.gif,44.gif,45.gif,46.gif,48.gif,50.gif,52.gif,54.gif,55.gif,57.gif,58.gif,59.gif,60.gif,61.gif,63.gif,64.gif,66.gif,67.gif,68.gif,69.gif,70.gif,72.gif,73.gif,75.gif,76.gif,77.gif,78.gif,80.gif,81.gif,82.gif,83.gif,86.gif,87.gif,88.gif,92.gif,93.gif,94.gif,95.gif,96.gif,97.gif,98.gif,99.gif,100.gif,101.gif,102.gif,103.gif,104.gif,105.gif,106.gif,108.gif,109.gif,110.gif,111.gif,112.gif,113.gif,115.gif,116.gif,117.gif,118.gif,119.gif,120.gif,122.gif,123.gif,124.gif,127.gif,129.gif,130.gif,131.gif,134.gif,135.gif,136.gif,138.gif,139.gif,141.gif,144.gif,146.gif,148.gif,149.gif,153.gif,154.gif,155.gif,157.gif,158.gif,159.gif,160.gif,161.gif,162.gif,164.gif,166.gif,167.gif,168.gif,169.gif,170.gif,171.gif,172.gif,173.gif,174.gif,175.gif,176.gif,177.gif,178.gif,181.gif,182.gif,183.gif,185.gif,186.gif,187.gif,188.gif,189.gif,190.gif,191.gif,192.gif,193.gif,195.gif,196.gif,197.gif,200.gif,201.gif,202.gif,203.gif,204.gif,205.gif,206.gif,207.gif,208.gif,209.gif,210.gif,211.gif,212.gif,213.gif,214.gif,215.gif,216.gif,217.gif,219.gif,220.gif,221.gif,222.gif,224.gif,225.gif,226.gif,227.gif,228.gif,230.gif,232.gif,233.gif,234.gif,235.gif,238.gif,240.gif,241.gif,243.gif,244.gif,245.gif,246.gif,247.gif,249.gif,250.gif,251.gif,253.gif'
+ knownBanners: '0.jpg,1.jpg,2.jpg,4.jpg,6.jpg,7.jpg,8.jpg,9.jpg,10.jpg,11.jpg,12.jpg,13.jpg,14.jpg,16.jpg,17.jpg,18.jpg,19.jpg,20.jpg,21.jpg,22.jpg,24.jpg,25.jpg,26.jpg,28.jpg,29.jpg,33.jpg,38.jpg,39.jpg,43.jpg,44.jpg,45.jpg,46.jpg,47.jpg,52.jpg,54.jpg,57.jpg,59.jpg,60.jpg,61.jpg,64.jpg,66.jpg,67.jpg,69.jpg,71.jpg,72.jpg,76.jpg,77.jpg,81.jpg,82.jpg,83.jpg,84.jpg,88.jpg,90.jpg,91.jpg,96.jpg,98.jpg,99.jpg,100.jpg,104.jpg,106.jpg,116.jpg,119.jpg,137.jpg,140.jpg,148.jpg,149.jpg,150.jpg,154.jpg,156.jpg,157.jpg,158.jpg,159.jpg,161.jpg,162.jpg,164.jpg,165.jpg,166.jpg,167.jpg,168.jpg,169.jpg,170.jpg,171.jpg,172.jpg,173.jpg,174.jpg,175.jpg,176.jpg,178.jpg,179.jpg,180.jpg,181.jpg,182.jpg,183.jpg,186.jpg,189.jpg,190.jpg,192.jpg,193.jpg,194.jpg,197.jpg,198.jpg,200.jpg,201.jpg,202.jpg,203.jpg,205.jpg,206.jpg,207.jpg,208.jpg,210.jpg,213.jpg,214.jpg,215.jpg,216.jpg,218.jpg,219.jpg,220.jpg,221.jpg,222.jpg,223.jpg,224.jpg,227.jpg,0.png,1.png,2.png,3.png,5.png,6.png,9.png,10.png,11.png,12.png,14.png,16.png,19.png,20.png,21.png,22.png,23.png,24.png,26.png,27.png,28.png,29.png,30.png,31.png,32.png,33.png,34.png,37.png,39.png,40.png,41.png,42.png,43.png,44.png,45.png,48.png,49.png,50.png,51.png,52.png,53.png,57.png,58.png,59.png,64.png,66.png,67.png,68.png,69.png,70.png,71.png,72.png,76.png,78.png,79.png,81.png,82.png,85.png,86.png,87.png,89.png,95.png,98.png,100.png,101.png,102.png,105.png,106.png,107.png,109.png,110.png,111.png,112.png,113.png,114.png,115.png,116.png,118.png,119.png,120.png,121.png,122.png,123.png,126.png,128.png,130.png,134.png,136.png,138.png,139.png,140.png,142.png,145.png,146.png,149.png,150.png,151.png,152.png,153.png,154.png,155.png,156.png,157.png,158.png,159.png,160.png,163.png,164.png,165.png,166.png,167.png,168.png,169.png,170.png,171.png,172.png,173.png,174.png,178.png,179.png,180.png,181.png,182.png,184.png,186.png,188.png,190.png,192.png,193.png,194.png,195.png,196.png,197.png,198.png,200.png,202.png,203.png,205.png,206.png,207.png,209.png,212.png,213.png,214.png,216.png,217.png,218.png,219.png,220.png,221.png,222.png,223.png,224.png,225.png,226.png,229.png,231.png,232.png,233.png,234.png,235.png,237.png,238.png,239.png,240.png,241.png,242.png,244.png,245.png,246.png,247.png,248.png,249.png,250.png,253.png,254.png,255.png,256.png,257.png,258.png,259.png,260.png,262.png,268.png,0.gif,1.gif,2.gif,3.gif,4.gif,5.gif,6.gif,7.gif,8.gif,9.gif,10.gif,12.gif,13.gif,14.gif,15.gif,16.gif,18.gif,19.gif,20.gif,21.gif,22.gif,23.gif,24.gif,28.gif,29.gif,30.gif,33.gif,34.gif,35.gif,36.gif,37.gif,39.gif,40.gif,42.gif,44.gif,45.gif,46.gif,48.gif,50.gif,52.gif,54.gif,55.gif,57.gif,58.gif,59.gif,60.gif,61.gif,63.gif,64.gif,66.gif,67.gif,68.gif,69.gif,70.gif,72.gif,73.gif,75.gif,76.gif,77.gif,78.gif,80.gif,81.gif,82.gif,83.gif,86.gif,87.gif,88.gif,92.gif,93.gif,94.gif,95.gif,96.gif,97.gif,98.gif,99.gif,100.gif,101.gif,102.gif,103.gif,104.gif,105.gif,106.gif,108.gif,109.gif,110.gif,111.gif,112.gif,113.gif,115.gif,116.gif,117.gif,118.gif,119.gif,120.gif,122.gif,123.gif,124.gif,127.gif,129.gif,130.gif,131.gif,134.gif,135.gif,136.gif,138.gif,139.gif,141.gif,144.gif,146.gif,148.gif,149.gif,153.gif,154.gif,155.gif,157.gif,158.gif,159.gif,160.gif,161.gif,162.gif,164.gif,166.gif,167.gif,168.gif,169.gif,170.gif,171.gif,172.gif,173.gif,174.gif,175.gif,176.gif,177.gif,178.gif,181.gif,182.gif,183.gif,185.gif,186.gif,187.gif,188.gif,189.gif,190.gif,191.gif,192.gif,193.gif,195.gif,196.gif,197.gif,200.gif,201.gif,202.gif,203.gif,204.gif,205.gif,206.gif,207.gif,208.gif,209.gif,210.gif,211.gif,212.gif,213.gif,214.gif,215.gif,216.gif,217.gif,219.gif,220.gif,221.gif,222.gif,224.gif,225.gif,226.gif,227.gif,228.gif,230.gif,232.gif,233.gif,234.gif,235.gif,238.gif,240.gif,241.gif,243.gif,244.gif,245.gif,246.gif,247.gif,249.gif,250.gif,251.gif,253.gif',
+ cachedTitles: [[]]
};
return Config;
@@ -2017,8 +2018,8 @@ div[data-checked=\"false\"] > .suboption-list {\n\
}\n\
#fourchanx-settings textarea {\n\
font-family: monospace;\n\
- min-width: 100%;\n\
- max-width: 100%;\n\
+ width: 100%;\n\
+ resize: vertical;\n\
}\n\
#fourchanx-settings code {\n\
color: #000;\n\
@@ -5247,23 +5248,23 @@ $ = (function() {
}
})();
- $.globalEval = function(code, data) {
- var script;
- script = $.el('script', {
- textContent: code
- });
- if (data) {
- $.extend(script.dataset, data);
- }
- $.add(d.head || doc, script);
- return $.rm(script);
- };
-
$.global = function(fn, data) {
+ var script;
if (doc) {
- return $.globalEval("(" + fn + ")();", data);
+ script = $.el('script', {
+ textContent: "(" + fn + ").call(document.currentScript.dataset);"
+ });
+ if (data) {
+ $.extend(script.dataset, data);
+ }
+ $.add(d.head || doc, script);
+ $.rm(script);
+ return script.dataset;
} else {
- return fn();
+ try {
+ fn.call(data);
+ } catch (error) {}
+ return data;
}
};
@@ -6627,23 +6628,17 @@ Fetcher = (function() {
results1 = [];
for (j = l = 0, len1 = ref.length; l < len1; j = ++l) {
text2 = ref[j];
- results1.push({
- innerHTML: ((j % 2) ? "
" + E(text2) + " " : E(text2))
- });
+ results1.push({innerHTML: ((j % 2) ? "
" + E(text2) + " " : E(text2))});
}
return results1;
})();
- text = {
- innerHTML: ((greentext) ? "
" + E.cat(text) + " " : E.cat(text))
- };
+ text = {innerHTML: ((greentext) ? "
" + E.cat(text) + " " : E.cat(text))};
results.push(text);
}
}
return results;
}).call(this);
- comment = {
- innerHTML: E.cat(comment)
- };
+ comment = {innerHTML: E.cat(comment)};
this.threadID = +data.thread_num;
o = {
ID: this.postID,
@@ -6734,71 +6729,29 @@ Fetcher = (function() {
};
Fetcher.prototype.archiveTags = {
- '\n': {
- innerHTML: "
"
- },
- '[b]': {
- innerHTML: "
"
- },
- '[/b]': {
- innerHTML: " "
- },
- '[spoiler]': {
- innerHTML: "
"
- },
- '[/spoiler]': {
- innerHTML: " "
- },
- '[code]': {
- innerHTML: "
"
- },
- '[/code]': {
- innerHTML: " "
- },
- '[moot]': {
- innerHTML: "
"
- },
- '[/moot]': {
- innerHTML: "
"
- },
- '[banned]': {
- innerHTML: "
"
- },
- '[/banned]': {
- innerHTML: " "
- },
+ '\n': {innerHTML: "
"},
+ '[b]': {innerHTML: "
"},
+ '[/b]': {innerHTML: " "},
+ '[spoiler]': {innerHTML: "
"},
+ '[/spoiler]': {innerHTML: " "},
+ '[code]': {innerHTML: "
"},
+ '[/code]': {innerHTML: " "},
+ '[moot]': {innerHTML: "
"},
+ '[/moot]': {innerHTML: "
"},
+ '[banned]': {innerHTML: "
"},
+ '[/banned]': {innerHTML: " "},
'[fortune]': function(text) {
- return {
- innerHTML: "
"
- };
+ return {innerHTML: ""};
},
- '[/fortune]': {
- innerHTML: " "
- },
- '[i]': {
- innerHTML: ""
- },
- '[/i]': {
- innerHTML: " "
- },
- '[red]': {
- innerHTML: ""
- },
- '[/red]': {
- innerHTML: " "
- },
- '[green]': {
- innerHTML: ""
- },
- '[/green]': {
- innerHTML: " "
- },
- '[blue]': {
- innerHTML: ""
- },
- '[/blue]': {
- innerHTML: " "
- }
+ '[/fortune]': {innerHTML: " "},
+ '[i]': {innerHTML: "
"},
+ '[/i]': {innerHTML: " "},
+ '[red]': {innerHTML: "
"},
+ '[/red]': {innerHTML: " "},
+ '[green]': {innerHTML: "
"},
+ '[/green]': {innerHTML: " "},
+ '[blue]': {innerHTML: "
"},
+ '[/blue]': {innerHTML: " "}
};
return Fetcher;
@@ -6819,9 +6772,7 @@ Notice = (function() {
this.onclose = onclose;
this.close = bind(this.close, this);
this.add = bind(this.add, this);
- this.el = $.el('div', {
- innerHTML: "
"
- });
+ this.el = $.el('div', {innerHTML: "
"});
this.el.style.opacity = 0;
this.setType(type);
$.on(this.el.firstElementChild, 'click', this.close);
@@ -7115,8 +7066,8 @@ Post = (function() {
}
$.extend(file, {
url: file.link.href,
- isImage: /(jpe?g|png|gif|bmp)$/i.test(file.link.href),
- isVideo: /(webm|mp4)$/i.test(file.link.href)
+ isImage: /\.(jpe?g|png|gif|bmp)$/i.test(file.link.href),
+ isVideo: /\.(webm|mp4)$/i.test(file.link.href)
});
size = +file.size.match(/[\d.]+/)[0];
unit = ['B', 'KB', 'MB', 'GB'].indexOf(file.size.match(/\w+$/)[0]);
@@ -8329,6 +8280,13 @@ SW = {};
},
isLinkified: function(link) {
return ImageHost.test(link.hostname);
+ },
+ testNativeExtension: function() {
+ return $.global(function() {
+ if (window.Parser.postMenuIcon) {
+ return this.enabled = 'true';
+ }
+ });
}
};
@@ -8508,9 +8466,7 @@ SW = {};
url = Build.threadURL(boardID, threadID);
postLink = url + "#p" + ID;
quoteLink = Build.sameThread(boardID, threadID) ? "javascript:quote('" + (+ID) + "');" : url + "#q" + ID;
- postInfo = {
- innerHTML: "
"
- };
+ postInfo = {innerHTML: "
"};
/* File Info */
if (file) {
@@ -8519,15 +8475,11 @@ SW = {};
shortFilename = Build.shortFilename(file.name);
fileThumb = file.isSpoiler ? Build.spoilerThumb(boardID) : file.thumbURL.replace(protocol, '');
}
- fileBlock = {
- innerHTML: ((file) ? "
" : ((o.fileDeleted) ? "
" : ""))
- };
+ fileBlock = {innerHTML: ((file) ? "
" : ((o.fileDeleted) ? "
" : ""))};
/* Whole Post */
postClass = o.isReply ? 'reply' : 'op';
- wholePost = {
- innerHTML: ((o.isReply) ? "
>>
" : "") + "
" + ((o.isReply) ? (postInfo).innerHTML + (fileBlock).innerHTML : (fileBlock).innerHTML + (postInfo).innerHTML) + "
" + (commentHTML).innerHTML + " "
- };
+ wholePost = {innerHTML: ((o.isReply) ? "
>>
" : "") + "
" + ((o.isReply) ? (postInfo).innerHTML + (fileBlock).innerHTML : (fileBlock).innerHTML + (postInfo).innerHTML) + "
" + (commentHTML).innerHTML + " "};
container = $.el('div', {
className: "postContainer " + postClass + "Container",
id: "pc" + ID
@@ -8618,9 +8570,7 @@ SW = {};
}
postCount = data.replies + 1;
fileCount = data.images + !!data.ext;
- container = $.el('div', {
- innerHTML: "
" + E(postCount) + " / " + E(fileCount) + " / " + E(pageCount) + " " + ((thread.isSticky) ? " " : "") + ((thread.isClosed) ? " " : "") + " "
- });
+ container = $.el('div', {innerHTML: "
" + E(postCount) + " / " + E(fileCount) + " / " + E(pageCount) + " " + ((thread.isSticky) ? " " : "") + ((thread.isClosed) ? " " : "") + " "});
$.before(thread.OP.nodes.info, slice.call(container.childNodes));
ref = $$('br', thread.OP.nodes.comment);
for (i = 0, len = ref.length; i < len; i++) {
@@ -8661,9 +8611,7 @@ SW = {};
link = Build.postURL(thread.board.ID, thread.ID, data.no);
return $.el('div', {
className: 'catalog-reply'
- }, {
- innerHTML: "
... : " + E(excerpt) + " ... "
- });
+ }, {innerHTML: "
... : " + E(excerpt) + " ... "});
}
};
@@ -9077,7 +9025,6 @@ Filter = (function() {
Filter = {
filters: $.dict(),
- results: $.dict(),
init: function() {
var base, base1, boards, err, excludes, file, filter, hide, hl, i, isstring, j, key, len, len1, line, mask, noti, op, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, regexp, stub, top, type, types;
if (!(((ref = g.VIEW) === 'index' || ref === 'thread' || ref === 'catalog') && Conf['Filter'])) {
@@ -9472,7 +9419,7 @@ Filter = (function() {
return ta.focus();
});
},
- quickFilterMD5: function() {
+ quickFilterMD5: function(e) {
var files, filter, links, msg, notice, origin, post;
post = Get.postFromNode(this);
files = post.files.filter(function(f) {
@@ -9491,15 +9438,19 @@ Filter = (function() {
} else if (g.VIEW === 'index') {
ThreadHiding.hide(origin.thread);
}
+ if (e.type !== 'keydown') {
+ if (post.nodes.post.getBoundingClientRect().height) {
+ new Notice('info', 'MD5 filtered.', 2);
+ }
+ return;
+ }
notice = Filter.quickFilterMD5.notice;
if (notice) {
notice.filters.push(filter);
notice.posts.push(origin);
return $('span', notice.el).textContent = notice.filters.length + " MD5s filtered.";
} else {
- msg = $.el('div', {
- innerHTML: "
MD5 filtered. [
show ] [
undo ]"
- });
+ msg = $.el('div', {innerHTML: "
MD5 filtered. [
show ] [
undo ]"});
notice = Filter.quickFilterMD5.notice = new Notice('info', msg, void 0, function() {
return delete Filter.quickFilterMD5.notice;
});
@@ -10204,9 +10155,7 @@ ThreadHiding = (function() {
className: type + "-thread-button",
href: 'javascript:;'
});
- $.extend(a, {
- innerHTML: "
"
- });
+ $.extend(a, {innerHTML: "
"});
a.dataset.fullID = thread.fullID;
$.on(a, 'click', ThreadHiding.toggle);
return a;
@@ -10524,13 +10473,22 @@ Header = (function() {
Header = {
init: function() {
var barFixedToggler, barPositionToggler, box, cs, customNavToggler, editCustomNav, footerToggler, headerToggler, linkJustifyToggler, menuButton, scrollHeaderToggler, shortcutToggler;
+ $.onExists(doc, 'body', (function(_this) {
+ return function() {
+ if (!Main.isThisPageLegit()) {
+ return;
+ }
+ $.add(_this.bar, [_this.noticesRoot, _this.toggle]);
+ $.prepend(d.body, _this.bar);
+ $.add(d.body, Header.hover);
+ return _this.setBarPosition(Conf['Bottom Header']);
+ };
+ })(this));
this.menu = new UI.Menu('header');
menuButton = $.el('span', {
className: 'menu-button'
});
- $.extend(menuButton, {
- innerHTML: "
"
- });
+ $.extend(menuButton, {innerHTML: "
"});
box = UI.checkbox;
barFixedToggler = box('Fixed Header', 'Fixed Header');
headerToggler = box('Header auto-hide', 'Auto-hide header');
@@ -10606,16 +10564,6 @@ Header = (function() {
$.on(window, 'load popstate', Header.hashScroll);
$.on(d, 'CreateNotification', this.createNotification);
this.setBoardList();
- $.onExists(doc, 'body', (function(_this) {
- return function() {
- if (!Main.isThisPageLegit()) {
- return;
- }
- $.prepend(d.body, _this.bar);
- $.add(d.body, Header.hover);
- return _this.setBarPosition(Conf['Bottom Header']);
- };
- })(this));
$.onExists(doc, g.SITE.selectors.boardList + " + *", Header.generateFullBoardList);
Main.ready(function() {
var a, absbot, footer, j, len, ref;
@@ -10628,7 +10576,9 @@ Header = (function() {
$('#navtopright', footer).id = 'navbotright';
$('#settingsWindowLink', footer).id = 'settingsWindowLinkBot';
$.before(absbot, footer);
- $.globalEval('window.cloneTopNav = function() {};');
+ $.global(function() {
+ return window.cloneTopNav = function() {};
+ });
}
if ((Header.bottomBoardList = $(g.SITE.selectors.boardListBottom))) {
ref = $$('a', Header.bottomBoardList);
@@ -10679,12 +10629,10 @@ Header = (function() {
Header.boardList = boardList = $.el('span', {
id: 'board-list'
});
- $.extend(boardList, {
- innerHTML: "
- "
- });
+ $.extend(boardList, {innerHTML: "
- "});
btn = $('.hide-board-list-button', boardList);
$.on(btn, 'click', Header.toggleBoardList);
- $.add(Header.bar, [Header.boardList, Header.shortcuts, Header.noticesRoot, Header.toggle]);
+ $.prepend(Header.bar, [Header.boardList, Header.shortcuts]);
Header.setCustomNav(Conf['Custom Board Navigation']);
Header.generateBoardList(Conf['boardnav']);
$.sync('Custom Board Navigation', Header.setCustomNav);
@@ -10971,8 +10919,10 @@ Header = (function() {
return Header.previousOffset = offsetY;
},
setBarPosition: function(bottom) {
- var args;
- Header.barPositionToggler.checked = bottom;
+ var args, ref;
+ if ((ref = Header.barPositionToggler) != null) {
+ ref.checked = bottom;
+ }
$.event('CloseMenu');
args = bottom ? ['bottom-header', 'top-header', 'after'] : ['top-header', 'bottom-header', 'add'];
$.addClass(doc, args[0]);
@@ -11156,9 +11106,7 @@ Header = (function() {
case 'denied':
return;
}
- el = $.el('span', {
- innerHTML: "4chan X needs your permission to show desktop notifications. [
FAQ ]
Authorize or
Disable "
- });
+ el = $.el('span', {innerHTML: "4chan X needs your permission to show desktop notifications. [
FAQ ]
Authorize or
Disable "});
ref = $$('button', el), authorize = ref[0], disable = ref[1];
$.on(authorize, 'click', function() {
return Notification.requestPermission(function(status) {
@@ -11281,9 +11229,7 @@ Index = (function() {
this.navLinks = $.el('div', {
className: 'navLinks json-index'
});
- $.extend(this.navLinks, {
- innerHTML: "
Index Catalog Archive Bottom ... × — [Show ] Index Sort Bump order Last reply Last long reply Creation date Reply count File count Image Size Small Large Index Mode Paged Infinite scrolling All threads Catalog "
- });
+ $.extend(this.navLinks, {innerHTML: "
Index Catalog Archive Bottom ... × — [Show ] Index Sort Bump order Last reply Last long reply Creation date Reply count File count Image Size Small Large Index Mode Paged Infinite scrolling All threads Catalog "});
$('.cataloglink a', this.navLinks).href = CatalogLinks.catalog();
if (!BoardConfig.isArchived(g.BOARD.ID)) {
$('.archlistlink', this.navLinks).hidden = true;
@@ -11331,9 +11277,7 @@ Index = (function() {
this.pagelist = $.el('div', {
className: 'pagelist json-index'
});
- $.extend(this.pagelist, {
- innerHTML: "
"
- });
+ $.extend(this.pagelist, {innerHTML: "
"});
$('.cataloglink a', this.pagelist).href = CatalogLinks.catalog();
$.on(this.pagelist, 'click', this.cb.pageNav);
this.update(true);
@@ -11421,9 +11365,7 @@ Index = (function() {
el: $.el('a', {
href: 'javascript:;',
className: 'has-shortcut-text'
- }, {
- innerHTML: "
Shift+click "
- }),
+ }, {innerHTML: "
Shift+click "}),
order: 20,
open: function(arg) {
var thread;
@@ -12084,7 +12026,7 @@ Index = (function() {
return PostHiding.isHidden(g.BOARD.ID, threadID, replyData.no) || Filter.isHidden(g.SITE.Build.parseJSON(replyData, g.BOARD));
},
buildThreads: function(threadIDs, isCatalog, withReplies) {
- var ID, OP, err, errors, isStale, k, lastPost, len1, newPosts, newThreads, obj, t, thread, threadData, threads;
+ var ID, OP, err, errors, isStale, k, lastPost, len1, newPosts, newThreads, obj, opRoot, t, thread, threadData, threads;
threads = [];
newThreads = [];
newPosts = [];
@@ -12119,7 +12061,8 @@ Index = (function() {
thread.setPage(Math.floor(Index.threadPosition[ID] / Index.threadsNumPerPage) + 1);
} else {
obj = Index.parsedThreads[ID];
- OP = new Post(g.SITE.Build.post(obj), thread, g.BOARD);
+ opRoot = g.SITE.Build.post(obj);
+ OP = new Post(opRoot, thread, g.BOARD);
OP.filterResults = obj.filterResults;
newPosts.push(OP);
}
@@ -12133,7 +12076,8 @@ Index = (function() {
}
errors.push({
message: "Parsing of Thread No." + thread + " failed. Thread will be skipped.",
- error: err
+ error: err,
+ html: opRoot != null ? opRoot.outerHTML : void 0
});
}
}
@@ -12185,7 +12129,8 @@ Index = (function() {
}
errors.push({
message: "Parsing of Post No." + data.no + " failed. Post will be skipped.",
- error: err
+ error: err,
+ html: node != null ? node.outerHTML : void 0
});
}
}
@@ -12570,7 +12515,7 @@ Settings = (function() {
$.on(d, 'OpenSettings', function(e) {
return Settings.open(e.detail);
});
- if (Conf['Disable Native Extension']) {
+ if (g.SITE.software === 'yotsuba' && Conf['Disable Native Extension']) {
if ($.hasStorage) {
return $.global(function() {
var settings;
@@ -12608,9 +12553,7 @@ Settings = (function() {
$.event('CloseMenu');
Settings.dialog = dialog = $.el('div', {
id: 'overlay'
- }, {
- innerHTML: "
"
- });
+ }, {innerHTML: "
"});
$.on($('.export', dialog), 'click', Settings["export"]);
$.on($('.import', dialog), 'click', Settings["import"]);
$.on($('.reset', dialog), 'click', Settings.reset);
@@ -12699,9 +12642,7 @@ Settings = (function() {
boardID: 'qa',
threadID: 362590
});
- return cb($.el('li', {
- innerHTML: "To protect yourself from
malicious ads , you should
block ads on 4chan."
- }));
+ return cb($.el('li', {innerHTML: "To protect yourself from
malicious ads , you should
block ads on 4chan."}));
});
});
}
@@ -12710,9 +12651,7 @@ Settings = (function() {
var addCheckboxes, addWarning, button, div, fs, inputs, items, key, keyFS, obj, ref, ref1, warning, warnings;
warnings = $.el('fieldset', {
hidden: true
- }, {
- innerHTML: "
Warnings "
- });
+ }, {innerHTML: "
Warnings "});
addWarning = function(item) {
$.add($('ul', warnings), item);
return warnings.hidden = false;
@@ -12735,9 +12674,7 @@ Settings = (function() {
continue;
}
description = arr[1];
- div = $.el('div', {
- innerHTML: "
" + E(key) + ": " + E(description) + " "
- });
+ div = $.el('div', {innerHTML: "
" + E(key) + ": " + E(description) + " "});
div.dataset.name = key;
input = $('input', div);
$.on(input, 'change', $.cb.checked);
@@ -12763,14 +12700,10 @@ Settings = (function() {
ref1 = Config.main;
for (keyFS in ref1) {
obj = ref1[keyFS];
- fs = $.el('fieldset', {
- innerHTML: "
" + E(keyFS) + " "
- });
+ fs = $.el('fieldset', {innerHTML: "
" + E(keyFS) + " "});
addCheckboxes(fs, obj);
if (keyFS === 'Posting and Captchas') {
- $.add(fs, $.el('p', {
- innerHTML: "For more info on captcha options and issues, see the
captcha FAQ ."
- }));
+ $.add(fs, $.el('p', {innerHTML: "For more info on captcha options and issues, see the
captcha FAQ ."}));
}
$.add(section, fs);
}
@@ -12789,9 +12722,7 @@ Settings = (function() {
inputs[key].parentNode.parentNode.dataset.checked = val;
}
});
- div = $.el('div', {
- innerHTML: "
: Clear manually-hidden threads and posts on all boards. Reload the page to apply."
- });
+ div = $.el('div', {innerHTML: ": Clear manually-hidden threads and posts on all boards. Reload the page to apply."});
button = $('button', div);
$.get({
hiddenThreads: $.dict(),
@@ -12935,17 +12866,20 @@ Settings = (function() {
'Disable 4chan\'s extension': 'Disable Native Extension',
'Comment Auto-Expansion': '',
'Remove Slug': '',
+ 'Always HTTPS': 'Redirect to HTTPS',
'Check for Updates': '',
'Recursive Filtering': 'Recursive Hiding',
'Reply Hiding': 'Reply Hiding Buttons',
'Thread Hiding': 'Thread Hiding Buttons',
'Show Stubs': 'Stubs',
'Image Auto-Gif': 'Replace GIF',
+ 'Expand All WebM': 'Expand videos',
'Reveal Spoilers': 'Reveal Spoiler Thumbnails',
'Expand From Current': 'Expand from here',
'Current Page': 'Page Count in Stats',
'Current Page Position': '',
'Alternative captcha': 'Use Recaptcha v1',
+ 'Alt index captcha': 'Use Recaptcha v1 on Index',
'Auto Submit': 'Post on Captcha Completion',
'Open Reply in New Tab': 'Open Post in New Tab',
'Remember QR size': 'Remember QR Size',
@@ -12967,6 +12901,7 @@ Settings = (function() {
'spoiler': 'Spoiler tags',
'sageru': 'Toggle sage',
'code': 'Code tags',
+ 'sjis': 'SJIS tags',
'submit': 'Submit QR',
'watch': 'Watch',
'update': 'Update',
@@ -12987,6 +12922,10 @@ Settings = (function() {
'Scrolling': 'Auto Scroll',
'Verbose': ''
});
+ if ('Always CDN' in data.Conf) {
+ data.Conf['fourchanImageHost'] = data.Conf['Always CDN'] ? 'i.4cdn.org' : '';
+ delete data.Conf['Always CDN'];
+ }
data.Conf.sauces = data.Conf.sauces.replace(/\$\d/g, function(c) {
switch (c) {
case '$1':
@@ -13013,15 +12952,17 @@ Settings = (function() {
}
}
if (data.WatchedThreads) {
- data.Conf['watchedThreads'] = {
- boards: $.dict()
- };
+ data.Conf['watchedThreads'] = $.dict.clone({
+ '4chan.org': {
+ boards: {}
+ }
+ });
ref1 = data.WatchedThreads;
for (boardID in ref1) {
threads = ref1[boardID];
for (threadID in threads) {
threadData = threads[threadID];
- ((base = data.Conf['watchedThreads'].boards)[boardID] || (base[boardID] = $.dict()))[threadID] = {
+ ((base = data.Conf['watchedThreads']['4chan.org'].boards)[boardID] || (base[boardID] = $.dict()))[threadID] = {
excerpt: threadData.textContent
};
}
@@ -13361,9 +13302,7 @@ Settings = (function() {
},
filter: function(section) {
var select;
- $.extend(section, {
- innerHTML: "Guide General Post number Name Unique ID Tripcode Capcode Pass Date Email Subject Comment Flag Filename Image dimensions Filesize Image MD5
"
- });
+ $.extend(section, {innerHTML: "Guide General Post number Name Unique ID Tripcode Capcode Pass Date Email Subject Comment Flag Filename Image dimensions Filesize Image MD5
"});
select = $('select', section);
$.on(select, 'change', Settings.selectFilter);
return Settings.selectFilter.call(select);
@@ -13391,20 +13330,14 @@ Settings = (function() {
filterTypes = Object.keys(Config.filter).filter(function(x) {
return x !== 'general';
}).map(function(x, i) {
- return {
- innerHTML: ((i) ? "," : "") + "" + E(x)
- };
- });
- $.extend(div, {
- innerHTML: "Filter is disabled.
Use regular expressions , one per line. Lines starting with a # will be ignored. For example, /weeaboo/i will filter posts containing the string `weeaboo`, case-insensitive. MD5 and Unique ID filtering use exact string matching, not regular expressions.
You can use these settings with each regular expression, separate them with semicolons:Per boards, separate them with commas. It is global if not specified. Use sfw and nsfw to reference all worksafe or not-worksafe boards. For example: boards:a,jp;. To specify boards on a particular site, put the beginning of the domain and a slash character before the list. Any initial www. should not be included, and all 4chan domains are considered 4chan.org. For example: boards:4:a,jp,sama:a,z;. An asterisk can be used to specify all boards on a site. For example: boards:4:*;. Select boards to be excluded from the filter. The syntax is the same as for the boards: option above. For example: exclude:vg,v;. Filter OPs only along with their threads (`only`) or replies only (`no`). For example: op:only; or op:no;. Filter only posts with files (`only`) or only posts without files (`no`). For example: file:only; or file:no;. Overrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`). For example: stub:yes; or stub:no;. Highlight instead of hiding. You can specify a class name to use with a userstyle. For example: highlight; or highlight:wallpaper;. Highlighted OPs will have their threads put on top of the board index by default. For example: top:yes; or top:no;. Show a desktop notification instead of hiding. For example: notify;. Filters in the \"General\" section apply to multiple fields, by default subject,name,filename,comment. The fields can be specified with the type option, separated by commas. For example: type:" + E.cat(filterTypes) + ";. Types can also be combined with a + sign; this indicates the filter applies to the given fields joined by newlines. For example: type:filename+filesize+dimensions;. "
+ return {innerHTML: ((i) ? "," : "") + "" + E(x)};
});
+ $.extend(div, {innerHTML: "Filter is disabled.
Use regular expressions , one per line. Lines starting with a # will be ignored. For example, /weeaboo/i will filter posts containing the string `weeaboo`, case-insensitive. MD5 and Unique ID filtering use exact string matching, not regular expressions.
You can use these settings with each regular expression, separate them with semicolons:Per boards, separate them with commas. It is global if not specified. Use sfw and nsfw to reference all worksafe or not-worksafe boards. For example: boards:a,jp;. To specify boards on a particular site, put the beginning of the domain and a slash character before the list. Any initial www. should not be included, and all 4chan domains are considered 4chan.org. For example: boards:4:a,jp,sama:a,z;. An asterisk can be used to specify all boards on a site. For example: boards:4:*;. Select boards to be excluded from the filter. The syntax is the same as for the boards: option above. For example: exclude:vg,v;. Filter OPs only along with their threads (`only`) or replies only (`no`). For example: op:only; or op:no;. Filter only posts with files (`only`) or only posts without files (`no`). For example: file:only; or file:no;. Overrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`). For example: stub:yes; or stub:no;. Highlight instead of hiding. You can specify a class name to use with a userstyle. For example: highlight; or highlight:wallpaper;. Highlighted OPs will have their threads put on top of the board index by default. For example: top:yes; or top:no;. Show a desktop notification instead of hiding. For example: notify;. Filters in the \"General\" section apply to multiple fields, by default subject,name,filename,comment. The fields can be specified with the type option, separated by commas. For example: type:" + E.cat(filterTypes) + ";. Types can also be combined with a + sign; this indicates the filter applies to the given fields joined by newlines. For example: type:filename+filesize+dimensions;. "});
return $('.warning', div).hidden = Conf['Filter'];
},
sauce: function(section) {
var ta;
- $.extend(section, {
- innerHTML: "Sauce is disabled.
[expand] These parameters will be replaced by their corresponding values in the URL and displayed text:
%IMG: Full image URL for GIF, JPG, and PNG; thumbnail URL for other types.%URL: Full image URL.%TURL: Thumbnail URL.%name: Original file name.%board: Current board.%MD5: MD5 hash in base64.%sMD5: MD5 hash in base64 using - and _.%hMD5: MD5 hash in hexadecimal.%$0: Matched regular expression within the filename.%$1, %$2, %$3, ... : Subexpressions within the matched regular expression.%%, %semi: Literal % and ;.Lines starting with a # will be ignored.
You can specify a display text by appending ;text:[text] to the URL.
You can specify the applicable boards/sites by appending ;boards:[board1],[board2]. See the Filter guide for details.
You can specify the applicable file types by appending ;types:[extension1],[extension2].
You can specify a regular expression the filename must match by appending ;regexp:[regular expression].
"
- });
+ $.extend(section, {innerHTML: "Sauce is disabled.
[expand] These parameters will be replaced by their corresponding values in the URL and displayed text:
%IMG: Full image URL for GIF, JPG, and PNG; thumbnail URL for other types.%URL: Full image URL.%TURL: Thumbnail URL.%name: Original file name.%board: Current board.%MD5: MD5 hash in base64.%sMD5: MD5 hash in base64 using - and _.%hMD5: MD5 hash in hexadecimal.%$0: Matched regular expression within the filename.%$1, %$2, %$3, ... : Subexpressions within the matched regular expression.%%, %semi: Literal % and ;.Lines starting with a # will be ignored.
You can specify a display text by appending ;text:[text] to the URL.
You can specify the applicable boards/sites by appending ;boards:[board1],[board2]. See the Filter guide for details.
You can specify the applicable file types by appending ;types:[extension1],[extension2].
You can specify a regular expression the filename must match by appending ;regexp:[regular expression].
"});
$('.warning', section).hidden = Conf['Sauce'];
ta = $('textarea', section);
$.get('sauces', Conf['sauces'], function(item) {
@@ -13415,9 +13348,7 @@ Settings = (function() {
},
advanced: function(section) {
var applyCSS, boardSelect, customCSS, event, input, inputs, interval, items, itemsArchive, j, k, l, len, len1, len2, len3, listImageHost, m, name, ref, ref1, ref2, ref3, ref4, table, textContent, updateArchives, warning;
- $.extend(section, {
- innerHTML: "Archives 404 Redirect is disabled.
Thread redirection Post fetching File redirection
Archive Lists : Each line below should be an archive list in
this format or a URL to load an archive list from.
Archive properties can be overriden by another item with the same
uid (or if absent, its
name).
Update now Last updated: Auto-updateExternal Catalog External Catalog is disabled. This will be used only as a fallback.
URLs of external catalog sites, where %board is to be replaced by the board name. Each URL should be followed by ;boards: and optionally ;exclude: and a list of supported/excluded boards in the format explained in the Filter guide.
Override 4chan Image Host Change 4chan image links to this domain. Leave blank for no change.
Captcha Language
Captcha Solving Service Supported services include
captcha.guru ,
2captcha , and any other service implementing the 2captcha API.
Leave blank to disable.
Domain: API Key:
Custom Board Navigation
New lines will be converted into spaces. In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
Board link: g
Archive link: g-archive
Internal archive link: g-expired
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:"Install Gentoo"
Index-only link: g-index
Catalog-only link: g-catalog
Index mode: g-mode:"infinite scrolling"
Index sort: g-sort:"creation date rev"
External link: external-text:"Google","http://www.google.com"
Combinations are possible: g-index-text:"Technology Index"
Full board list toggle: toggle-all
[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"] will give you[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy] if you are on /g/.
Time Formatting is disabled. :
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Literal %: %%
Quote Backlinks formatting is disabled. :
Default pasted content filename .png
File Info Formatting is disabled. :
Link: %l (truncated), %L (untruncated), %T (4chan filename)
Filename: %n (truncated), %N (untruncated), %t (4chan filename)
Download button: %d
Quick filter MD5: %f
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Tag:
%gLiteral %: %%
Quick Reply Personas One item per line. Items will be added in the relevant input's auto-completion list. Password items will always be used, since there is no password input. Lines starting with a # will be ignored.
You can use these settings with each item, separate them with semicolons:Possible items are: name, options (or equivalently email), subject and password. Wrap values of items with quotes, like this: options:"sage". Force values as defaults with the always keyword, for example: options:"sage";always. Select specific boards for an item, separated with commas, for example: options:"sage";boards:jp;always. Unread Favicon is disabled. ferongr xat- 4chanJS Mayhem Original Metro Thread Updater is disabled. Interval: seconds
Custom Cooldown Time Seconds:
Custom CSSFor more information about customizing 4chan X's CSS, see the
styling guide .
Apply CSS Javascript Whitelist Sources from which Javascript is allowed to be loaded by
Content Security Policy .
Lines starting with a
# will be ignored.
Known Banners List of known banners, used for click-to-change feature.
"
- });
+ $.extend(section, {innerHTML: "
Archives 404 Redirect is disabled.
Thread redirection Post fetching File redirection
Archive Lists : Each line below should be an archive list in
this format or a URL to load an archive list from.
Archive properties can be overriden by another item with the same
uid (or if absent, its
name).
Update now Last updated: Auto-updateExternal Catalog External Catalog is disabled. This will be used only as a fallback.
URLs of external catalog sites, where %board is to be replaced by the board name. Each URL should be followed by ;boards: and optionally ;exclude: and a list of supported/excluded boards in the format explained in the Filter guide.
Override 4chan Image Host Change 4chan image links to this domain. Leave blank for no change.
Captcha Language
Captcha Solving Service Supported services include
captcha.guru ,
2captcha , and any other service implementing the 2captcha API.
Leave blank to disable.
Domain: API Key:
Custom Board Navigation
New lines will be converted into spaces. In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
Board link: g
Archive link: g-archive
Internal archive link: g-expired
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:"Install Gentoo"
Index-only link: g-index
Catalog-only link: g-catalog
Index mode: g-mode:"infinite scrolling"
Index sort: g-sort:"creation date rev"
External link: external-text:"Google","http://www.google.com"
Combinations are possible: g-index-text:"Technology Index"
Full board list toggle: toggle-all
[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"] will give you[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy] if you are on /g/.
Time Formatting is disabled. :
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Literal %: %%
Quote Backlinks formatting is disabled. :
Default pasted content filename .png
File Info Formatting is disabled. :
Link: %l (truncated), %L (untruncated), %T (4chan filename)
Filename: %n (truncated), %N (untruncated), %t (4chan filename)
Download button: %d
Quick filter MD5: %f
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Tag:
%gLiteral %: %%
Quick Reply Personas One item per line. Items will be added in the relevant input's auto-completion list. Password items will always be used, since there is no password input. Lines starting with a # will be ignored.
You can use these settings with each item, separate them with semicolons:Possible items are: name, options (or equivalently email), subject and password. Wrap values of items with quotes, like this: options:"sage". Force values as defaults with the always keyword, for example: options:"sage";always. Select specific boards for an item, separated with commas, for example: options:"sage";boards:jp;always. Unread Favicon is disabled. ferongr xat- 4chanJS Mayhem Original Metro Thread Updater is disabled. Interval: seconds
Custom Cooldown Time Seconds:
Custom CSSFor more information about customizing 4chan X's CSS, see the
styling guide .
Apply CSS Javascript Whitelist Sources from which Javascript is allowed to be loaded by
Content Security Policy .
Lines starting with a
# will be ignored.
Known Banners List of known banners, used for click-to-change feature.
"});
ref = $$('.warning', section);
for (j = 0, len = ref.length; j < len; j++) {
warning = ref[j];
@@ -13607,9 +13538,7 @@ Settings = (function() {
textContent: archive[1]
}));
}
- $.extend(td, {
- innerHTML: "
"
- });
+ $.extend(td, {innerHTML: "
"});
select = td.firstElementChild;
if (!(select.disabled = length === 1)) {
select.setAttribute('data-boardid', boardID);
@@ -13731,9 +13660,7 @@ Settings = (function() {
},
keybinds: function(section) {
var arr, input, inputs, items, key, ref, tbody, tr;
- $.extend(section, {
- innerHTML: "
Keybinds are disabled.
Allowed keys: a-z , 0-9 , Ctrl , Shift , Alt , Meta , Enter , Esc , Up , Down , Right , Left .
Press Backspace to disable a keybind.
"
- });
+ $.extend(section, {innerHTML: "
Keybinds are disabled.
Allowed keys: a-z , 0-9 , Ctrl , Shift , Alt , Meta , Enter , Esc , Up , Down , Right , Left .
Press Backspace to disable a keybind.
"});
$('.warning', section).hidden = Conf['Keybinds'];
tbody = $('tbody', section);
items = $.dict();
@@ -13741,9 +13668,7 @@ Settings = (function() {
ref = Config.hotkeys;
for (key in ref) {
arr = ref[key];
- tr = $.el('tr', {
- innerHTML: "
" + E(arr[1]) + " "
- });
+ tr = $.el('tr', {innerHTML: "
" + E(arr[1]) + " "});
input = $('input', tr);
input.name = key;
input.spellcheck = false;
@@ -14424,9 +14349,7 @@ Gallery = (function() {
nodes.el = dialog = $.el('div', {
id: 'a-gallery'
});
- $.extend(dialog, {
- innerHTML: "
"
- });
+ $.extend(dialog, {innerHTML: "
"});
ref = {
buttons: '.gal-buttons',
frame: '.gal-image',
@@ -14875,9 +14798,7 @@ Gallery = (function() {
}
return results;
})();
- delayLabel = $.el('label', {
- innerHTML: "Slide Delay:
"
- });
+ delayLabel = $.el('label', {innerHTML: "Slide Delay:
"});
delayInput = delayLabel.firstElementChild;
delayInput.value = Gallery.delay;
$.on(delayInput, 'change', Gallery.cb.setDelay);
@@ -14991,7 +14912,7 @@ ImageCommon = (function() {
onloadend: function() {
var i, len, postObj, ref, ref1;
if (this.status === 404) {
- post.kill(!post.isClone);
+ post.kill(!post.isClone, fileObj.index);
}
if (this.status !== 200) {
return redirect();
@@ -15083,9 +15004,7 @@ ImageExpand = (function() {
this.videoControls = $.el('span', {
className: 'video-controls'
});
- $.extend(this.videoControls, {
- innerHTML: "
contract "
- });
+ $.extend(this.videoControls, {innerHTML: "
contract "});
return Callbacks.Post.push({
name: 'Image Expansion',
cb: this.node
@@ -15693,9 +15612,7 @@ ImageLoader = (function() {
if (!(Conf['Image Prefetching'] && ((ref1 = g.VIEW) === 'index' || ref1 === 'thread'))) {
return;
}
- prefetch = $.el('label', {
- innerHTML: "
Prefetch Images"
- });
+ prefetch = $.el('label', {innerHTML: "
Prefetch Images"});
this.el = prefetch.firstElementChild;
$.on(this.el, 'change', this.toggle);
return Header.menu.addEntry({
@@ -15741,12 +15658,19 @@ ImageLoader = (function() {
return file.videoThumb = true;
},
prefetch: function(post, file) {
- var clone, el, i, isImage, isVideo, len, match, ref, replace, thumb, type, url;
+ var clone, el, i, isImage, isVideo, len, ref, ref1, replace, thumb, type, url;
isImage = file.isImage, isVideo = file.isVideo, thumb = file.thumb, url = file.url;
if (file.isPrefetched || !(isImage || isVideo) || post.isHidden || post.thread.isHidden) {
return;
}
- type = (match = url.match(/\.([^.]+)$/)[1].toUpperCase()) === 'JPEG' ? 'JPG' : match;
+ if (isVideo) {
+ type = 'WEBM';
+ } else {
+ type = (ref = url.match(/\.([^.]+)$/)) != null ? ref[1].toUpperCase() : void 0;
+ if (type === 'JPEG') {
+ type = 'JPG';
+ }
+ }
replace = Conf["Replace " + type] && !/spoiler/.test(thumb.src || thumb.dataset.src);
if (!(replace || Conf['prefetch'])) {
return;
@@ -15761,9 +15685,9 @@ ImageLoader = (function() {
}
file.isPrefetched = true;
if (file.videoThumb) {
- ref = post.clones;
- for (i = 0, len = ref.length; i < len; i++) {
- clone = ref[i];
+ ref1 = post.clones;
+ for (i = 0, len = ref1.length; i < len; i++) {
+ clone = ref1[i];
clone.file.thumb.preload = 'auto';
}
thumb.preload = 'auto';
@@ -15777,10 +15701,10 @@ ImageLoader = (function() {
el = $.el(isImage ? 'img' : 'video');
if (replace && isImage) {
$.on(el, 'load', function() {
- var j, len1, ref1;
- ref1 = post.clones;
- for (j = 0, len1 = ref1.length; j < len1; j++) {
- clone = ref1[j];
+ var j, len1, ref2;
+ ref2 = post.clones;
+ for (j = 0, len1 = ref2.length; j < len1; j++) {
+ clone = ref2[j];
clone.file.thumb.src = url;
}
return thumb.src = url;
@@ -15860,9 +15784,7 @@ Metadata = (function() {
className: 'webm-title'
});
el.dataset.index = i;
- $.extend(el, {
- innerHTML: "
"
- });
+ $.extend(el, {innerHTML: "
"});
$.add(file.text, [$.tn(' '), el]);
}
if (el.children.length === 1) {
@@ -16249,9 +16171,7 @@ Volume = (function() {
volumeEntry = $.el('label', {
title: 'Default volume for videos.'
});
- $.extend(volumeEntry, {
- innerHTML: "
Volume"
- });
+ $.extend(volumeEntry, {innerHTML: "
Volume"});
this.inputs = {
unmute: unmuteEntry.firstElementChild,
volume: volumeEntry.firstElementChild
@@ -16361,20 +16281,18 @@ Embedding = (function() {
this.types[type.key] = type;
}
if (Conf['Embedding'] && g.VIEW !== 'archive') {
- this.dialog = UI.dialog('embedding', {
- innerHTML: "
"
- });
+ this.dialog = UI.dialog('embedding', {innerHTML: "
"});
this.media = $('#media-embed', this.dialog);
$.one(d, '4chanXInitFinished', this.ready);
$.on(d, 'IndexRefreshInternal', function() {
return g.posts.forEach(function(post) {
- var embed, k, l, len1, len2, ref2, ref3;
+ var embed, l, len1, len2, n, ref2, ref3;
ref2 = [post].concat(slice.call(post.clones));
- for (k = 0, len1 = ref2.length; k < len1; k++) {
- post = ref2[k];
+ for (l = 0, len1 = ref2.length; l < len1; l++) {
+ post = ref2[l];
ref3 = post.nodes.embedlinks;
- for (l = 0, len2 = ref3.length; l < len2; l++) {
- embed = ref3[l];
+ for (n = 0, len2 = ref3.length; n < len2; n++) {
+ embed = ref3[n];
Embedding.cb.catalogRemove.call(embed);
}
}
@@ -16382,7 +16300,7 @@ Embedding = (function() {
});
}
if (Conf['Link Title']) {
- return $.on(d, '4chanXInitFinished PostsInserted', function() {
+ $.on(d, '4chanXInitFinished PostsInserted', function() {
var key, ref2, ref3, service;
ref2 = Embedding.types;
for (key in ref2) {
@@ -16392,6 +16310,8 @@ Embedding = (function() {
}
}
});
+ this.cache.init(Conf['cachedTitles']);
+ return $.sync('cachedTitles', this.cache.sync);
}
},
events: function(post) {
@@ -16464,9 +16384,7 @@ Embedding = (function() {
embed = $.el('a', {
className: 'embedder',
href: 'javascript:;'
- }, {
- innerHTML: "(
un embed)"
- });
+ }, {innerHTML: "(
un embed)"});
ref = {
key: key,
uid: uid,
@@ -16521,13 +16439,15 @@ Embedding = (function() {
return style.pointerEvents = 'none';
},
title: function(data) {
- var key, link, options, post, service, uid;
+ var key, link, options, post, service, text, uid;
key = data.key, uid = data.uid, options = data.options, link = data.link, post = data.post;
if (!(service = Embedding.types[key].title)) {
return;
}
$.addClass(link, key.toLowerCase());
- if (service.batchSize) {
+ if ((text = Embedding.cache.get(data))) {
+ return Embedding.cb.titleText(text, data);
+ } else if (service.batchSize) {
(service.queue || (service.queue = [])).push(data);
if (service.queue.length >= service.batchSize) {
return Embedding.flushTitles(service);
@@ -16562,6 +16482,70 @@ Embedding = (function() {
return results;
})()), cb);
},
+ cache: (function() {
+ var get, init, newEntries, save, set, sync, titles;
+ titles = $.dict();
+ newEntries = [];
+ init = function(data) {
+ var j, key, len, ref, text, uid;
+ try {
+ for (j = 0, len = data.length; j < len; j++) {
+ ref = data[j], key = ref.key, uid = ref.uid, text = ref.text;
+ titles[key + "." + uid] = text;
+ }
+ } catch (error) {}
+ };
+ sync = function(data) {
+ var j, k, key, len, ref, text, uid;
+ try {
+ for (j = 0, len = data.length; j < len; j++) {
+ ref = data[j], key = ref.key, uid = ref.uid, text = ref.text;
+ k = key + "." + uid;
+ if (k in titles) {
+ break;
+ }
+ titles[k] = text;
+ }
+ } catch (error) {}
+ };
+ get = function(arg) {
+ var key, uid;
+ key = arg.key, uid = arg.uid;
+ return titles[key + "." + uid];
+ };
+ set = function(arg, text) {
+ var key, uid;
+ key = arg.key, uid = arg.uid;
+ titles[key + "." + uid] = text;
+ newEntries.push({
+ key: key,
+ uid: uid,
+ text: text
+ });
+ return save();
+ };
+ save = $.debounce(2 * $.SECOND, function() {
+ return $.get('cachedTitles', Conf['cachedTitles'], function(arg) {
+ var cachedTitles;
+ cachedTitles = arg.cachedTitles;
+ sync(cachedTitles);
+ try {
+ cachedTitles = newEntries.concat(cachedTitles).slice(-100);
+ } catch (error) {
+ cachedTitles = newEntries;
+ }
+ newEntries = [];
+ return $.set('cachedTitles', cachedTitles);
+ });
+ });
+ return {
+ init: init,
+ sync: sync,
+ get: get,
+ set: set,
+ save: save
+ };
+ })(),
preview: function(data) {
var key, link, service, uid;
key = data.key, uid = data.uid, link = data.link;
@@ -16627,34 +16611,42 @@ Embedding = (function() {
}
},
title: function(req, data) {
- var base1, j, k, key, len, len1, link, link2, options, post, post2, ref, ref1, service, status, text, uid;
+ var key, service, status, text, uid;
if (!req.status) {
return;
}
- key = data.key, uid = data.uid, options = data.options, link = data.link, post = data.post;
+ key = data.key, uid = data.uid;
status = req.status;
service = Embedding.types[key].title;
- text = "[" + key + "] " + ((function() {
- switch (status) {
- case 200:
- case 304:
- return service.text(req.response, uid);
- case 404:
- return "Not Found";
- case 403:
- return "Forbidden or Private";
- default:
- return status + "'d";
- }
- })());
+ switch (status) {
+ case 200:
+ case 304:
+ text = service.text(req.response, uid);
+ Embedding.cache.set(data, text);
+ break;
+ case 404:
+ text = "Not Found";
+ break;
+ case 403:
+ text = "Forbidden or Private";
+ break;
+ default:
+ text = status + "'d";
+ }
+ return Embedding.cb.titleText(text, data);
+ },
+ titleText: function(text, data) {
+ var base1, j, key, l, len, len1, link, link2, post, post2, ref, ref1;
+ key = data.key, link = data.link, post = data.post;
+ text = "[" + key + "] " + text;
link.dataset.original = link.textContent;
link.textContent = text;
ref = post.clones;
for (j = 0, len = ref.length; j < len; j++) {
post2 = ref[j];
ref1 = $$('a.linkify', post2.nodes.comment);
- for (k = 0, len1 = ref1.length; k < len1; k++) {
- link2 = ref1[k];
+ for (l = 0, len1 = ref1.length; l < len1; l++) {
+ link2 = ref1[l];
if (!(link2.href === link.href)) {
continue;
}
@@ -16683,9 +16675,7 @@ Embedding = (function() {
regExp: /^[^?#]+\.(?:gif|png|jpg|jpeg|bmp)(?::\w+)?(?:[?#]|$)/i,
style: '',
el: function(a) {
- return $.el('div', {
- innerHTML: "
"
- });
+ return $.el('div', {innerHTML: "
"});
}
}, {
key: 'video',
@@ -16845,10 +16835,10 @@ Embedding = (function() {
}
}, {
key: 'Loopvid',
- regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\/#?((?:pf|kd|lv|gd|gh|db|dx|nn|cp|wu|ig|ky|mf|m2|pc|1c|pi|ni|wl|ko|gc)\/[\w\-\/]+(?:,[\w\-\/]+)*|fc\/\w+\/\d+|https?:\/\/.+)/,
+ regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\/#?((?:pf|kd|lv|gd|gh|db|dx|nn|cp|wu|ig|ky|mf|m2|pc|1c|pi|ni|wl|ko|mm|ic|gc)\/[\w\-\/]+(?:,[\w\-\/]+)*|fc\/\w+\/\d+|https?:\/\/.+)/,
style: 'max-width: 80vw; max-height: 80vh;',
el: function(a) {
- var _, base, el, host, j, k, l, len, len1, len2, name, names, ref, ref1, type, types, url, urls;
+ var _, base, el, host, j, l, len, len1, len2, n, name, names, ref, ref1, type, types, url, urls;
el = $.el('video', {
controls: true,
preload: 'auto',
@@ -16876,8 +16866,8 @@ Embedding = (function() {
ref1 = names.split(',');
for (j = 0, len = ref1.length; j < len; j++) {
name = ref1[j];
- for (k = 0, len1 = types.length; k < len1; k++) {
- type = types[k];
+ for (l = 0, len1 = types.length; l < len1; l++) {
+ type = types[l];
base = "" + name + type;
urls = (function() {
switch (host) {
@@ -16910,25 +16900,29 @@ Embedding = (function() {
case 'm2':
return ["https://kastden.org/_loopvid_media/m2/" + base];
case 'pc':
- return ["http://a.pomf.cat/" + base];
+ return ["https://kastden.org/_loopvid_media/pc/" + base, "https://web.archive.org/web/2/http://a.pomf.cat/" + base];
case '1c':
return ["http://b.1339.cf/" + base];
case 'pi':
- return ["https://u.pomf.is/" + base];
+ return ["https://kastden.org/_loopvid_media/pi/" + base, "https://web.archive.org/web/2/https://u.pomf.is/" + base];
case 'ni':
- return ["https://u.nya.is/" + base];
+ return ["https://kastden.org/_loopvid_media/ni/" + base, "https://web.archive.org/web/2/https://u.nya.is/" + base];
case 'wl':
return ["http://webm.land/media/" + base];
case 'ko':
return ["https://kordy.kastden.org/loopvid/" + base];
+ case 'mm':
+ return ["https://kastden.org/_loopvid_media/mm/" + base, "https://web.archive.org/web/2/https://my.mixtape.moe/" + base];
+ case 'ic':
+ return ["https://media.8ch.net/file_store/" + base];
case 'fc':
return ["//" + (ImageHost.host()) + "/" + base + ".webm"];
case 'gc':
return ["https://" + type + ".gfycat.com/" + name + ".webm"];
}
})();
- for (l = 0, len2 = urls.length; l < len2; l++) {
- url = urls[l];
+ for (n = 0, len2 = urls.length; n < len2; n++) {
+ url = urls[n];
$.add(el, $.el('source', {
src: url
}));
@@ -17567,9 +17561,7 @@ DeleteLink = (function() {
}
link.textContent = DeleteLink.linkText(fileOnly);
if (resDoc.title === '4chan - Banned') {
- el = $.el('span', {
- innerHTML: "You can't delete posts because you are
banned ."
- });
+ el = $.el('span', {innerHTML: "You can't delete posts because you are
banned ."});
return new Notice('warning', el, 20);
} else if (msg = resDoc.getElementById('errmsg')) {
new Notice('warning', msg.textContent, 20);
@@ -17681,9 +17673,7 @@ Menu = (function() {
className: 'menu-button',
href: 'javascript:;'
});
- $.extend(this.button, {
- innerHTML: "
"
- });
+ $.extend(this.button, {innerHTML: "
"});
this.menu = new UI.Menu('post');
Callbacks.Post.push({
name: 'Menu',
@@ -18542,14 +18532,10 @@ FileInfo = (function() {
var a, i, j, len, len1, output, ref, ref1;
output = [];
formatString.replace(/%(.)|[^%]+/g, function(s, c) {
- output.push($.hasOwn(FileInfo.formatters, c) ? FileInfo.formatters[c].call(post) : {
- innerHTML: E(s)
- });
+ output.push($.hasOwn(FileInfo.formatters, c) ? FileInfo.formatters[c].call(post) : {innerHTML: E(s)});
return '';
});
- $.extend(outputNode, {
- innerHTML: E.cat(output)
- });
+ $.extend(outputNode, {innerHTML: E.cat(output)});
ref = $$('.download-button', outputNode);
for (i = 0, len = ref.length; i < len; i++) {
a = ref[i];
@@ -18563,93 +18549,59 @@ FileInfo = (function() {
},
formatters: {
t: function() {
- return {
- innerHTML: E(this.file.url.match(/[^/]*$/)[0])
- };
+ return {innerHTML: E(this.file.url.match(/[^/]*$/)[0])};
},
T: function() {
- return {
- innerHTML: "
" + (FileInfo.formatters.t.call(this)).innerHTML + " "
- };
+ return {innerHTML: "
" + (FileInfo.formatters.t.call(this)).innerHTML + " "};
},
l: function() {
- return {
- innerHTML: "
" + (FileInfo.formatters.n.call(this)).innerHTML + " "
- };
+ return {innerHTML: "
" + (FileInfo.formatters.n.call(this)).innerHTML + " "};
},
L: function() {
- return {
- innerHTML: "
" + (FileInfo.formatters.N.call(this)).innerHTML + " "
- };
+ return {innerHTML: "
" + (FileInfo.formatters.N.call(this)).innerHTML + " "};
},
n: function() {
var fullname, shortname;
fullname = this.file.name;
shortname = g.SITE.Build.shortFilename(this.file.name, this.isReply);
if (fullname === shortname) {
- return {
- innerHTML: E(fullname)
- };
+ return {innerHTML: E(fullname)};
} else {
- return {
- innerHTML: "
" + E(shortname) + " " + E(fullname) + " "
- };
+ return {innerHTML: "
" + E(shortname) + " " + E(fullname) + " "};
}
},
N: function() {
- return {
- innerHTML: E(this.file.name)
- };
+ return {innerHTML: E(this.file.name)};
},
d: function() {
- return {
- innerHTML: "
"
- };
+ return {innerHTML: "
"};
},
f: function() {
- return {
- innerHTML: "
"
- };
+ return {innerHTML: "
"};
},
p: function() {
- return {
- innerHTML: ((this.file.isSpoiler) ? "Spoiler, " : "")
- };
+ return {innerHTML: ((this.file.isSpoiler) ? "Spoiler, " : "")};
},
s: function() {
- return {
- innerHTML: E(this.file.size)
- };
+ return {innerHTML: E(this.file.size)};
},
B: function() {
- return {
- innerHTML: E(Math.round(this.file.sizeInBytes)) + " Bytes"
- };
+ return {innerHTML: E(Math.round(this.file.sizeInBytes)) + " Bytes"};
},
K: function() {
- return {
- innerHTML: E(Math.round(this.file.sizeInBytes/1024)) + " KB"
- };
+ return {innerHTML: E(Math.round(this.file.sizeInBytes/1024)) + " KB"};
},
M: function() {
- return {
- innerHTML: E(Math.round(this.file.sizeInBytes/1048576*100)/100) + " MB"
- };
+ return {innerHTML: E(Math.round(this.file.sizeInBytes/1048576*100)/100) + " MB"};
},
r: function() {
- return {
- innerHTML: E(this.file.dimensions || "PDF")
- };
+ return {innerHTML: E(this.file.dimensions || "PDF")};
},
g: function() {
- return {
- innerHTML: ((this.file.tag) ? ", " + E(this.file.tag) : "")
- };
+ return {innerHTML: ((this.file.tag) ? ", " + E(this.file.tag) : "")};
},
'%': function() {
- return {
- innerHTML: "%"
- };
+ return {innerHTML: "%"};
}
}
};
@@ -18718,7 +18670,17 @@ Fourchan = (function() {
return $.addClass(pre, 'prettyprinted');
}
});
- $.globalEval('window.addEventListener(\'prettyprint\', function(e) {\n window.dispatchEvent(new CustomEvent(\'prettyprint:cb\', {\n detail: {\n ID: e.detail.ID,\n i: e.detail.i,\n html: prettyPrintOne(e.detail.html)\n }\n }));\n}, false);');
+ $.global(function() {
+ return window.addEventListener('prettyprint', function(e) {
+ return window.dispatchEvent(new CustomEvent('prettyprint:cb', {
+ detail: {
+ ID: e.detail.ID,
+ i: e.detail.i,
+ html: window.prettyPrintOne(e.detail.html)
+ }
+ }));
+ }, false);
+ });
Callbacks.Post.push({
name: 'Parse [code] tags',
cb: Fourchan.code
@@ -19317,7 +19279,7 @@ Keybinds = (function() {
}
post = Keybinds.post(threadRoot);
Keybinds.hl(+1, threadRoot);
- Filter.quickFilterMD5.call(post);
+ Filter.quickFilterMD5.call(post, e);
break;
case Conf['Previous Post Quoting You']:
if (!(threadRoot && QuoteYou.db)) {
@@ -19531,34 +19493,24 @@ ModContact = (function() {
}
},
template: function(capcode) {
- return {
- innerHTML: "
feedback " + (ModContact.specific[capcode]()).innerHTML
- };
+ return {innerHTML: "
feedback " + (ModContact.specific[capcode]()).innerHTML};
},
specific: {
Mod: function() {
- return {
- innerHTML: "
IRC "
- };
+ return {innerHTML: "
IRC "};
},
Manager: function() {
return ModContact.specific.Mod();
},
Developer: function() {
- return {
- innerHTML: "
github "
- };
+ return {innerHTML: "
github "};
},
Admin: function() {
- return {
- innerHTML: "
twitter "
- };
+ return {innerHTML: "
twitter "};
}
},
moveNote: {
- qa: {
- innerHTML: "Moving a thread to /qa/ does not imply mods will read it. If you wish to contact mods, use
feedback (https://www.4chan.org/feedback) or
IRC (https://www.4chan-x.net/4chan-irc.html) ."
- }
+ qa: {innerHTML: "Moving a thread to /qa/ does not imply mods will read it. If you wish to contact mods, use
feedback (https://www.4chan.org/feedback) or
IRC (https://www.4chan-x.net/4chan-irc.html) ."}
}
};
@@ -19889,9 +19841,7 @@ PostJumper = (function() {
span = $.el('span', {
className: 'postJumper'
});
- $.extend(span, {
- innerHTML: "
" + E(charPrev) + " " + E(charNext) + " "
- });
+ $.extend(span, {innerHTML: "
" + E(charPrev) + " " + E(charNext) + " "});
return span;
},
scroll: function(fromJumper, toJumper) {
@@ -20121,9 +20071,7 @@ Report = (function() {
fieldset = $.el('fieldset', {
id: 'archive-report',
hidden: true
- }, {
- innerHTML: "
Report illegal content to archivesDetails Illegal content Submit "
- });
+ }, {innerHTML: "
Report illegal content to archivesDetails Illegal content Submit "});
enabled = $('#archive-report-enabled', fieldset);
reason = $('#archive-report-reason', fieldset);
submit = $('#archive-report-submit', fieldset);
@@ -20590,9 +20538,7 @@ ReplyPruning = (function() {
label = UI.checkbox('Prune Replies', 'Show Last', Conf['Prune All Threads']);
el = $.el('span', {
title: 'Maximum number of replies to show.'
- }, {
- innerHTML: "
"
- });
+ }, {innerHTML: "
"});
$.prepend(el, label);
this.inputs = {
enabled: label.firstElementChild,
@@ -20736,9 +20682,7 @@ ThreadStats = (function() {
if (Conf['Page Count in Stats']) {
this[(typeof (base = g.SITE).isPrunedByAge === "function" ? base.isPrunedByAge(g.BOARD) : void 0) ? 'showPurgePos' : 'showPage'] = true;
}
- statsHTML = {
- innerHTML: "
? /
? " + ((Conf["IP Count in Stats"] && g.SITE.hasIPCount) ? " /
? " : "") + ((Conf["Page Count in Stats"]) ? " /
? " : "")
- };
+ statsHTML = {innerHTML: "
? /
? " + ((Conf["IP Count in Stats"] && g.SITE.hasIPCount) ? " /
? " : "") + ((Conf["Page Count in Stats"]) ? " /
? " : "")};
statsTitle = 'Posts / Files';
if (Conf['IP Count in Stats'] && g.SITE.hasIPCount) {
statsTitle += ' / IPs';
@@ -20754,9 +20698,7 @@ ThreadStats = (function() {
$.extend(sc, statsHTML);
Header.addShortcut('stats', sc, 200);
} else {
- this.dialog = sc = UI.dialog('thread-stats', {
- innerHTML: "
" + (statsHTML).innerHTML + "
"
- });
+ this.dialog = sc = UI.dialog('thread-stats', {innerHTML: "
" + (statsHTML).innerHTML + "
"});
$.addClass(doc, 'float');
$.ready(function() {
return $.add(d.body, sc);
@@ -20925,14 +20867,10 @@ ThreadUpdater = (function() {
this.dialog = sc = $.el('span', {
id: 'updater'
});
- $.extend(sc, {
- innerHTML: "
"
- });
+ $.extend(sc, {innerHTML: "
"});
Header.addShortcut('updater', sc, 100);
} else {
- this.dialog = sc = UI.dialog('updater', {
- innerHTML: "
"
- });
+ this.dialog = sc = UI.dialog('updater', {innerHTML: "
"});
$.addClass(doc, 'float');
$.ready(function() {
return $.add(d.body, sc);
@@ -20946,9 +20884,7 @@ ThreadUpdater = (function() {
updateLink = $.el('span', {
className: 'brackets-wrap updatelink'
});
- $.extend(updateLink, {
- innerHTML: "
Update "
- });
+ $.extend(updateLink, {innerHTML: "
Update "});
Main.ready(function() {
var navLinksBot;
if ((navLinksBot = $('.navLinksBot'))) {
@@ -20974,9 +20910,7 @@ ThreadUpdater = (function() {
el: el
});
}
- this.settings = $.el('span', {
- innerHTML: "
Interval "
- });
+ this.settings = $.el('span', {innerHTML: "
Interval "});
$.on(this.settings, 'click', this.intervalShortcut);
subEntries.push({
el: this.settings
@@ -21359,9 +21293,7 @@ ThreadWatcher = (function() {
});
this.db = new DataBoard('watchedThreads', this.refresh, true);
this.dbLM = new DataBoard('watcherLastModified', null, true);
- this.dialog = UI.dialog('thread-watcher', {
- innerHTML: "
"
- });
+ this.dialog = UI.dialog('thread-watcher', {innerHTML: "
"});
this.status = $('#watcher-status', this.dialog);
this.list = this.dialog.lastElementChild;
this.refreshButton = $('.refresh', this.dialog);
@@ -21399,9 +21331,7 @@ ThreadWatcher = (function() {
el: $.el('a', {
href: 'javascript:;',
className: 'has-shortcut-text'
- }, {
- innerHTML: "
Alt+click "
- }),
+ }, {innerHTML: "
Alt+click "}),
order: 6,
open: function(arg) {
var thread;
@@ -23486,9 +23416,7 @@ Captcha = {};
root = $.el('div', {
className: 'captcha-root'
});
- $.extend(root, {
- innerHTML: "
"
- });
+ $.extend(root, {innerHTML: "
"});
counter = $('.captcha-counter > a', root);
this.nodes = {
root: root,
@@ -23767,9 +23695,7 @@ PassLink = (function() {
passLink = $.el('span', {
className: 'brackets-wrap pass-link-container'
});
- $.extend(passLink, {
- innerHTML: "
4chan Pass "
- });
+ $.extend(passLink, {innerHTML: "
4chan Pass "});
$.on(passLink.firstElementChild, 'click', function() {
return window.open("//sys." + (location.hostname.split('.')[1]) + ".org/auth", Date.now(), 'width=500,height=280,toolbar=0');
});
@@ -23940,9 +23866,7 @@ QR = (function() {
link = $.el('h1', {
className: "qr-link-container"
});
- $.extend(link, {
- innerHTML: "
" + ((g.VIEW === "thread") ? "Reply to Thread" : "Start a Thread") + " "
- });
+ $.extend(link, {innerHTML: "
" + ((g.VIEW === "thread") ? "Reply to Thread" : "Start a Thread") + " "});
QR.link = link.firstElementChild;
$.on(link.firstChild, 'click', function() {
QR.open();
@@ -23955,9 +23879,7 @@ QR = (function() {
linkBot = $.el('div', {
className: "brackets-wrap qr-link-container-bottom"
});
- $.extend(linkBot, {
- innerHTML: "
Reply to Thread "
- });
+ $.extend(linkBot, {innerHTML: "
Reply to Thread "});
$.on(linkBot.firstElementChild, 'click', function() {
QR.open();
return QR.nodes.com.focus();
@@ -24156,9 +24078,7 @@ QR = (function() {
}
},
connectionError: function() {
- return $.el('span', {
- innerHTML: "Connection error while posting. [
More info ]"
- });
+ return $.el('span', {innerHTML: "Connection error while posting. [
More info ]"});
},
notifications: [],
cleanNotifications: function() {
@@ -24306,9 +24226,7 @@ QR = (function() {
openError: function() {
var div;
div = $.el('div');
- $.extend(div, {
- innerHTML: "Could not open file. [
More info ]"
- });
+ $.extend(div, {innerHTML: "Could not open file. [
More info ]"});
return QR.error(div);
},
setFile: function(e) {
@@ -24486,9 +24404,7 @@ QR = (function() {
dialog: function() {
var classList, config, dialog, event, i, items, name, node, nodes, save, setNode;
QR.nodes = nodes = {
- el: dialog = UI.dialog('qr', {
- innerHTML: "
∀ TE X
Width: Height:
Hentai Porn Japanese Anime Game Loop Other "
- })
+ el: dialog = UI.dialog('qr', {innerHTML: "
∀ TE X
Width: Height:
Hentai Porn Japanese Anime Game Loop Other "})
};
setNode = function(name, query) {
return nodes[name] = $(query, dialog);
@@ -24544,6 +24460,7 @@ QR = (function() {
QR.flagsInput();
$.on(nodes.autohide, 'change', QR.toggleHide);
$.on(nodes.close, 'click', QR.close);
+ $.on(nodes.status, 'click', QR.submit);
$.on(nodes.form, 'submit', QR.submit);
$.on(nodes.sjisToggle, 'click', QR.toggleSJIS);
$.on(nodes.texButton, 'mousedown', QR.texPreviewShow);
@@ -24657,19 +24574,24 @@ QR = (function() {
}
},
submit: function(e) {
- var captcha, cb, err, filetag, formData, options, post, ref, thread, threadID;
+ var captcha, cb, err, filetag, force, formData, options, post, ref, thread, threadID;
if (e != null) {
e.preventDefault();
}
+ force = e != null ? e.shiftKey : void 0;
if (QR.req) {
QR.abort();
return;
}
$.forceSync('cooldowns');
if (QR.cooldown.seconds) {
- QR.cooldown.auto = !QR.cooldown.auto;
- QR.status();
- return;
+ if (force) {
+ QR.cooldown.clear();
+ } else {
+ QR.cooldown.auto = !QR.cooldown.auto;
+ QR.status();
+ return;
+ }
}
post = QR.posts[0];
post.forceSave();
@@ -24703,7 +24625,7 @@ QR = (function() {
}
}
QR.cleanNotifications();
- if (err) {
+ if (err && !force) {
QR.cooldown.auto = false;
QR.status();
QR.error(err);
@@ -24789,7 +24711,7 @@ QR = (function() {
return QR.status();
},
response: function() {
- var URL, _, connErr, err, h1, isReply, lastPostToThread, m, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
+ var URL, _, connErr, err, h1, isReply, j, lastPostToThread, len, m, mi, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
if (this !== QR.req) {
return;
}
@@ -24823,9 +24745,13 @@ QR = (function() {
QR.cooldown.auto = QR.captcha.isEnabled || connErr;
QR.cooldown.addDelay(post, 2);
}
- } else if (err.textContent && (m = err.textContent.match(/(?:(\d+)\s+minutes?\s+)?(\d+)\s+second/i)) && !/duplicate|hour/i.test(err.textContent)) {
+ } else if (err.textContent && (m = err.textContent.match(/\d+\s+(?:minute|second)/gi)) && !/duplicate|hour/i.test(err.textContent)) {
QR.cooldown.auto = !/have\s+been\s+muted/i.test(err.textContent);
- seconds = 60 * (+(m[1] || 0)) + (+m[2]);
+ seconds = 0;
+ for (j = 0, len = m.length; j < len; j++) {
+ mi = m[j];
+ seconds += (/minute/i.test(mi) ? 60 : 1) * (+mi.match(/\d+/)[0]);
+ }
if (/muted/i.test(err.textContent)) {
QR.cooldown.addMute(seconds);
} else {
@@ -24858,10 +24784,10 @@ QR = (function() {
postsCount = QR.posts.length - 1;
QR.cooldown.auto = postsCount && isReply;
lastPostToThread = !((function() {
- var j, len, p, ref4;
+ var k, len1, p, ref4;
ref4 = QR.posts.slice(1);
- for (j = 0, len = ref4.length; j < len; j++) {
- p = ref4[j];
+ for (k = 0, len1 = ref4.length; k < len1; k++) {
+ p = ref4[k];
if (p.thread === post.thread) {
return true;
}
@@ -25102,6 +25028,13 @@ QR = (function() {
});
});
},
+ clear: function() {
+ QR.cooldown.data = $.dict();
+ QR.cooldown.changes = $.dict();
+ QR.cooldown.auto = false;
+ QR.cooldown.update();
+ return $.queueTask($["delete"], 'cooldowns');
+ },
update: function() {
var base, cooldown, cooldowns, elapsed, i, len, maxDelay, nCooldowns, now, ref, ref1, save, scope, seconds, start, suffix, threadID, type, update;
if (!QR.cooldown.isCounting) {
@@ -25524,9 +25457,7 @@ QR = (function() {
draggable: true,
href: 'javascript:;'
});
- $.extend(el, {
- innerHTML: "
Spoiler"
- });
+ $.extend(el, {innerHTML: "
Spoiler"});
this.nodes = {
el: el,
rm: el.firstChild,
@@ -25763,9 +25694,7 @@ QR = (function() {
div = $.el('div', {
className: className
});
- $.extend(div, {
- innerHTML: E(message) + ((link) ? " [
More info ]" : "") + "
[
delete post ] [
delete all ]"
- });
+ $.extend(div, {innerHTML: E(message) + ((link) ? " [
More info ]" : "") + "
[
delete post ] [
delete all ]"});
(this.errors || (this.errors = [])).push(div);
ref = $$('a', div), rm = ref[0], rmAll = ref[1];
$.on(div, 'click', (function(_this) {
@@ -26568,16 +26497,12 @@ QuoteThreading =
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
- this.controls = $.el('label', {
- innerHTML: "
Threading"
- });
+ this.controls = $.el('label', {innerHTML: "
Threading"});
this.threadNewLink = $.el('span', {
className: 'brackets-wrap threadnewlink',
hidden: true
});
- $.extend(this.threadNewLink, {
- innerHTML: "
Thread New Posts "
- });
+ $.extend(this.threadNewLink, {innerHTML: "
Thread New Posts "});
this.input = $('input', this.controls);
this.input.checked = Conf['Thread Quotes'];
$.on(this.input, 'change', this.setEnabled);
@@ -26872,9 +26797,7 @@ QuoteYou = (function() {
var input, label, ref;
label = $.el('label', {
className: 'toggle-you'
- }, {
- innerHTML: "
You"
- });
+ }, {innerHTML: "
You"});
input = $('input', label);
$.on(input, 'change', QuoteYou.menu.toggle);
return (ref = Menu.menu) != null ? ref.addEntry({
@@ -27276,6 +27199,7 @@ Main = (function() {
if ($.cantSet) {
} else if (items.previousversion == null) {
+ Main.isFirstRun = true;
Main.ready(function() {
$.set('previousversion', g.VERSION);
return Settings.open();
@@ -27299,9 +27223,7 @@ Main = (function() {
return $.set(changes, function() {
var el, ref;
if ((ref = items['Show Updated Notifications']) != null ? ref : true) {
- el = $.el('span', {
- innerHTML: "4chan X has been updated to
version " + E(g.VERSION) + " ."
- });
+ el = $.el('span', {innerHTML: "4chan X has been updated to
version " + E(g.VERSION) + " ."});
return new Notice('info', el, 15);
}
});
@@ -27541,9 +27463,7 @@ Main = (function() {
return;
}
if (typeof (base1 = g.SITE).isIncomplete === "function" ? base1.isIncomplete() : void 0) {
- msg = $.el('div', {
- innerHTML: "The page didn't load completely.
Some features may not work unless you
reload ."
- });
+ msg = $.el('div', {innerHTML: "The page didn't load completely.
Some features may not work unless you
reload ."});
$.on($('a', msg), 'click', function() {
return location.reload();
});
@@ -27627,7 +27547,8 @@ Main = (function() {
err = error1;
errors.push({
message: "Parsing of Post No." + (postRoot.id.match(/\d+/)) + " failed. Post will be skipped.",
- error: err
+ error: err,
+ html: postRoot.outerHTML
});
}
}
@@ -27746,7 +27667,8 @@ Main = (function() {
err = error1;
errors.push({
message: "Parsing of Catalog Thread No." + ((threadRoot.dataset.id || threadRoot.id).match(/\d+/)) + " failed. Thread will be skipped.",
- error: err
+ error: err,
+ html: threadRoot.outerHTML
});
}
}
@@ -27810,11 +27732,21 @@ Main = (function() {
return softTask();
},
handleErrors: function(errors) {
- var div, error, j, len, logs;
+ var div, enabled, error, j, len, logs, msg;
if (d.body && $.hasClass(d.body, 'fourchan_x') && !$.hasClass(doc, 'tainted')) {
new Notice('error', 'Error: Multiple copies of 4chan X are enabled.');
$.addClass(doc, 'tainted');
}
+ if (g.SITE.testNativeExtension && !$.hasClass(doc, 'tainted')) {
+ enabled = g.SITE.testNativeExtension().enabled;
+ if (enabled) {
+ $.addClass(doc, 'tainted');
+ if (Conf['Disable Native Extension'] && !Main.isFirstRun) {
+ msg = $.el('div', {innerHTML: "Failed to disable the native extension. You may need to
block it ."});
+ new Notice('error', msg);
+ }
+ }
+ }
if (!(errors instanceof Array)) {
error = errors;
} else if (errors.length === 1) {
@@ -27824,9 +27756,7 @@ Main = (function() {
new Notice('error', Main.parseError(error, Main.reportLink([error])), 15);
return;
}
- div = $.el('div', {
- innerHTML: E(errors.length) + " errors occurred." + (Main.reportLink(errors)).innerHTML + " [
show ]"
- });
+ div = $.el('div', {innerHTML: E(errors.length) + " errors occurred." + (Main.reportLink(errors)).innerHTML + " [
show ]"});
$.on(div.lastElementChild, 'click', function() {
var ref;
return ref = this.textContent === 'show' ? ['hide', false] : ['show', true], this.textContent = ref[0], logs.hidden = ref[1], ref;
@@ -27843,9 +27773,7 @@ Main = (function() {
parseError: function(data, reportLink) {
var context, error, lines, message, ref, ref1;
c.error(data.message, data.error.stack);
- message = $.el('div', {
- innerHTML: E(data.message) + ((reportLink) ? (reportLink).innerHTML : "")
- });
+ message = $.el('div', {innerHTML: E(data.message) + ((reportLink) ? (reportLink).innerHTML : "")});
error = $.el('div', {
textContent: (data.error.name || 'Error') + ": " + (data.error.message || 'see console for details')
});
@@ -27856,7 +27784,7 @@ Main = (function() {
return [message, error, context];
},
reportLink: function(errors) {
- var addDetails, data, details, title, url;
+ var addDetails, data, details, info, title, url;
data = errors[0];
title = data.message;
if (errors.length > 1) {
@@ -27868,7 +27796,10 @@ Main = (function() {
return details += text + '\n';
}
};
- addDetails("[Please describe the steps needed to reproduce this error.]\n\nScript: 4chan X ccd0 v" + g.VERSION + " " + $.platform + "\nUser agent: " + navigator.userAgent + "\nURL: " + location.href);
+ addDetails("[Please describe the steps needed to reproduce this error.]\n\nScript: 4chan X ccd0 v" + g.VERSION + " " + $.platform + "\nURL: " + location.href + "\nUser agent: " + navigator.userAgent);
+ if ($.platform === 'userscript' && (info = typeof GM !== "undefined" && GM !== null ? GM.info : (typeof GM_info !== "undefined" && GM_info !== null ? GM_info : void 0))) {
+ addDetails("Userscript manager: " + info.scriptHandler + " " + info.version);
+ }
addDetails('\n' + data.error);
if (data.error.stack) {
addDetails(data.error.stack.replace(data.error.toString(), '').trim());
@@ -27877,10 +27808,8 @@ Main = (function() {
addDetails('\n`' + data.html + '`');
}
details = details.replace(/file:\/{3}.+\//g, '');
- url = "https://gitreports.com/issue/ccd0/4chan-x?issue_title=" + (encodeURIComponent(title)) + "&details=" + (encodeURIComponent(details));
- return {
- innerHTML: "
[report ] "
- };
+ url = 'https://gitreports.com/issue/ccd0/4chan-x?issue_title=%title&details=%details'.replace('%title', encodeURIComponent(title)).replace('%details', encodeURIComponent(details));
+ return {innerHTML: "
[report ] "};
},
isThisPageLegit: function() {
if (!('thisPageIsLegit' in Main)) {
diff --git a/builds/4chan-X.zip b/builds/4chan-X.zip
index 1725a4ca7..5a4a0b6ea 100644
Binary files a/builds/4chan-X.zip and b/builds/4chan-X.zip differ
diff --git a/builds/updates-beta.json b/builds/updates-beta.json
index 49926a1cc..7987f4264 100644
--- a/builds/updates-beta.json
+++ b/builds/updates-beta.json
@@ -3,7 +3,7 @@
"4chan-x@4chan-x.net": {
"updates": [
{
- "version": "1.14.11.1",
+ "version": "1.14.12.0",
"update_link": "https://www.4chan-x.net/builds/4chan-X-beta.crx"
}
]
diff --git a/builds/updates-beta.xml b/builds/updates-beta.xml
index 7c2804231..1c2d10b63 100644
--- a/builds/updates-beta.xml
+++ b/builds/updates-beta.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/builds/updates.json b/builds/updates.json
index 5f6b080fc..e0b313ec6 100644
--- a/builds/updates.json
+++ b/builds/updates.json
@@ -3,7 +3,7 @@
"4chan-x@4chan-x.net": {
"updates": [
{
- "version": "1.14.11.1",
+ "version": "1.14.12.0",
"update_link": "https://www.4chan-x.net/builds/4chan-X.crx"
}
]
diff --git a/builds/updates.xml b/builds/updates.xml
index f274a4127..2210c2c98 100644
--- a/builds/updates.xml
+++ b/builds/updates.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/version.json b/version.json
index 4cc5217a9..be0d9ccaf 100644
--- a/version.json
+++ b/version.json
@@ -1,4 +1,4 @@
{
- "version": "1.14.11.1",
- "date": "2019-08-03T18:01:40.027Z"
+ "version": "1.14.12.0",
+ "date": "2019-08-05T05:48:40.635Z"
}
\ No newline at end of file