diff --git a/CHANGELOG.md b/CHANGELOG.md index d60b7ca90..92d62b5e3 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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")] diff --git a/builds/4chan-X-beta.crx b/builds/4chan-X-beta.crx index 4008f8fcd..0fdacfa8b 100644 Binary files a/builds/4chan-X-beta.crx and b/builds/4chan-X-beta.crx differ diff --git a/builds/4chan-X-beta.meta.js b/builds/4chan-X-beta.meta.js index c0df5cf4e..33642b3cb 100644 --- a/builds/4chan-X-beta.meta.js +++ b/builds/4chan-X-beta.meta.js @@ -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 diff --git a/builds/4chan-X-beta.user.js b/builds/4chan-X-beta.user.js index b66b246c9..ee11f4501 100644 --- a/builds/4chan-X-beta.user.js +++ b/builds/4chan-X-beta.user.js @@ -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: "
×
+
No selected file
" + innerHTML: "
×
+
No selected file
" }) }; 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) + "
[delete] [delete all]" + }); + (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" + diff --git a/builds/4chan-X-noupdate.crx b/builds/4chan-X-noupdate.crx index fe0de38ac..718d91506 100644 Binary files a/builds/4chan-X-noupdate.crx and b/builds/4chan-X-noupdate.crx differ diff --git a/builds/4chan-X-noupdate.user.js b/builds/4chan-X-noupdate.user.js index 003426b02..88c83df5b 100644 --- a/builds/4chan-X-noupdate.user.js +++ b/builds/4chan-X-noupdate.user.js @@ -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: "
×
+
No selected file
" + innerHTML: "
×
+
No selected file
" }) }; 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) + "
[delete] [delete all]" + }); + (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" + diff --git a/builds/4chan-X.crx b/builds/4chan-X.crx index 43418b6a5..0c74586c8 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 0e58afeae..025829f8c 100644 --- a/builds/4chan-X.meta.js +++ b/builds/4chan-X.meta.js @@ -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 diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 2e10b3571..0aafc1b8d 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript // ==UserScript== // @name 4chan X -// @version 1.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: "
×
+
No selected file
" + innerHTML: "
×
+
No selected file
" }) }; 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) + "
[delete] [delete all]" + }); + (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" + diff --git a/builds/4chan-X.zip b/builds/4chan-X.zip index 4e39c267a..4fdaf0355 100644 Binary files a/builds/4chan-X.zip and b/builds/4chan-X.zip differ diff --git a/builds/updates-beta.xml b/builds/updates-beta.xml index 11d58e258..3267787a3 100644 --- a/builds/updates-beta.xml +++ b/builds/updates-beta.xml @@ -1,7 +1,7 @@ - + diff --git a/builds/updates.xml b/builds/updates.xml index c2ba7c9e0..246264b63 100644 --- a/builds/updates.xml +++ b/builds/updates.xml @@ -1,7 +1,7 @@ - + diff --git a/package.json b/package.json index 847ec768a..63fc49f96 100755 --- a/package.json +++ b/package.json @@ -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/",