Merge branch 'v3' of git://github.com/MayhemYDG/4chan-x into v3
Conflicts: CHANGELOG.md LICENSE css/style.css html/Monitoring/ThreadWatcher.html json/archives.json package.json src/General/Config.coffee src/General/Header.coffee src/General/Main.coffee src/General/img/favicons/empty.gif src/Linkification/Linkify.coffee src/Miscellaneous/ExpandComment.coffee src/Monitoring/Favicon.coffee src/Monitoring/ThreadWatcher.coffee src/Monitoring/Unread.coffee src/Posting/QuickReply.coffee
This commit is contained in:
commit
ccc0335b79
@ -1,3 +1,8 @@
|
|||||||
|
|
||||||
|
**MayhemYDG**:
|
||||||
|
- New desktop notification:
|
||||||
|
- The QR will now warn you when you are running low on cached captchas while auto-posting.
|
||||||
|
|
||||||
### v1.2.35
|
### v1.2.35
|
||||||
*2013-08-20*
|
*2013-08-20*
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ module.exports = (grunt) ->
|
|||||||
'src/Linkification/**/*'
|
'src/Linkification/**/*'
|
||||||
'src/Posting/**/*'
|
'src/Posting/**/*'
|
||||||
'src/Images/**/*'
|
'src/Images/**/*'
|
||||||
|
'src/Linkification/**/*'
|
||||||
'src/Menu/**/*'
|
'src/Menu/**/*'
|
||||||
'src/Monitoring/**/*'
|
'src/Monitoring/**/*'
|
||||||
'src/Archive/**/*'
|
'src/Archive/**/*'
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 4chan X - Version 1.2.35 - 2013-08-20
|
* 4chan X - Version 1.2.35 - 2013-08-22
|
||||||
*
|
*
|
||||||
* Licensed under the MIT license.
|
* Licensed under the MIT license.
|
||||||
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 4chan X - Version 1.2.35 - 2013-08-20
|
* 4chan X - Version 1.2.35 - 2013-08-22
|
||||||
*
|
*
|
||||||
* Licensed under the MIT license.
|
* Licensed under the MIT license.
|
||||||
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
||||||
@ -945,6 +945,7 @@
|
|||||||
Post.prototype.parseComment = function() {
|
Post.prototype.parseComment = function() {
|
||||||
var bq, i, node, nodes, text;
|
var bq, i, node, nodes, text;
|
||||||
|
|
||||||
|
this.nodes.comment.normalize();
|
||||||
bq = this.nodes.comment.cloneNode(true);
|
bq = this.nodes.comment.cloneNode(true);
|
||||||
nodes = $$('.abbr, .capcodeReplies, .exif, b', bq);
|
nodes = $$('.abbr, .capcodeReplies, .exif, b', bq);
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -1872,7 +1873,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
el = $.el('span', {
|
el = $.el('span', {
|
||||||
innerHTML: "Desktop notification permissions are not granted:<br>\n<button>Authorize</button> or <button>Disable</button>"
|
innerHTML: "Desktop notification permissions are not granted.\n[<a href='https://github.com/MayhemYDG/4chan-x/wiki/FAQ#desktop-notifications' target=_blank>FAQ</a>]<br>\n<button>Authorize</button> or <button>Disable</button>"
|
||||||
});
|
});
|
||||||
_ref = $$('button', el), authorize = _ref[0], disable = _ref[1];
|
_ref = $$('button', el), authorize = _ref[0], disable = _ref[1];
|
||||||
$.on(authorize, 'click', function() {
|
$.on(authorize, 'click', function() {
|
||||||
@ -5505,7 +5506,7 @@
|
|||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
QR.open();
|
QR.open();
|
||||||
QR.fileInput(e.dataTransfer.files);
|
QR.handleFiles(e.dataTransfer.files);
|
||||||
return $.addClass(QR.nodes.el, 'dump');
|
return $.addClass(QR.nodes.el, 'dump');
|
||||||
},
|
},
|
||||||
paste: function(e) {
|
paste: function(e) {
|
||||||
@ -5515,84 +5516,72 @@
|
|||||||
_ref = e.clipboardData.items;
|
_ref = e.clipboardData.items;
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
item = _ref[_i];
|
item = _ref[_i];
|
||||||
if (item.kind === 'file') {
|
if (!(item.kind === 'file')) {
|
||||||
blob = item.getAsFile();
|
continue;
|
||||||
blob.name = 'file';
|
|
||||||
if (blob.type) {
|
|
||||||
blob.name += '.' + blob.type.split('/')[1];
|
|
||||||
}
|
|
||||||
files.push(blob);
|
|
||||||
}
|
}
|
||||||
|
blob = item.getAsFile();
|
||||||
|
blob.name = 'file';
|
||||||
|
if (blob.type) {
|
||||||
|
blob.name += '.' + blob.type.split('/')[1];
|
||||||
|
}
|
||||||
|
files.push(blob);
|
||||||
}
|
}
|
||||||
if (!files.length) {
|
if (!files.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QR.open();
|
QR.open();
|
||||||
return QR.fileInput(files);
|
QR.handleFiles(files);
|
||||||
|
return $.addClass(QR.nodes.el, 'dump');
|
||||||
},
|
},
|
||||||
openFileInput: function(e) {
|
handleFiles: function(files) {
|
||||||
e.stopPropagation();
|
var file, isSingle, max, _i, _len;
|
||||||
if (e.shiftKey && e.type === 'click') {
|
|
||||||
return QR.selected.rmFile();
|
|
||||||
}
|
|
||||||
if (e.ctrlKey && e.type === 'click') {
|
|
||||||
$.addClass(QR.nodes.filename, 'edit');
|
|
||||||
QR.nodes.filename.focus();
|
|
||||||
return $.on(QR.nodes.filename, 'blur', function() {
|
|
||||||
return $.rmClass(QR.nodes.filename, 'edit');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (e.target.nodeName === 'INPUT' || (e.keyCode && ![32, 13].contains(e.keyCode)) || e.ctrlKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
return QR.nodes.fileInput.click();
|
|
||||||
},
|
|
||||||
fileInput: function(files) {
|
|
||||||
var file, length, max, post, _i, _len;
|
|
||||||
|
|
||||||
if (this instanceof Element) {
|
if (this !== QR) {
|
||||||
files = __slice.call(this.files);
|
files = __slice.call(this.files);
|
||||||
QR.nodes.fileInput.value = null;
|
this.value = null;
|
||||||
}
|
}
|
||||||
length = files.length;
|
if (!files.length) {
|
||||||
if (!length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
max = QR.nodes.fileInput.max;
|
max = QR.nodes.fileInput.max;
|
||||||
|
isSingle = files.length === 1;
|
||||||
QR.cleanNotifications();
|
QR.cleanNotifications();
|
||||||
if (length === 1) {
|
|
||||||
file = files[0];
|
|
||||||
if (/^text/.test(file.type)) {
|
|
||||||
QR.selected.pasteText(file);
|
|
||||||
} else if (file.size > max) {
|
|
||||||
QR.error("File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
|
|
||||||
} else if (!QR.mimeTypes.contains(file.type)) {
|
|
||||||
QR.error('Unsupported file type.');
|
|
||||||
} else {
|
|
||||||
QR.selected.setFile(file);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
||||||
file = files[_i];
|
file = files[_i];
|
||||||
if (/^text/.test(file.type)) {
|
QR.handleFile(file, isSingle, max);
|
||||||
if ((post = QR.posts[QR.posts.length - 1]).com) {
|
|
||||||
post = new QR.post();
|
|
||||||
}
|
|
||||||
post.pasteText(file);
|
|
||||||
} else if (file.size > max) {
|
|
||||||
QR.error("" + file.name + ": File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
|
|
||||||
} else if (!QR.mimeTypes.contains(file.type)) {
|
|
||||||
QR.error("" + file.name + ": Unsupported file type.");
|
|
||||||
} else {
|
|
||||||
if ((post = QR.posts[QR.posts.length - 1]).file) {
|
|
||||||
post = new QR.post();
|
|
||||||
}
|
|
||||||
post.setFile(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $.addClass(QR.nodes.el, 'dump');
|
if (!isSingle) {
|
||||||
|
return $.addClass(QR.nodes.el, 'dump');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleFile: function(file, isSingle, max) {
|
||||||
|
var post;
|
||||||
|
|
||||||
|
if (file.size > max) {
|
||||||
|
QR.error("" + file.name + ": File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
|
||||||
|
return;
|
||||||
|
} else if (!QR.mimeTypes.contains(file.type)) {
|
||||||
|
if (!/^text/.test(file.type)) {
|
||||||
|
QR.error("" + file.name + ": Unsupported file type.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isSingle) {
|
||||||
|
post = QR.selected;
|
||||||
|
} else if ((post = QR.posts[QR.posts.length - 1]).com) {
|
||||||
|
post = new QR.post();
|
||||||
|
}
|
||||||
|
post.pasteText(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isSingle) {
|
||||||
|
post = QR.selected;
|
||||||
|
} else if ((post = QR.posts[QR.posts.length - 1]).file) {
|
||||||
|
post = new QR.post();
|
||||||
|
}
|
||||||
|
return post.setFile(file);
|
||||||
|
},
|
||||||
|
openFileInput: function() {
|
||||||
|
return QR.nodes.fileInput.click();
|
||||||
},
|
},
|
||||||
posts: [],
|
posts: [],
|
||||||
post: (function() {
|
post: (function() {
|
||||||
@ -5892,7 +5881,8 @@
|
|||||||
return reader.readAsText(file);
|
return reader.readAsText(file);
|
||||||
};
|
};
|
||||||
|
|
||||||
_Class.prototype.dragStart = function() {
|
_Class.prototype.dragStart = function(e) {
|
||||||
|
e.dataTransfer.setDragImage(this, e.layerX, e.layerY);
|
||||||
return $.addClass(this, 'drag');
|
return $.addClass(this, 'drag');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -6198,7 +6188,7 @@
|
|||||||
$.on(nodes.spoiler, 'change', function() {
|
$.on(nodes.spoiler, 'change', function() {
|
||||||
return QR.selected.nodes.spoiler.click();
|
return QR.selected.nodes.spoiler.click();
|
||||||
});
|
});
|
||||||
$.on(nodes.fileInput, 'change', QR.fileInput);
|
$.on(nodes.fileInput, 'change', QR.handleFiles);
|
||||||
items = ['name', 'email', 'sub', 'com', 'filename'];
|
items = ['name', 'email', 'sub', 'com', 'filename'];
|
||||||
i = 0;
|
i = 0;
|
||||||
while (name = items[i++]) {
|
while (name = items[i++]) {
|
||||||
@ -6344,7 +6334,7 @@
|
|||||||
return QR.status();
|
return QR.status();
|
||||||
},
|
},
|
||||||
response: function() {
|
response: function() {
|
||||||
var URL, ban, board, err, h1, isReply, m, post, postID, req, resDoc, threadID, _, _ref, _ref1;
|
var URL, ban, board, captchasCount, err, h1, isReply, m, notif, post, postID, postsCount, req, resDoc, threadID, _, _ref, _ref1;
|
||||||
|
|
||||||
req = QR.req;
|
req = QR.req;
|
||||||
delete QR.req;
|
delete QR.req;
|
||||||
@ -6408,7 +6398,22 @@
|
|||||||
threadID: threadID,
|
threadID: threadID,
|
||||||
postID: postID
|
postID: postID
|
||||||
});
|
});
|
||||||
QR.cooldown.auto = QR.posts.length > 1 && isReply;
|
postsCount = QR.posts.length;
|
||||||
|
QR.cooldown.auto = postsCount > 1 && 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();
|
||||||
|
QR.captcha.nodes.input.focus();
|
||||||
|
return window.focus();
|
||||||
|
};
|
||||||
|
setTimeout(function() {
|
||||||
|
return notif.close();
|
||||||
|
}, 7 * $.SECOND);
|
||||||
|
}
|
||||||
if (!(Conf['Persistent QR'] || QR.cooldown.auto)) {
|
if (!(Conf['Persistent QR'] || QR.cooldown.auto)) {
|
||||||
QR.close();
|
QR.close();
|
||||||
} else {
|
} else {
|
||||||
@ -7367,7 +7372,6 @@
|
|||||||
return Favicon.unreadY = Favicon.unreadNSFWY;
|
return Favicon.unreadY = Favicon.unreadNSFWY;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
empty: 'data:image/gif;base64,R0lGODlhEAAQAJEAAAAAAP///9vb2////yH5BAEAAAMALAAAAAAQABAAAAIvnI+pq+D9DBAUoFkPFnbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
|
|
||||||
dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
|
dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
|
||||||
logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACAAgMAAAC+UIlYAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAGlJREFUWMPtlkEKADEIA/tJP9lXLttQto2yHxgDHozTi0ToGK2WKZZ+HAQQMZc+xBwI4EZ+wAC2IfPuSIDOZJrSZQEAX9eVJhhwIuUYAnQe8rhAEMAZlTI2MID9f5Clyh0JeE1V1ZEAvB4qDfwuJTSGRAAAAABJRU5ErkJggg=='
|
logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACAAgMAAAC+UIlYAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAGlJREFUWMPtlkEKADEIA/tJP9lXLttQto2yHxgDHozTi0ToGK2WKZZ+HAQQMZc+xBwI4EZ+wAC2IfPuSIDOZJrSZQEAX9eVJhhwIuUYAnQe8rhAEMAZlTI2MID9f5Clyh0JeE1V1ZEAvB4qDfwuJTSGRAAAAABJRU5ErkJggg=='
|
||||||
};
|
};
|
||||||
@ -8168,7 +8172,7 @@
|
|||||||
return div;
|
return div;
|
||||||
},
|
},
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
var boardID, data, list, nodes, refresher, thread, threadID, toggler, watched, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3;
|
var boardID, data, helper, list, nodes, refresher, thread, threadID, toggler, watched, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3;
|
||||||
|
|
||||||
nodes = [];
|
nodes = [];
|
||||||
_ref = ThreadWatcher.getAll();
|
_ref = ThreadWatcher.getAll();
|
||||||
@ -8187,7 +8191,9 @@
|
|||||||
boardID: thread.board.ID,
|
boardID: thread.board.ID,
|
||||||
threadID: threadID
|
threadID: threadID
|
||||||
});
|
});
|
||||||
$[watched ? 'addClass' : 'rmClass'](toggler, 'watched');
|
helper = watched ? ['addClass', 'Unwatch'] : ['rmClass', 'Watch'];
|
||||||
|
$[helper[0]](toggler, 'watched');
|
||||||
|
toggler.title = "" + helper[1] + " Thread";
|
||||||
}
|
}
|
||||||
_ref3 = ThreadWatcher.menu.refreshers;
|
_ref3 = ThreadWatcher.menu.refreshers;
|
||||||
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
|
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
|
||||||
@ -8390,7 +8396,7 @@
|
|||||||
|
|
||||||
Unread = {
|
Unread = {
|
||||||
init: function() {
|
init: function() {
|
||||||
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) {
|
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Desktop Notifications']) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.db = new DataBoard('lastReadPosts', this.sync);
|
this.db = new DataBoard('lastReadPosts', this.sync);
|
||||||
@ -8432,18 +8438,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Unread.addPosts(posts);
|
Unread.addPosts(posts);
|
||||||
if (Conf['Scroll to Last Read Post']) {
|
return Unread.scroll();
|
||||||
return Unread.scroll();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
scroll: function() {
|
scroll: function() {
|
||||||
var checkPosition, hash, onload, post, posts, root;
|
var checkPosition, hash, onload, post, posts, root;
|
||||||
|
|
||||||
|
if (!Conf['Scroll to Last Read Post']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
|
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Unread.posts.length) {
|
if (post = Unread.posts[0]) {
|
||||||
post = Unread.posts[0];
|
|
||||||
while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root)) {
|
while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root)) {
|
||||||
if (!(post = Get.postFromRoot(root)).isHidden) {
|
if (!(post = Get.postFromRoot(root)).isHidden) {
|
||||||
break;
|
break;
|
||||||
@ -8467,10 +8473,7 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
checkPosition = function(target) {
|
checkPosition = function(target) {
|
||||||
var height, top, _ref;
|
return target.getBoundingClientRect().bottom > doc.clientHeight;
|
||||||
|
|
||||||
_ref = target.getBoundingClientRect(), top = _ref.top, height = _ref.height;
|
|
||||||
return top + height - doc.clientHeight > 0;
|
|
||||||
};
|
};
|
||||||
return $.on(window, 'load', onload);
|
return $.on(window, 'load', onload);
|
||||||
},
|
},
|
||||||
@ -8488,7 +8491,9 @@
|
|||||||
Unread.lastReadPost = lastReadPost;
|
Unread.lastReadPost = lastReadPost;
|
||||||
Unread.readArray(Unread.posts);
|
Unread.readArray(Unread.posts);
|
||||||
Unread.readArray(Unread.postsQuotingYou);
|
Unread.readArray(Unread.postsQuotingYou);
|
||||||
Unread.setLine();
|
if (Conf['Unread Line']) {
|
||||||
|
Unread.setLine();
|
||||||
|
}
|
||||||
return Unread.update();
|
return Unread.update();
|
||||||
},
|
},
|
||||||
addPosts: function(posts) {
|
addPosts: function(posts) {
|
||||||
@ -8533,7 +8538,6 @@
|
|||||||
}
|
}
|
||||||
Unread.postsQuotingYou.push(post);
|
Unread.postsQuotingYou.push(post);
|
||||||
Unread.openNotification(post);
|
Unread.openNotification(post);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openNotification: function(post) {
|
openNotification: function(post) {
|
||||||
@ -8553,7 +8557,7 @@
|
|||||||
};
|
};
|
||||||
return setTimeout(function() {
|
return setTimeout(function() {
|
||||||
return notif.close();
|
return notif.close();
|
||||||
}, 5 * $.SECOND);
|
}, 7 * $.SECOND);
|
||||||
},
|
},
|
||||||
onUpdate: function(e) {
|
onUpdate: function(e) {
|
||||||
if (e.detail[404]) {
|
if (e.detail[404]) {
|
||||||
@ -8590,7 +8594,7 @@
|
|||||||
return arr.splice(0, i);
|
return arr.splice(0, i);
|
||||||
},
|
},
|
||||||
read: $.debounce(50, function(e) {
|
read: $.debounce(50, function(e) {
|
||||||
var ID, bottom, height, i, post, posts;
|
var ID, height, i, post, posts;
|
||||||
|
|
||||||
if (d.hidden || !Unread.posts.length) {
|
if (d.hidden || !Unread.posts.length) {
|
||||||
return;
|
return;
|
||||||
@ -8599,8 +8603,7 @@
|
|||||||
posts = Unread.posts;
|
posts = Unread.posts;
|
||||||
i = 0;
|
i = 0;
|
||||||
while (post = posts[i]) {
|
while (post = posts[i]) {
|
||||||
bottom = post.nodes.root.getBoundingClientRect().bottom;
|
if (post.nodes.root.getBoundingClientRect().bottom < height) {
|
||||||
if (bottom < height) {
|
|
||||||
ID = post.ID;
|
ID = post.ID;
|
||||||
if (Conf['Mark Quotes of You']) {
|
if (Conf['Mark Quotes of You']) {
|
||||||
if (post.info.yours) {
|
if (post.info.yours) {
|
||||||
@ -8618,10 +8621,8 @@
|
|||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (!Conf['Quote Threading']) {
|
if (i && !Conf['Quote Threading']) {
|
||||||
if (i) {
|
posts.splice(0, i);
|
||||||
posts.splice(0, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!ID) {
|
if (!ID) {
|
||||||
return;
|
return;
|
||||||
@ -8646,19 +8647,17 @@
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
setLine: function(force) {
|
setLine: function(force) {
|
||||||
var post, root;
|
var post;
|
||||||
|
|
||||||
if (!(d.hidden || force === true)) {
|
if (!(d.hidden || force === true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (post = Unread.posts[0]) {
|
if (!(post = Unread.posts[0])) {
|
||||||
root = post.nodes.root;
|
|
||||||
if (root !== $('.thread > .replyContainer', root.parentNode)) {
|
|
||||||
return $.before(root, Unread.hr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return $.rm(Unread.hr);
|
return $.rm(Unread.hr);
|
||||||
}
|
}
|
||||||
|
if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.nodes.root)) {
|
||||||
|
return $.before(post.nodes.root, Unread.hr);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
update: function() {
|
update: function() {
|
||||||
var count;
|
var count;
|
||||||
@ -8670,7 +8669,7 @@
|
|||||||
if (!Conf['Unread Favicon']) {
|
if (!Conf['Unread Favicon']) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Favicon.el.href = g.DEAD ? Unread.postsQuotingYou.length ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou.length ? Favicon.unreadY : Favicon.unread : Favicon["default"];
|
Favicon.el.href = g.DEAD ? Unread.postsQuotingYou[0] ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou[0] ? Favicon.unreadY : Favicon.unread : Favicon["default"];
|
||||||
return $.add(d.head, Favicon.el);
|
return $.add(d.head, Favicon.el);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -11291,6 +11290,7 @@
|
|||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
err = _error;
|
err = _error;
|
||||||
new Notice('warning', 'Cookies need to be enabled on 4chan for 4chan X to properly function.', 30);
|
new Notice('warning', 'Cookies need to be enabled on 4chan for 4chan X to properly function.', 30);
|
||||||
|
Main.disableReports = true;
|
||||||
}
|
}
|
||||||
return $.event('4chanXInitFinished');
|
return $.event('4chanXInitFinished');
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// Generated by CoffeeScript
|
// Generated by CoffeeScript
|
||||||
/*
|
/*
|
||||||
* 4chan X - Version 1.2.35 - 2013-08-20
|
* 4chan X - Version 1.2.35 - 2013-08-22
|
||||||
*
|
*
|
||||||
* Licensed under the MIT license.
|
* Licensed under the MIT license.
|
||||||
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
||||||
@ -954,6 +954,7 @@
|
|||||||
Post.prototype.parseComment = function() {
|
Post.prototype.parseComment = function() {
|
||||||
var bq, i, node, nodes, text;
|
var bq, i, node, nodes, text;
|
||||||
|
|
||||||
|
this.nodes.comment.normalize();
|
||||||
bq = this.nodes.comment.cloneNode(true);
|
bq = this.nodes.comment.cloneNode(true);
|
||||||
nodes = $$('.abbr, .capcodeReplies, .exif, b', bq);
|
nodes = $$('.abbr, .capcodeReplies, .exif, b', bq);
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -1886,7 +1887,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
el = $.el('span', {
|
el = $.el('span', {
|
||||||
innerHTML: "Desktop notification permissions are not granted:<br>\n<button>Authorize</button> or <button>Disable</button>"
|
innerHTML: "Desktop notification permissions are not granted.\n[<a href='https://github.com/MayhemYDG/4chan-x/wiki/FAQ#desktop-notifications' target=_blank>FAQ</a>]<br>\n<button>Authorize</button> or <button>Disable</button>"
|
||||||
});
|
});
|
||||||
_ref = $$('button', el), authorize = _ref[0], disable = _ref[1];
|
_ref = $$('button', el), authorize = _ref[0], disable = _ref[1];
|
||||||
$.on(authorize, 'click', function() {
|
$.on(authorize, 'click', function() {
|
||||||
@ -5179,7 +5180,7 @@
|
|||||||
return setTimeout(function() {
|
return setTimeout(function() {
|
||||||
notif.onclose = null;
|
notif.onclose = null;
|
||||||
return notif.close();
|
return notif.close();
|
||||||
}, 5 * $.SECOND);
|
}, 7 * $.SECOND);
|
||||||
},
|
},
|
||||||
notifications: [],
|
notifications: [],
|
||||||
cleanNotifications: function() {
|
cleanNotifications: function() {
|
||||||
@ -5515,7 +5516,7 @@
|
|||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
QR.open();
|
QR.open();
|
||||||
QR.fileInput(e.dataTransfer.files);
|
QR.handleFiles(e.dataTransfer.files);
|
||||||
return $.addClass(QR.nodes.el, 'dump');
|
return $.addClass(QR.nodes.el, 'dump');
|
||||||
},
|
},
|
||||||
paste: function(e) {
|
paste: function(e) {
|
||||||
@ -5525,84 +5526,72 @@
|
|||||||
_ref = e.clipboardData.items;
|
_ref = e.clipboardData.items;
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
item = _ref[_i];
|
item = _ref[_i];
|
||||||
if (item.kind === 'file') {
|
if (!(item.kind === 'file')) {
|
||||||
blob = item.getAsFile();
|
continue;
|
||||||
blob.name = 'file';
|
|
||||||
if (blob.type) {
|
|
||||||
blob.name += '.' + blob.type.split('/')[1];
|
|
||||||
}
|
|
||||||
files.push(blob);
|
|
||||||
}
|
}
|
||||||
|
blob = item.getAsFile();
|
||||||
|
blob.name = 'file';
|
||||||
|
if (blob.type) {
|
||||||
|
blob.name += '.' + blob.type.split('/')[1];
|
||||||
|
}
|
||||||
|
files.push(blob);
|
||||||
}
|
}
|
||||||
if (!files.length) {
|
if (!files.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QR.open();
|
QR.open();
|
||||||
return QR.fileInput(files);
|
QR.handleFiles(files);
|
||||||
|
return $.addClass(QR.nodes.el, 'dump');
|
||||||
},
|
},
|
||||||
openFileInput: function(e) {
|
handleFiles: function(files) {
|
||||||
e.stopPropagation();
|
var file, isSingle, max, _i, _len;
|
||||||
if (e.shiftKey && e.type === 'click') {
|
|
||||||
return QR.selected.rmFile();
|
|
||||||
}
|
|
||||||
if (e.ctrlKey && e.type === 'click') {
|
|
||||||
$.addClass(QR.nodes.filename, 'edit');
|
|
||||||
QR.nodes.filename.focus();
|
|
||||||
return $.on(QR.nodes.filename, 'blur', function() {
|
|
||||||
return $.rmClass(QR.nodes.filename, 'edit');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (e.target.nodeName === 'INPUT' || (e.keyCode && ![32, 13].contains(e.keyCode)) || e.ctrlKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
return QR.nodes.fileInput.click();
|
|
||||||
},
|
|
||||||
fileInput: function(files) {
|
|
||||||
var file, length, max, post, _i, _len;
|
|
||||||
|
|
||||||
if (this instanceof Element) {
|
if (this !== QR) {
|
||||||
files = __slice.call(this.files);
|
files = __slice.call(this.files);
|
||||||
QR.nodes.fileInput.value = null;
|
this.value = null;
|
||||||
}
|
}
|
||||||
length = files.length;
|
if (!files.length) {
|
||||||
if (!length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
max = QR.nodes.fileInput.max;
|
max = QR.nodes.fileInput.max;
|
||||||
|
isSingle = files.length === 1;
|
||||||
QR.cleanNotifications();
|
QR.cleanNotifications();
|
||||||
if (length === 1) {
|
|
||||||
file = files[0];
|
|
||||||
if (/^text/.test(file.type)) {
|
|
||||||
QR.selected.pasteText(file);
|
|
||||||
} else if (file.size > max) {
|
|
||||||
QR.error("File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
|
|
||||||
} else if (!QR.mimeTypes.contains(file.type)) {
|
|
||||||
QR.error('Unsupported file type.');
|
|
||||||
} else {
|
|
||||||
QR.selected.setFile(file);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
||||||
file = files[_i];
|
file = files[_i];
|
||||||
if (/^text/.test(file.type)) {
|
QR.handleFile(file, isSingle, max);
|
||||||
if ((post = QR.posts[QR.posts.length - 1]).com) {
|
|
||||||
post = new QR.post();
|
|
||||||
}
|
|
||||||
post.pasteText(file);
|
|
||||||
} else if (file.size > max) {
|
|
||||||
QR.error("" + file.name + ": File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
|
|
||||||
} else if (!QR.mimeTypes.contains(file.type)) {
|
|
||||||
QR.error("" + file.name + ": Unsupported file type.");
|
|
||||||
} else {
|
|
||||||
if ((post = QR.posts[QR.posts.length - 1]).file) {
|
|
||||||
post = new QR.post();
|
|
||||||
}
|
|
||||||
post.setFile(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $.addClass(QR.nodes.el, 'dump');
|
if (!isSingle) {
|
||||||
|
return $.addClass(QR.nodes.el, 'dump');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleFile: function(file, isSingle, max) {
|
||||||
|
var post;
|
||||||
|
|
||||||
|
if (file.size > max) {
|
||||||
|
QR.error("" + file.name + ": File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
|
||||||
|
return;
|
||||||
|
} else if (!QR.mimeTypes.contains(file.type)) {
|
||||||
|
if (!/^text/.test(file.type)) {
|
||||||
|
QR.error("" + file.name + ": Unsupported file type.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isSingle) {
|
||||||
|
post = QR.selected;
|
||||||
|
} else if ((post = QR.posts[QR.posts.length - 1]).com) {
|
||||||
|
post = new QR.post();
|
||||||
|
}
|
||||||
|
post.pasteText(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isSingle) {
|
||||||
|
post = QR.selected;
|
||||||
|
} else if ((post = QR.posts[QR.posts.length - 1]).file) {
|
||||||
|
post = new QR.post();
|
||||||
|
}
|
||||||
|
return post.setFile(file);
|
||||||
|
},
|
||||||
|
openFileInput: function() {
|
||||||
|
return QR.nodes.fileInput.click();
|
||||||
},
|
},
|
||||||
posts: [],
|
posts: [],
|
||||||
post: (function() {
|
post: (function() {
|
||||||
@ -5896,7 +5885,8 @@
|
|||||||
return reader.readAsText(file);
|
return reader.readAsText(file);
|
||||||
};
|
};
|
||||||
|
|
||||||
_Class.prototype.dragStart = function() {
|
_Class.prototype.dragStart = function(e) {
|
||||||
|
e.dataTransfer.setDragImage(this, e.layerX, e.layerY);
|
||||||
return $.addClass(this, 'drag');
|
return $.addClass(this, 'drag');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -6194,7 +6184,7 @@
|
|||||||
$.on(nodes.spoiler, 'change', function() {
|
$.on(nodes.spoiler, 'change', function() {
|
||||||
return QR.selected.nodes.spoiler.click();
|
return QR.selected.nodes.spoiler.click();
|
||||||
});
|
});
|
||||||
$.on(nodes.fileInput, 'change', QR.fileInput);
|
$.on(nodes.fileInput, 'change', QR.handleFiles);
|
||||||
items = ['name', 'email', 'sub', 'com', 'filename'];
|
items = ['name', 'email', 'sub', 'com', 'filename'];
|
||||||
i = 0;
|
i = 0;
|
||||||
while (name = items[i++]) {
|
while (name = items[i++]) {
|
||||||
@ -6329,7 +6319,7 @@
|
|||||||
return QR.status();
|
return QR.status();
|
||||||
},
|
},
|
||||||
response: function() {
|
response: function() {
|
||||||
var URL, ban, board, err, h1, isReply, m, post, postID, req, resDoc, threadID, _, _ref, _ref1;
|
var URL, ban, board, captchasCount, err, h1, isReply, m, notif, post, postID, postsCount, req, resDoc, threadID, _, _ref, _ref1;
|
||||||
|
|
||||||
req = QR.req;
|
req = QR.req;
|
||||||
delete QR.req;
|
delete QR.req;
|
||||||
@ -6393,7 +6383,22 @@
|
|||||||
threadID: threadID,
|
threadID: threadID,
|
||||||
postID: postID
|
postID: postID
|
||||||
});
|
});
|
||||||
QR.cooldown.auto = QR.posts.length > 1 && isReply;
|
postsCount = QR.posts.length;
|
||||||
|
QR.cooldown.auto = postsCount > 1 && 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();
|
||||||
|
QR.captcha.nodes.input.focus();
|
||||||
|
return window.focus();
|
||||||
|
};
|
||||||
|
setTimeout(function() {
|
||||||
|
return notif.close();
|
||||||
|
}, 7 * $.SECOND);
|
||||||
|
}
|
||||||
if (!(Conf['Persistent QR'] || QR.cooldown.auto)) {
|
if (!(Conf['Persistent QR'] || QR.cooldown.auto)) {
|
||||||
QR.close();
|
QR.close();
|
||||||
} else {
|
} else {
|
||||||
@ -7352,7 +7357,6 @@
|
|||||||
return Favicon.unreadY = Favicon.unreadNSFWY;
|
return Favicon.unreadY = Favicon.unreadNSFWY;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
empty: 'data:image/gif;base64,R0lGODlhEAAQAJEAAAAAAP///9vb2////yH5BAEAAAMALAAAAAAQABAAAAIvnI+pq+D9DBAUoFkPFnbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
|
|
||||||
dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
|
dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
|
||||||
logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACAAgMAAAC+UIlYAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAGlJREFUWMPtlkEKADEIA/tJP9lXLttQto2yHxgDHozTi0ToGK2WKZZ+HAQQMZc+xBwI4EZ+wAC2IfPuSIDOZJrSZQEAX9eVJhhwIuUYAnQe8rhAEMAZlTI2MID9f5Clyh0JeE1V1ZEAvB4qDfwuJTSGRAAAAABJRU5ErkJggg=='
|
logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACAAgMAAAC+UIlYAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAGlJREFUWMPtlkEKADEIA/tJP9lXLttQto2yHxgDHozTi0ToGK2WKZZ+HAQQMZc+xBwI4EZ+wAC2IfPuSIDOZJrSZQEAX9eVJhhwIuUYAnQe8rhAEMAZlTI2MID9f5Clyh0JeE1V1ZEAvB4qDfwuJTSGRAAAAABJRU5ErkJggg=='
|
||||||
};
|
};
|
||||||
@ -8153,7 +8157,7 @@
|
|||||||
return div;
|
return div;
|
||||||
},
|
},
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
var boardID, data, list, nodes, refresher, thread, threadID, toggler, watched, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3;
|
var boardID, data, helper, list, nodes, refresher, thread, threadID, toggler, watched, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3;
|
||||||
|
|
||||||
nodes = [];
|
nodes = [];
|
||||||
_ref = ThreadWatcher.getAll();
|
_ref = ThreadWatcher.getAll();
|
||||||
@ -8172,7 +8176,9 @@
|
|||||||
boardID: thread.board.ID,
|
boardID: thread.board.ID,
|
||||||
threadID: threadID
|
threadID: threadID
|
||||||
});
|
});
|
||||||
$[watched ? 'addClass' : 'rmClass'](toggler, 'watched');
|
helper = watched ? ['addClass', 'Unwatch'] : ['rmClass', 'Watch'];
|
||||||
|
$[helper[0]](toggler, 'watched');
|
||||||
|
toggler.title = "" + helper[1] + " Thread";
|
||||||
}
|
}
|
||||||
_ref3 = ThreadWatcher.menu.refreshers;
|
_ref3 = ThreadWatcher.menu.refreshers;
|
||||||
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
|
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
|
||||||
@ -8375,7 +8381,7 @@
|
|||||||
|
|
||||||
Unread = {
|
Unread = {
|
||||||
init: function() {
|
init: function() {
|
||||||
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) {
|
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Desktop Notifications']) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.db = new DataBoard('lastReadPosts', this.sync);
|
this.db = new DataBoard('lastReadPosts', this.sync);
|
||||||
@ -8417,18 +8423,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Unread.addPosts(posts);
|
Unread.addPosts(posts);
|
||||||
if (Conf['Scroll to Last Read Post']) {
|
return Unread.scroll();
|
||||||
return Unread.scroll();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
scroll: function() {
|
scroll: function() {
|
||||||
var checkPosition, hash, onload, post, posts, root;
|
var checkPosition, hash, onload, post, posts, root;
|
||||||
|
|
||||||
|
if (!Conf['Scroll to Last Read Post']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
|
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Unread.posts.length) {
|
if (post = Unread.posts[0]) {
|
||||||
post = Unread.posts[0];
|
|
||||||
while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root)) {
|
while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root)) {
|
||||||
if (!(post = Get.postFromRoot(root)).isHidden) {
|
if (!(post = Get.postFromRoot(root)).isHidden) {
|
||||||
break;
|
break;
|
||||||
@ -8452,10 +8458,7 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
checkPosition = function(target) {
|
checkPosition = function(target) {
|
||||||
var height, top, _ref;
|
return target.getBoundingClientRect().bottom > doc.clientHeight;
|
||||||
|
|
||||||
_ref = target.getBoundingClientRect(), top = _ref.top, height = _ref.height;
|
|
||||||
return top + height - doc.clientHeight > 0;
|
|
||||||
};
|
};
|
||||||
return $.on(window, 'load', onload);
|
return $.on(window, 'load', onload);
|
||||||
},
|
},
|
||||||
@ -8473,7 +8476,9 @@
|
|||||||
Unread.lastReadPost = lastReadPost;
|
Unread.lastReadPost = lastReadPost;
|
||||||
Unread.readArray(Unread.posts);
|
Unread.readArray(Unread.posts);
|
||||||
Unread.readArray(Unread.postsQuotingYou);
|
Unread.readArray(Unread.postsQuotingYou);
|
||||||
Unread.setLine();
|
if (Conf['Unread Line']) {
|
||||||
|
Unread.setLine();
|
||||||
|
}
|
||||||
return Unread.update();
|
return Unread.update();
|
||||||
},
|
},
|
||||||
addPosts: function(posts) {
|
addPosts: function(posts) {
|
||||||
@ -8518,7 +8523,6 @@
|
|||||||
}
|
}
|
||||||
Unread.postsQuotingYou.push(post);
|
Unread.postsQuotingYou.push(post);
|
||||||
Unread.openNotification(post);
|
Unread.openNotification(post);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openNotification: function(post) {
|
openNotification: function(post) {
|
||||||
@ -8538,7 +8542,7 @@
|
|||||||
};
|
};
|
||||||
return setTimeout(function() {
|
return setTimeout(function() {
|
||||||
return notif.close();
|
return notif.close();
|
||||||
}, 5 * $.SECOND);
|
}, 7 * $.SECOND);
|
||||||
},
|
},
|
||||||
onUpdate: function(e) {
|
onUpdate: function(e) {
|
||||||
if (e.detail[404]) {
|
if (e.detail[404]) {
|
||||||
@ -8575,7 +8579,7 @@
|
|||||||
return arr.splice(0, i);
|
return arr.splice(0, i);
|
||||||
},
|
},
|
||||||
read: $.debounce(50, function(e) {
|
read: $.debounce(50, function(e) {
|
||||||
var ID, bottom, height, i, post, posts;
|
var ID, height, i, post, posts;
|
||||||
|
|
||||||
if (d.hidden || !Unread.posts.length) {
|
if (d.hidden || !Unread.posts.length) {
|
||||||
return;
|
return;
|
||||||
@ -8584,8 +8588,7 @@
|
|||||||
posts = Unread.posts;
|
posts = Unread.posts;
|
||||||
i = 0;
|
i = 0;
|
||||||
while (post = posts[i]) {
|
while (post = posts[i]) {
|
||||||
bottom = post.nodes.root.getBoundingClientRect().bottom;
|
if (post.nodes.root.getBoundingClientRect().bottom < height) {
|
||||||
if (bottom < height) {
|
|
||||||
ID = post.ID;
|
ID = post.ID;
|
||||||
if (Conf['Mark Quotes of You']) {
|
if (Conf['Mark Quotes of You']) {
|
||||||
if (post.info.yours) {
|
if (post.info.yours) {
|
||||||
@ -8603,10 +8606,8 @@
|
|||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (!Conf['Quote Threading']) {
|
if (i && !Conf['Quote Threading']) {
|
||||||
if (i) {
|
posts.splice(0, i);
|
||||||
posts.splice(0, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!ID) {
|
if (!ID) {
|
||||||
return;
|
return;
|
||||||
@ -8631,19 +8632,17 @@
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
setLine: function(force) {
|
setLine: function(force) {
|
||||||
var post, root;
|
var post;
|
||||||
|
|
||||||
if (!(d.hidden || force === true)) {
|
if (!(d.hidden || force === true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (post = Unread.posts[0]) {
|
if (!(post = Unread.posts[0])) {
|
||||||
root = post.nodes.root;
|
|
||||||
if (root !== $('.thread > .replyContainer', root.parentNode)) {
|
|
||||||
return $.before(root, Unread.hr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return $.rm(Unread.hr);
|
return $.rm(Unread.hr);
|
||||||
}
|
}
|
||||||
|
if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.nodes.root)) {
|
||||||
|
return $.before(post.nodes.root, Unread.hr);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
update: function(dontrepeat) {
|
update: function(dontrepeat) {
|
||||||
var count;
|
var count;
|
||||||
@ -8651,17 +8650,18 @@
|
|||||||
count = Unread.posts.length;
|
count = Unread.posts.length;
|
||||||
if (Conf['Unread Count']) {
|
if (Conf['Unread Count']) {
|
||||||
d.title = "" + (Conf['Quoted Title'] && Unread.postsQuotingYou.length ? '(!) ' : '') + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title);
|
d.title = "" + (Conf['Quoted Title'] && Unread.postsQuotingYou.length ? '(!) ' : '') + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title);
|
||||||
if (!dontrepeat) {
|
if (dontrepeat) {
|
||||||
setTimeout(function() {
|
return;
|
||||||
d.title = '';
|
|
||||||
return Unread.update(true);
|
|
||||||
}, $.SECOND);
|
|
||||||
}
|
}
|
||||||
|
setTimeout(function() {
|
||||||
|
d.title = '';
|
||||||
|
return Unread.update(true);
|
||||||
|
}, $.SECOND);
|
||||||
}
|
}
|
||||||
if (!Conf['Unread Favicon']) {
|
if (!Conf['Unread Favicon']) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return Favicon.el.href = g.DEAD ? Unread.postsQuotingYou.length ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou.length ? Favicon.unreadY : Favicon.unread : Favicon["default"];
|
return Favicon.el.href = g.DEAD ? Unread.postsQuotingYou[0] ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou[0] ? Favicon.unreadY : Favicon.unread : Favicon["default"];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -11046,7 +11046,7 @@
|
|||||||
}));
|
}));
|
||||||
Main.logError({
|
Main.logError({
|
||||||
message: 'Chrome Storage API bug',
|
message: 'Chrome Storage API bug',
|
||||||
error: new Error(chrome.runtime.lastError.message || 'no lastError.message')
|
error: new Error('~')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Main.initFeatures();
|
return Main.initFeatures();
|
||||||
@ -11288,6 +11288,7 @@
|
|||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
err = _error;
|
err = _error;
|
||||||
new Notice('warning', 'Cookies need to be enabled on 4chan for 4chan X to properly function.', 30);
|
new Notice('warning', 'Cookies need to be enabled on 4chan for 4chan X to properly function.', 30);
|
||||||
|
Main.disableReports = true;
|
||||||
}
|
}
|
||||||
return $.event('4chanXInitFinished');
|
return $.event('4chanXInitFinished');
|
||||||
},
|
},
|
||||||
|
|||||||
@ -29,7 +29,7 @@ Header =
|
|||||||
@linkJustifyToggler = linkJustifyToggler.firstElementChild
|
@linkJustifyToggler = linkJustifyToggler.firstElementChild
|
||||||
@headerToggler = headerToggler.firstElementChild
|
@headerToggler = headerToggler.firstElementChild
|
||||||
@footerToggler = footerToggler.firstElementChild
|
@footerToggler = footerToggler.firstElementChild
|
||||||
@shortcutToggler = shortcutToggler.firstElementChild
|
@shortcutToggler = shortcutToggler.firstElementChild
|
||||||
@customNavToggler = customNavToggler.firstElementChild
|
@customNavToggler = customNavToggler.firstElementChild
|
||||||
|
|
||||||
$.on menuButton, 'click', @menuToggle
|
$.on menuButton, 'click', @menuToggle
|
||||||
@ -362,7 +362,8 @@ Header =
|
|||||||
|
|
||||||
el = $.el 'span',
|
el = $.el 'span',
|
||||||
innerHTML: """
|
innerHTML: """
|
||||||
Desktop notification permissions are not granted:<br>
|
Desktop notification permissions are not granted.
|
||||||
|
[<a href='https://github.com/MayhemYDG/4chan-x/wiki/FAQ#desktop-notifications' target=_blank>FAQ</a>]<br>
|
||||||
<button>Authorize</button> or <button>Disable</button>
|
<button>Authorize</button> or <button>Disable</button>
|
||||||
"""
|
"""
|
||||||
[authorize, disable] = $$ 'button', el
|
[authorize, disable] = $$ 'button', el
|
||||||
|
|||||||
@ -29,7 +29,7 @@ Main =
|
|||||||
# Track resolution of this bug.
|
# Track resolution of this bug.
|
||||||
Main.logError
|
Main.logError
|
||||||
message: 'Chrome Storage API bug'
|
message: 'Chrome Storage API bug'
|
||||||
error: new Error chrome.runtime.lastError.message or 'no lastError.message'
|
error: new Error '~'
|
||||||
<% } %>
|
<% } %>
|
||||||
Main.initFeatures()
|
Main.initFeatures()
|
||||||
|
|
||||||
@ -237,6 +237,7 @@ Main =
|
|||||||
localStorage.getItem '4chan-settings'
|
localStorage.getItem '4chan-settings'
|
||||||
catch err
|
catch err
|
||||||
new Notice 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to properly function.', 30
|
new Notice 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to properly function.', 30
|
||||||
|
Main.disableReports = true
|
||||||
|
|
||||||
$.event '4chanXInitFinished'
|
$.event '4chanXInitFinished'
|
||||||
|
|
||||||
|
|||||||
@ -62,6 +62,8 @@ class Post
|
|||||||
@kill() if that.isArchived
|
@kill() if that.isArchived
|
||||||
|
|
||||||
parseComment: ->
|
parseComment: ->
|
||||||
|
# Merge text nodes and remove empty ones.
|
||||||
|
@nodes.comment.normalize()
|
||||||
# Get the comment's text.
|
# Get the comment's text.
|
||||||
# <br> -> \n
|
# <br> -> \n
|
||||||
# Remove:
|
# Remove:
|
||||||
|
|||||||
@ -399,3 +399,4 @@ Linkify =
|
|||||||
title:
|
title:
|
||||||
api: (uid) -> "https://gdata.youtube.com/feeds/api/videos/#{uid}?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode"
|
api: (uid) -> "https://gdata.youtube.com/feeds/api/videos/#{uid}?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode"
|
||||||
text: (data) -> data.entry.title.$t
|
text: (data) -> data.entry.title.$t
|
||||||
|
|
||||||
|
|||||||
@ -45,6 +45,5 @@ Favicon =
|
|||||||
Favicon.unread = Favicon.unreadNSFW
|
Favicon.unread = Favicon.unreadNSFW
|
||||||
Favicon.unreadY = Favicon.unreadNSFWY
|
Favicon.unreadY = Favicon.unreadNSFWY
|
||||||
|
|
||||||
empty: 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/empty.gif", {encoding: "base64"}) %>'
|
|
||||||
dead: 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/dead.gif", {encoding: "base64"}) %>'
|
dead: 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/dead.gif", {encoding: "base64"}) %>'
|
||||||
logo: 'data:image/png;base64,<%= grunt.file.read("src/General/img/icon128.png", {encoding: "base64"}) %>'
|
logo: 'data:image/png;base64,<%= grunt.file.read("src/General/img/icon128.png", {encoding: "base64"}) %>'
|
||||||
|
|||||||
@ -177,7 +177,9 @@ ThreadWatcher =
|
|||||||
for threadID, thread of g.BOARD.threads
|
for threadID, thread of g.BOARD.threads
|
||||||
toggler = $ '.watch-thread-link', thread.OP.nodes.post
|
toggler = $ '.watch-thread-link', thread.OP.nodes.post
|
||||||
watched = ThreadWatcher.db.get {boardID: thread.board.ID, threadID}
|
watched = ThreadWatcher.db.get {boardID: thread.board.ID, threadID}
|
||||||
$[if watched then 'addClass' else 'rmClass'] toggler, 'watched'
|
helper = if watched then ['addClass', 'Unwatch'] else ['rmClass', 'Watch']
|
||||||
|
$[helper[0]] toggler, 'watched'
|
||||||
|
toggler.title = "#{helper[1]} Thread"
|
||||||
|
|
||||||
for refresher in ThreadWatcher.menu.refreshers
|
for refresher in ThreadWatcher.menu.refreshers
|
||||||
refresher()
|
refresher()
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
Unread =
|
Unread =
|
||||||
init: ->
|
init: ->
|
||||||
return if g.VIEW isnt 'thread' or !Conf['Unread Count'] and !Conf['Unread Favicon']
|
return if g.VIEW isnt 'thread' or !Conf['Unread Count'] and !Conf['Unread Favicon'] and !Conf['Desktop Notifications']
|
||||||
|
|
||||||
@db = new DataBoard 'lastReadPosts', @sync
|
@db = new DataBoard 'lastReadPosts', @sync
|
||||||
@hr = $.el 'hr',
|
@hr = $.el 'hr',
|
||||||
@ -30,14 +30,14 @@ Unread =
|
|||||||
for ID, post of Unread.thread.posts
|
for ID, post of Unread.thread.posts
|
||||||
posts.push post if post.isReply
|
posts.push post if post.isReply
|
||||||
Unread.addPosts posts
|
Unread.addPosts posts
|
||||||
Unread.scroll() if Conf['Scroll to Last Read Post']
|
Unread.scroll()
|
||||||
|
|
||||||
scroll: ->
|
scroll: ->
|
||||||
|
return unless Conf['Scroll to Last Read Post']
|
||||||
# Let the header's onload callback handle it.
|
# Let the header's onload callback handle it.
|
||||||
return if (hash = location.hash.match /\d+/) and hash[0] of Unread.thread.posts
|
return if (hash = location.hash.match /\d+/) and hash[0] of Unread.thread.posts
|
||||||
if Unread.posts.length
|
if post = Unread.posts[0]
|
||||||
# Scroll to a non-hidden, non-OP post that's before the first unread post.
|
# Scroll to a non-hidden, non-OP post that's before the first unread post.
|
||||||
post = Unread.posts[0]
|
|
||||||
while root = $.x 'preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root
|
while root = $.x 'preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root
|
||||||
break unless (post = Get.postFromRoot root).isHidden
|
break unless (post = Get.postFromRoot root).isHidden
|
||||||
return unless root
|
return unless root
|
||||||
@ -48,11 +48,8 @@ Unread =
|
|||||||
{root} = Unread.thread.posts[posts[posts.length - 1]].nodes
|
{root} = Unread.thread.posts[posts[posts.length - 1]].nodes
|
||||||
onload = -> Header.scrollToPost root if checkPosition root
|
onload = -> Header.scrollToPost root if checkPosition root
|
||||||
checkPosition = (target) ->
|
checkPosition = (target) ->
|
||||||
# Don't scroll to the target if
|
# Scroll to the target unless we scrolled past it.
|
||||||
# - it's visible.
|
target.getBoundingClientRect().bottom > doc.clientHeight
|
||||||
# - we've scrolled past it.
|
|
||||||
{top, height} = target.getBoundingClientRect()
|
|
||||||
top + height - doc.clientHeight > 0
|
|
||||||
# Prevent the browser to scroll back to
|
# Prevent the browser to scroll back to
|
||||||
# the previous scroll location on page load.
|
# the previous scroll location on page load.
|
||||||
$.on window, 'load', onload
|
$.on window, 'load', onload
|
||||||
@ -66,7 +63,7 @@ Unread =
|
|||||||
Unread.lastReadPost = lastReadPost
|
Unread.lastReadPost = lastReadPost
|
||||||
Unread.readArray Unread.posts
|
Unread.readArray Unread.posts
|
||||||
Unread.readArray Unread.postsQuotingYou
|
Unread.readArray Unread.postsQuotingYou
|
||||||
Unread.setLine()
|
Unread.setLine() if Conf['Unread Line']
|
||||||
Unread.update()
|
Unread.update()
|
||||||
|
|
||||||
addPosts: (posts) ->
|
addPosts: (posts) ->
|
||||||
@ -93,7 +90,8 @@ Unread =
|
|||||||
for quotelink in post.nodes.quotelinks when QR.db.get Get.postDataFromLink quotelink
|
for quotelink in post.nodes.quotelinks when QR.db.get Get.postDataFromLink quotelink
|
||||||
Unread.postsQuotingYou.push post
|
Unread.postsQuotingYou.push post
|
||||||
Unread.openNotification post
|
Unread.openNotification post
|
||||||
return
|
return
|
||||||
|
|
||||||
openNotification: (post) ->
|
openNotification: (post) ->
|
||||||
return unless Header.areNotificationsEnabled
|
return unless Header.areNotificationsEnabled
|
||||||
name = if Conf['Anonymize']
|
name = if Conf['Anonymize']
|
||||||
@ -108,7 +106,7 @@ Unread =
|
|||||||
window.focus()
|
window.focus()
|
||||||
setTimeout ->
|
setTimeout ->
|
||||||
notif.close()
|
notif.close()
|
||||||
, 5 * $.SECOND
|
, 7 * $.SECOND
|
||||||
|
|
||||||
onUpdate: (e) ->
|
onUpdate: (e) ->
|
||||||
if e.detail[404]
|
if e.detail[404]
|
||||||
@ -138,8 +136,7 @@ Unread =
|
|||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
while post = posts[i]
|
while post = posts[i]
|
||||||
{bottom} = post.nodes.root.getBoundingClientRect()
|
if post.nodes.root.getBoundingClientRect().bottom < height # post is not completely read
|
||||||
if bottom < height # post is completely read
|
|
||||||
{ID} = post
|
{ID} = post
|
||||||
if Conf['Mark Quotes of You']
|
if Conf['Mark Quotes of You']
|
||||||
if post.info.yours
|
if post.info.yours
|
||||||
@ -152,9 +149,8 @@ Unread =
|
|||||||
break
|
break
|
||||||
i++
|
i++
|
||||||
|
|
||||||
unless Conf['Quote Threading']
|
if i and !Conf['Quote Threading']
|
||||||
if i
|
posts.splice 0, i
|
||||||
posts.splice 0, i
|
|
||||||
|
|
||||||
return unless ID
|
return unless ID
|
||||||
|
|
||||||
@ -172,12 +168,9 @@ Unread =
|
|||||||
|
|
||||||
setLine: (force) ->
|
setLine: (force) ->
|
||||||
return unless d.hidden or force is true
|
return unless d.hidden or force is true
|
||||||
if post = Unread.posts[0]
|
return $.rm Unread.hr unless post = Unread.posts[0]
|
||||||
{root} = post.nodes
|
if $.x 'preceding-sibling::div[contains(@class,"replyContainer")]', post.nodes.root # not the first reply
|
||||||
if root isnt $ '.thread > .replyContainer', root.parentNode # not the first reply
|
$.before post.nodes.root, Unread.hr
|
||||||
$.before root, Unread.hr
|
|
||||||
else
|
|
||||||
$.rm Unread.hr
|
|
||||||
|
|
||||||
update: <% if (type === 'crx') { %>(dontrepeat) <% } %>->
|
update: <% if (type === 'crx') { %>(dontrepeat) <% } %>->
|
||||||
count = Unread.posts.length
|
count = Unread.posts.length
|
||||||
@ -189,18 +182,18 @@ Unread =
|
|||||||
# crbug.com/124381
|
# crbug.com/124381
|
||||||
# Call it one second later,
|
# Call it one second later,
|
||||||
# but don't display outdated unread count.
|
# but don't display outdated unread count.
|
||||||
unless dontrepeat
|
return if dontrepeat
|
||||||
setTimeout ->
|
setTimeout ->
|
||||||
d.title = ''
|
d.title = ''
|
||||||
Unread.update true
|
Unread.update true
|
||||||
, $.SECOND
|
, $.SECOND
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
return unless Conf['Unread Favicon']
|
return unless Conf['Unread Favicon']
|
||||||
|
|
||||||
Favicon.el.href =
|
Favicon.el.href =
|
||||||
if g.DEAD
|
if g.DEAD
|
||||||
if Unread.postsQuotingYou.length
|
if Unread.postsQuotingYou[0]
|
||||||
Favicon.unreadDeadY
|
Favicon.unreadDeadY
|
||||||
else if count
|
else if count
|
||||||
Favicon.unreadDead
|
Favicon.unreadDead
|
||||||
@ -208,7 +201,7 @@ Unread =
|
|||||||
Favicon.dead
|
Favicon.dead
|
||||||
else
|
else
|
||||||
if count
|
if count
|
||||||
if Unread.postsQuotingYou.length
|
if Unread.postsQuotingYou[0]
|
||||||
Favicon.unreadY
|
Favicon.unreadY
|
||||||
else
|
else
|
||||||
Favicon.unread
|
Favicon.unread
|
||||||
|
|||||||
@ -165,7 +165,7 @@ QR =
|
|||||||
setTimeout ->
|
setTimeout ->
|
||||||
notif.onclose = null
|
notif.onclose = null
|
||||||
notif.close()
|
notif.close()
|
||||||
, 5 * $.SECOND
|
, 7 * $.SECOND
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
notifications: []
|
notifications: []
|
||||||
@ -448,69 +448,56 @@ QR =
|
|||||||
return unless e.dataTransfer.files.length
|
return unless e.dataTransfer.files.length
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
QR.open()
|
QR.open()
|
||||||
QR.fileInput e.dataTransfer.files
|
QR.handleFiles e.dataTransfer.files
|
||||||
$.addClass QR.nodes.el, 'dump'
|
$.addClass QR.nodes.el, 'dump'
|
||||||
|
|
||||||
paste: (e) ->
|
paste: (e) ->
|
||||||
files = []
|
files = []
|
||||||
for item in e.clipboardData.items
|
for item in e.clipboardData.items when item.kind is 'file'
|
||||||
if item.kind is 'file'
|
blob = item.getAsFile()
|
||||||
blob = item.getAsFile()
|
blob.name = 'file'
|
||||||
blob.name = 'file'
|
blob.name += '.' + blob.type.split('/')[1] if blob.type
|
||||||
blob.name += '.' + blob.type.split('/')[1] if blob.type
|
files.push blob
|
||||||
files.push blob
|
|
||||||
return unless files.length
|
return unless files.length
|
||||||
QR.open()
|
QR.open()
|
||||||
QR.fileInput files
|
QR.handleFiles files
|
||||||
|
|
||||||
openFileInput: (e) ->
|
|
||||||
e.stopPropagation()
|
|
||||||
if e.shiftKey and e.type is 'click'
|
|
||||||
return QR.selected.rmFile()
|
|
||||||
if e.ctrlKey and e.type is 'click'
|
|
||||||
$.addClass QR.nodes.filename, 'edit'
|
|
||||||
QR.nodes.filename.focus()
|
|
||||||
return $.on QR.nodes.filename, 'blur', -> $.rmClass QR.nodes.filename, 'edit'
|
|
||||||
return if e.target.nodeName is 'INPUT' or (e.keyCode and not [32, 13].contains e.keyCode) or e.ctrlKey
|
|
||||||
e.preventDefault()
|
|
||||||
QR.nodes.fileInput.click()
|
|
||||||
|
|
||||||
fileInput: (files) ->
|
|
||||||
if @ instanceof Element # file input, revert to "files instanceof Event" after a Pale Moon update
|
|
||||||
files = [@files...]
|
|
||||||
QR.nodes.fileInput.value = null # Don't hold the files from being modified on windows
|
|
||||||
{length} = files
|
|
||||||
return unless length
|
|
||||||
max = QR.nodes.fileInput.max
|
|
||||||
QR.cleanNotifications()
|
|
||||||
# Set or change current post's file.
|
|
||||||
if length is 1
|
|
||||||
file = files[0]
|
|
||||||
if /^text/.test file.type
|
|
||||||
QR.selected.pasteText file
|
|
||||||
else if file.size > max
|
|
||||||
QR.error "File too large (file: #{$.bytesToString file.size}, max: #{$.bytesToString max})."
|
|
||||||
else unless QR.mimeTypes.contains file.type
|
|
||||||
QR.error 'Unsupported file type.'
|
|
||||||
else
|
|
||||||
QR.selected.setFile file
|
|
||||||
return
|
|
||||||
# Create new posts with these files.
|
|
||||||
for file in files
|
|
||||||
if /^text/.test file.type
|
|
||||||
if (post = QR.posts[QR.posts.length - 1]).com
|
|
||||||
post = new QR.post()
|
|
||||||
post.pasteText file
|
|
||||||
else if file.size > max
|
|
||||||
QR.error "#{file.name}: File too large (file: #{$.bytesToString file.size}, max: #{$.bytesToString max})."
|
|
||||||
else unless QR.mimeTypes.contains file.type
|
|
||||||
QR.error "#{file.name}: Unsupported file type."
|
|
||||||
else
|
|
||||||
if (post = QR.posts[QR.posts.length - 1]).file
|
|
||||||
post = new QR.post()
|
|
||||||
post.setFile file
|
|
||||||
$.addClass QR.nodes.el, 'dump'
|
$.addClass QR.nodes.el, 'dump'
|
||||||
|
|
||||||
|
handleFiles: (files) ->
|
||||||
|
if @ isnt QR # file input
|
||||||
|
files = [@files...]
|
||||||
|
@value = null
|
||||||
|
return unless files.length
|
||||||
|
max = QR.nodes.fileInput.max
|
||||||
|
isSingle = files.length is 1
|
||||||
|
QR.cleanNotifications()
|
||||||
|
for file in files
|
||||||
|
QR.handleFile file, isSingle, max
|
||||||
|
$.addClass QR.nodes.el, 'dump' unless isSingle
|
||||||
|
|
||||||
|
handleFile: (file, isSingle, max) ->
|
||||||
|
if file.size > max
|
||||||
|
QR.error "#{file.name}: File too large (file: #{$.bytesToString file.size}, max: #{$.bytesToString max})."
|
||||||
|
return
|
||||||
|
else unless QR.mimeTypes.contains file.type
|
||||||
|
unless /^text/.test file.type
|
||||||
|
QR.error "#{file.name}: Unsupported file type."
|
||||||
|
return
|
||||||
|
if isSingle
|
||||||
|
post = QR.selected
|
||||||
|
else if (post = QR.posts[QR.posts.length - 1]).com
|
||||||
|
post = new QR.post()
|
||||||
|
post.pasteText file
|
||||||
|
return
|
||||||
|
if isSingle
|
||||||
|
post = QR.selected
|
||||||
|
else if (post = QR.posts[QR.posts.length - 1]).file
|
||||||
|
post = new QR.post()
|
||||||
|
post.setFile file
|
||||||
|
|
||||||
|
openFileInput: ->
|
||||||
|
QR.nodes.fileInput.click()
|
||||||
|
|
||||||
posts: []
|
posts: []
|
||||||
|
|
||||||
post: class
|
post: class
|
||||||
@ -748,7 +735,9 @@ QR =
|
|||||||
@nodes.span.textContent = @com
|
@nodes.span.textContent = @com
|
||||||
reader.readAsText file
|
reader.readAsText file
|
||||||
|
|
||||||
dragStart: -> $.addClass @, 'drag'
|
dragStart: (e) ->
|
||||||
|
e.dataTransfer.setDragImage @, e.layerX, e.layerY
|
||||||
|
$.addClass @, 'drag'
|
||||||
dragEnd: -> $.rmClass @, 'drag'
|
dragEnd: -> $.rmClass @, 'drag'
|
||||||
dragEnter: -> $.addClass @, 'over'
|
dragEnter: -> $.addClass @, 'over'
|
||||||
dragLeave: -> $.rmClass @, 'over'
|
dragLeave: -> $.rmClass @, 'over'
|
||||||
@ -987,7 +976,7 @@ QR =
|
|||||||
$.on nodes.fileRM, 'click', -> QR.selected.rmFile()
|
$.on nodes.fileRM, 'click', -> QR.selected.rmFile()
|
||||||
$.on nodes.fileExtras, 'click', (e) -> e.stopPropagation()
|
$.on nodes.fileExtras, 'click', (e) -> e.stopPropagation()
|
||||||
$.on nodes.spoiler, 'change', -> QR.selected.nodes.spoiler.click()
|
$.on nodes.spoiler, 'change', -> QR.selected.nodes.spoiler.click()
|
||||||
$.on nodes.fileInput, 'change', QR.fileInput
|
$.on nodes.fileInput, 'change', QR.handleFiles
|
||||||
# save selected post's data
|
# save selected post's data
|
||||||
items = ['name', 'email', 'sub', 'com', 'filename']
|
items = ['name', 'email', 'sub', 'com', 'filename']
|
||||||
i = 0
|
i = 0
|
||||||
@ -1213,7 +1202,19 @@ QR =
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Enable auto-posting if we have stuff to post, disable it otherwise.
|
# Enable auto-posting if we have stuff to post, disable it otherwise.
|
||||||
QR.cooldown.auto = QR.posts.length > 1 and isReply
|
postsCount = QR.posts.length
|
||||||
|
QR.cooldown.auto = postsCount > 1 and isReply
|
||||||
|
if QR.cooldown.auto and QR.captcha.isEnabled and (captchasCount = QR.captcha.captchas.length) < 3 and captchasCount < postsCount
|
||||||
|
notif = new Notification 'Quick reply warning',
|
||||||
|
body: "You are running low on cached captchas. Cache count: #{captchasCount}."
|
||||||
|
icon: Favicon.logo
|
||||||
|
notif.onclick = ->
|
||||||
|
QR.open()
|
||||||
|
QR.captcha.nodes.input.focus()
|
||||||
|
window.focus()
|
||||||
|
setTimeout ->
|
||||||
|
notif.close()
|
||||||
|
, 7 * $.SECOND
|
||||||
|
|
||||||
unless Conf['Persistent QR'] or QR.cooldown.auto
|
unless Conf['Persistent QR'] or QR.cooldown.auto
|
||||||
QR.close()
|
QR.close()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user