Release 4chan X v1.10.3.0.

This commit is contained in:
ccd0 2015-03-01 01:24:09 -08:00
parent bf8d530b29
commit 6ab3969672
13 changed files with 765 additions and 812 deletions

View File

@ -2,6 +2,16 @@ Sometimes the changelog has notes (not comprehensive) acknowledging people's wor
The links to individual versions below are to copies of the script with the update URL removed. If you want automatic updates, install the script from the links on the [main page](https://github.com/ccd0/4chan-x).
### v1.10.3
**v1.10.3.0** *(2015-03-01)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.3.0/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.3.0/builds/4chan-X-noupdate.crx "Chromium version")]
- Make the filename in the Quick Reply editable immediately without having to Control+click it.
- Add a "Files" button which can be used to open the file picker even if a file has already been selected. This also fixes issues with opening the file picker via keyboard on Firefox.
- Move the spoiler checkbox into the box containing the filename.
- Always merely warn about disallowed file types / sizes / dimensions, rather than outright preventing them from being posted. Links to `[delete]` and `[delete all]` such posts have been added to the warning messages to make removing the files from a dumplist convenient.
- Remove the "low on cached captchas" notifications as the 2-minute captcha expiry time has made them more annoying than useful.
- Minor bugfixes.
### v1.10.2
**v1.10.2.8** *(2015-02-28)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.2.8/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.2.8/builds/4chan-X-noupdate.crx "Chromium version")]

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X beta
// @version 1.10.2.8
// @version 1.10.3.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X beta
// @version 1.10.2.8
// @version 1.10.3.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@ -393,7 +393,7 @@
doc = d.documentElement;
g = {
VERSION: '1.10.2.8',
VERSION: '1.10.3.0',
NAMESPACE: '4chan X.',
NAME: '4chan X',
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
@ -3066,7 +3066,7 @@
el: $.el('span', {
textContent: 'Index Navigation'
}),
order: 98,
order: 100,
subEntries: [repliesEntry, pinEntry, anchorEntry, refNavEntry]
});
$.addClass(doc, 'index-loading', (Conf['Index Mode'].replace(/\ /g, '-')) + "-mode");
@ -6392,7 +6392,7 @@
$.on(this.threadNewLink.firstElementChild, 'click', this.rethread);
Header.menu.addEntry(this.entry = {
el: this.controls,
order: 98
order: 99
});
Thread.callbacks.push({
name: 'Quote Threading',
@ -7169,6 +7169,7 @@
if (url === null) {
return;
}
QR.nodes.fileButton.focus();
return CrossOrigin.file(url, function(blob) {
if (blob) {
return QR.handleFiles([blob]);
@ -7178,7 +7179,7 @@
});
},
handleFiles: function(files) {
var file, i, k, len1;
var file, k, len1;
if (this !== QR) {
files = slice.call(this.files);
this.value = null;
@ -7187,147 +7188,36 @@
return;
}
QR.cleanNotifications();
for (i = k = 0, len1 = files.length; k < len1; i = ++k) {
file = files[i];
QR.handleFile(file, i, files.length);
for (k = 0, len1 = files.length; k < len1; k++) {
file = files[k];
QR.handleFile(file, files.length);
}
if (files.length !== 1) {
return $.addClass(QR.nodes.el, 'dump');
$.addClass(QR.nodes.el, 'dump');
}
if (d.activeElement === QR.nodes.fileButton && $.hasClass(QR.nodes.fileSubmit, 'has-file')) {
return QR.nodes.filename.focus();
}
},
handleFile: function(file, index, nfiles) {
var isNewPost, isSingle, max, post, ref;
isSingle = nfiles === 1;
if (/^text\//.test(file.type)) {
if (isSingle) {
post = QR.selected;
} else if (index !== 0 || (post = QR.posts[QR.posts.length - 1]).com) {
handleFile: function(file, nfiles) {
var isText, post;
isText = /^text\//.test(file.type);
if (nfiles === 1) {
post = QR.selected;
} else {
post = QR.posts[QR.posts.length - 1];
if ((isText ? post.com || post.pasting : post.file)) {
post = new QR.post();
}
post.pasteText(file);
}
return post[isText ? 'pasteText' : 'setFile'](file);
},
openFileInput: function() {
if (QR.nodes.fileButton.disabled) {
return;
}
if (ref = file.type, indexOf.call(QR.mimeTypes, ref) < 0) {
QR.error(file.name + ": Unsupported file type.");
if (!isSingle) {
return;
}
}
max = QR.nodes.fileInput.max;
if (/^video\//.test(file.type)) {
max = Math.min(max, QR.max_size_video);
}
if (file.size > max) {
QR.error(file.name + ": File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
if (!isSingle) {
return;
}
}
isNewPost = false;
if (isSingle) {
post = QR.selected;
} else if (index !== 0 || (post = QR.posts[QR.posts.length - 1]).file) {
isNewPost = true;
post = new QR.post();
}
return QR.checkDimensions(file, function(pass, el) {
if (pass || isSingle) {
return post.setFile(file, el);
} else if (isNewPost) {
post.rm();
if (el) {
return URL.revokeObjectURL(el.src);
}
}
});
},
checkDimensions: function(file, cb) {
var img, video;
if (/^image\//.test(file.type)) {
img = new Image();
img.onload = function() {
var height, pass, width;
height = img.height, width = img.width;
pass = true;
if (height > QR.max_height || width > QR.max_width) {
QR.error(file.name + ": Image too large (image: " + height + "x" + width + "px, max: " + QR.max_height + "x" + QR.max_width + "px)");
pass = false;
}
if (height < QR.min_height || width < QR.min_width) {
QR.error(file.name + ": Image too small (image: " + height + "x" + width + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
pass = false;
}
return cb(pass, img);
};
img.onerror = function() {
return cb(false, null);
};
return img.src = URL.createObjectURL(file);
} else if (/^video\//.test(file.type)) {
video = $.el('video');
$.on(video, 'loadeddata', function() {
var duration, max_height, max_width, pass, ref, videoHeight, videoWidth;
if (!cb) {
return;
}
videoHeight = video.videoHeight, videoWidth = video.videoWidth, duration = video.duration;
max_height = Math.min(QR.max_height, QR.max_height_video);
max_width = Math.min(QR.max_width, QR.max_width_video);
pass = true;
if (videoHeight > max_height || videoWidth > max_width) {
QR.error(file.name + ": Video too large (video: " + videoHeight + "x" + videoWidth + "px, max: " + max_height + "x" + max_width + "px)");
pass = false;
}
if (videoHeight < QR.min_height || videoWidth < QR.min_width) {
QR.error(file.name + ": Video too small (video: " + videoHeight + "x" + videoWidth + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
pass = false;
}
if (!isFinite(duration)) {
QR.error(file.name + ": Video lacks duration metadata (try remuxing)");
pass = false;
} else if (duration > QR.max_duration_video) {
QR.error(file.name + ": Video too long (video: " + duration + "s, max: " + QR.max_duration_video + "s)");
pass = false;
}
if (((ref = g.BOARD.ID) !== 'gif' && ref !== 'wsg') && $.hasAudio(video)) {
QR.error(file.name + ": Audio not allowed");
pass = false;
}
cb(pass, video);
return cb = null;
});
$.on(video, 'error', function() {
var ref;
if (!cb) {
return;
}
if (ref = file.type, indexOf.call(QR.mimeTypes, ref) >= 0) {
QR.error(file.name + ": Video appears corrupt");
}
URL.revokeObjectURL(file);
cb(false, null);
return cb = null;
});
return video.src = URL.createObjectURL(file);
} else {
return cb(true, null);
}
},
openFileInput: function(e) {
var ref;
e.stopPropagation();
if (e.shiftKey && e.type === 'click') {
return QR.selected.rmFile();
}
if ((e.ctrlKey || e.metaKey) && e.type === 'click') {
$.addClass(QR.nodes.filename, 'edit');
QR.nodes.filename.focus();
}
if (e.target.nodeName === 'INPUT' || (e.keyCode && ((ref = e.keyCode) !== 32 && ref !== 13)) || e.ctrlKey) {
return;
}
e.preventDefault();
return QR.nodes.fileInput.click();
QR.nodes.fileInput.click();
return QR.nodes.fileButton.focus();
},
generatePostableThreadsList: function() {
var k, len1, list, options, ref, thread, val;
@ -7358,7 +7248,7 @@
var dialog, event, i, items, m, match_max, match_min, name, node, nodes, ref, rules, save, setNode;
QR.nodes = nodes = {
el: dialog = UI.dialog('qr', 'top: 50px; right: 0px;', {
innerHTML: "<div class=move><label><input type=checkbox id=autohide title=Auto-hide>Quick Reply</label><a href=javascript:; class=close title=Close>×</a><select data-name=thread title='Create a new thread / Reply'><option value=new>New thread</option></select></div><form><div class=persona><input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1><input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1><input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1></div><div class=textarea><textarea data-name=com placeholder=Comment class=field></textarea><span id=char-count></span></div><div id=dump-list-container><div id=dump-list></div><a id=add-post href=javascript:; title=\"Add a post\">+</a></div><div id=file-n-submit><span id=qr-filename-container class=field tabindex=0><span id=qr-no-file>No selected file</span><input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\"><span id=\"qr-extras-container\"><a href=\"javascript:;\" id=\"qr-filerm\" title=\"Remove file\"><i class=\"fa fa-times-circle\"></i></a><a id=\"url-button\" title=\"Post from url\"><i class=\"fa fa-link\"></i></a><a id=\"custom-cooldown-button\" title=\"Toggle custom cooldown\" class=\"disabled\"><i class=\"fa fa-clock-o\"></i></a><a id=\"dump-button\" title=\"Dump list\"><i class=\"fa fa-plus-square\"></i></a></span></span><label id=qr-spoiler-label><input type=checkbox id=qr-file-spoiler title='Spoiler image'></label><input type=submit></div><input type=file multiple></form><datalist id=\"list-name\"></datalist><datalist id=\"list-email\"></datalist><datalist id=\"list-sub\"></datalist> "
innerHTML: "<div class=move><label><input type=checkbox id=autohide title=Auto-hide>Quick Reply</label><a href=javascript:; class=close title=Close>×</a><select data-name=thread title='Create a new thread / Reply'><option value=new>New thread</option></select></div><form><div class=persona><input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1><input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1><input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1></div><div class=textarea><textarea data-name=com placeholder=Comment class=field></textarea><span id=char-count></span></div><div id=dump-list-container><div id=dump-list></div><a id=add-post href=javascript:; title=\"Add a post\">+</a></div><div id=\"file-n-submit\"><input type=\"button\" id=\"qr-file-button\" value=\"Files\"><span id=\"qr-filename-container\" class=\"field\"><span id=\"qr-no-file\">No selected file</span><input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\"><label id=\"qr-spoiler-label\"><input type=\"checkbox\" id=\"qr-file-spoiler\" title=\"Spoiler image\"></label><a href=\"javascript:;\" id=\"qr-filerm\" title=\"Remove file\"><i class=\"fa fa-times-circle\"></i></a><a id=\"url-button\" title=\"Post from url\"><i class=\"fa fa-link\"></i></a><a id=\"custom-cooldown-button\" title=\"Toggle custom cooldown\" class=\"disabled\"><i class=\"fa fa-clock-o\"></i></a><a id=\"dump-button\" title=\"Dump list\"><i class=\"fa fa-plus-square\"></i></a></span><input type=\"submit\"></div><input type=\"file\" multiple></form><datalist id=\"list-name\"></datalist><datalist id=\"list-email\"></datalist><datalist id=\"list-sub\"></datalist> "
})
};
setNode = function(name, query) {
@ -7380,10 +7270,10 @@
setNode('addPost', '#add-post');
setNode('charCount', '#char-count');
setNode('fileSubmit', '#file-n-submit');
setNode('fileButton', '#qr-file-button');
setNode('noFile', '#qr-no-file');
setNode('filename', '#qr-filename');
setNode('fileContainer', '#qr-filename-container');
setNode('fileRM', '#qr-filerm');
setNode('fileExtras', '#qr-extras-container');
setNode('spoiler', '#qr-file-spoiler');
setNode('spoilerPar', '#qr-spoiler-label');
setNode('status', '[type=submit]');
@ -7437,7 +7327,8 @@
nodes.flashTag.dataset["default"] = '4';
$.add(nodes.form, nodes.flashTag);
}
$.on(nodes.filename.parentNode, 'click keydown', QR.openFileInput);
$.on(nodes.fileButton, 'click', QR.openFileInput);
$.on(nodes.noFile, 'click', QR.openFileInput);
$.on(nodes.autohide, 'change', QR.toggleHide);
$.on(nodes.close, 'click', QR.close);
$.on(nodes.dumpButton, 'click', function() {
@ -7448,15 +7339,9 @@
return new QR.post(true);
});
$.on(nodes.form, 'submit', QR.submit);
$.on(nodes.filename, 'blur', function() {
return $.rmClass(this, 'edit');
});
$.on(nodes.fileRM, 'click', function() {
return QR.selected.rmFile();
});
$.on(nodes.fileExtras, 'click', function(e) {
return e.stopPropagation();
});
$.on(nodes.spoiler, 'change', function() {
return QR.selected.nodes.spoiler.click();
});
@ -7626,7 +7511,7 @@
return QR.status();
},
response: function() {
var URL, _, ban, captchasCount, err, h1, isReply, m, notif, post, postID, postsCount, ref, ref1, req, resDoc, threadID;
var URL, _, ban, err, h1, isReply, m, post, postID, postsCount, ref, ref1, req, resDoc, threadID;
req = QR.req;
delete QR.req;
post = QR.posts[0];
@ -7696,22 +7581,6 @@
});
postsCount = QR.posts.length - 1;
QR.cooldown.auto = postsCount && isReply;
if (QR.cooldown.auto && QR.captcha.isEnabled && (captchasCount = QR.captcha.captchas.length) < 3 && captchasCount < postsCount) {
notif = new Notification('Quick reply warning', {
body: "You are running low on cached captchas. Cache count: " + captchasCount + ".",
icon: Favicon.logo
});
notif.onclick = function() {
QR.open();
window.focus();
return QR.captcha.setup(true);
};
notif.onshow = function() {
return setTimeout(function() {
return notif.close();
}, 7 * $.SECOND);
};
}
if (!(Conf['Persistent QR'] || postsCount)) {
QR.close();
} else {
@ -8119,7 +7988,7 @@
return $.on(window, 'focus', function() {
return $.queueTask(function() {
var checkbox;
if (!(checkbox = $.id('recaptcha-anchor'))) {
if (!(d.hasFocus() && (checkbox = $.id('recaptcha-anchor')))) {
return;
}
if (d.activeElement !== checkbox) {
@ -8166,7 +8035,6 @@
if (!(this.isEnabled && (this.needed() || force))) {
return;
}
$.addClass(QR.nodes.el, 'captcha-open');
if (focus) {
this.shouldFocus = true;
}
@ -8210,6 +8078,7 @@
},
setupIFrame: function(iframe) {
this.setupTime = Date.now();
$.addClass(QR.nodes.el, 'captcha-open');
if (QR.nodes.el.getBoundingClientRect().bottom > doc.clientHeight) {
QR.nodes.el.style.top = null;
QR.nodes.el.style.bottom = '0px';
@ -8693,7 +8562,8 @@
_Class.prototype["delete"] = function() {
$.rm(this.nodes.el);
return URL.revokeObjectURL(this.URL);
URL.revokeObjectURL(this.URL);
return this.dismissErrors();
};
_Class.prototype.lock = function(lock) {
@ -8713,7 +8583,6 @@
}
}
this.nodes.rm.style.visibility = lock ? 'hidden' : '';
(lock ? $.off : $.on)(QR.nodes.filename.previousElementSibling, 'click', QR.openFileInput);
this.nodes.spoiler.disabled = lock;
return this.nodes.el.draggable = !lock;
};
@ -8799,10 +8668,82 @@
}
};
_Class.prototype.setFile = function(file1, el) {
_Class.rmErrored = function(e) {
var error, errors, k, len1, post, q, ref;
e.stopPropagation();
ref = QR.posts;
for (k = ref.length - 1; k >= 0; k += -1) {
post = ref[k];
if (errors = post.errors) {
for (q = 0, len1 = errors.length; q < len1; q++) {
error = errors[q];
if (!(doc.contains(error))) {
continue;
}
post.rm();
break;
}
}
}
};
_Class.prototype.error = function(className, message) {
var div, ref, rm, rmAll;
div = $.el('div', {
className: className
});
$.extend(div, {
innerHTML: E(message) + "<br>[<a href=\"javascript:;\">delete</a>] [<a href=\"javascript:;\">delete all</a>]"
});
(this.errors || (this.errors = [])).push(div);
ref = $$('a', div), rm = ref[0], rmAll = ref[1];
$.on(div, 'click', (function(_this) {
return function() {
if (indexOf.call(QR.posts, _this) >= 0) {
return _this.select();
}
};
})(this));
$.on(rm, 'click', (function(_this) {
return function(e) {
e.stopPropagation();
if (indexOf.call(QR.posts, _this) >= 0) {
return _this.rm();
}
};
})(this));
$.on(rmAll, 'click', QR.post.rmErrored);
return QR.error(div);
};
_Class.prototype.fileError = function(message) {
return this.error('file-error', this.filename + ": " + message);
};
_Class.prototype.dismissErrors = function(test) {
var error, k, len1, ref;
if (test == null) {
test = function() {
return true;
};
}
if (this.errors) {
ref = this.errors;
for (k = 0, len1 = ref.length; k < len1; k++) {
error = ref[k];
if (doc.contains(error) && test(error)) {
error.parentNode.previousElementSibling.click();
}
}
}
};
_Class.prototype.setFile = function(file1) {
var ref;
this.file = file1;
this.filename = this.file.name;
this.filesize = $.bytesToString(this.file.size);
this.checkSize();
if (QR.spoiler) {
this.nodes.label.hidden = false;
}
@ -8813,10 +8754,79 @@
} else {
this.updateFilename();
}
if (el) {
return this.setThumbnail(el);
this.nodes.el.style.backgroundImage = null;
if (ref = this.file.type, indexOf.call(QR.mimeTypes, ref) < 0) {
return this.fileError('Unsupported file type.');
} else if (/^(image|video)\//.test(this.file.type)) {
return this.readFile();
}
};
_Class.prototype.checkSize = function() {
var max;
max = QR.nodes.fileInput.max;
if (/^video\//.test(this.file.type)) {
max = Math.min(max, QR.max_size_video);
}
if (this.file.size > max) {
return this.fileError("File too large (file: " + this.filesize + ", max: " + ($.bytesToString(max)) + ").");
}
};
_Class.prototype.readFile = function() {
var el, event, isVideo, onerror, onload;
isVideo = /^video\//.test(this.file.type);
el = $.el(isVideo ? 'video' : 'img');
event = isVideo ? 'loadeddata' : 'load';
onload = (function(_this) {
return function() {
$.off(el, event, onload);
$.off(el, 'error', onerror);
_this.checkDimensions(el);
return _this.setThumbnail(el);
};
})(this);
onerror = (function(_this) {
return function() {
$.off(el, event, onload);
$.off(el, 'error', onerror);
_this.fileError((isVideo ? 'Video' : 'Image') + " appears corrupt");
return URL.revokeObjectURL(el.src);
};
})(this);
$.on(el, event, onload);
$.on(el, 'error', onerror);
return el.src = URL.createObjectURL(this.file);
};
_Class.prototype.checkDimensions = function(el) {
var duration, height, max_height, max_width, ref, videoHeight, videoWidth, width;
if (el.tagName === 'IMG') {
height = el.height, width = el.width;
if (height > QR.max_height || width > QR.max_width) {
this.fileError("Image too large (image: " + height + "x" + width + "px, max: " + QR.max_height + "x" + QR.max_width + "px)");
}
if (height < QR.min_height || width < QR.min_width) {
return this.fileError("Image too small (image: " + height + "x" + width + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
}
} else {
return this.nodes.el.style.backgroundImage = null;
videoHeight = el.videoHeight, videoWidth = el.videoWidth, duration = el.duration;
max_height = Math.min(QR.max_height, QR.max_height_video);
max_width = Math.min(QR.max_width, QR.max_width_video);
if (videoHeight > max_height || videoWidth > max_width) {
this.fileError("Video too large (video: " + videoHeight + "x" + videoWidth + "px, max: " + max_height + "x" + max_width + "px)");
}
if (videoHeight < QR.min_height || videoWidth < QR.min_width) {
this.fileError("Video too small (video: " + videoHeight + "x" + videoWidth + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
}
if (!isFinite(duration)) {
this.fileError('Video lacks duration metadata (try remuxing)');
} else if (duration > QR.max_duration_video) {
this.fileError("Video too long (video: " + duration + "s, max: " + QR.max_duration_video + "s)");
}
if (((ref = g.BOARD.ID) !== 'gif' && ref !== 'wsg') && $.hasAudio(el)) {
return this.fileError('Audio not allowed');
}
}
};
@ -8866,23 +8876,26 @@
delete this.filename;
delete this.filesize;
this.nodes.el.title = null;
QR.nodes.fileContainer.title = '';
QR.nodes.filename.title = '';
this.nodes.el.style.backgroundImage = null;
if (QR.spoiler) {
this.nodes.label.hidden = true;
}
this.showFileData();
return URL.revokeObjectURL(this.URL);
URL.revokeObjectURL(this.URL);
return this.dismissErrors(function(error) {
return $.hasClass(error, 'file-error');
});
};
_Class.prototype.updateFilename = function() {
var long;
long = this.filename + " (" + this.filesize + ")\nCtrl/\u2318+click to edit filename. Shift+click to clear.";
long = this.filename + " (" + this.filesize + ")";
this.nodes.el.title = long;
if (this !== QR.selected) {
return;
}
return QR.nodes.fileContainer.title = long;
return QR.nodes.filename.title = long;
};
_Class.prototype.showFileData = function() {
@ -8898,6 +8911,7 @@
_Class.prototype.pasteText = function(file) {
var reader;
this.pasting = true;
reader = new FileReader();
reader.onload = (function(_this) {
return function(e) {
@ -8911,7 +8925,8 @@
if (QR.selected === _this) {
QR.nodes.com.value = _this.com;
}
return _this.nodes.span.textContent = _this.com;
_this.nodes.span.textContent = _this.com;
return delete _this.pasting;
};
})(this);
return reader.readAsText(file);
@ -10166,7 +10181,7 @@
$.on(this.el, 'change', this.toggle);
return Header.menu.addEntry({
el: prefetch,
order: 104
order: 98
});
},
node: function() {
@ -17020,9 +17035,6 @@
"body.hasDropDownNav{\n" +
" margin-top: 5px;\n" +
"}\n" +
"a {\n" +
" outline: none !important;\n" +
"}\n" +
".painted {\n" +
" border-radius: 3px;\n" +
" padding: 0px 2px;\n" +
@ -17667,7 +17679,7 @@
" text-align: center;\n" +
"}\n" +
"/* /tg/ dice rolls */\n" +
".catalog-thread > .comment > b {\n" +
".board_tg .catalog-thread > .comment > b {\n" +
" font-weight: normal;\n" +
"}\n" +
".catalog-code {\n" +
@ -18118,17 +18130,6 @@
" -webkit-flex-direction: row;\n" +
" flex-direction: row;\n" +
"}\n" +
"#url-button, #custom-cooldown-button, #dump-button {\n" +
" width: 10%;\n" +
" margin: 0;\n" +
" margin-right: 4px;\n" +
" font: 13px sans-serif;\n" +
" padding: 1px 0px 2px;\n" +
" opacity: 0.6;\n" +
"}\n" +
"#custom-cooldown-button.disabled {\n" +
" opacity: 0.27;\n" +
"}\n" +
".persona .field {\n" +
" -webkit-flex: 1;\n" +
" flex: 1;\n" +
@ -18151,8 +18152,18 @@
" text-shadow: none !important;\n" +
"}\n" +
"#qr textarea {\n" +
" min-width: 100%;\n" +
" resize: both;\n" +
"}\n" +
".field {\n" +
" -moz-box-sizing: border-box;\n" +
" margin: 0px;\n" +
" padding: 2px 4px 3px;\n" +
"}\n" +
"#qr label input[type=\"checkbox\"] {\n" +
" position: relative;\n" +
" top: 2px;\n" +
"}\n" +
"/* Noscript Recaptcha */\n" +
".captcha-img {\n" +
" margin: 0px;\n" +
@ -18196,111 +18207,81 @@
" display: block;\n" +
" width: 100%;\n" +
"}\n" +
".field {\n" +
" -moz-box-sizing: border-box;\n" +
" margin: 0px;\n" +
" padding: 2px 4px 3px;\n" +
"/* File Input, Submit Button */\n" +
"#file-n-submit {\n" +
" display: -webkit-flex;\n" +
" display: flex;\n" +
" -webkit-align-items: stretch;\n" +
" align-items: stretch;\n" +
" margin-top: 1px;\n" +
"}\n" +
"#qr textarea {\n" +
" min-width: 100%;\n" +
":root.gecko #file-n-submit > input {\n" +
" margin: 0px -1px -1px;\n" +
"}\n" +
"#qr [type=\"submit\"] {\n" +
"#file-n-submit input[type=\"submit\"] {\n" +
" width: 25%;\n" +
" vertical-align: top;\n" +
"}\n" +
":root.webkit #qr [type=\"submit\"] {\n" +
" height: 24px;\n" +
"}\n" +
"#qr label input[type=\"checkbox\"] {\n" +
"#qr-filename-container {\n" +
" -webkit-flex: 1 1 auto;\n" +
" flex: 1 1 auto;\n" +
" width: 0;\n" +
" display: -webkit-flex;\n" +
" display: flex;\n" +
" -webkit-align-items: center;\n" +
" align-items: center;\n" +
" position: relative;\n" +
" top: 2px;\n" +
" padding: 1px;\n" +
"}\n" +
"/* Fake File Input */\n" +
"input#qr-filename {\n" +
" border: none !important;\n" +
" width: 80%;\n" +
" padding: 0px 4px;\n" +
" position: relative;\n" +
" bottom: 1px;\n" +
" background: none !important;\n" +
"}\n" +
"input#qr-filename:not(.edit) {\n" +
" pointer-events: none;\n" +
"}\n" +
"#qr-filename,\n" +
"#qr-filesize,\n" +
".has-file #qr-no-file {\n" +
" display: none;\n" +
"}\n" +
"#qr-no-file,\n" +
".has-file #qr-filename,\n" +
".has-file #qr-filesize {\n" +
".has-file #qr-filename {\n" +
" -webkit-flex: 1 1 auto;\n" +
" flex: 1 1 auto;\n" +
" display: inline-block;\n" +
" margin: 0 0 2px;\n" +
" padding: 0;\n" +
" padding-left: 3px;\n" +
" overflow: hidden;\n" +
" text-overflow: ellipsis;\n" +
" vertical-align: top;\n" +
"}\n" +
"#qr-no-file {\n" +
" color: #AAA;\n" +
" padding: 1px 4px;\n" +
"}\n" +
"#qr-filename-container {\n" +
" -moz-box-sizing: border-box;\n" +
" display: inline-block;\n" +
" position: relative;\n" +
" width: 100px;\n" +
" min-width: 74.6%;\n" +
" max-width: 74.6%;\n" +
" margin-right: 0.4%;\n" +
" margin-top: 1px;\n" +
" overflow: hidden;\n" +
" padding: 2px 1px 0;\n" +
" height: 22px;\n" +
"}\n" +
"#qr-filename-container:hover {\n" +
" cursor: text;\n" +
"}\n" +
"#qr-extras-container {\n" +
" position: absolute;\n" +
" right: 0px;\n" +
"}\n" +
"#qr-filerm {\n" +
" margin-right: 3px;\n" +
" z-index: 2;\n" +
"}\n" +
"#file-n-submit {\n" +
" height: 23px;\n" +
"}\n" +
"#file-n-submit:not(.custom-cooldown) #custom-cooldown-button {\n" +
" display: none;\n" +
"}\n" +
"#qr input[type=\"file\"] {\n" +
" visibility: hidden;\n" +
" position: absolute;\n" +
"}\n" +
"/* Thread Select / Spoiler Label */\n" +
"#qr select[data-name=\"thread\"] {\n" +
" float: right;\n" +
"/* Spoiler Checkbox, QR Icons */\n" +
"#qr-spoiler-label, #qr-filename-container > a {\n" +
" -webkit-flex: none;\n" +
" flex: none;\n" +
" margin: 0;\n" +
" margin-right: 3px;\n" +
" font: 13px sans-serif;\n" +
"}\n" +
"#qr.has-spoiler .has-file #qr-spoiler-label {\n" +
" width: 6.7%;\n" +
" min-width: 6.7%;\n" +
" max-width: 6.7%;\n" +
" display: inline-block;\n" +
" text-align: center;\n" +
" vertical-align: top;\n" +
"}\n" +
"#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label {\n" +
"#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label,\n" +
".has-file #url-button,\n" +
"#file-n-submit:not(.custom-cooldown) #custom-cooldown-button {\n" +
" display: none;\n" +
"}\n" +
"#qr.has-spoiler .has-file #qr-filename-container {\n" +
" max-width: 67.9%;\n" +
" min-width: 67.9%;\n" +
"#qr-file-spoiler {\n" +
" margin: 0;\n" +
"}\n" +
"#qr-spoiler-label input {\n" +
" position: relative;\n" +
" top: 3px;\n" +
"#url-button, #custom-cooldown-button, #dump-button {\n" +
" opacity: 0.6;\n" +
"}\n" +
"#custom-cooldown-button.disabled {\n" +
" opacity: 0.27;\n" +
"}\n" +
"/* Thread Select */\n" +
"#qr select[data-name=\"thread\"] {\n" +
" float: right;\n" +
"}\n" +
"/* Dumping UI */\n" +
".dump #dump-list-container {\n" +

Binary file not shown.

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X
// @version 1.10.2.8
// @version 1.10.3.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@ -392,7 +392,7 @@
doc = d.documentElement;
g = {
VERSION: '1.10.2.8',
VERSION: '1.10.3.0',
NAMESPACE: '4chan X.',
NAME: '4chan X',
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
@ -3065,7 +3065,7 @@
el: $.el('span', {
textContent: 'Index Navigation'
}),
order: 98,
order: 100,
subEntries: [repliesEntry, pinEntry, anchorEntry, refNavEntry]
});
$.addClass(doc, 'index-loading', (Conf['Index Mode'].replace(/\ /g, '-')) + "-mode");
@ -6391,7 +6391,7 @@
$.on(this.threadNewLink.firstElementChild, 'click', this.rethread);
Header.menu.addEntry(this.entry = {
el: this.controls,
order: 98
order: 99
});
Thread.callbacks.push({
name: 'Quote Threading',
@ -7168,6 +7168,7 @@
if (url === null) {
return;
}
QR.nodes.fileButton.focus();
return CrossOrigin.file(url, function(blob) {
if (blob) {
return QR.handleFiles([blob]);
@ -7177,7 +7178,7 @@
});
},
handleFiles: function(files) {
var file, i, k, len1;
var file, k, len1;
if (this !== QR) {
files = slice.call(this.files);
this.value = null;
@ -7186,147 +7187,36 @@
return;
}
QR.cleanNotifications();
for (i = k = 0, len1 = files.length; k < len1; i = ++k) {
file = files[i];
QR.handleFile(file, i, files.length);
for (k = 0, len1 = files.length; k < len1; k++) {
file = files[k];
QR.handleFile(file, files.length);
}
if (files.length !== 1) {
return $.addClass(QR.nodes.el, 'dump');
$.addClass(QR.nodes.el, 'dump');
}
if (d.activeElement === QR.nodes.fileButton && $.hasClass(QR.nodes.fileSubmit, 'has-file')) {
return QR.nodes.filename.focus();
}
},
handleFile: function(file, index, nfiles) {
var isNewPost, isSingle, max, post, ref;
isSingle = nfiles === 1;
if (/^text\//.test(file.type)) {
if (isSingle) {
post = QR.selected;
} else if (index !== 0 || (post = QR.posts[QR.posts.length - 1]).com) {
handleFile: function(file, nfiles) {
var isText, post;
isText = /^text\//.test(file.type);
if (nfiles === 1) {
post = QR.selected;
} else {
post = QR.posts[QR.posts.length - 1];
if ((isText ? post.com || post.pasting : post.file)) {
post = new QR.post();
}
post.pasteText(file);
}
return post[isText ? 'pasteText' : 'setFile'](file);
},
openFileInput: function() {
if (QR.nodes.fileButton.disabled) {
return;
}
if (ref = file.type, indexOf.call(QR.mimeTypes, ref) < 0) {
QR.error(file.name + ": Unsupported file type.");
if (!isSingle) {
return;
}
}
max = QR.nodes.fileInput.max;
if (/^video\//.test(file.type)) {
max = Math.min(max, QR.max_size_video);
}
if (file.size > max) {
QR.error(file.name + ": File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
if (!isSingle) {
return;
}
}
isNewPost = false;
if (isSingle) {
post = QR.selected;
} else if (index !== 0 || (post = QR.posts[QR.posts.length - 1]).file) {
isNewPost = true;
post = new QR.post();
}
return QR.checkDimensions(file, function(pass, el) {
if (pass || isSingle) {
return post.setFile(file, el);
} else if (isNewPost) {
post.rm();
if (el) {
return URL.revokeObjectURL(el.src);
}
}
});
},
checkDimensions: function(file, cb) {
var img, video;
if (/^image\//.test(file.type)) {
img = new Image();
img.onload = function() {
var height, pass, width;
height = img.height, width = img.width;
pass = true;
if (height > QR.max_height || width > QR.max_width) {
QR.error(file.name + ": Image too large (image: " + height + "x" + width + "px, max: " + QR.max_height + "x" + QR.max_width + "px)");
pass = false;
}
if (height < QR.min_height || width < QR.min_width) {
QR.error(file.name + ": Image too small (image: " + height + "x" + width + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
pass = false;
}
return cb(pass, img);
};
img.onerror = function() {
return cb(false, null);
};
return img.src = URL.createObjectURL(file);
} else if (/^video\//.test(file.type)) {
video = $.el('video');
$.on(video, 'loadeddata', function() {
var duration, max_height, max_width, pass, ref, videoHeight, videoWidth;
if (!cb) {
return;
}
videoHeight = video.videoHeight, videoWidth = video.videoWidth, duration = video.duration;
max_height = Math.min(QR.max_height, QR.max_height_video);
max_width = Math.min(QR.max_width, QR.max_width_video);
pass = true;
if (videoHeight > max_height || videoWidth > max_width) {
QR.error(file.name + ": Video too large (video: " + videoHeight + "x" + videoWidth + "px, max: " + max_height + "x" + max_width + "px)");
pass = false;
}
if (videoHeight < QR.min_height || videoWidth < QR.min_width) {
QR.error(file.name + ": Video too small (video: " + videoHeight + "x" + videoWidth + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
pass = false;
}
if (!isFinite(duration)) {
QR.error(file.name + ": Video lacks duration metadata (try remuxing)");
pass = false;
} else if (duration > QR.max_duration_video) {
QR.error(file.name + ": Video too long (video: " + duration + "s, max: " + QR.max_duration_video + "s)");
pass = false;
}
if (((ref = g.BOARD.ID) !== 'gif' && ref !== 'wsg') && $.hasAudio(video)) {
QR.error(file.name + ": Audio not allowed");
pass = false;
}
cb(pass, video);
return cb = null;
});
$.on(video, 'error', function() {
var ref;
if (!cb) {
return;
}
if (ref = file.type, indexOf.call(QR.mimeTypes, ref) >= 0) {
QR.error(file.name + ": Video appears corrupt");
}
URL.revokeObjectURL(file);
cb(false, null);
return cb = null;
});
return video.src = URL.createObjectURL(file);
} else {
return cb(true, null);
}
},
openFileInput: function(e) {
var ref;
e.stopPropagation();
if (e.shiftKey && e.type === 'click') {
return QR.selected.rmFile();
}
if ((e.ctrlKey || e.metaKey) && e.type === 'click') {
$.addClass(QR.nodes.filename, 'edit');
QR.nodes.filename.focus();
}
if (e.target.nodeName === 'INPUT' || (e.keyCode && ((ref = e.keyCode) !== 32 && ref !== 13)) || e.ctrlKey) {
return;
}
e.preventDefault();
return QR.nodes.fileInput.click();
QR.nodes.fileInput.click();
return QR.nodes.fileButton.focus();
},
generatePostableThreadsList: function() {
var k, len1, list, options, ref, thread, val;
@ -7357,7 +7247,7 @@
var dialog, event, i, items, m, match_max, match_min, name, node, nodes, ref, rules, save, setNode;
QR.nodes = nodes = {
el: dialog = UI.dialog('qr', 'top: 50px; right: 0px;', {
innerHTML: "<div class=move><label><input type=checkbox id=autohide title=Auto-hide>Quick Reply</label><a href=javascript:; class=close title=Close>×</a><select data-name=thread title='Create a new thread / Reply'><option value=new>New thread</option></select></div><form><div class=persona><input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1><input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1><input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1></div><div class=textarea><textarea data-name=com placeholder=Comment class=field></textarea><span id=char-count></span></div><div id=dump-list-container><div id=dump-list></div><a id=add-post href=javascript:; title=\"Add a post\">+</a></div><div id=file-n-submit><span id=qr-filename-container class=field tabindex=0><span id=qr-no-file>No selected file</span><input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\"><span id=\"qr-extras-container\"><a href=\"javascript:;\" id=\"qr-filerm\" title=\"Remove file\"><i class=\"fa fa-times-circle\"></i></a><a id=\"url-button\" title=\"Post from url\"><i class=\"fa fa-link\"></i></a><a id=\"custom-cooldown-button\" title=\"Toggle custom cooldown\" class=\"disabled\"><i class=\"fa fa-clock-o\"></i></a><a id=\"dump-button\" title=\"Dump list\"><i class=\"fa fa-plus-square\"></i></a></span></span><label id=qr-spoiler-label><input type=checkbox id=qr-file-spoiler title='Spoiler image'></label><input type=submit></div><input type=file multiple></form><datalist id=\"list-name\"></datalist><datalist id=\"list-email\"></datalist><datalist id=\"list-sub\"></datalist> "
innerHTML: "<div class=move><label><input type=checkbox id=autohide title=Auto-hide>Quick Reply</label><a href=javascript:; class=close title=Close>×</a><select data-name=thread title='Create a new thread / Reply'><option value=new>New thread</option></select></div><form><div class=persona><input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1><input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1><input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1></div><div class=textarea><textarea data-name=com placeholder=Comment class=field></textarea><span id=char-count></span></div><div id=dump-list-container><div id=dump-list></div><a id=add-post href=javascript:; title=\"Add a post\">+</a></div><div id=\"file-n-submit\"><input type=\"button\" id=\"qr-file-button\" value=\"Files\"><span id=\"qr-filename-container\" class=\"field\"><span id=\"qr-no-file\">No selected file</span><input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\"><label id=\"qr-spoiler-label\"><input type=\"checkbox\" id=\"qr-file-spoiler\" title=\"Spoiler image\"></label><a href=\"javascript:;\" id=\"qr-filerm\" title=\"Remove file\"><i class=\"fa fa-times-circle\"></i></a><a id=\"url-button\" title=\"Post from url\"><i class=\"fa fa-link\"></i></a><a id=\"custom-cooldown-button\" title=\"Toggle custom cooldown\" class=\"disabled\"><i class=\"fa fa-clock-o\"></i></a><a id=\"dump-button\" title=\"Dump list\"><i class=\"fa fa-plus-square\"></i></a></span><input type=\"submit\"></div><input type=\"file\" multiple></form><datalist id=\"list-name\"></datalist><datalist id=\"list-email\"></datalist><datalist id=\"list-sub\"></datalist> "
})
};
setNode = function(name, query) {
@ -7379,10 +7269,10 @@
setNode('addPost', '#add-post');
setNode('charCount', '#char-count');
setNode('fileSubmit', '#file-n-submit');
setNode('fileButton', '#qr-file-button');
setNode('noFile', '#qr-no-file');
setNode('filename', '#qr-filename');
setNode('fileContainer', '#qr-filename-container');
setNode('fileRM', '#qr-filerm');
setNode('fileExtras', '#qr-extras-container');
setNode('spoiler', '#qr-file-spoiler');
setNode('spoilerPar', '#qr-spoiler-label');
setNode('status', '[type=submit]');
@ -7436,7 +7326,8 @@
nodes.flashTag.dataset["default"] = '4';
$.add(nodes.form, nodes.flashTag);
}
$.on(nodes.filename.parentNode, 'click keydown', QR.openFileInput);
$.on(nodes.fileButton, 'click', QR.openFileInput);
$.on(nodes.noFile, 'click', QR.openFileInput);
$.on(nodes.autohide, 'change', QR.toggleHide);
$.on(nodes.close, 'click', QR.close);
$.on(nodes.dumpButton, 'click', function() {
@ -7447,15 +7338,9 @@
return new QR.post(true);
});
$.on(nodes.form, 'submit', QR.submit);
$.on(nodes.filename, 'blur', function() {
return $.rmClass(this, 'edit');
});
$.on(nodes.fileRM, 'click', function() {
return QR.selected.rmFile();
});
$.on(nodes.fileExtras, 'click', function(e) {
return e.stopPropagation();
});
$.on(nodes.spoiler, 'change', function() {
return QR.selected.nodes.spoiler.click();
});
@ -7625,7 +7510,7 @@
return QR.status();
},
response: function() {
var URL, _, ban, captchasCount, err, h1, isReply, m, notif, post, postID, postsCount, ref, ref1, req, resDoc, threadID;
var URL, _, ban, err, h1, isReply, m, post, postID, postsCount, ref, ref1, req, resDoc, threadID;
req = QR.req;
delete QR.req;
post = QR.posts[0];
@ -7695,22 +7580,6 @@
});
postsCount = QR.posts.length - 1;
QR.cooldown.auto = postsCount && isReply;
if (QR.cooldown.auto && QR.captcha.isEnabled && (captchasCount = QR.captcha.captchas.length) < 3 && captchasCount < postsCount) {
notif = new Notification('Quick reply warning', {
body: "You are running low on cached captchas. Cache count: " + captchasCount + ".",
icon: Favicon.logo
});
notif.onclick = function() {
QR.open();
window.focus();
return QR.captcha.setup(true);
};
notif.onshow = function() {
return setTimeout(function() {
return notif.close();
}, 7 * $.SECOND);
};
}
if (!(Conf['Persistent QR'] || postsCount)) {
QR.close();
} else {
@ -8118,7 +7987,7 @@
return $.on(window, 'focus', function() {
return $.queueTask(function() {
var checkbox;
if (!(checkbox = $.id('recaptcha-anchor'))) {
if (!(d.hasFocus() && (checkbox = $.id('recaptcha-anchor')))) {
return;
}
if (d.activeElement !== checkbox) {
@ -8165,7 +8034,6 @@
if (!(this.isEnabled && (this.needed() || force))) {
return;
}
$.addClass(QR.nodes.el, 'captcha-open');
if (focus) {
this.shouldFocus = true;
}
@ -8209,6 +8077,7 @@
},
setupIFrame: function(iframe) {
this.setupTime = Date.now();
$.addClass(QR.nodes.el, 'captcha-open');
if (QR.nodes.el.getBoundingClientRect().bottom > doc.clientHeight) {
QR.nodes.el.style.top = null;
QR.nodes.el.style.bottom = '0px';
@ -8692,7 +8561,8 @@
_Class.prototype["delete"] = function() {
$.rm(this.nodes.el);
return URL.revokeObjectURL(this.URL);
URL.revokeObjectURL(this.URL);
return this.dismissErrors();
};
_Class.prototype.lock = function(lock) {
@ -8712,7 +8582,6 @@
}
}
this.nodes.rm.style.visibility = lock ? 'hidden' : '';
(lock ? $.off : $.on)(QR.nodes.filename.previousElementSibling, 'click', QR.openFileInput);
this.nodes.spoiler.disabled = lock;
return this.nodes.el.draggable = !lock;
};
@ -8798,10 +8667,82 @@
}
};
_Class.prototype.setFile = function(file1, el) {
_Class.rmErrored = function(e) {
var error, errors, k, len1, post, q, ref;
e.stopPropagation();
ref = QR.posts;
for (k = ref.length - 1; k >= 0; k += -1) {
post = ref[k];
if (errors = post.errors) {
for (q = 0, len1 = errors.length; q < len1; q++) {
error = errors[q];
if (!(doc.contains(error))) {
continue;
}
post.rm();
break;
}
}
}
};
_Class.prototype.error = function(className, message) {
var div, ref, rm, rmAll;
div = $.el('div', {
className: className
});
$.extend(div, {
innerHTML: E(message) + "<br>[<a href=\"javascript:;\">delete</a>] [<a href=\"javascript:;\">delete all</a>]"
});
(this.errors || (this.errors = [])).push(div);
ref = $$('a', div), rm = ref[0], rmAll = ref[1];
$.on(div, 'click', (function(_this) {
return function() {
if (indexOf.call(QR.posts, _this) >= 0) {
return _this.select();
}
};
})(this));
$.on(rm, 'click', (function(_this) {
return function(e) {
e.stopPropagation();
if (indexOf.call(QR.posts, _this) >= 0) {
return _this.rm();
}
};
})(this));
$.on(rmAll, 'click', QR.post.rmErrored);
return QR.error(div);
};
_Class.prototype.fileError = function(message) {
return this.error('file-error', this.filename + ": " + message);
};
_Class.prototype.dismissErrors = function(test) {
var error, k, len1, ref;
if (test == null) {
test = function() {
return true;
};
}
if (this.errors) {
ref = this.errors;
for (k = 0, len1 = ref.length; k < len1; k++) {
error = ref[k];
if (doc.contains(error) && test(error)) {
error.parentNode.previousElementSibling.click();
}
}
}
};
_Class.prototype.setFile = function(file1) {
var ref;
this.file = file1;
this.filename = this.file.name;
this.filesize = $.bytesToString(this.file.size);
this.checkSize();
if (QR.spoiler) {
this.nodes.label.hidden = false;
}
@ -8812,10 +8753,79 @@
} else {
this.updateFilename();
}
if (el) {
return this.setThumbnail(el);
this.nodes.el.style.backgroundImage = null;
if (ref = this.file.type, indexOf.call(QR.mimeTypes, ref) < 0) {
return this.fileError('Unsupported file type.');
} else if (/^(image|video)\//.test(this.file.type)) {
return this.readFile();
}
};
_Class.prototype.checkSize = function() {
var max;
max = QR.nodes.fileInput.max;
if (/^video\//.test(this.file.type)) {
max = Math.min(max, QR.max_size_video);
}
if (this.file.size > max) {
return this.fileError("File too large (file: " + this.filesize + ", max: " + ($.bytesToString(max)) + ").");
}
};
_Class.prototype.readFile = function() {
var el, event, isVideo, onerror, onload;
isVideo = /^video\//.test(this.file.type);
el = $.el(isVideo ? 'video' : 'img');
event = isVideo ? 'loadeddata' : 'load';
onload = (function(_this) {
return function() {
$.off(el, event, onload);
$.off(el, 'error', onerror);
_this.checkDimensions(el);
return _this.setThumbnail(el);
};
})(this);
onerror = (function(_this) {
return function() {
$.off(el, event, onload);
$.off(el, 'error', onerror);
_this.fileError((isVideo ? 'Video' : 'Image') + " appears corrupt");
return URL.revokeObjectURL(el.src);
};
})(this);
$.on(el, event, onload);
$.on(el, 'error', onerror);
return el.src = URL.createObjectURL(this.file);
};
_Class.prototype.checkDimensions = function(el) {
var duration, height, max_height, max_width, ref, videoHeight, videoWidth, width;
if (el.tagName === 'IMG') {
height = el.height, width = el.width;
if (height > QR.max_height || width > QR.max_width) {
this.fileError("Image too large (image: " + height + "x" + width + "px, max: " + QR.max_height + "x" + QR.max_width + "px)");
}
if (height < QR.min_height || width < QR.min_width) {
return this.fileError("Image too small (image: " + height + "x" + width + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
}
} else {
return this.nodes.el.style.backgroundImage = null;
videoHeight = el.videoHeight, videoWidth = el.videoWidth, duration = el.duration;
max_height = Math.min(QR.max_height, QR.max_height_video);
max_width = Math.min(QR.max_width, QR.max_width_video);
if (videoHeight > max_height || videoWidth > max_width) {
this.fileError("Video too large (video: " + videoHeight + "x" + videoWidth + "px, max: " + max_height + "x" + max_width + "px)");
}
if (videoHeight < QR.min_height || videoWidth < QR.min_width) {
this.fileError("Video too small (video: " + videoHeight + "x" + videoWidth + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
}
if (!isFinite(duration)) {
this.fileError('Video lacks duration metadata (try remuxing)');
} else if (duration > QR.max_duration_video) {
this.fileError("Video too long (video: " + duration + "s, max: " + QR.max_duration_video + "s)");
}
if (((ref = g.BOARD.ID) !== 'gif' && ref !== 'wsg') && $.hasAudio(el)) {
return this.fileError('Audio not allowed');
}
}
};
@ -8865,23 +8875,26 @@
delete this.filename;
delete this.filesize;
this.nodes.el.title = null;
QR.nodes.fileContainer.title = '';
QR.nodes.filename.title = '';
this.nodes.el.style.backgroundImage = null;
if (QR.spoiler) {
this.nodes.label.hidden = true;
}
this.showFileData();
return URL.revokeObjectURL(this.URL);
URL.revokeObjectURL(this.URL);
return this.dismissErrors(function(error) {
return $.hasClass(error, 'file-error');
});
};
_Class.prototype.updateFilename = function() {
var long;
long = this.filename + " (" + this.filesize + ")\nCtrl/\u2318+click to edit filename. Shift+click to clear.";
long = this.filename + " (" + this.filesize + ")";
this.nodes.el.title = long;
if (this !== QR.selected) {
return;
}
return QR.nodes.fileContainer.title = long;
return QR.nodes.filename.title = long;
};
_Class.prototype.showFileData = function() {
@ -8897,6 +8910,7 @@
_Class.prototype.pasteText = function(file) {
var reader;
this.pasting = true;
reader = new FileReader();
reader.onload = (function(_this) {
return function(e) {
@ -8910,7 +8924,8 @@
if (QR.selected === _this) {
QR.nodes.com.value = _this.com;
}
return _this.nodes.span.textContent = _this.com;
_this.nodes.span.textContent = _this.com;
return delete _this.pasting;
};
})(this);
return reader.readAsText(file);
@ -10165,7 +10180,7 @@
$.on(this.el, 'change', this.toggle);
return Header.menu.addEntry({
el: prefetch,
order: 104
order: 98
});
},
node: function() {
@ -17019,9 +17034,6 @@
"body.hasDropDownNav{\n" +
" margin-top: 5px;\n" +
"}\n" +
"a {\n" +
" outline: none !important;\n" +
"}\n" +
".painted {\n" +
" border-radius: 3px;\n" +
" padding: 0px 2px;\n" +
@ -17666,7 +17678,7 @@
" text-align: center;\n" +
"}\n" +
"/* /tg/ dice rolls */\n" +
".catalog-thread > .comment > b {\n" +
".board_tg .catalog-thread > .comment > b {\n" +
" font-weight: normal;\n" +
"}\n" +
".catalog-code {\n" +
@ -18117,17 +18129,6 @@
" -webkit-flex-direction: row;\n" +
" flex-direction: row;\n" +
"}\n" +
"#url-button, #custom-cooldown-button, #dump-button {\n" +
" width: 10%;\n" +
" margin: 0;\n" +
" margin-right: 4px;\n" +
" font: 13px sans-serif;\n" +
" padding: 1px 0px 2px;\n" +
" opacity: 0.6;\n" +
"}\n" +
"#custom-cooldown-button.disabled {\n" +
" opacity: 0.27;\n" +
"}\n" +
".persona .field {\n" +
" -webkit-flex: 1;\n" +
" flex: 1;\n" +
@ -18150,8 +18151,18 @@
" text-shadow: none !important;\n" +
"}\n" +
"#qr textarea {\n" +
" min-width: 100%;\n" +
" resize: both;\n" +
"}\n" +
".field {\n" +
" -moz-box-sizing: border-box;\n" +
" margin: 0px;\n" +
" padding: 2px 4px 3px;\n" +
"}\n" +
"#qr label input[type=\"checkbox\"] {\n" +
" position: relative;\n" +
" top: 2px;\n" +
"}\n" +
"/* Noscript Recaptcha */\n" +
".captcha-img {\n" +
" margin: 0px;\n" +
@ -18195,111 +18206,81 @@
" display: block;\n" +
" width: 100%;\n" +
"}\n" +
".field {\n" +
" -moz-box-sizing: border-box;\n" +
" margin: 0px;\n" +
" padding: 2px 4px 3px;\n" +
"/* File Input, Submit Button */\n" +
"#file-n-submit {\n" +
" display: -webkit-flex;\n" +
" display: flex;\n" +
" -webkit-align-items: stretch;\n" +
" align-items: stretch;\n" +
" margin-top: 1px;\n" +
"}\n" +
"#qr textarea {\n" +
" min-width: 100%;\n" +
":root.gecko #file-n-submit > input {\n" +
" margin: 0px -1px -1px;\n" +
"}\n" +
"#qr [type=\"submit\"] {\n" +
"#file-n-submit input[type=\"submit\"] {\n" +
" width: 25%;\n" +
" vertical-align: top;\n" +
"}\n" +
":root.webkit #qr [type=\"submit\"] {\n" +
" height: 24px;\n" +
"}\n" +
"#qr label input[type=\"checkbox\"] {\n" +
"#qr-filename-container {\n" +
" -webkit-flex: 1 1 auto;\n" +
" flex: 1 1 auto;\n" +
" width: 0;\n" +
" display: -webkit-flex;\n" +
" display: flex;\n" +
" -webkit-align-items: center;\n" +
" align-items: center;\n" +
" position: relative;\n" +
" top: 2px;\n" +
" padding: 1px;\n" +
"}\n" +
"/* Fake File Input */\n" +
"input#qr-filename {\n" +
" border: none !important;\n" +
" width: 80%;\n" +
" padding: 0px 4px;\n" +
" position: relative;\n" +
" bottom: 1px;\n" +
" background: none !important;\n" +
"}\n" +
"input#qr-filename:not(.edit) {\n" +
" pointer-events: none;\n" +
"}\n" +
"#qr-filename,\n" +
"#qr-filesize,\n" +
".has-file #qr-no-file {\n" +
" display: none;\n" +
"}\n" +
"#qr-no-file,\n" +
".has-file #qr-filename,\n" +
".has-file #qr-filesize {\n" +
".has-file #qr-filename {\n" +
" -webkit-flex: 1 1 auto;\n" +
" flex: 1 1 auto;\n" +
" display: inline-block;\n" +
" margin: 0 0 2px;\n" +
" padding: 0;\n" +
" padding-left: 3px;\n" +
" overflow: hidden;\n" +
" text-overflow: ellipsis;\n" +
" vertical-align: top;\n" +
"}\n" +
"#qr-no-file {\n" +
" color: #AAA;\n" +
" padding: 1px 4px;\n" +
"}\n" +
"#qr-filename-container {\n" +
" -moz-box-sizing: border-box;\n" +
" display: inline-block;\n" +
" position: relative;\n" +
" width: 100px;\n" +
" min-width: 74.6%;\n" +
" max-width: 74.6%;\n" +
" margin-right: 0.4%;\n" +
" margin-top: 1px;\n" +
" overflow: hidden;\n" +
" padding: 2px 1px 0;\n" +
" height: 22px;\n" +
"}\n" +
"#qr-filename-container:hover {\n" +
" cursor: text;\n" +
"}\n" +
"#qr-extras-container {\n" +
" position: absolute;\n" +
" right: 0px;\n" +
"}\n" +
"#qr-filerm {\n" +
" margin-right: 3px;\n" +
" z-index: 2;\n" +
"}\n" +
"#file-n-submit {\n" +
" height: 23px;\n" +
"}\n" +
"#file-n-submit:not(.custom-cooldown) #custom-cooldown-button {\n" +
" display: none;\n" +
"}\n" +
"#qr input[type=\"file\"] {\n" +
" visibility: hidden;\n" +
" position: absolute;\n" +
"}\n" +
"/* Thread Select / Spoiler Label */\n" +
"#qr select[data-name=\"thread\"] {\n" +
" float: right;\n" +
"/* Spoiler Checkbox, QR Icons */\n" +
"#qr-spoiler-label, #qr-filename-container > a {\n" +
" -webkit-flex: none;\n" +
" flex: none;\n" +
" margin: 0;\n" +
" margin-right: 3px;\n" +
" font: 13px sans-serif;\n" +
"}\n" +
"#qr.has-spoiler .has-file #qr-spoiler-label {\n" +
" width: 6.7%;\n" +
" min-width: 6.7%;\n" +
" max-width: 6.7%;\n" +
" display: inline-block;\n" +
" text-align: center;\n" +
" vertical-align: top;\n" +
"}\n" +
"#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label {\n" +
"#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label,\n" +
".has-file #url-button,\n" +
"#file-n-submit:not(.custom-cooldown) #custom-cooldown-button {\n" +
" display: none;\n" +
"}\n" +
"#qr.has-spoiler .has-file #qr-filename-container {\n" +
" max-width: 67.9%;\n" +
" min-width: 67.9%;\n" +
"#qr-file-spoiler {\n" +
" margin: 0;\n" +
"}\n" +
"#qr-spoiler-label input {\n" +
" position: relative;\n" +
" top: 3px;\n" +
"#url-button, #custom-cooldown-button, #dump-button {\n" +
" opacity: 0.6;\n" +
"}\n" +
"#custom-cooldown-button.disabled {\n" +
" opacity: 0.27;\n" +
"}\n" +
"/* Thread Select */\n" +
"#qr select[data-name=\"thread\"] {\n" +
" float: right;\n" +
"}\n" +
"/* Dumping UI */\n" +
".dump #dump-list-container {\n" +

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
// @version 1.10.2.8
// @version 1.10.3.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X
// @version 1.10.2.8
// @version 1.10.3.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@ -393,7 +393,7 @@
doc = d.documentElement;
g = {
VERSION: '1.10.2.8',
VERSION: '1.10.3.0',
NAMESPACE: '4chan X.',
NAME: '4chan X',
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
@ -3066,7 +3066,7 @@
el: $.el('span', {
textContent: 'Index Navigation'
}),
order: 98,
order: 100,
subEntries: [repliesEntry, pinEntry, anchorEntry, refNavEntry]
});
$.addClass(doc, 'index-loading', (Conf['Index Mode'].replace(/\ /g, '-')) + "-mode");
@ -6392,7 +6392,7 @@
$.on(this.threadNewLink.firstElementChild, 'click', this.rethread);
Header.menu.addEntry(this.entry = {
el: this.controls,
order: 98
order: 99
});
Thread.callbacks.push({
name: 'Quote Threading',
@ -7169,6 +7169,7 @@
if (url === null) {
return;
}
QR.nodes.fileButton.focus();
return CrossOrigin.file(url, function(blob) {
if (blob) {
return QR.handleFiles([blob]);
@ -7178,7 +7179,7 @@
});
},
handleFiles: function(files) {
var file, i, k, len1;
var file, k, len1;
if (this !== QR) {
files = slice.call(this.files);
this.value = null;
@ -7187,147 +7188,36 @@
return;
}
QR.cleanNotifications();
for (i = k = 0, len1 = files.length; k < len1; i = ++k) {
file = files[i];
QR.handleFile(file, i, files.length);
for (k = 0, len1 = files.length; k < len1; k++) {
file = files[k];
QR.handleFile(file, files.length);
}
if (files.length !== 1) {
return $.addClass(QR.nodes.el, 'dump');
$.addClass(QR.nodes.el, 'dump');
}
if (d.activeElement === QR.nodes.fileButton && $.hasClass(QR.nodes.fileSubmit, 'has-file')) {
return QR.nodes.filename.focus();
}
},
handleFile: function(file, index, nfiles) {
var isNewPost, isSingle, max, post, ref;
isSingle = nfiles === 1;
if (/^text\//.test(file.type)) {
if (isSingle) {
post = QR.selected;
} else if (index !== 0 || (post = QR.posts[QR.posts.length - 1]).com) {
handleFile: function(file, nfiles) {
var isText, post;
isText = /^text\//.test(file.type);
if (nfiles === 1) {
post = QR.selected;
} else {
post = QR.posts[QR.posts.length - 1];
if ((isText ? post.com || post.pasting : post.file)) {
post = new QR.post();
}
post.pasteText(file);
}
return post[isText ? 'pasteText' : 'setFile'](file);
},
openFileInput: function() {
if (QR.nodes.fileButton.disabled) {
return;
}
if (ref = file.type, indexOf.call(QR.mimeTypes, ref) < 0) {
QR.error(file.name + ": Unsupported file type.");
if (!isSingle) {
return;
}
}
max = QR.nodes.fileInput.max;
if (/^video\//.test(file.type)) {
max = Math.min(max, QR.max_size_video);
}
if (file.size > max) {
QR.error(file.name + ": File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
if (!isSingle) {
return;
}
}
isNewPost = false;
if (isSingle) {
post = QR.selected;
} else if (index !== 0 || (post = QR.posts[QR.posts.length - 1]).file) {
isNewPost = true;
post = new QR.post();
}
return QR.checkDimensions(file, function(pass, el) {
if (pass || isSingle) {
return post.setFile(file, el);
} else if (isNewPost) {
post.rm();
if (el) {
return URL.revokeObjectURL(el.src);
}
}
});
},
checkDimensions: function(file, cb) {
var img, video;
if (/^image\//.test(file.type)) {
img = new Image();
img.onload = function() {
var height, pass, width;
height = img.height, width = img.width;
pass = true;
if (height > QR.max_height || width > QR.max_width) {
QR.error(file.name + ": Image too large (image: " + height + "x" + width + "px, max: " + QR.max_height + "x" + QR.max_width + "px)");
pass = false;
}
if (height < QR.min_height || width < QR.min_width) {
QR.error(file.name + ": Image too small (image: " + height + "x" + width + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
pass = false;
}
return cb(pass, img);
};
img.onerror = function() {
return cb(false, null);
};
return img.src = URL.createObjectURL(file);
} else if (/^video\//.test(file.type)) {
video = $.el('video');
$.on(video, 'loadeddata', function() {
var duration, max_height, max_width, pass, ref, videoHeight, videoWidth;
if (!cb) {
return;
}
videoHeight = video.videoHeight, videoWidth = video.videoWidth, duration = video.duration;
max_height = Math.min(QR.max_height, QR.max_height_video);
max_width = Math.min(QR.max_width, QR.max_width_video);
pass = true;
if (videoHeight > max_height || videoWidth > max_width) {
QR.error(file.name + ": Video too large (video: " + videoHeight + "x" + videoWidth + "px, max: " + max_height + "x" + max_width + "px)");
pass = false;
}
if (videoHeight < QR.min_height || videoWidth < QR.min_width) {
QR.error(file.name + ": Video too small (video: " + videoHeight + "x" + videoWidth + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
pass = false;
}
if (!isFinite(duration)) {
QR.error(file.name + ": Video lacks duration metadata (try remuxing)");
pass = false;
} else if (duration > QR.max_duration_video) {
QR.error(file.name + ": Video too long (video: " + duration + "s, max: " + QR.max_duration_video + "s)");
pass = false;
}
if (((ref = g.BOARD.ID) !== 'gif' && ref !== 'wsg') && $.hasAudio(video)) {
QR.error(file.name + ": Audio not allowed");
pass = false;
}
cb(pass, video);
return cb = null;
});
$.on(video, 'error', function() {
var ref;
if (!cb) {
return;
}
if (ref = file.type, indexOf.call(QR.mimeTypes, ref) >= 0) {
QR.error(file.name + ": Video appears corrupt");
}
URL.revokeObjectURL(file);
cb(false, null);
return cb = null;
});
return video.src = URL.createObjectURL(file);
} else {
return cb(true, null);
}
},
openFileInput: function(e) {
var ref;
e.stopPropagation();
if (e.shiftKey && e.type === 'click') {
return QR.selected.rmFile();
}
if ((e.ctrlKey || e.metaKey) && e.type === 'click') {
$.addClass(QR.nodes.filename, 'edit');
QR.nodes.filename.focus();
}
if (e.target.nodeName === 'INPUT' || (e.keyCode && ((ref = e.keyCode) !== 32 && ref !== 13)) || e.ctrlKey) {
return;
}
e.preventDefault();
return QR.nodes.fileInput.click();
QR.nodes.fileInput.click();
return QR.nodes.fileButton.focus();
},
generatePostableThreadsList: function() {
var k, len1, list, options, ref, thread, val;
@ -7358,7 +7248,7 @@
var dialog, event, i, items, m, match_max, match_min, name, node, nodes, ref, rules, save, setNode;
QR.nodes = nodes = {
el: dialog = UI.dialog('qr', 'top: 50px; right: 0px;', {
innerHTML: "<div class=move><label><input type=checkbox id=autohide title=Auto-hide>Quick Reply</label><a href=javascript:; class=close title=Close>×</a><select data-name=thread title='Create a new thread / Reply'><option value=new>New thread</option></select></div><form><div class=persona><input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1><input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1><input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1></div><div class=textarea><textarea data-name=com placeholder=Comment class=field></textarea><span id=char-count></span></div><div id=dump-list-container><div id=dump-list></div><a id=add-post href=javascript:; title=\"Add a post\">+</a></div><div id=file-n-submit><span id=qr-filename-container class=field tabindex=0><span id=qr-no-file>No selected file</span><input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\"><span id=\"qr-extras-container\"><a href=\"javascript:;\" id=\"qr-filerm\" title=\"Remove file\"><i class=\"fa fa-times-circle\"></i></a><a id=\"url-button\" title=\"Post from url\"><i class=\"fa fa-link\"></i></a><a id=\"custom-cooldown-button\" title=\"Toggle custom cooldown\" class=\"disabled\"><i class=\"fa fa-clock-o\"></i></a><a id=\"dump-button\" title=\"Dump list\"><i class=\"fa fa-plus-square\"></i></a></span></span><label id=qr-spoiler-label><input type=checkbox id=qr-file-spoiler title='Spoiler image'></label><input type=submit></div><input type=file multiple></form><datalist id=\"list-name\"></datalist><datalist id=\"list-email\"></datalist><datalist id=\"list-sub\"></datalist> "
innerHTML: "<div class=move><label><input type=checkbox id=autohide title=Auto-hide>Quick Reply</label><a href=javascript:; class=close title=Close>×</a><select data-name=thread title='Create a new thread / Reply'><option value=new>New thread</option></select></div><form><div class=persona><input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1><input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1><input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1></div><div class=textarea><textarea data-name=com placeholder=Comment class=field></textarea><span id=char-count></span></div><div id=dump-list-container><div id=dump-list></div><a id=add-post href=javascript:; title=\"Add a post\">+</a></div><div id=\"file-n-submit\"><input type=\"button\" id=\"qr-file-button\" value=\"Files\"><span id=\"qr-filename-container\" class=\"field\"><span id=\"qr-no-file\">No selected file</span><input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\"><label id=\"qr-spoiler-label\"><input type=\"checkbox\" id=\"qr-file-spoiler\" title=\"Spoiler image\"></label><a href=\"javascript:;\" id=\"qr-filerm\" title=\"Remove file\"><i class=\"fa fa-times-circle\"></i></a><a id=\"url-button\" title=\"Post from url\"><i class=\"fa fa-link\"></i></a><a id=\"custom-cooldown-button\" title=\"Toggle custom cooldown\" class=\"disabled\"><i class=\"fa fa-clock-o\"></i></a><a id=\"dump-button\" title=\"Dump list\"><i class=\"fa fa-plus-square\"></i></a></span><input type=\"submit\"></div><input type=\"file\" multiple></form><datalist id=\"list-name\"></datalist><datalist id=\"list-email\"></datalist><datalist id=\"list-sub\"></datalist> "
})
};
setNode = function(name, query) {
@ -7380,10 +7270,10 @@
setNode('addPost', '#add-post');
setNode('charCount', '#char-count');
setNode('fileSubmit', '#file-n-submit');
setNode('fileButton', '#qr-file-button');
setNode('noFile', '#qr-no-file');
setNode('filename', '#qr-filename');
setNode('fileContainer', '#qr-filename-container');
setNode('fileRM', '#qr-filerm');
setNode('fileExtras', '#qr-extras-container');
setNode('spoiler', '#qr-file-spoiler');
setNode('spoilerPar', '#qr-spoiler-label');
setNode('status', '[type=submit]');
@ -7437,7 +7327,8 @@
nodes.flashTag.dataset["default"] = '4';
$.add(nodes.form, nodes.flashTag);
}
$.on(nodes.filename.parentNode, 'click keydown', QR.openFileInput);
$.on(nodes.fileButton, 'click', QR.openFileInput);
$.on(nodes.noFile, 'click', QR.openFileInput);
$.on(nodes.autohide, 'change', QR.toggleHide);
$.on(nodes.close, 'click', QR.close);
$.on(nodes.dumpButton, 'click', function() {
@ -7448,15 +7339,9 @@
return new QR.post(true);
});
$.on(nodes.form, 'submit', QR.submit);
$.on(nodes.filename, 'blur', function() {
return $.rmClass(this, 'edit');
});
$.on(nodes.fileRM, 'click', function() {
return QR.selected.rmFile();
});
$.on(nodes.fileExtras, 'click', function(e) {
return e.stopPropagation();
});
$.on(nodes.spoiler, 'change', function() {
return QR.selected.nodes.spoiler.click();
});
@ -7626,7 +7511,7 @@
return QR.status();
},
response: function() {
var URL, _, ban, captchasCount, err, h1, isReply, m, notif, post, postID, postsCount, ref, ref1, req, resDoc, threadID;
var URL, _, ban, err, h1, isReply, m, post, postID, postsCount, ref, ref1, req, resDoc, threadID;
req = QR.req;
delete QR.req;
post = QR.posts[0];
@ -7696,22 +7581,6 @@
});
postsCount = QR.posts.length - 1;
QR.cooldown.auto = postsCount && isReply;
if (QR.cooldown.auto && QR.captcha.isEnabled && (captchasCount = QR.captcha.captchas.length) < 3 && captchasCount < postsCount) {
notif = new Notification('Quick reply warning', {
body: "You are running low on cached captchas. Cache count: " + captchasCount + ".",
icon: Favicon.logo
});
notif.onclick = function() {
QR.open();
window.focus();
return QR.captcha.setup(true);
};
notif.onshow = function() {
return setTimeout(function() {
return notif.close();
}, 7 * $.SECOND);
};
}
if (!(Conf['Persistent QR'] || postsCount)) {
QR.close();
} else {
@ -8119,7 +7988,7 @@
return $.on(window, 'focus', function() {
return $.queueTask(function() {
var checkbox;
if (!(checkbox = $.id('recaptcha-anchor'))) {
if (!(d.hasFocus() && (checkbox = $.id('recaptcha-anchor')))) {
return;
}
if (d.activeElement !== checkbox) {
@ -8166,7 +8035,6 @@
if (!(this.isEnabled && (this.needed() || force))) {
return;
}
$.addClass(QR.nodes.el, 'captcha-open');
if (focus) {
this.shouldFocus = true;
}
@ -8210,6 +8078,7 @@
},
setupIFrame: function(iframe) {
this.setupTime = Date.now();
$.addClass(QR.nodes.el, 'captcha-open');
if (QR.nodes.el.getBoundingClientRect().bottom > doc.clientHeight) {
QR.nodes.el.style.top = null;
QR.nodes.el.style.bottom = '0px';
@ -8693,7 +8562,8 @@
_Class.prototype["delete"] = function() {
$.rm(this.nodes.el);
return URL.revokeObjectURL(this.URL);
URL.revokeObjectURL(this.URL);
return this.dismissErrors();
};
_Class.prototype.lock = function(lock) {
@ -8713,7 +8583,6 @@
}
}
this.nodes.rm.style.visibility = lock ? 'hidden' : '';
(lock ? $.off : $.on)(QR.nodes.filename.previousElementSibling, 'click', QR.openFileInput);
this.nodes.spoiler.disabled = lock;
return this.nodes.el.draggable = !lock;
};
@ -8799,10 +8668,82 @@
}
};
_Class.prototype.setFile = function(file1, el) {
_Class.rmErrored = function(e) {
var error, errors, k, len1, post, q, ref;
e.stopPropagation();
ref = QR.posts;
for (k = ref.length - 1; k >= 0; k += -1) {
post = ref[k];
if (errors = post.errors) {
for (q = 0, len1 = errors.length; q < len1; q++) {
error = errors[q];
if (!(doc.contains(error))) {
continue;
}
post.rm();
break;
}
}
}
};
_Class.prototype.error = function(className, message) {
var div, ref, rm, rmAll;
div = $.el('div', {
className: className
});
$.extend(div, {
innerHTML: E(message) + "<br>[<a href=\"javascript:;\">delete</a>] [<a href=\"javascript:;\">delete all</a>]"
});
(this.errors || (this.errors = [])).push(div);
ref = $$('a', div), rm = ref[0], rmAll = ref[1];
$.on(div, 'click', (function(_this) {
return function() {
if (indexOf.call(QR.posts, _this) >= 0) {
return _this.select();
}
};
})(this));
$.on(rm, 'click', (function(_this) {
return function(e) {
e.stopPropagation();
if (indexOf.call(QR.posts, _this) >= 0) {
return _this.rm();
}
};
})(this));
$.on(rmAll, 'click', QR.post.rmErrored);
return QR.error(div);
};
_Class.prototype.fileError = function(message) {
return this.error('file-error', this.filename + ": " + message);
};
_Class.prototype.dismissErrors = function(test) {
var error, k, len1, ref;
if (test == null) {
test = function() {
return true;
};
}
if (this.errors) {
ref = this.errors;
for (k = 0, len1 = ref.length; k < len1; k++) {
error = ref[k];
if (doc.contains(error) && test(error)) {
error.parentNode.previousElementSibling.click();
}
}
}
};
_Class.prototype.setFile = function(file1) {
var ref;
this.file = file1;
this.filename = this.file.name;
this.filesize = $.bytesToString(this.file.size);
this.checkSize();
if (QR.spoiler) {
this.nodes.label.hidden = false;
}
@ -8813,10 +8754,79 @@
} else {
this.updateFilename();
}
if (el) {
return this.setThumbnail(el);
this.nodes.el.style.backgroundImage = null;
if (ref = this.file.type, indexOf.call(QR.mimeTypes, ref) < 0) {
return this.fileError('Unsupported file type.');
} else if (/^(image|video)\//.test(this.file.type)) {
return this.readFile();
}
};
_Class.prototype.checkSize = function() {
var max;
max = QR.nodes.fileInput.max;
if (/^video\//.test(this.file.type)) {
max = Math.min(max, QR.max_size_video);
}
if (this.file.size > max) {
return this.fileError("File too large (file: " + this.filesize + ", max: " + ($.bytesToString(max)) + ").");
}
};
_Class.prototype.readFile = function() {
var el, event, isVideo, onerror, onload;
isVideo = /^video\//.test(this.file.type);
el = $.el(isVideo ? 'video' : 'img');
event = isVideo ? 'loadeddata' : 'load';
onload = (function(_this) {
return function() {
$.off(el, event, onload);
$.off(el, 'error', onerror);
_this.checkDimensions(el);
return _this.setThumbnail(el);
};
})(this);
onerror = (function(_this) {
return function() {
$.off(el, event, onload);
$.off(el, 'error', onerror);
_this.fileError((isVideo ? 'Video' : 'Image') + " appears corrupt");
return URL.revokeObjectURL(el.src);
};
})(this);
$.on(el, event, onload);
$.on(el, 'error', onerror);
return el.src = URL.createObjectURL(this.file);
};
_Class.prototype.checkDimensions = function(el) {
var duration, height, max_height, max_width, ref, videoHeight, videoWidth, width;
if (el.tagName === 'IMG') {
height = el.height, width = el.width;
if (height > QR.max_height || width > QR.max_width) {
this.fileError("Image too large (image: " + height + "x" + width + "px, max: " + QR.max_height + "x" + QR.max_width + "px)");
}
if (height < QR.min_height || width < QR.min_width) {
return this.fileError("Image too small (image: " + height + "x" + width + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
}
} else {
return this.nodes.el.style.backgroundImage = null;
videoHeight = el.videoHeight, videoWidth = el.videoWidth, duration = el.duration;
max_height = Math.min(QR.max_height, QR.max_height_video);
max_width = Math.min(QR.max_width, QR.max_width_video);
if (videoHeight > max_height || videoWidth > max_width) {
this.fileError("Video too large (video: " + videoHeight + "x" + videoWidth + "px, max: " + max_height + "x" + max_width + "px)");
}
if (videoHeight < QR.min_height || videoWidth < QR.min_width) {
this.fileError("Video too small (video: " + videoHeight + "x" + videoWidth + "px, min: " + QR.min_height + "x" + QR.min_width + "px)");
}
if (!isFinite(duration)) {
this.fileError('Video lacks duration metadata (try remuxing)');
} else if (duration > QR.max_duration_video) {
this.fileError("Video too long (video: " + duration + "s, max: " + QR.max_duration_video + "s)");
}
if (((ref = g.BOARD.ID) !== 'gif' && ref !== 'wsg') && $.hasAudio(el)) {
return this.fileError('Audio not allowed');
}
}
};
@ -8866,23 +8876,26 @@
delete this.filename;
delete this.filesize;
this.nodes.el.title = null;
QR.nodes.fileContainer.title = '';
QR.nodes.filename.title = '';
this.nodes.el.style.backgroundImage = null;
if (QR.spoiler) {
this.nodes.label.hidden = true;
}
this.showFileData();
return URL.revokeObjectURL(this.URL);
URL.revokeObjectURL(this.URL);
return this.dismissErrors(function(error) {
return $.hasClass(error, 'file-error');
});
};
_Class.prototype.updateFilename = function() {
var long;
long = this.filename + " (" + this.filesize + ")\nCtrl/\u2318+click to edit filename. Shift+click to clear.";
long = this.filename + " (" + this.filesize + ")";
this.nodes.el.title = long;
if (this !== QR.selected) {
return;
}
return QR.nodes.fileContainer.title = long;
return QR.nodes.filename.title = long;
};
_Class.prototype.showFileData = function() {
@ -8898,6 +8911,7 @@
_Class.prototype.pasteText = function(file) {
var reader;
this.pasting = true;
reader = new FileReader();
reader.onload = (function(_this) {
return function(e) {
@ -8911,7 +8925,8 @@
if (QR.selected === _this) {
QR.nodes.com.value = _this.com;
}
return _this.nodes.span.textContent = _this.com;
_this.nodes.span.textContent = _this.com;
return delete _this.pasting;
};
})(this);
return reader.readAsText(file);
@ -10166,7 +10181,7 @@
$.on(this.el, 'change', this.toggle);
return Header.menu.addEntry({
el: prefetch,
order: 104
order: 98
});
},
node: function() {
@ -17020,9 +17035,6 @@
"body.hasDropDownNav{\n" +
" margin-top: 5px;\n" +
"}\n" +
"a {\n" +
" outline: none !important;\n" +
"}\n" +
".painted {\n" +
" border-radius: 3px;\n" +
" padding: 0px 2px;\n" +
@ -17667,7 +17679,7 @@
" text-align: center;\n" +
"}\n" +
"/* /tg/ dice rolls */\n" +
".catalog-thread > .comment > b {\n" +
".board_tg .catalog-thread > .comment > b {\n" +
" font-weight: normal;\n" +
"}\n" +
".catalog-code {\n" +
@ -18118,17 +18130,6 @@
" -webkit-flex-direction: row;\n" +
" flex-direction: row;\n" +
"}\n" +
"#url-button, #custom-cooldown-button, #dump-button {\n" +
" width: 10%;\n" +
" margin: 0;\n" +
" margin-right: 4px;\n" +
" font: 13px sans-serif;\n" +
" padding: 1px 0px 2px;\n" +
" opacity: 0.6;\n" +
"}\n" +
"#custom-cooldown-button.disabled {\n" +
" opacity: 0.27;\n" +
"}\n" +
".persona .field {\n" +
" -webkit-flex: 1;\n" +
" flex: 1;\n" +
@ -18151,8 +18152,18 @@
" text-shadow: none !important;\n" +
"}\n" +
"#qr textarea {\n" +
" min-width: 100%;\n" +
" resize: both;\n" +
"}\n" +
".field {\n" +
" -moz-box-sizing: border-box;\n" +
" margin: 0px;\n" +
" padding: 2px 4px 3px;\n" +
"}\n" +
"#qr label input[type=\"checkbox\"] {\n" +
" position: relative;\n" +
" top: 2px;\n" +
"}\n" +
"/* Noscript Recaptcha */\n" +
".captcha-img {\n" +
" margin: 0px;\n" +
@ -18196,111 +18207,81 @@
" display: block;\n" +
" width: 100%;\n" +
"}\n" +
".field {\n" +
" -moz-box-sizing: border-box;\n" +
" margin: 0px;\n" +
" padding: 2px 4px 3px;\n" +
"/* File Input, Submit Button */\n" +
"#file-n-submit {\n" +
" display: -webkit-flex;\n" +
" display: flex;\n" +
" -webkit-align-items: stretch;\n" +
" align-items: stretch;\n" +
" margin-top: 1px;\n" +
"}\n" +
"#qr textarea {\n" +
" min-width: 100%;\n" +
":root.gecko #file-n-submit > input {\n" +
" margin: 0px -1px -1px;\n" +
"}\n" +
"#qr [type=\"submit\"] {\n" +
"#file-n-submit input[type=\"submit\"] {\n" +
" width: 25%;\n" +
" vertical-align: top;\n" +
"}\n" +
":root.webkit #qr [type=\"submit\"] {\n" +
" height: 24px;\n" +
"}\n" +
"#qr label input[type=\"checkbox\"] {\n" +
"#qr-filename-container {\n" +
" -webkit-flex: 1 1 auto;\n" +
" flex: 1 1 auto;\n" +
" width: 0;\n" +
" display: -webkit-flex;\n" +
" display: flex;\n" +
" -webkit-align-items: center;\n" +
" align-items: center;\n" +
" position: relative;\n" +
" top: 2px;\n" +
" padding: 1px;\n" +
"}\n" +
"/* Fake File Input */\n" +
"input#qr-filename {\n" +
" border: none !important;\n" +
" width: 80%;\n" +
" padding: 0px 4px;\n" +
" position: relative;\n" +
" bottom: 1px;\n" +
" background: none !important;\n" +
"}\n" +
"input#qr-filename:not(.edit) {\n" +
" pointer-events: none;\n" +
"}\n" +
"#qr-filename,\n" +
"#qr-filesize,\n" +
".has-file #qr-no-file {\n" +
" display: none;\n" +
"}\n" +
"#qr-no-file,\n" +
".has-file #qr-filename,\n" +
".has-file #qr-filesize {\n" +
".has-file #qr-filename {\n" +
" -webkit-flex: 1 1 auto;\n" +
" flex: 1 1 auto;\n" +
" display: inline-block;\n" +
" margin: 0 0 2px;\n" +
" padding: 0;\n" +
" padding-left: 3px;\n" +
" overflow: hidden;\n" +
" text-overflow: ellipsis;\n" +
" vertical-align: top;\n" +
"}\n" +
"#qr-no-file {\n" +
" color: #AAA;\n" +
" padding: 1px 4px;\n" +
"}\n" +
"#qr-filename-container {\n" +
" -moz-box-sizing: border-box;\n" +
" display: inline-block;\n" +
" position: relative;\n" +
" width: 100px;\n" +
" min-width: 74.6%;\n" +
" max-width: 74.6%;\n" +
" margin-right: 0.4%;\n" +
" margin-top: 1px;\n" +
" overflow: hidden;\n" +
" padding: 2px 1px 0;\n" +
" height: 22px;\n" +
"}\n" +
"#qr-filename-container:hover {\n" +
" cursor: text;\n" +
"}\n" +
"#qr-extras-container {\n" +
" position: absolute;\n" +
" right: 0px;\n" +
"}\n" +
"#qr-filerm {\n" +
" margin-right: 3px;\n" +
" z-index: 2;\n" +
"}\n" +
"#file-n-submit {\n" +
" height: 23px;\n" +
"}\n" +
"#file-n-submit:not(.custom-cooldown) #custom-cooldown-button {\n" +
" display: none;\n" +
"}\n" +
"#qr input[type=\"file\"] {\n" +
" visibility: hidden;\n" +
" position: absolute;\n" +
"}\n" +
"/* Thread Select / Spoiler Label */\n" +
"#qr select[data-name=\"thread\"] {\n" +
" float: right;\n" +
"/* Spoiler Checkbox, QR Icons */\n" +
"#qr-spoiler-label, #qr-filename-container > a {\n" +
" -webkit-flex: none;\n" +
" flex: none;\n" +
" margin: 0;\n" +
" margin-right: 3px;\n" +
" font: 13px sans-serif;\n" +
"}\n" +
"#qr.has-spoiler .has-file #qr-spoiler-label {\n" +
" width: 6.7%;\n" +
" min-width: 6.7%;\n" +
" max-width: 6.7%;\n" +
" display: inline-block;\n" +
" text-align: center;\n" +
" vertical-align: top;\n" +
"}\n" +
"#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label {\n" +
"#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label,\n" +
".has-file #url-button,\n" +
"#file-n-submit:not(.custom-cooldown) #custom-cooldown-button {\n" +
" display: none;\n" +
"}\n" +
"#qr.has-spoiler .has-file #qr-filename-container {\n" +
" max-width: 67.9%;\n" +
" min-width: 67.9%;\n" +
"#qr-file-spoiler {\n" +
" margin: 0;\n" +
"}\n" +
"#qr-spoiler-label input {\n" +
" position: relative;\n" +
" top: 3px;\n" +
"#url-button, #custom-cooldown-button, #dump-button {\n" +
" opacity: 0.6;\n" +
"}\n" +
"#custom-cooldown-button.disabled {\n" +
" opacity: 0.27;\n" +
"}\n" +
"/* Thread Select */\n" +
"#qr select[data-name=\"thread\"] {\n" +
" float: right;\n" +
"}\n" +
"/* Dumping UI */\n" +
".dump #dump-list-container {\n" +

Binary file not shown.

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.10.2.8' />
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.10.3.0' />
</app>
</gupdate>

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.10.2.8' />
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.10.3.0' />
</app>
</gupdate>

View File

@ -3,7 +3,7 @@
"description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": {
"name": "4chan X",
"version": "1.10.2.8",
"version": "1.10.3.0",
"repo": "https://github.com/ccd0/4chan-x/",
"page": "https://github.com/ccd0/4chan-x",
"downloads": "https://ccd0.github.io/4chan-x/builds/",