Merge branch 'master' into getarchivedquotes
This commit is contained in:
commit
081ae491f4
165
4chan_x.user.js
165
4chan_x.user.js
@ -1,6 +1,6 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name 4chan x
|
// @name 4chan x
|
||||||
// @version 2.31.5
|
// @version 2.32.1
|
||||||
// @namespace aeosynth
|
// @namespace aeosynth
|
||||||
// @description Adds various features.
|
// @description Adds various features.
|
||||||
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||||
@ -19,7 +19,7 @@
|
|||||||
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||||
* Copyright (c) 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
* Copyright (c) 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||||
* http://mayhemydg.github.com/4chan-x/
|
* http://mayhemydg.github.com/4chan-x/
|
||||||
* 4chan X 2.31.5
|
* 4chan X 2.32.1
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation
|
* obtaining a copy of this software and associated documentation
|
||||||
@ -72,7 +72,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var $, $$, Anonymize, AutoGif, Conf, Config, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, Get, ImageExpand, ImageHover, Keybinds, Main, Nav, Options, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Redirect, ReplyHiding, ReportButton, RevealSpoilers, Sauce, StrikethroughQuotes, ThreadHiding, ThreadStats, Time, TitlePost, UI, Unread, Updater, Watcher, d, g, _base;
|
var $, $$, Anonymize, AutoGif, Conf, Config, DeleteButton, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, Get, ImageExpand, ImageHover, Keybinds, Main, Nav, Options, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Redirect, ReplyHiding, ReportButton, RevealSpoilers, Sauce, StrikethroughQuotes, ThreadHiding, ThreadStats, Time, TitlePost, UI, Unread, Updater, Watcher, d, g, _base;
|
||||||
|
|
||||||
Config = {
|
Config = {
|
||||||
main: {
|
main: {
|
||||||
@ -82,6 +82,7 @@
|
|||||||
'Time Formatting': [true, 'Arbitrarily formatted timestamps, using your local time'],
|
'Time Formatting': [true, 'Arbitrarily formatted timestamps, using your local time'],
|
||||||
'File Info Formatting': [true, 'Reformats the file information'],
|
'File Info Formatting': [true, 'Reformats the file information'],
|
||||||
'Report Button': [true, 'Add report buttons'],
|
'Report Button': [true, 'Add report buttons'],
|
||||||
|
'Delete Button': [false, 'Add delete buttons'],
|
||||||
'Comment Expansion': [true, 'Expand too long comments'],
|
'Comment Expansion': [true, 'Expand too long comments'],
|
||||||
'Thread Expansion': [true, 'View all replies'],
|
'Thread Expansion': [true, 'View all replies'],
|
||||||
'Index Navigation': [true, 'Navigate to previous / next thread'],
|
'Index Navigation': [true, 'Navigate to previous / next thread'],
|
||||||
@ -310,6 +311,21 @@
|
|||||||
id: function(id) {
|
id: function(id) {
|
||||||
return d.getElementById(id);
|
return d.getElementById(id);
|
||||||
},
|
},
|
||||||
|
formData: function(arg) {
|
||||||
|
var fd, key, val;
|
||||||
|
if (arg instanceof HTMLFormElement) {
|
||||||
|
fd = new FormData(arg);
|
||||||
|
} else {
|
||||||
|
fd = new FormData();
|
||||||
|
for (key in arg) {
|
||||||
|
val = arg[key];
|
||||||
|
if (val) {
|
||||||
|
fd.append(key, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
},
|
||||||
ajax: function(url, callbacks, opts) {
|
ajax: function(url, callbacks, opts) {
|
||||||
var form, headers, key, r, type, upCallbacks, val;
|
var form, headers, key, r, type, upCallbacks, val;
|
||||||
if (opts == null) {
|
if (opts == null) {
|
||||||
@ -317,18 +333,15 @@
|
|||||||
}
|
}
|
||||||
type = opts.type, headers = opts.headers, upCallbacks = opts.upCallbacks, form = opts.form;
|
type = opts.type, headers = opts.headers, upCallbacks = opts.upCallbacks, form = opts.form;
|
||||||
r = new XMLHttpRequest();
|
r = new XMLHttpRequest();
|
||||||
r.open(type || 'get', url, true);
|
type || (type = form && 'post' || 'get');
|
||||||
|
r.open(type, url, true);
|
||||||
for (key in headers) {
|
for (key in headers) {
|
||||||
val = headers[key];
|
val = headers[key];
|
||||||
r.setRequestHeader(key, val);
|
r.setRequestHeader(key, val);
|
||||||
}
|
}
|
||||||
$.extend(r, callbacks);
|
$.extend(r, callbacks);
|
||||||
$.extend(r.upload, upCallbacks);
|
$.extend(r.upload, upCallbacks);
|
||||||
if (typeof form === 'string') {
|
r.send(form);
|
||||||
r.sendAsBinary(form);
|
|
||||||
} else {
|
|
||||||
r.send(form);
|
|
||||||
}
|
|
||||||
return r;
|
return r;
|
||||||
},
|
},
|
||||||
cache: function(url, cb) {
|
cache: function(url, cb) {
|
||||||
@ -706,7 +719,7 @@
|
|||||||
return Main.callbacks.push(this.node);
|
return Main.callbacks.push(this.node);
|
||||||
},
|
},
|
||||||
node: function(post) {
|
node: function(post) {
|
||||||
var el, quote, _i, _len, _ref;
|
var el, quote, show_stub, _i, _len, _ref;
|
||||||
if (post.isInlined) {
|
if (post.isInlined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -716,7 +729,8 @@
|
|||||||
if ((el = $.id(quote.hash.slice(1))) && el.hidden) {
|
if ((el = $.id(quote.hash.slice(1))) && el.hidden) {
|
||||||
$.addClass(quote, 'filtered');
|
$.addClass(quote, 'filtered');
|
||||||
if (Conf['Recursive Filtering']) {
|
if (Conf['Recursive Filtering']) {
|
||||||
ReplyHiding.hide(post.root);
|
show_stub = !!$.x('preceding-sibling::div[contains(@class,"stub")]', el);
|
||||||
|
ReplyHiding.hide(post.root, show_stub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1244,13 +1258,16 @@
|
|||||||
return key;
|
return key;
|
||||||
},
|
},
|
||||||
tags: function(tag, ta) {
|
tags: function(tag, ta) {
|
||||||
var range, selEnd, selStart, value;
|
var e, range, selEnd, selStart, value;
|
||||||
value = ta.value;
|
value = ta.value;
|
||||||
selStart = ta.selectionStart;
|
selStart = ta.selectionStart;
|
||||||
selEnd = ta.selectionEnd;
|
selEnd = ta.selectionEnd;
|
||||||
ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
|
ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
|
||||||
range = ("[" + tag + "]").length + selEnd;
|
range = ("[" + tag + "]").length + selEnd;
|
||||||
return ta.setSelectionRange(range, range);
|
ta.setSelectionRange(range, range);
|
||||||
|
e = d.createEvent('Event');
|
||||||
|
e.initEvent('input', true, false);
|
||||||
|
return ta.dispatchEvent(e);
|
||||||
},
|
},
|
||||||
img: function(thread, all) {
|
img: function(thread, all) {
|
||||||
var thumb;
|
var thumb;
|
||||||
@ -1550,10 +1567,13 @@
|
|||||||
}
|
}
|
||||||
ta = $('textarea', QR.el);
|
ta = $('textarea', QR.el);
|
||||||
caretPos = ta.selectionStart;
|
caretPos = ta.selectionStart;
|
||||||
QR.selected.el.lastChild.textContent = QR.selected.com = ta.value = ta.value.slice(0, caretPos) + text + ta.value.slice(ta.selectionEnd);
|
ta.value = ta.value.slice(0, caretPos) + text + ta.value.slice(ta.selectionEnd);
|
||||||
ta.focus();
|
ta.focus();
|
||||||
range = caretPos + text.length;
|
range = caretPos + text.length;
|
||||||
return ta.setSelectionRange(range, range);
|
ta.setSelectionRange(range, range);
|
||||||
|
e = d.createEvent('Event');
|
||||||
|
e.initEvent('input', true, false);
|
||||||
|
return ta.dispatchEvent(e);
|
||||||
},
|
},
|
||||||
drag: function(e) {
|
drag: function(e) {
|
||||||
var i;
|
var i;
|
||||||
@ -1834,7 +1854,7 @@
|
|||||||
},
|
},
|
||||||
load: function() {
|
load: function() {
|
||||||
var challenge;
|
var challenge;
|
||||||
this.timeout = Date.now() + 26 * $.MINUTE;
|
this.timeout = Date.now() + 4 * $.MINUTE;
|
||||||
challenge = this.challenge.firstChild.value;
|
challenge = this.challenge.firstChild.value;
|
||||||
this.img.alt = challenge;
|
this.img.alt = challenge;
|
||||||
this.img.src = "//www.google.com/recaptcha/api/image?c=" + challenge;
|
this.img.src = "//www.google.com/recaptcha/api/image?c=" + challenge;
|
||||||
@ -1973,7 +1993,7 @@
|
|||||||
return QR.el.dispatchEvent(e);
|
return QR.el.dispatchEvent(e);
|
||||||
},
|
},
|
||||||
submit: function(e) {
|
submit: function(e) {
|
||||||
var callbacks, captcha, captchas, challenge, err, form, m, name, opts, post, reply, response, threadID, val;
|
var callbacks, captcha, captchas, challenge, err, m, opts, post, reply, response, threadID;
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
@ -2040,13 +2060,6 @@
|
|||||||
recaptcha_challenge_field: challenge,
|
recaptcha_challenge_field: challenge,
|
||||||
recaptcha_response_field: response + ' '
|
recaptcha_response_field: response + ' '
|
||||||
};
|
};
|
||||||
form = new FormData();
|
|
||||||
for (name in post) {
|
|
||||||
val = post[name];
|
|
||||||
if (val) {
|
|
||||||
form.append(name, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callbacks = {
|
callbacks = {
|
||||||
onload: function() {
|
onload: function() {
|
||||||
return QR.response(this.response);
|
return QR.response(this.response);
|
||||||
@ -2061,8 +2074,7 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
opts = {
|
opts = {
|
||||||
form: form,
|
form: $.formData(post),
|
||||||
type: 'POST',
|
|
||||||
upCallbacks: {
|
upCallbacks: {
|
||||||
onload: function() {
|
onload: function() {
|
||||||
return QR.status({
|
return QR.status({
|
||||||
@ -2356,7 +2368,8 @@
|
|||||||
});
|
});
|
||||||
$.add(overlay, dialog);
|
$.add(overlay, dialog);
|
||||||
$.add(d.body, overlay);
|
$.add(d.body, overlay);
|
||||||
d.body.style.setProperty('overflow', 'hidden', null);
|
d.body.style.setProperty('width', "" + d.body.clientWidth + "px", null);
|
||||||
|
$.addClass(d.body, 'unscroll');
|
||||||
Options.backlink.call(back);
|
Options.backlink.call(back);
|
||||||
Options.time.call(time);
|
Options.time.call(time);
|
||||||
Options.fileInfo.call(fileInfo);
|
Options.fileInfo.call(fileInfo);
|
||||||
@ -2364,7 +2377,8 @@
|
|||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
$.rm(this);
|
$.rm(this);
|
||||||
return d.body.style.removeProperty('overflow');
|
d.body.style.removeProperty('width');
|
||||||
|
return $.rmClass(d.body, 'unscroll');
|
||||||
},
|
},
|
||||||
clearHidden: function() {
|
clearHidden: function() {
|
||||||
$["delete"]("hiddenReplies/" + g.BOARD + "/");
|
$["delete"]("hiddenReplies/" + g.BOARD + "/");
|
||||||
@ -2447,10 +2461,7 @@
|
|||||||
Conf[input.name] = input.checked;
|
Conf[input.name] = input.checked;
|
||||||
}
|
}
|
||||||
} else if (input.name === 'Interval') {
|
} else if (input.name === 'Interval') {
|
||||||
$.on(input, 'input', function() {
|
$.on(input, 'input', this.cb.interval);
|
||||||
this.value = parseInt(this.value, 10) || Conf['Interval'];
|
|
||||||
return $.cb.value.call(this);
|
|
||||||
});
|
|
||||||
} else if (input.type === 'button') {
|
} else if (input.type === 'button') {
|
||||||
$.on(input, 'click', this.update);
|
$.on(input, 'click', this.update);
|
||||||
}
|
}
|
||||||
@ -2460,6 +2471,12 @@
|
|||||||
return this.lastModified = 0;
|
return this.lastModified = 0;
|
||||||
},
|
},
|
||||||
cb: {
|
cb: {
|
||||||
|
interval: function() {
|
||||||
|
var val;
|
||||||
|
val = parseInt(this.value, 10);
|
||||||
|
this.value = val > 0 ? val : 1;
|
||||||
|
return $.cb.value.call(this);
|
||||||
|
},
|
||||||
verbose: function() {
|
verbose: function() {
|
||||||
if (Conf['Verbose']) {
|
if (Conf['Verbose']) {
|
||||||
Updater.count.textContent = '+0';
|
Updater.count.textContent = '+0';
|
||||||
@ -3594,6 +3611,72 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DeleteButton = {
|
||||||
|
init: function() {
|
||||||
|
this.a = $.el('a', {
|
||||||
|
className: 'delete_button',
|
||||||
|
innerHTML: '[ × ]',
|
||||||
|
href: 'javascript:;'
|
||||||
|
});
|
||||||
|
return Main.callbacks.push(this.node);
|
||||||
|
},
|
||||||
|
node: function(post) {
|
||||||
|
var a;
|
||||||
|
if (!(a = $('.delete_button', post.el))) {
|
||||||
|
a = DeleteButton.a.cloneNode(true);
|
||||||
|
$.add($('.postInfo', post.el), a);
|
||||||
|
}
|
||||||
|
return $.on(a, 'click', DeleteButton["delete"]);
|
||||||
|
},
|
||||||
|
"delete": function() {
|
||||||
|
var board, form, id, m, o, pwd, self;
|
||||||
|
$.off(this, 'click', DeleteButton["delete"]);
|
||||||
|
this.textContent = 'Deleting...';
|
||||||
|
if (m = d.cookie.match(/4chan_pass=([^;]+)/)) {
|
||||||
|
pwd = decodeURIComponent(m[1]);
|
||||||
|
} else {
|
||||||
|
pwd = $.id('delPassword').value;
|
||||||
|
}
|
||||||
|
id = $.x('preceding-sibling::input', this).name;
|
||||||
|
board = $.x('preceding-sibling::span[1]/a', this).pathname.match(/\w+/)[0];
|
||||||
|
self = this;
|
||||||
|
o = {
|
||||||
|
mode: 'usrdel',
|
||||||
|
pwd: pwd
|
||||||
|
};
|
||||||
|
o[id] = 'delete';
|
||||||
|
form = $.formData(o);
|
||||||
|
return $.ajax("https://sys.4chan.org/" + board + "/imgboard.php", {
|
||||||
|
onload: function() {
|
||||||
|
return DeleteButton.load(self, this.response);
|
||||||
|
},
|
||||||
|
onerror: function() {
|
||||||
|
return DeleteButton.error(self);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
form: form
|
||||||
|
});
|
||||||
|
},
|
||||||
|
load: function(self, html) {
|
||||||
|
var doc, msg, s;
|
||||||
|
doc = d.implementation.createHTMLDocument('');
|
||||||
|
doc.documentElement.innerHTML = html;
|
||||||
|
if (doc.title === '4chan - Banned') {
|
||||||
|
s = 'Banned!';
|
||||||
|
} else if (msg = doc.getElementById('errmsg')) {
|
||||||
|
s = msg.textContent;
|
||||||
|
$.on(self, 'click', DeleteButton["delete"]);
|
||||||
|
} else {
|
||||||
|
s = 'Deleted';
|
||||||
|
}
|
||||||
|
return self.innerHTML = "[ " + s + " ]";
|
||||||
|
},
|
||||||
|
error: function(self) {
|
||||||
|
self.innerHTML = '[ Connection error, please retry. ]';
|
||||||
|
return $.on(self, 'click', DeleteButton["delete"]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ReportButton = {
|
ReportButton = {
|
||||||
init: function() {
|
init: function() {
|
||||||
this.a = $.el('a', {
|
this.a = $.el('a', {
|
||||||
@ -3631,8 +3714,9 @@
|
|||||||
switch (g.BOARD) {
|
switch (g.BOARD) {
|
||||||
case 'a':
|
case 'a':
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'mlp':
|
|
||||||
case 'v':
|
case 'v':
|
||||||
|
case 'co':
|
||||||
|
case 'mlp':
|
||||||
return 251;
|
return 251;
|
||||||
case 'vg':
|
case 'vg':
|
||||||
return 501;
|
return 501;
|
||||||
@ -3947,7 +4031,8 @@
|
|||||||
|
|
||||||
AutoGif = {
|
AutoGif = {
|
||||||
init: function() {
|
init: function() {
|
||||||
if (g.BOARD === 'gif') {
|
var _ref;
|
||||||
|
if ((_ref = g.BOARD) === 'gif' || _ref === 'wsg') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return Main.callbacks.push(this.node);
|
return Main.callbacks.push(this.node);
|
||||||
@ -4244,6 +4329,9 @@
|
|||||||
if (Conf['Report Button']) {
|
if (Conf['Report Button']) {
|
||||||
ReportButton.init();
|
ReportButton.init();
|
||||||
}
|
}
|
||||||
|
if (Conf['Delete Button']) {
|
||||||
|
DeleteButton.init();
|
||||||
|
}
|
||||||
if (Conf['Resurrect Quotes']) {
|
if (Conf['Resurrect Quotes']) {
|
||||||
Quotify.init();
|
Quotify.init();
|
||||||
}
|
}
|
||||||
@ -4471,7 +4559,7 @@
|
|||||||
return $.globalEval(("(" + code + ")()").replace('_id_', bq.id));
|
return $.globalEval(("(" + code + ")()").replace('_id_', bq.id));
|
||||||
},
|
},
|
||||||
namespace: '4chan_x.',
|
namespace: '4chan_x.',
|
||||||
version: '2.31.5',
|
version: '2.32.1',
|
||||||
callbacks: [],
|
callbacks: [],
|
||||||
css: '\
|
css: '\
|
||||||
/* dialog styling */\
|
/* dialog styling */\
|
||||||
@ -4737,6 +4825,13 @@ textarea.field {\
|
|||||||
right: 5px;\
|
right: 5px;\
|
||||||
}\
|
}\
|
||||||
\
|
\
|
||||||
|
body {\
|
||||||
|
box-sizing: border-box;\
|
||||||
|
-moz-box-sizing: border-box;\
|
||||||
|
}\
|
||||||
|
body.unscroll {\
|
||||||
|
overflow: hidden;\
|
||||||
|
}\
|
||||||
#overlay {\
|
#overlay {\
|
||||||
top: 0;\
|
top: 0;\
|
||||||
right: 0;\
|
right: 0;\
|
||||||
|
|||||||
2
Cakefile
2
Cakefile
@ -2,7 +2,7 @@
|
|||||||
{exec} = require 'child_process'
|
{exec} = require 'child_process'
|
||||||
fs = require 'fs'
|
fs = require 'fs'
|
||||||
|
|
||||||
VERSION = '2.31.5'
|
VERSION = '2.32.1'
|
||||||
|
|
||||||
HEADER = """
|
HEADER = """
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
|
|||||||
14
changelog
14
changelog
@ -1,5 +1,19 @@
|
|||||||
master
|
master
|
||||||
|
|
||||||
|
2.32.1
|
||||||
|
- Mayhem
|
||||||
|
Fix images uploaded as spoilers.
|
||||||
|
|
||||||
|
2.32.0
|
||||||
|
- aeosynth
|
||||||
|
delete button
|
||||||
|
- Mayhem
|
||||||
|
Fix spoiler/code tag keybinds being ignored on post submission.
|
||||||
|
|
||||||
|
2.31.6
|
||||||
|
- Mayhem
|
||||||
|
Update captcha longevity to 5 minutes max, as according to 4chan's change.
|
||||||
|
|
||||||
2.31.5
|
2.31.5
|
||||||
- Mayhem
|
- Mayhem
|
||||||
Fix spoiler and code tag keybinds regression.
|
Fix spoiler and code tag keybinds regression.
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
postMessage({version:'2.31.5'},'*')
|
postMessage({version:'2.32.1'},'*')
|
||||||
126
script.coffee
126
script.coffee
@ -6,6 +6,7 @@ Config =
|
|||||||
'Time Formatting': [true, 'Arbitrarily formatted timestamps, using your local time']
|
'Time Formatting': [true, 'Arbitrarily formatted timestamps, using your local time']
|
||||||
'File Info Formatting': [true, 'Reformats the file information']
|
'File Info Formatting': [true, 'Reformats the file information']
|
||||||
'Report Button': [true, 'Add report buttons']
|
'Report Button': [true, 'Add report buttons']
|
||||||
|
'Delete Button': [false, 'Add delete buttons']
|
||||||
'Comment Expansion': [true, 'Expand too long comments']
|
'Comment Expansion': [true, 'Expand too long comments']
|
||||||
'Thread Expansion': [true, 'View all replies']
|
'Thread Expansion': [true, 'View all replies']
|
||||||
'Index Navigation': [true, 'Navigate to previous / next thread']
|
'Index Navigation': [true, 'Navigate to previous / next thread']
|
||||||
@ -265,15 +266,24 @@ $.extend $,
|
|||||||
cb JSON.parse e.newValue if e.key is "#{Main.namespace}#{key}"
|
cb JSON.parse e.newValue if e.key is "#{Main.namespace}#{key}"
|
||||||
id: (id) ->
|
id: (id) ->
|
||||||
d.getElementById id
|
d.getElementById id
|
||||||
|
formData: (arg) ->
|
||||||
|
if arg instanceof HTMLFormElement
|
||||||
|
fd = new FormData arg
|
||||||
|
else
|
||||||
|
fd = new FormData()
|
||||||
|
for key, val of arg
|
||||||
|
fd.append key, val if val
|
||||||
|
fd
|
||||||
ajax: (url, callbacks, opts={}) ->
|
ajax: (url, callbacks, opts={}) ->
|
||||||
{type, headers, upCallbacks, form} = opts
|
{type, headers, upCallbacks, form} = opts
|
||||||
r = new XMLHttpRequest()
|
r = new XMLHttpRequest()
|
||||||
r.open type or 'get', url, true
|
type or= form and 'post' or 'get'
|
||||||
|
r.open type, url, true
|
||||||
for key, val of headers
|
for key, val of headers
|
||||||
r.setRequestHeader key, val
|
r.setRequestHeader key, val
|
||||||
$.extend r, callbacks
|
$.extend r, callbacks
|
||||||
$.extend r.upload, upCallbacks
|
$.extend r.upload, upCallbacks
|
||||||
if typeof form is 'string' then r.sendAsBinary form else r.send form
|
r.send form
|
||||||
r
|
r
|
||||||
cache: (url, cb) ->
|
cache: (url, cb) ->
|
||||||
if req = $.cache.requests[url]
|
if req = $.cache.requests[url]
|
||||||
@ -554,7 +564,9 @@ StrikethroughQuotes =
|
|||||||
for quote in post.quotes
|
for quote in post.quotes
|
||||||
if (el = $.id quote.hash[1..]) and el.hidden
|
if (el = $.id quote.hash[1..]) and el.hidden
|
||||||
$.addClass quote, 'filtered'
|
$.addClass quote, 'filtered'
|
||||||
ReplyHiding.hide post.root if Conf['Recursive Filtering']
|
if Conf['Recursive Filtering']
|
||||||
|
show_stub = !!$.x 'preceding-sibling::div[contains(@class,"stub")]', el
|
||||||
|
ReplyHiding.hide post.root, show_stub
|
||||||
return
|
return
|
||||||
|
|
||||||
ExpandComment =
|
ExpandComment =
|
||||||
@ -905,6 +917,11 @@ Keybinds =
|
|||||||
# Move the caret to the end of the selection.
|
# Move the caret to the end of the selection.
|
||||||
ta.setSelectionRange range, range
|
ta.setSelectionRange range, range
|
||||||
|
|
||||||
|
# Fire the 'input' event
|
||||||
|
e = d.createEvent 'Event'
|
||||||
|
e.initEvent 'input', true, false
|
||||||
|
ta.dispatchEvent e
|
||||||
|
|
||||||
img: (thread, all) ->
|
img: (thread, all) ->
|
||||||
if all
|
if all
|
||||||
$.id('imageExpand').click()
|
$.id('imageExpand').click()
|
||||||
@ -1134,16 +1151,17 @@ QR =
|
|||||||
ta = $ 'textarea', QR.el
|
ta = $ 'textarea', QR.el
|
||||||
caretPos = ta.selectionStart
|
caretPos = ta.selectionStart
|
||||||
# Replace selection for text.
|
# Replace selection for text.
|
||||||
# onchange event isn't triggered, save value.
|
ta.value = ta.value[...caretPos] + text + ta.value[ta.selectionEnd..]
|
||||||
QR.selected.el.lastChild.textContent =
|
|
||||||
QR.selected.com =
|
|
||||||
ta.value =
|
|
||||||
ta.value[...caretPos] + text + ta.value[ta.selectionEnd..]
|
|
||||||
ta.focus()
|
ta.focus()
|
||||||
# Move the caret to the end of the new quote.
|
# Move the caret to the end of the new quote.
|
||||||
range = caretPos + text.length
|
range = caretPos + text.length
|
||||||
ta.setSelectionRange range, range
|
ta.setSelectionRange range, range
|
||||||
|
|
||||||
|
# Fire the 'input' event
|
||||||
|
e = d.createEvent 'Event'
|
||||||
|
e.initEvent 'input', true, false
|
||||||
|
ta.dispatchEvent e
|
||||||
|
|
||||||
drag: (e) ->
|
drag: (e) ->
|
||||||
# Let it drag anything from the page.
|
# Let it drag anything from the page.
|
||||||
i = if e.type is 'dragstart' then 'off' else 'on'
|
i = if e.type is 'dragstart' then 'off' else 'on'
|
||||||
@ -1358,7 +1376,8 @@ QR =
|
|||||||
@reload()
|
@reload()
|
||||||
load: ->
|
load: ->
|
||||||
# Timeout is available at RecaptchaState.timeout in seconds.
|
# Timeout is available at RecaptchaState.timeout in seconds.
|
||||||
@timeout = Date.now() + 26*$.MINUTE
|
# We use 5-1 minutes to give upload some time.
|
||||||
|
@timeout = Date.now() + 4*$.MINUTE
|
||||||
challenge = @challenge.firstChild.value
|
challenge = @challenge.firstChild.value
|
||||||
@img.alt = challenge
|
@img.alt = challenge
|
||||||
@img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}"
|
@img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}"
|
||||||
@ -1540,10 +1559,6 @@ QR =
|
|||||||
recaptcha_challenge_field: challenge
|
recaptcha_challenge_field: challenge
|
||||||
recaptcha_response_field: response + ' '
|
recaptcha_response_field: response + ' '
|
||||||
|
|
||||||
form = new FormData()
|
|
||||||
for name, val of post
|
|
||||||
form.append name, val if val
|
|
||||||
|
|
||||||
callbacks =
|
callbacks =
|
||||||
onload: ->
|
onload: ->
|
||||||
QR.response @response
|
QR.response @response
|
||||||
@ -1556,8 +1571,7 @@ QR =
|
|||||||
target: '_blank'
|
target: '_blank'
|
||||||
textContent: 'Connection error, or you are banned.'
|
textContent: 'Connection error, or you are banned.'
|
||||||
opts =
|
opts =
|
||||||
form: form
|
form: $.formData post
|
||||||
type: 'POST'
|
|
||||||
upCallbacks:
|
upCallbacks:
|
||||||
onload: ->
|
onload: ->
|
||||||
# Upload done, waiting for response.
|
# Upload done, waiting for response.
|
||||||
@ -1824,7 +1838,8 @@ Options =
|
|||||||
$.on dialog, 'click', (e) -> e.stopPropagation()
|
$.on dialog, 'click', (e) -> e.stopPropagation()
|
||||||
$.add overlay, dialog
|
$.add overlay, dialog
|
||||||
$.add d.body, overlay
|
$.add d.body, overlay
|
||||||
d.body.style.setProperty 'overflow', 'hidden', null
|
d.body.style.setProperty 'width', "#{d.body.clientWidth}px", null
|
||||||
|
$.addClass d.body, 'unscroll'
|
||||||
|
|
||||||
Options.backlink.call back
|
Options.backlink.call back
|
||||||
Options.time.call time
|
Options.time.call time
|
||||||
@ -1833,7 +1848,8 @@ Options =
|
|||||||
|
|
||||||
close: ->
|
close: ->
|
||||||
$.rm this
|
$.rm this
|
||||||
d.body.style.removeProperty 'overflow'
|
d.body.style.removeProperty 'width'
|
||||||
|
$.rmClass d.body, 'unscroll'
|
||||||
|
|
||||||
clearHidden: ->
|
clearHidden: ->
|
||||||
#'hidden' might be misleading; it's the number of IDs we're *looking* for,
|
#'hidden' might be misleading; it's the number of IDs we're *looking* for,
|
||||||
@ -1907,9 +1923,7 @@ Updater =
|
|||||||
# Required for the QR's update after posting.
|
# Required for the QR's update after posting.
|
||||||
Conf[input.name] = input.checked
|
Conf[input.name] = input.checked
|
||||||
else if input.name is 'Interval'
|
else if input.name is 'Interval'
|
||||||
$.on input, 'input', ->
|
$.on input, 'input', @cb.interval
|
||||||
@value = parseInt(@value, 10) or Conf['Interval']
|
|
||||||
$.cb.value.call @
|
|
||||||
else if input.type is 'button'
|
else if input.type is 'button'
|
||||||
$.on input, 'click', @update
|
$.on input, 'click', @update
|
||||||
|
|
||||||
@ -1919,6 +1933,10 @@ Updater =
|
|||||||
@lastModified = 0
|
@lastModified = 0
|
||||||
|
|
||||||
cb:
|
cb:
|
||||||
|
interval: ->
|
||||||
|
val = parseInt @value, 10
|
||||||
|
@value = if val > 0 then val else 1
|
||||||
|
$.cb.value.call @
|
||||||
verbose: ->
|
verbose: ->
|
||||||
if Conf['Verbose']
|
if Conf['Verbose']
|
||||||
Updater.count.textContent = '+0'
|
Updater.count.textContent = '+0'
|
||||||
@ -2796,6 +2814,58 @@ Quotify =
|
|||||||
$.replace node, nodes
|
$.replace node, nodes
|
||||||
return
|
return
|
||||||
|
|
||||||
|
DeleteButton =
|
||||||
|
init: ->
|
||||||
|
@a = $.el 'a',
|
||||||
|
className: 'delete_button'
|
||||||
|
innerHTML: '[ × ]'
|
||||||
|
href: 'javascript:;'
|
||||||
|
Main.callbacks.push @node
|
||||||
|
node: (post) ->
|
||||||
|
unless a = $ '.delete_button', post.el
|
||||||
|
a = DeleteButton.a.cloneNode true
|
||||||
|
$.add $('.postInfo', post.el), a
|
||||||
|
$.on a, 'click', DeleteButton.delete
|
||||||
|
delete: ->
|
||||||
|
$.off @, 'click', DeleteButton.delete
|
||||||
|
@textContent = 'Deleting...'
|
||||||
|
|
||||||
|
if m = d.cookie.match /4chan_pass=([^;]+)/
|
||||||
|
pwd = decodeURIComponent m[1]
|
||||||
|
else
|
||||||
|
pwd = $.id('delPassword').value
|
||||||
|
id = $.x('preceding-sibling::input', @).name
|
||||||
|
board = $.x('preceding-sibling::span[1]/a', @).pathname.match(/\w+/)[0]
|
||||||
|
self = this
|
||||||
|
|
||||||
|
o =
|
||||||
|
mode: 'usrdel'
|
||||||
|
pwd: pwd
|
||||||
|
o[id] = 'delete'
|
||||||
|
form = $.formData o
|
||||||
|
|
||||||
|
$.ajax "https://sys.4chan.org/#{board}/imgboard.php", {
|
||||||
|
onload: -> DeleteButton.load self, @response
|
||||||
|
onerror: -> DeleteButton.error self
|
||||||
|
}, {
|
||||||
|
form: form
|
||||||
|
}
|
||||||
|
|
||||||
|
load: (self, html) ->
|
||||||
|
doc = d.implementation.createHTMLDocument ''
|
||||||
|
doc.documentElement.innerHTML = html
|
||||||
|
if doc.title is '4chan - Banned' # Ban/warn check
|
||||||
|
s = 'Banned!'
|
||||||
|
else if msg = doc.getElementById 'errmsg' # error!
|
||||||
|
s = msg.textContent
|
||||||
|
$.on self, 'click', DeleteButton.delete
|
||||||
|
else
|
||||||
|
s = 'Deleted'
|
||||||
|
self.innerHTML = "[ #{s} ]"
|
||||||
|
error: (self) ->
|
||||||
|
self.innerHTML = '[ Connection error, please retry. ]'
|
||||||
|
$.on self, 'click', DeleteButton.delete
|
||||||
|
|
||||||
ReportButton =
|
ReportButton =
|
||||||
init: ->
|
init: ->
|
||||||
@a = $.el 'a',
|
@a = $.el 'a',
|
||||||
@ -2822,7 +2892,7 @@ ThreadStats =
|
|||||||
@posts = @images = 0
|
@posts = @images = 0
|
||||||
@imgLimit =
|
@imgLimit =
|
||||||
switch g.BOARD
|
switch g.BOARD
|
||||||
when 'a', 'b', 'mlp', 'v'
|
when 'a', 'b', 'v', 'co', 'mlp'
|
||||||
251
|
251
|
||||||
when 'vg'
|
when 'vg'
|
||||||
501
|
501
|
||||||
@ -3052,7 +3122,7 @@ ImageHover =
|
|||||||
|
|
||||||
AutoGif =
|
AutoGif =
|
||||||
init: ->
|
init: ->
|
||||||
return if g.BOARD is 'gif'
|
return if g.BOARD in ['gif', 'wsg']
|
||||||
Main.callbacks.push @node
|
Main.callbacks.push @node
|
||||||
node: (post) ->
|
node: (post) ->
|
||||||
{img} = post
|
{img} = post
|
||||||
@ -3277,6 +3347,9 @@ Main =
|
|||||||
if Conf['Report Button']
|
if Conf['Report Button']
|
||||||
ReportButton.init()
|
ReportButton.init()
|
||||||
|
|
||||||
|
if Conf['Delete Button']
|
||||||
|
DeleteButton.init()
|
||||||
|
|
||||||
if Conf['Resurrect Quotes']
|
if Conf['Resurrect Quotes']
|
||||||
Quotify.init()
|
Quotify.init()
|
||||||
|
|
||||||
@ -3444,7 +3517,7 @@ Main =
|
|||||||
$.globalEval "(#{code})()".replace '_id_', bq.id
|
$.globalEval "(#{code})()".replace '_id_', bq.id
|
||||||
|
|
||||||
namespace: '4chan_x.'
|
namespace: '4chan_x.'
|
||||||
version: '2.31.5'
|
version: '2.32.1'
|
||||||
callbacks: []
|
callbacks: []
|
||||||
css: '
|
css: '
|
||||||
/* dialog styling */
|
/* dialog styling */
|
||||||
@ -3710,6 +3783,13 @@ textarea.field {
|
|||||||
right: 5px;
|
right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body.unscroll {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
#overlay {
|
#overlay {
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user