Merge branch 'v3' into Av2
Conflicts: LICENSE builds/4chan-X.meta.js builds/4chan-X.user.js builds/crx/manifest.json builds/crx/script.js builds/version package.json src/General/Main.coffee src/General/css/style.css src/Posting/QuickReply.coffee src/Quotelinks/QuoteInline.coffee
This commit is contained in:
commit
93b94ec9d0
39
CHANGELOG.md
39
CHANGELOG.md
@ -1,7 +1,33 @@
|
||||
### 1.1.13 - 2013-05-06
|
||||
seaweedchan:
|
||||
- Disable settings removing scroll bar when opened, thus fixing the issue where it jumps up the page randomly
|
||||
- Hide watcher by default, add [Watcher] shortcut.
|
||||
|
||||
### 1.1.12 - 2013-05-06
|
||||
detharonil
|
||||
- Support for %Y in time formatting
|
||||
- More future-proof %y
|
||||
|
||||
MayhemYDG:
|
||||
- Fix whitespaces not being preserved in code tags in /g/.
|
||||
|
||||
seaweedchan:
|
||||
- Fix QR not being able to drag to the top with fixed header disabled
|
||||
|
||||
zixaphir:
|
||||
- Fix custom CSS
|
||||
- Fix [Deleted] showing up randomly after submitting a post
|
||||
|
||||
### 1.1.11 - 2013-05-04
|
||||
seaweedchan:
|
||||
- Add `Highlight Posts Quoting You` option
|
||||
- Add 'catalog', 'index', or 'thread' classes to document depending on what's open
|
||||
- Add `Filtered Backlinks` options that when disabled, hides filtered backlinks
|
||||
|
||||
### 1.1.10 - 2013-05-03
|
||||
seaweedchan:
|
||||
- Fix update checking
|
||||
|
||||
### 1.1.9 - 2013-05-02
|
||||
seaweedchan
|
||||
- Fix boards with previously deleted archives not switching to new archives
|
||||
@ -25,7 +51,6 @@ seaweedchan:
|
||||
- Add paste.installgentoo.com embedding
|
||||
- Added `Posting Success Notifications` option to make "Post Successful!" and "_____ uploaded" notifications optional
|
||||
- Added `Allow False Positives` option under Linkification, giving the user more control over what's linkified.
|
||||
- Fix URL for update checking
|
||||
|
||||
### 1.1.6 - 2013-05-01
|
||||
seaweedchan:
|
||||
@ -62,18 +87,6 @@ seaweedchan:
|
||||
- Toggle keybind for header auto-hiding
|
||||
|
||||
MayhemYDG:
|
||||
=======
|
||||
- Access it in the `QR` tab of the Settings window.
|
||||
- Updated archive redirection for /h/, /v/ and /vg/.
|
||||
|
||||
### 3.2.3 - *2013-04-30*
|
||||
|
||||
- Update archive redirection for /c/, /d/, /v/, /vg/, /w/ and /wg/.
|
||||
- Minor fixes.
|
||||
|
||||
### 3.2.2 - *2013-04-27*
|
||||
|
||||
>>>>>>> b74e0c92fdf2d755d996cb574dddb3c8d964e91a
|
||||
- Fix Unread Count taking into account hidden posts.
|
||||
|
||||
### 1.1.2 - 2013-04-26
|
||||
|
||||
@ -43,7 +43,7 @@ module.exports = (grunt) ->
|
||||
options: concatOptions
|
||||
files:
|
||||
'LICENSE': 'src/General/meta/banner.js',
|
||||
'builds/version': 'src/General/meta/version.js'
|
||||
'latest.js': 'src/General/meta/latest.js'
|
||||
|
||||
crx:
|
||||
options: concatOptions
|
||||
|
||||
File diff suppressed because one or more lines are too long
19
builds/4chan-X.meta.js
Normal file
19
builds/4chan-X.meta.js
Normal file
@ -0,0 +1,19 @@
|
||||
// ==UserScript==
|
||||
// @name 4chan X
|
||||
// @version 1.1.13
|
||||
// @namespace 4chan-X
|
||||
// @description Cross-browser userscript for maximum lurking on 4chan.
|
||||
// @license MIT; https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
||||
// @match *://api.4chan.org/*
|
||||
// @match *://boards.4chan.org/*
|
||||
// @match *://images.4chan.org/*
|
||||
// @match *://sys.4chan.org/*
|
||||
// @grant GM_getValue
|
||||
// @grant GM_setValue
|
||||
// @grant GM_deleteValue
|
||||
// @grant GM_openInTab
|
||||
// @run-at document-start
|
||||
// @updateURL https://github.com/seaweedchan/4chan-x/raw/stable/builds/4chan_X.meta.js
|
||||
// @downloadURL https://github.com/seaweedchan/4chan-x/raw/stable/builds/4chan_X.user.js
|
||||
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC
|
||||
// ==/UserScript==
|
||||
10256
builds/4chan-X.user.js
Normal file
10256
builds/4chan-X.user.js
Normal file
File diff suppressed because one or more lines are too long
@ -118,7 +118,7 @@
|
||||
__slice = [].slice,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||
|
||||
Config = {
|
||||
main: {
|
||||
@ -154,6 +154,7 @@
|
||||
'Recursive Hiding': [true, 'Hide replies of hidden posts, recursively.'],
|
||||
'Thread Hiding Buttons': [true, 'Add buttons to hide entire threads.'],
|
||||
'Reply Hiding Buttons': [true, 'Add buttons to hide single replies.'],
|
||||
'Filtered Backlinks': [true, 'When enabled, shows backlinks to filtered posts with a line-through decoration. Otherwise, hides the backlinks.'],
|
||||
'Stubs': [true, 'Show stubs of hidden threads / replies.']
|
||||
},
|
||||
'Images': {
|
||||
@ -204,11 +205,13 @@
|
||||
'Quote Backlinks': [true, 'Add quote backlinks.'],
|
||||
'OP Backlinks': [true, 'Add backlinks to the OP.'],
|
||||
'Quote Inlining': [true, 'Inline quoted post on click.'],
|
||||
'Quote Hash Navigation': [false, 'Include an extra link after quotes for autoscrolling to quoted posts.'],
|
||||
'Forward Hiding': [true, 'Hide original posts of inlined backlinks.'],
|
||||
'Quote Previewing': [true, 'Show quoted post on hover.'],
|
||||
'Quote Highlighting': [true, 'Highlight the previewed post.'],
|
||||
'Resurrect Quotes': [true, 'Link dead quotes to the archives.'],
|
||||
'Mark Quotes of You': [true, 'Add \'(You)\' to quotes linking to your posts.'],
|
||||
'Highlight Posts Quoting You': [false, 'Highlights any posts that contain a quote to your post.'],
|
||||
'Highlight Own Posts': [false, 'Highlights own posts if Mark Quotes of You is enabled.'],
|
||||
'Mark OP Quotes': [true, 'Add \'(OP)\' to OP quotes.'],
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.'],
|
||||
@ -3574,12 +3577,10 @@
|
||||
})();
|
||||
|
||||
Notification = (function() {
|
||||
var add, close;
|
||||
|
||||
function Notification(type, content, timeout) {
|
||||
this.timeout = timeout;
|
||||
this.add = add.bind(this);
|
||||
this.close = close.bind(this);
|
||||
this.close = __bind(this.close, this);
|
||||
this.add = __bind(this.add, this);
|
||||
this.el = $.el('div', {
|
||||
innerHTML: '<a href=javascript:; class=close title=Close>×</a><div class=message></div>'
|
||||
});
|
||||
@ -3597,7 +3598,7 @@
|
||||
return this.el.className = "notification " + type;
|
||||
};
|
||||
|
||||
add = function() {
|
||||
Notification.prototype.add = function() {
|
||||
if (d.hidden) {
|
||||
$.on(d, 'visibilitychange', this.add);
|
||||
return;
|
||||
@ -3611,7 +3612,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
close = function() {
|
||||
Notification.prototype.close = function() {
|
||||
return $.rm(this.el);
|
||||
};
|
||||
|
||||
@ -4653,7 +4654,7 @@
|
||||
screenWidth: screenWidth,
|
||||
isTouching: isTouching
|
||||
};
|
||||
_ref = Conf['Header auto-hide'] ? [0, 0] : Conf['Bottom Header'] ? [0, Header.bar.getBoundingClientRect().height] : [Header.bar.getBoundingClientRect().height, 0], o.topBorder = _ref[0], o.bottomBorder = _ref[1];
|
||||
_ref = Conf['Header auto-hide'] || !Conf['Fixed Header'] ? [0, 0] : Conf['Bottom Header'] ? [0, Header.bar.getBoundingClientRect().height] : [Header.bar.getBoundingClientRect().height, 0], o.topBorder = _ref[0], o.bottomBorder = _ref[1];
|
||||
if (isTouching) {
|
||||
o.identifier = e.identifier;
|
||||
o.move = touchmove.bind(o);
|
||||
@ -4821,6 +4822,9 @@
|
||||
if (g.VIEW === 'catalog' || !Conf['Filter']) {
|
||||
return;
|
||||
}
|
||||
if (!Conf['Filtered Backlinks']) {
|
||||
$.addClass(doc, 'hide-backlinks');
|
||||
}
|
||||
for (key in Config.filter) {
|
||||
this.filters[key] = [];
|
||||
_ref = Conf[key].split('\n');
|
||||
@ -5685,7 +5689,7 @@
|
||||
});
|
||||
},
|
||||
firstNode: function() {
|
||||
var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
||||
var a, clone, container, containers, frag, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
||||
|
||||
if (this.isClone || !this.quotes.length) {
|
||||
return;
|
||||
@ -5708,14 +5712,17 @@
|
||||
}
|
||||
for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
|
||||
container = containers[_k];
|
||||
link = a.cloneNode(true);
|
||||
frag = [$.tn(' '), link = a.cloneNode(true)];
|
||||
if (Conf['Quote Previewing']) {
|
||||
$.on(link, 'mouseover', QuotePreview.mouseover);
|
||||
}
|
||||
if (Conf['Quote Inlining']) {
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
if (Conf['Quote Hash Navigation']) {
|
||||
frag.pushArrays(QuoteInline.qiQuote(link, $.hasClass(link, 'filtered')));
|
||||
}
|
||||
}
|
||||
$.add(container, [$.tn(' '), link]);
|
||||
$.add(container, frag);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -5791,19 +5798,43 @@
|
||||
if (Conf['Comment Expansion']) {
|
||||
ExpandComment.callbacks.push(this.node);
|
||||
}
|
||||
if (Conf['Quote Hash Navigation']) {
|
||||
this.node = function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
if (!this.isClone) {
|
||||
$.after(link, QuoteInline.qiQuote(link, $.hasClass(link, 'filtered')));
|
||||
}
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
this.node = function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
};
|
||||
}
|
||||
return Post.prototype.callbacks.push({
|
||||
name: 'Quote Inlining',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
node: function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
qiQuote: function(link, hidden) {
|
||||
return [
|
||||
$.tn(' '), $.el('a', {
|
||||
className: hidden ? 'hashlink filtered' : 'hashlink',
|
||||
textContent: '#',
|
||||
href: link.href
|
||||
})
|
||||
];
|
||||
},
|
||||
toggle: function(e) {
|
||||
var boardID, context, postID, threadID, _ref;
|
||||
@ -6212,6 +6243,9 @@
|
||||
if (Conf['Highlight Own Posts']) {
|
||||
$.addClass(doc, 'highlight-own');
|
||||
}
|
||||
if (Conf['Highlight Posts Quoting You']) {
|
||||
$.addClass(doc, 'highlight-you');
|
||||
}
|
||||
if (!(quotes = this.quotes).length) {
|
||||
return;
|
||||
}
|
||||
@ -6220,6 +6254,7 @@
|
||||
quotelink = quotelinks[_i];
|
||||
if (QR.db.get(Get.postDataFromLink(quotelink))) {
|
||||
$.add(quotelink, $.tn(QuoteYou.text));
|
||||
$.addClass(this.nodes.root, 'quotesYou');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6854,7 +6889,7 @@
|
||||
});
|
||||
},
|
||||
parseItem: function(item, types) {
|
||||
var boards, match, type, val, _ref, _ref1, _ref2;
|
||||
var boards, match, type, val, _ref, _ref1;
|
||||
|
||||
if (item[0] === '#') {
|
||||
return;
|
||||
@ -6865,7 +6900,7 @@
|
||||
_ref = match, match = _ref[0], type = _ref[1], val = _ref[2];
|
||||
item = item.replace(match, '');
|
||||
boards = ((_ref1 = item.match(/boards:([^;]+)/i)) != null ? _ref1[1].toLowerCase() : void 0) || 'global';
|
||||
if (boards !== 'global' && !(_ref2 = g.BOARD.ID, __indexOf.call(boards.split(','), _ref2) >= 0)) {
|
||||
if (boards !== 'global' && !((boards.split(',')).contains(g.BOARD.ID))) {
|
||||
return;
|
||||
}
|
||||
if (type === 'password') {
|
||||
@ -6878,7 +6913,7 @@
|
||||
if (/always/i.test(item)) {
|
||||
QR.persona.always[type] = val;
|
||||
}
|
||||
if (__indexOf.call(types[type], val) < 0) {
|
||||
if (!types[type].contains(val)) {
|
||||
return types[type].push(val);
|
||||
}
|
||||
},
|
||||
@ -8933,7 +8968,9 @@
|
||||
innerHTML: "<span id=post-count>0</span> / <span id=file-count>0</span>",
|
||||
id: 'thread-stats'
|
||||
});
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
return Header.addShortcut(sc);
|
||||
});
|
||||
} else {
|
||||
this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "<div class=move><span id=post-count>0</span> / <span id=file-count>0</span></div>");
|
||||
$.ready(function() {
|
||||
@ -8998,7 +9035,9 @@
|
||||
innerHTML: "<span id=update-status></span><span id=update-timer title='Update now'></span>",
|
||||
id: 'updater'
|
||||
});
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
return Header.addShortcut(sc);
|
||||
});
|
||||
} else {
|
||||
this.dialog = sc = UI.dialog('updater', 'bottom: 0px; left: 0px;', "<div class=move></div><span id=update-status></span><span id=update-timer title='Update now'></span>");
|
||||
$.addClass(doc, 'float');
|
||||
@ -9096,10 +9135,19 @@
|
||||
return setTimeout(ThreadUpdater.update, 1000);
|
||||
}
|
||||
},
|
||||
checkpost: function() {
|
||||
checkpost: function(e) {
|
||||
if (!ThreadUpdater.checkPostCount) {
|
||||
if (e.detail.threadID !== ThreadUpdater.thread.ID) {
|
||||
return;
|
||||
}
|
||||
ThreadUpdater.seconds = 0;
|
||||
ThreadUpdater.outdateCount = 0;
|
||||
ThreadUpdater.set('timer', '...');
|
||||
}
|
||||
if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) {
|
||||
return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
|
||||
}
|
||||
ThreadUpdater.set('timer', ThreadUpdater.getInterval());
|
||||
ThreadUpdater.checkPostCount = 0;
|
||||
delete ThreadUpdater.foundPost;
|
||||
return delete ThreadUpdater.postID;
|
||||
@ -9384,13 +9432,28 @@
|
||||
|
||||
ThreadWatcher = {
|
||||
init: function() {
|
||||
var sc;
|
||||
|
||||
if (!Conf['Thread Watcher']) {
|
||||
return;
|
||||
}
|
||||
this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '<div class=move>Thread Watcher</div>');
|
||||
this.shortcut = sc = $.el('a', {
|
||||
textContent: 'Watcher',
|
||||
id: 'watcher-link',
|
||||
href: 'javascript:;',
|
||||
className: 'disabled'
|
||||
});
|
||||
this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '<div class=move>Thread Watcher<a class=close href=javascript:;>×</a></div>');
|
||||
$.on(d, 'QRPostSuccessful', this.cb.post);
|
||||
$.on(d, '4chanXInitFinished', this.ready);
|
||||
$.sync('WatchedThreads', this.refresh);
|
||||
$.on(sc, 'click', this.toggleWatcher);
|
||||
$.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher);
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
ThreadWatcher.refresh();
|
||||
$.add(d.body, ThreadWatcher.dialog);
|
||||
return ThreadWatcher.dialog.hidden = true;
|
||||
});
|
||||
return Thread.prototype.callbacks.push({
|
||||
name: 'Thread Watcher',
|
||||
cb: this.node
|
||||
@ -9416,14 +9479,6 @@
|
||||
return $["delete"]('AutoWatch');
|
||||
});
|
||||
},
|
||||
ready: function() {
|
||||
$.off(d, '4chanXInitFinished', ThreadWatcher.ready);
|
||||
if (!Main.isThisPageLegit()) {
|
||||
return;
|
||||
}
|
||||
ThreadWatcher.refresh();
|
||||
return $.add(d.body, ThreadWatcher.dialog);
|
||||
},
|
||||
refresh: function(watched) {
|
||||
var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
|
||||
|
||||
@ -9461,6 +9516,10 @@
|
||||
favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
|
||||
}
|
||||
},
|
||||
toggleWatcher: function() {
|
||||
$.toggleClass(ThreadWatcher.shortcut, 'disabled');
|
||||
return ThreadWatcher.dialog.hidden = !ThreadWatcher.dialog.hidden;
|
||||
},
|
||||
cb: {
|
||||
toggle: function() {
|
||||
return ThreadWatcher.toggle(Get.postFromNode(this).thread);
|
||||
@ -9546,7 +9605,10 @@
|
||||
});
|
||||
$.on(d, '4chanXInitFinished', Unread.ready);
|
||||
$.on(d, 'ThreadUpdate', Unread.onUpdate);
|
||||
return $.on(d, 'scroll visibilitychange', Unread.read);
|
||||
$.on(d, 'scroll visibilitychange', Unread.read);
|
||||
if (Conf['Unread Line']) {
|
||||
return $.on(d, 'visibilitychange', Unread.setLine);
|
||||
}
|
||||
},
|
||||
ready: function() {
|
||||
var ID, post, posts, _ref;
|
||||
@ -9561,9 +9623,6 @@
|
||||
}
|
||||
}
|
||||
Unread.addPosts(posts);
|
||||
if (Conf['Unread Line']) {
|
||||
Unread.setLine();
|
||||
}
|
||||
if (Conf['Scroll to Last Read Post']) {
|
||||
return Unread.scroll();
|
||||
}
|
||||
@ -12207,7 +12266,7 @@
|
||||
}
|
||||
board = g.BOARD.ID;
|
||||
if (board === 'g') {
|
||||
$.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
|
||||
$.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML.replace(/\\s/g, ' '));\n}, false);");
|
||||
Post.prototype.callbacks.push({
|
||||
name: 'Parse /g/ code',
|
||||
cb: this.code
|
||||
@ -12230,7 +12289,9 @@
|
||||
_ref = $$('.prettyprint', this.nodes.comment);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
pre = _ref[_i];
|
||||
$.event('prettyprint', pre, window);
|
||||
if (!$('.pln', pre)) {
|
||||
$.event('prettyprint', pre, window);
|
||||
}
|
||||
}
|
||||
},
|
||||
math: function() {
|
||||
@ -13087,16 +13148,12 @@
|
||||
(sectionToOpen ? sectionToOpen : links[0]).click();
|
||||
$.on($('.close', dialog), 'click', Settings.close);
|
||||
$.on(overlay, 'click', Settings.close);
|
||||
d.body.style.width = "" + d.body.clientWidth + "px";
|
||||
$.addClass(d.body, 'unscroll');
|
||||
return $.add(d.body, [overlay, dialog]);
|
||||
},
|
||||
close: function() {
|
||||
if (!Settings.dialog) {
|
||||
return;
|
||||
}
|
||||
d.body.style.removeProperty('width');
|
||||
$.rmClass(d.body, 'unscroll');
|
||||
$.rm(Settings.overlay);
|
||||
$.rm(Settings.dialog);
|
||||
delete Settings.overlay;
|
||||
@ -13468,11 +13525,14 @@
|
||||
|
||||
for (key in items) {
|
||||
val = items[key];
|
||||
if (['usercss', 'emojiPos', 'archiver'].contains(key)) {
|
||||
if (['emojiPos', 'archiver'].contains(key)) {
|
||||
continue;
|
||||
}
|
||||
input = inputs[key];
|
||||
input.value = val;
|
||||
if (key === 'usercss') {
|
||||
continue;
|
||||
}
|
||||
$.on(input, event, Settings[key]);
|
||||
Settings[key].call(input);
|
||||
}
|
||||
@ -14416,6 +14476,17 @@
|
||||
obj.callback.isAddon = true;
|
||||
return Klass.prototype.callbacks.push(obj.callback);
|
||||
},
|
||||
message: function(e) {
|
||||
var el, version;
|
||||
|
||||
version = e.data.version;
|
||||
if (version && version !== g.VERSION) {
|
||||
el = $.el('span', {
|
||||
innerHTML: "Update: appchan x v" + version + " is out, get it <a href=http://zixaphir.github.com/appchan-x/ target=_blank>here</a>."
|
||||
});
|
||||
return new Notification('info', el, 120);
|
||||
}
|
||||
},
|
||||
checkUpdate: function() {
|
||||
var freq, items, now;
|
||||
|
||||
@ -14432,27 +14503,12 @@
|
||||
if (items.lastupdate > now - freq || items.lastchecked > now - $.DAY) {
|
||||
return;
|
||||
}
|
||||
return $.ajax('https://github.com/zixaphir/appchan-x/raw/Av2/builds/version', {
|
||||
onload: function() {
|
||||
var el, version;
|
||||
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
version = this.response;
|
||||
if (!/^\d\.\d+\.\d+$/.test(version)) {
|
||||
return;
|
||||
}
|
||||
if (g.VERSION === version) {
|
||||
$.set('lastupdate', now);
|
||||
return;
|
||||
}
|
||||
$.set('lastchecked', now);
|
||||
el = $.el('span', {
|
||||
innerHTML: "Update: appchan x v" + version + " is out, get it <a href=http://zixaphir.github.com/appchan-x/ target=_blank>here</a>."
|
||||
});
|
||||
return new Notification('info', el, 120);
|
||||
}
|
||||
return $.ready(function() {
|
||||
$.on(window, 'message', Main.message);
|
||||
$.set('lastUpdate', now);
|
||||
return $.add(d.head, $.el('script', {
|
||||
src: 'https://github.com/zixaphir/appchan-x/raw/Av2/latest.js'
|
||||
}));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@ -118,7 +118,7 @@
|
||||
__slice = [].slice,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||
|
||||
Config = {
|
||||
main: {
|
||||
@ -154,6 +154,7 @@
|
||||
'Recursive Hiding': [true, 'Hide replies of hidden posts, recursively.'],
|
||||
'Thread Hiding Buttons': [true, 'Add buttons to hide entire threads.'],
|
||||
'Reply Hiding Buttons': [true, 'Add buttons to hide single replies.'],
|
||||
'Filtered Backlinks': [true, 'When enabled, shows backlinks to filtered posts with a line-through decoration. Otherwise, hides the backlinks.'],
|
||||
'Stubs': [true, 'Show stubs of hidden threads / replies.']
|
||||
},
|
||||
'Images': {
|
||||
@ -205,11 +206,13 @@
|
||||
'Quote Backlinks': [true, 'Add quote backlinks.'],
|
||||
'OP Backlinks': [true, 'Add backlinks to the OP.'],
|
||||
'Quote Inlining': [true, 'Inline quoted post on click.'],
|
||||
'Quote Hash Navigation': [false, 'Include an extra link after quotes for autoscrolling to quoted posts.'],
|
||||
'Forward Hiding': [true, 'Hide original posts of inlined backlinks.'],
|
||||
'Quote Previewing': [true, 'Show quoted post on hover.'],
|
||||
'Quote Highlighting': [true, 'Highlight the previewed post.'],
|
||||
'Resurrect Quotes': [true, 'Link dead quotes to the archives.'],
|
||||
'Mark Quotes of You': [true, 'Add \'(You)\' to quotes linking to your posts.'],
|
||||
'Highlight Posts Quoting You': [false, 'Highlights any posts that contain a quote to your post.'],
|
||||
'Highlight Own Posts': [false, 'Highlights own posts if Mark Quotes of You is enabled.'],
|
||||
'Mark OP Quotes': [true, 'Add \'(OP)\' to OP quotes.'],
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.'],
|
||||
@ -3570,12 +3573,10 @@
|
||||
})();
|
||||
|
||||
Notification = (function() {
|
||||
var add, close;
|
||||
|
||||
function Notification(type, content, timeout) {
|
||||
this.timeout = timeout;
|
||||
this.add = add.bind(this);
|
||||
this.close = close.bind(this);
|
||||
this.close = __bind(this.close, this);
|
||||
this.add = __bind(this.add, this);
|
||||
this.el = $.el('div', {
|
||||
innerHTML: '<a href=javascript:; class=close title=Close>×</a><div class=message></div>'
|
||||
});
|
||||
@ -3593,7 +3594,7 @@
|
||||
return this.el.className = "notification " + type;
|
||||
};
|
||||
|
||||
add = function() {
|
||||
Notification.prototype.add = function() {
|
||||
if (d.hidden) {
|
||||
$.on(d, 'visibilitychange', this.add);
|
||||
return;
|
||||
@ -3607,7 +3608,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
close = function() {
|
||||
Notification.prototype.close = function() {
|
||||
return $.rm(this.el);
|
||||
};
|
||||
|
||||
@ -4649,7 +4650,7 @@
|
||||
screenWidth: screenWidth,
|
||||
isTouching: isTouching
|
||||
};
|
||||
_ref = Conf['Header auto-hide'] ? [0, 0] : Conf['Bottom Header'] ? [0, Header.bar.getBoundingClientRect().height] : [Header.bar.getBoundingClientRect().height, 0], o.topBorder = _ref[0], o.bottomBorder = _ref[1];
|
||||
_ref = Conf['Header auto-hide'] || !Conf['Fixed Header'] ? [0, 0] : Conf['Bottom Header'] ? [0, Header.bar.getBoundingClientRect().height] : [Header.bar.getBoundingClientRect().height, 0], o.topBorder = _ref[0], o.bottomBorder = _ref[1];
|
||||
if (isTouching) {
|
||||
o.identifier = e.identifier;
|
||||
o.move = touchmove.bind(o);
|
||||
@ -4817,6 +4818,9 @@
|
||||
if (g.VIEW === 'catalog' || !Conf['Filter']) {
|
||||
return;
|
||||
}
|
||||
if (!Conf['Filtered Backlinks']) {
|
||||
$.addClass(doc, 'hide-backlinks');
|
||||
}
|
||||
for (key in Config.filter) {
|
||||
this.filters[key] = [];
|
||||
_ref = Conf[key].split('\n');
|
||||
@ -5681,7 +5685,7 @@
|
||||
});
|
||||
},
|
||||
firstNode: function() {
|
||||
var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
||||
var a, clone, container, containers, frag, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
||||
|
||||
if (this.isClone || !this.quotes.length) {
|
||||
return;
|
||||
@ -5704,14 +5708,17 @@
|
||||
}
|
||||
for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
|
||||
container = containers[_k];
|
||||
link = a.cloneNode(true);
|
||||
frag = [$.tn(' '), link = a.cloneNode(true)];
|
||||
if (Conf['Quote Previewing']) {
|
||||
$.on(link, 'mouseover', QuotePreview.mouseover);
|
||||
}
|
||||
if (Conf['Quote Inlining']) {
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
if (Conf['Quote Hash Navigation']) {
|
||||
frag.pushArrays(QuoteInline.qiQuote(link, $.hasClass(link, 'filtered')));
|
||||
}
|
||||
}
|
||||
$.add(container, [$.tn(' '), link]);
|
||||
$.add(container, frag);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -5787,19 +5794,43 @@
|
||||
if (Conf['Comment Expansion']) {
|
||||
ExpandComment.callbacks.push(this.node);
|
||||
}
|
||||
if (Conf['Quote Hash Navigation']) {
|
||||
this.node = function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
if (!this.isClone) {
|
||||
$.after(link, QuoteInline.qiQuote(link, $.hasClass(link, 'filtered')));
|
||||
}
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
this.node = function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
};
|
||||
}
|
||||
return Post.prototype.callbacks.push({
|
||||
name: 'Quote Inlining',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
node: function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
qiQuote: function(link, hidden) {
|
||||
return [
|
||||
$.tn(' '), $.el('a', {
|
||||
className: hidden ? 'hashlink filtered' : 'hashlink',
|
||||
textContent: '#',
|
||||
href: link.href
|
||||
})
|
||||
];
|
||||
},
|
||||
toggle: function(e) {
|
||||
var boardID, context, postID, threadID, _ref;
|
||||
@ -6208,6 +6239,9 @@
|
||||
if (Conf['Highlight Own Posts']) {
|
||||
$.addClass(doc, 'highlight-own');
|
||||
}
|
||||
if (Conf['Highlight Posts Quoting You']) {
|
||||
$.addClass(doc, 'highlight-you');
|
||||
}
|
||||
if (!(quotes = this.quotes).length) {
|
||||
return;
|
||||
}
|
||||
@ -6216,6 +6250,7 @@
|
||||
quotelink = quotelinks[_i];
|
||||
if (QR.db.get(Get.postDataFromLink(quotelink))) {
|
||||
$.add(quotelink, $.tn(QuoteYou.text));
|
||||
$.addClass(this.nodes.root, 'quotesYou');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6850,7 +6885,7 @@
|
||||
});
|
||||
},
|
||||
parseItem: function(item, types) {
|
||||
var boards, match, type, val, _ref, _ref1, _ref2;
|
||||
var boards, match, type, val, _ref, _ref1;
|
||||
|
||||
if (item[0] === '#') {
|
||||
return;
|
||||
@ -6861,7 +6896,7 @@
|
||||
_ref = match, match = _ref[0], type = _ref[1], val = _ref[2];
|
||||
item = item.replace(match, '');
|
||||
boards = ((_ref1 = item.match(/boards:([^;]+)/i)) != null ? _ref1[1].toLowerCase() : void 0) || 'global';
|
||||
if (boards !== 'global' && !(_ref2 = g.BOARD.ID, __indexOf.call(boards.split(','), _ref2) >= 0)) {
|
||||
if (boards !== 'global' && !((boards.split(',')).contains(g.BOARD.ID))) {
|
||||
return;
|
||||
}
|
||||
if (type === 'password') {
|
||||
@ -6874,7 +6909,7 @@
|
||||
if (/always/i.test(item)) {
|
||||
QR.persona.always[type] = val;
|
||||
}
|
||||
if (__indexOf.call(types[type], val) < 0) {
|
||||
if (!types[type].contains(val)) {
|
||||
return types[type].push(val);
|
||||
}
|
||||
},
|
||||
@ -8954,7 +8989,9 @@
|
||||
innerHTML: "<span id=post-count>0</span> / <span id=file-count>0</span>",
|
||||
id: 'thread-stats'
|
||||
});
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
return Header.addShortcut(sc);
|
||||
});
|
||||
} else {
|
||||
this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "<div class=move><span id=post-count>0</span> / <span id=file-count>0</span></div>");
|
||||
$.ready(function() {
|
||||
@ -9019,7 +9056,9 @@
|
||||
innerHTML: "<span id=update-status></span><span id=update-timer title='Update now'></span>",
|
||||
id: 'updater'
|
||||
});
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
return Header.addShortcut(sc);
|
||||
});
|
||||
} else {
|
||||
this.dialog = sc = UI.dialog('updater', 'bottom: 0px; left: 0px;', "<div class=move></div><span id=update-status></span><span id=update-timer title='Update now'></span>");
|
||||
$.addClass(doc, 'float');
|
||||
@ -9117,10 +9156,19 @@
|
||||
return setTimeout(ThreadUpdater.update, 1000);
|
||||
}
|
||||
},
|
||||
checkpost: function() {
|
||||
checkpost: function(e) {
|
||||
if (!ThreadUpdater.checkPostCount) {
|
||||
if (e.detail.threadID !== ThreadUpdater.thread.ID) {
|
||||
return;
|
||||
}
|
||||
ThreadUpdater.seconds = 0;
|
||||
ThreadUpdater.outdateCount = 0;
|
||||
ThreadUpdater.set('timer', '...');
|
||||
}
|
||||
if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) {
|
||||
return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
|
||||
}
|
||||
ThreadUpdater.set('timer', ThreadUpdater.getInterval());
|
||||
ThreadUpdater.checkPostCount = 0;
|
||||
delete ThreadUpdater.foundPost;
|
||||
return delete ThreadUpdater.postID;
|
||||
@ -9405,13 +9453,28 @@
|
||||
|
||||
ThreadWatcher = {
|
||||
init: function() {
|
||||
var sc;
|
||||
|
||||
if (!Conf['Thread Watcher']) {
|
||||
return;
|
||||
}
|
||||
this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '<div class=move>Thread Watcher</div>');
|
||||
this.shortcut = sc = $.el('a', {
|
||||
textContent: 'Watcher',
|
||||
id: 'watcher-link',
|
||||
href: 'javascript:;',
|
||||
className: 'disabled'
|
||||
});
|
||||
this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '<div class=move>Thread Watcher<a class=close href=javascript:;>×</a></div>');
|
||||
$.on(d, 'QRPostSuccessful', this.cb.post);
|
||||
$.on(d, '4chanXInitFinished', this.ready);
|
||||
$.sync('WatchedThreads', this.refresh);
|
||||
$.on(sc, 'click', this.toggleWatcher);
|
||||
$.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher);
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
ThreadWatcher.refresh();
|
||||
$.add(d.body, ThreadWatcher.dialog);
|
||||
return ThreadWatcher.dialog.hidden = true;
|
||||
});
|
||||
return Thread.prototype.callbacks.push({
|
||||
name: 'Thread Watcher',
|
||||
cb: this.node
|
||||
@ -9437,14 +9500,6 @@
|
||||
return $["delete"]('AutoWatch');
|
||||
});
|
||||
},
|
||||
ready: function() {
|
||||
$.off(d, '4chanXInitFinished', ThreadWatcher.ready);
|
||||
if (!Main.isThisPageLegit()) {
|
||||
return;
|
||||
}
|
||||
ThreadWatcher.refresh();
|
||||
return $.add(d.body, ThreadWatcher.dialog);
|
||||
},
|
||||
refresh: function(watched) {
|
||||
var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
|
||||
|
||||
@ -9482,6 +9537,10 @@
|
||||
favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
|
||||
}
|
||||
},
|
||||
toggleWatcher: function() {
|
||||
$.toggleClass(ThreadWatcher.shortcut, 'disabled');
|
||||
return ThreadWatcher.dialog.hidden = !ThreadWatcher.dialog.hidden;
|
||||
},
|
||||
cb: {
|
||||
toggle: function() {
|
||||
return ThreadWatcher.toggle(Get.postFromNode(this).thread);
|
||||
@ -9567,7 +9626,10 @@
|
||||
});
|
||||
$.on(d, '4chanXInitFinished', Unread.ready);
|
||||
$.on(d, 'ThreadUpdate', Unread.onUpdate);
|
||||
return $.on(d, 'scroll visibilitychange', Unread.read);
|
||||
$.on(d, 'scroll visibilitychange', Unread.read);
|
||||
if (Conf['Unread Line']) {
|
||||
return $.on(d, 'visibilitychange', Unread.setLine);
|
||||
}
|
||||
},
|
||||
ready: function() {
|
||||
var ID, post, posts, _ref;
|
||||
@ -9582,9 +9644,6 @@
|
||||
}
|
||||
}
|
||||
Unread.addPosts(posts);
|
||||
if (Conf['Unread Line']) {
|
||||
Unread.setLine();
|
||||
}
|
||||
if (Conf['Scroll to Last Read Post']) {
|
||||
return Unread.scroll();
|
||||
}
|
||||
@ -12228,7 +12287,7 @@
|
||||
}
|
||||
board = g.BOARD.ID;
|
||||
if (board === 'g') {
|
||||
$.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
|
||||
$.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML.replace(/\\s/g, ' '));\n}, false);");
|
||||
Post.prototype.callbacks.push({
|
||||
name: 'Parse /g/ code',
|
||||
cb: this.code
|
||||
@ -12251,7 +12310,9 @@
|
||||
_ref = $$('.prettyprint', this.nodes.comment);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
pre = _ref[_i];
|
||||
$.event('prettyprint', pre, window);
|
||||
if (!$('.pln', pre)) {
|
||||
$.event('prettyprint', pre, window);
|
||||
}
|
||||
}
|
||||
},
|
||||
math: function() {
|
||||
@ -13108,16 +13169,12 @@
|
||||
(sectionToOpen ? sectionToOpen : links[0]).click();
|
||||
$.on($('.close', dialog), 'click', Settings.close);
|
||||
$.on(overlay, 'click', Settings.close);
|
||||
d.body.style.width = "" + d.body.clientWidth + "px";
|
||||
$.addClass(d.body, 'unscroll');
|
||||
return $.add(d.body, [overlay, dialog]);
|
||||
},
|
||||
close: function() {
|
||||
if (!Settings.dialog) {
|
||||
return;
|
||||
}
|
||||
d.body.style.removeProperty('width');
|
||||
$.rmClass(d.body, 'unscroll');
|
||||
$.rm(Settings.overlay);
|
||||
$.rm(Settings.dialog);
|
||||
delete Settings.overlay;
|
||||
@ -13487,11 +13544,14 @@
|
||||
|
||||
for (key in items) {
|
||||
val = items[key];
|
||||
if (['usercss', 'emojiPos', 'archiver'].contains(key)) {
|
||||
if (['emojiPos', 'archiver'].contains(key)) {
|
||||
continue;
|
||||
}
|
||||
input = inputs[key];
|
||||
input.value = val;
|
||||
if (key === 'usercss') {
|
||||
continue;
|
||||
}
|
||||
$.on(input, event, Settings[key]);
|
||||
Settings[key].call(input);
|
||||
}
|
||||
@ -14435,6 +14495,17 @@
|
||||
obj.callback.isAddon = true;
|
||||
return Klass.prototype.callbacks.push(obj.callback);
|
||||
},
|
||||
message: function(e) {
|
||||
var el, version;
|
||||
|
||||
version = e.data.version;
|
||||
if (version && version !== g.VERSION) {
|
||||
el = $.el('span', {
|
||||
innerHTML: "Update: appchan x v" + version + " is out, get it <a href=http://zixaphir.github.com/appchan-x/ target=_blank>here</a>."
|
||||
});
|
||||
return new Notification('info', el, 120);
|
||||
}
|
||||
},
|
||||
checkUpdate: function() {
|
||||
var freq, items, now;
|
||||
|
||||
@ -14451,27 +14522,12 @@
|
||||
if (items.lastupdate > now - freq || items.lastchecked > now - $.DAY) {
|
||||
return;
|
||||
}
|
||||
return $.ajax('https://github.com/zixaphir/appchan-x/raw/Av2/builds/version', {
|
||||
onload: function() {
|
||||
var el, version;
|
||||
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
version = this.response;
|
||||
if (!/^\d\.\d+\.\d+$/.test(version)) {
|
||||
return;
|
||||
}
|
||||
if (g.VERSION === version) {
|
||||
$.set('lastupdate', now);
|
||||
return;
|
||||
}
|
||||
$.set('lastchecked', now);
|
||||
el = $.el('span', {
|
||||
innerHTML: "Update: appchan x v" + version + " is out, get it <a href=http://zixaphir.github.com/appchan-x/ target=_blank>here</a>."
|
||||
});
|
||||
return new Notification('info', el, 120);
|
||||
}
|
||||
return $.ready(function() {
|
||||
$.on(window, 'message', Main.message);
|
||||
$.set('lastUpdate', now);
|
||||
return $.add(d.head, $.el('script', {
|
||||
src: 'https://github.com/zixaphir/appchan-x/raw/Av2/latest.js'
|
||||
}));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@ -98,7 +98,8 @@
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
||||
__slice = [].slice,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||
|
||||
Config = {
|
||||
main: {
|
||||
@ -134,6 +135,7 @@
|
||||
'Recursive Hiding': [true, 'Hide replies of hidden posts, recursively.'],
|
||||
'Thread Hiding Buttons': [true, 'Add buttons to hide entire threads.'],
|
||||
'Reply Hiding Buttons': [true, 'Add buttons to hide single replies.'],
|
||||
'Filtered Backlinks': [true, 'When enabled, shows backlinks to filtered posts with a line-through decoration. Otherwise, hides the backlinks.'],
|
||||
'Stubs': [true, 'Show stubs of hidden threads / replies.']
|
||||
},
|
||||
'Images': {
|
||||
@ -185,11 +187,13 @@
|
||||
'Quote Backlinks': [true, 'Add quote backlinks.'],
|
||||
'OP Backlinks': [true, 'Add backlinks to the OP.'],
|
||||
'Quote Inlining': [true, 'Inline quoted post on click.'],
|
||||
'Quote Hash Navigation': [false, 'Include an extra link after quotes for autoscrolling to quoted posts.'],
|
||||
'Forward Hiding': [true, 'Hide original posts of inlined backlinks.'],
|
||||
'Quote Previewing': [true, 'Show quoted post on hover.'],
|
||||
'Quote Highlighting': [true, 'Highlight the previewed post.'],
|
||||
'Resurrect Quotes': [true, 'Link dead quotes to the archives.'],
|
||||
'Mark Quotes of You': [true, 'Add \'(You)\' to quotes linking to your posts.'],
|
||||
'Highlight Posts Quoting You': [false, 'Highlights any posts that contain a quote to your post.'],
|
||||
'Highlight Own Posts': [false, 'Highlights own posts if Mark Quotes of You is enabled.'],
|
||||
'Mark OP Quotes': [true, 'Add \'(OP)\' to OP quotes.'],
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.'],
|
||||
@ -3571,12 +3575,10 @@
|
||||
})();
|
||||
|
||||
Notification = (function() {
|
||||
var add, close;
|
||||
|
||||
function Notification(type, content, timeout) {
|
||||
this.timeout = timeout;
|
||||
this.add = add.bind(this);
|
||||
this.close = close.bind(this);
|
||||
this.close = __bind(this.close, this);
|
||||
this.add = __bind(this.add, this);
|
||||
this.el = $.el('div', {
|
||||
innerHTML: '<a href=javascript:; class=close title=Close>×</a><div class=message></div>'
|
||||
});
|
||||
@ -3594,7 +3596,7 @@
|
||||
return this.el.className = "notification " + type;
|
||||
};
|
||||
|
||||
add = function() {
|
||||
Notification.prototype.add = function() {
|
||||
if (d.hidden) {
|
||||
$.on(d, 'visibilitychange', this.add);
|
||||
return;
|
||||
@ -3608,7 +3610,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
close = function() {
|
||||
Notification.prototype.close = function() {
|
||||
return $.rm(this.el);
|
||||
};
|
||||
|
||||
@ -4650,7 +4652,7 @@
|
||||
screenWidth: screenWidth,
|
||||
isTouching: isTouching
|
||||
};
|
||||
_ref = Conf['Header auto-hide'] ? [0, 0] : Conf['Bottom Header'] ? [0, Header.bar.getBoundingClientRect().height] : [Header.bar.getBoundingClientRect().height, 0], o.topBorder = _ref[0], o.bottomBorder = _ref[1];
|
||||
_ref = Conf['Header auto-hide'] || !Conf['Fixed Header'] ? [0, 0] : Conf['Bottom Header'] ? [0, Header.bar.getBoundingClientRect().height] : [Header.bar.getBoundingClientRect().height, 0], o.topBorder = _ref[0], o.bottomBorder = _ref[1];
|
||||
if (isTouching) {
|
||||
o.identifier = e.identifier;
|
||||
o.move = touchmove.bind(o);
|
||||
@ -4818,6 +4820,9 @@
|
||||
if (g.VIEW === 'catalog' || !Conf['Filter']) {
|
||||
return;
|
||||
}
|
||||
if (!Conf['Filtered Backlinks']) {
|
||||
$.addClass(doc, 'hide-backlinks');
|
||||
}
|
||||
for (key in Config.filter) {
|
||||
this.filters[key] = [];
|
||||
_ref = Conf[key].split('\n');
|
||||
@ -5682,7 +5687,7 @@
|
||||
});
|
||||
},
|
||||
firstNode: function() {
|
||||
var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
||||
var a, clone, container, containers, frag, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
||||
|
||||
if (this.isClone || !this.quotes.length) {
|
||||
return;
|
||||
@ -5705,14 +5710,17 @@
|
||||
}
|
||||
for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
|
||||
container = containers[_k];
|
||||
link = a.cloneNode(true);
|
||||
frag = [$.tn(' '), link = a.cloneNode(true)];
|
||||
if (Conf['Quote Previewing']) {
|
||||
$.on(link, 'mouseover', QuotePreview.mouseover);
|
||||
}
|
||||
if (Conf['Quote Inlining']) {
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
if (Conf['Quote Hash Navigation']) {
|
||||
frag.pushArrays(QuoteInline.qiQuote(link, $.hasClass(link, 'filtered')));
|
||||
}
|
||||
}
|
||||
$.add(container, [$.tn(' '), link]);
|
||||
$.add(container, frag);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -5788,19 +5796,43 @@
|
||||
if (Conf['Comment Expansion']) {
|
||||
ExpandComment.callbacks.push(this.node);
|
||||
}
|
||||
if (Conf['Quote Hash Navigation']) {
|
||||
this.node = function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
if (!this.isClone) {
|
||||
$.after(link, QuoteInline.qiQuote(link, $.hasClass(link, 'filtered')));
|
||||
}
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
this.node = function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
};
|
||||
}
|
||||
return Post.prototype.callbacks.push({
|
||||
name: 'Quote Inlining',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
node: function() {
|
||||
var link, _i, _len, _ref;
|
||||
|
||||
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
link = _ref[_i];
|
||||
$.on(link, 'click', QuoteInline.toggle);
|
||||
}
|
||||
qiQuote: function(link, hidden) {
|
||||
return [
|
||||
$.tn(' '), $.el('a', {
|
||||
className: hidden ? 'hashlink filtered' : 'hashlink',
|
||||
textContent: '#',
|
||||
href: link.href
|
||||
})
|
||||
];
|
||||
},
|
||||
toggle: function(e) {
|
||||
var boardID, context, postID, threadID, _ref;
|
||||
@ -6209,6 +6241,9 @@
|
||||
if (Conf['Highlight Own Posts']) {
|
||||
$.addClass(doc, 'highlight-own');
|
||||
}
|
||||
if (Conf['Highlight Posts Quoting You']) {
|
||||
$.addClass(doc, 'highlight-you');
|
||||
}
|
||||
if (!(quotes = this.quotes).length) {
|
||||
return;
|
||||
}
|
||||
@ -6217,6 +6252,7 @@
|
||||
quotelink = quotelinks[_i];
|
||||
if (QR.db.get(Get.postDataFromLink(quotelink))) {
|
||||
$.add(quotelink, $.tn(QuoteYou.text));
|
||||
$.addClass(this.nodes.root, 'quotesYou');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6852,7 +6888,7 @@
|
||||
});
|
||||
},
|
||||
parseItem: function(item, types) {
|
||||
var boards, match, type, val, _ref, _ref1, _ref2;
|
||||
var boards, match, type, val, _ref, _ref1;
|
||||
|
||||
if (item[0] === '#') {
|
||||
return;
|
||||
@ -6863,7 +6899,7 @@
|
||||
_ref = match, match = _ref[0], type = _ref[1], val = _ref[2];
|
||||
item = item.replace(match, '');
|
||||
boards = ((_ref1 = item.match(/boards:([^;]+)/i)) != null ? _ref1[1].toLowerCase() : void 0) || 'global';
|
||||
if (boards !== 'global' && !(_ref2 = g.BOARD.ID, __indexOf.call(boards.split(','), _ref2) >= 0)) {
|
||||
if (boards !== 'global' && !((boards.split(',')).contains(g.BOARD.ID))) {
|
||||
return;
|
||||
}
|
||||
if (type === 'password') {
|
||||
@ -6876,7 +6912,7 @@
|
||||
if (/always/i.test(item)) {
|
||||
QR.persona.always[type] = val;
|
||||
}
|
||||
if (__indexOf.call(types[type], val) < 0) {
|
||||
if (!types[type].contains(val)) {
|
||||
return types[type].push(val);
|
||||
}
|
||||
},
|
||||
@ -8931,7 +8967,9 @@
|
||||
innerHTML: "<span id=post-count>0</span> / <span id=file-count>0</span>",
|
||||
id: 'thread-stats'
|
||||
});
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
return Header.addShortcut(sc);
|
||||
});
|
||||
} else {
|
||||
this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "<div class=move><span id=post-count>0</span> / <span id=file-count>0</span></div>");
|
||||
$.ready(function() {
|
||||
@ -8996,7 +9034,9 @@
|
||||
innerHTML: "<span id=update-status></span><span id=update-timer title='Update now'></span>",
|
||||
id: 'updater'
|
||||
});
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
return Header.addShortcut(sc);
|
||||
});
|
||||
} else {
|
||||
this.dialog = sc = UI.dialog('updater', 'bottom: 0px; left: 0px;', "<div class=move></div><span id=update-status></span><span id=update-timer title='Update now'></span>");
|
||||
$.addClass(doc, 'float');
|
||||
@ -9094,10 +9134,19 @@
|
||||
return setTimeout(ThreadUpdater.update, 1000);
|
||||
}
|
||||
},
|
||||
checkpost: function() {
|
||||
checkpost: function(e) {
|
||||
if (!ThreadUpdater.checkPostCount) {
|
||||
if (e.detail.threadID !== ThreadUpdater.thread.ID) {
|
||||
return;
|
||||
}
|
||||
ThreadUpdater.seconds = 0;
|
||||
ThreadUpdater.outdateCount = 0;
|
||||
ThreadUpdater.set('timer', '...');
|
||||
}
|
||||
if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) {
|
||||
return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
|
||||
}
|
||||
ThreadUpdater.set('timer', ThreadUpdater.getInterval());
|
||||
ThreadUpdater.checkPostCount = 0;
|
||||
delete ThreadUpdater.foundPost;
|
||||
return delete ThreadUpdater.postID;
|
||||
@ -9382,13 +9431,28 @@
|
||||
|
||||
ThreadWatcher = {
|
||||
init: function() {
|
||||
var sc;
|
||||
|
||||
if (!Conf['Thread Watcher']) {
|
||||
return;
|
||||
}
|
||||
this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '<div class=move>Thread Watcher</div>');
|
||||
this.shortcut = sc = $.el('a', {
|
||||
textContent: 'Watcher',
|
||||
id: 'watcher-link',
|
||||
href: 'javascript:;',
|
||||
className: 'disabled'
|
||||
});
|
||||
this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '<div class=move>Thread Watcher<a class=close href=javascript:;>×</a></div>');
|
||||
$.on(d, 'QRPostSuccessful', this.cb.post);
|
||||
$.on(d, '4chanXInitFinished', this.ready);
|
||||
$.sync('WatchedThreads', this.refresh);
|
||||
$.on(sc, 'click', this.toggleWatcher);
|
||||
$.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher);
|
||||
Header.addShortcut(sc);
|
||||
$.ready(function() {
|
||||
ThreadWatcher.refresh();
|
||||
$.add(d.body, ThreadWatcher.dialog);
|
||||
return ThreadWatcher.dialog.hidden = true;
|
||||
});
|
||||
return Thread.prototype.callbacks.push({
|
||||
name: 'Thread Watcher',
|
||||
cb: this.node
|
||||
@ -9414,14 +9478,6 @@
|
||||
return $["delete"]('AutoWatch');
|
||||
});
|
||||
},
|
||||
ready: function() {
|
||||
$.off(d, '4chanXInitFinished', ThreadWatcher.ready);
|
||||
if (!Main.isThisPageLegit()) {
|
||||
return;
|
||||
}
|
||||
ThreadWatcher.refresh();
|
||||
return $.add(d.body, ThreadWatcher.dialog);
|
||||
},
|
||||
refresh: function(watched) {
|
||||
var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
|
||||
|
||||
@ -9459,6 +9515,10 @@
|
||||
favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
|
||||
}
|
||||
},
|
||||
toggleWatcher: function() {
|
||||
$.toggleClass(ThreadWatcher.shortcut, 'disabled');
|
||||
return ThreadWatcher.dialog.hidden = !ThreadWatcher.dialog.hidden;
|
||||
},
|
||||
cb: {
|
||||
toggle: function() {
|
||||
return ThreadWatcher.toggle(Get.postFromNode(this).thread);
|
||||
@ -9544,7 +9604,10 @@
|
||||
});
|
||||
$.on(d, '4chanXInitFinished', Unread.ready);
|
||||
$.on(d, 'ThreadUpdate', Unread.onUpdate);
|
||||
return $.on(d, 'scroll visibilitychange', Unread.read);
|
||||
$.on(d, 'scroll visibilitychange', Unread.read);
|
||||
if (Conf['Unread Line']) {
|
||||
return $.on(d, 'visibilitychange', Unread.setLine);
|
||||
}
|
||||
},
|
||||
ready: function() {
|
||||
var ID, post, posts, _ref;
|
||||
@ -9559,9 +9622,6 @@
|
||||
}
|
||||
}
|
||||
Unread.addPosts(posts);
|
||||
if (Conf['Unread Line']) {
|
||||
Unread.setLine();
|
||||
}
|
||||
if (Conf['Scroll to Last Read Post']) {
|
||||
return Unread.scroll();
|
||||
}
|
||||
@ -12210,7 +12270,7 @@
|
||||
}
|
||||
board = g.BOARD.ID;
|
||||
if (board === 'g') {
|
||||
$.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
|
||||
$.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML.replace(/\\s/g, ' '));\n}, false);");
|
||||
Post.prototype.callbacks.push({
|
||||
name: 'Parse /g/ code',
|
||||
cb: this.code
|
||||
@ -12233,7 +12293,9 @@
|
||||
_ref = $$('.prettyprint', this.nodes.comment);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
pre = _ref[_i];
|
||||
$.event('prettyprint', pre, window);
|
||||
if (!$('.pln', pre)) {
|
||||
$.event('prettyprint', pre, window);
|
||||
}
|
||||
}
|
||||
},
|
||||
math: function() {
|
||||
@ -13090,16 +13152,12 @@
|
||||
(sectionToOpen ? sectionToOpen : links[0]).click();
|
||||
$.on($('.close', dialog), 'click', Settings.close);
|
||||
$.on(overlay, 'click', Settings.close);
|
||||
d.body.style.width = "" + d.body.clientWidth + "px";
|
||||
$.addClass(d.body, 'unscroll');
|
||||
return $.add(d.body, [overlay, dialog]);
|
||||
},
|
||||
close: function() {
|
||||
if (!Settings.dialog) {
|
||||
return;
|
||||
}
|
||||
d.body.style.removeProperty('width');
|
||||
$.rmClass(d.body, 'unscroll');
|
||||
$.rm(Settings.overlay);
|
||||
$.rm(Settings.dialog);
|
||||
delete Settings.overlay;
|
||||
@ -13471,11 +13529,14 @@
|
||||
|
||||
for (key in items) {
|
||||
val = items[key];
|
||||
if (['usercss', 'emojiPos', 'archiver'].contains(key)) {
|
||||
if (['emojiPos', 'archiver'].contains(key)) {
|
||||
continue;
|
||||
}
|
||||
input = inputs[key];
|
||||
input.value = val;
|
||||
if (key === 'usercss') {
|
||||
continue;
|
||||
}
|
||||
$.on(input, event, Settings[key]);
|
||||
Settings[key].call(input);
|
||||
}
|
||||
@ -14419,6 +14480,17 @@
|
||||
obj.callback.isAddon = true;
|
||||
return Klass.prototype.callbacks.push(obj.callback);
|
||||
},
|
||||
message: function(e) {
|
||||
var el, version;
|
||||
|
||||
version = e.data.version;
|
||||
if (version && version !== g.VERSION) {
|
||||
el = $.el('span', {
|
||||
innerHTML: "Update: appchan x v" + version + " is out, get it <a href=http://zixaphir.github.com/appchan-x/ target=_blank>here</a>."
|
||||
});
|
||||
return new Notification('info', el, 120);
|
||||
}
|
||||
},
|
||||
checkUpdate: function() {
|
||||
var freq, items, now;
|
||||
|
||||
@ -14435,27 +14507,12 @@
|
||||
if (items.lastupdate > now - freq || items.lastchecked > now - $.DAY) {
|
||||
return;
|
||||
}
|
||||
return $.ajax('https://github.com/zixaphir/appchan-x/raw/Av2/builds/version', {
|
||||
onload: function() {
|
||||
var el, version;
|
||||
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
version = this.response;
|
||||
if (!/^\d\.\d+\.\d+$/.test(version)) {
|
||||
return;
|
||||
}
|
||||
if (g.VERSION === version) {
|
||||
$.set('lastupdate', now);
|
||||
return;
|
||||
}
|
||||
$.set('lastchecked', now);
|
||||
el = $.el('span', {
|
||||
innerHTML: "Update: appchan x v" + version + " is out, get it <a href=http://zixaphir.github.com/appchan-x/ target=_blank>here</a>."
|
||||
});
|
||||
return new Notification('info', el, 120);
|
||||
}
|
||||
return $.ready(function() {
|
||||
$.on(window, 'message', Main.message);
|
||||
$.set('lastUpdate', now);
|
||||
return $.add(d.head, $.el('script', {
|
||||
src: 'https://github.com/zixaphir/appchan-x/raw/Av2/latest.js'
|
||||
}));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"name": "appchan-x",
|
||||
"version": "2.0.0",
|
||||
"description": "The most comprehensive 4chan userscript.",
|
||||
|
||||
"meta": {
|
||||
"name": "appchan x",
|
||||
"namespace": "zixaphir",
|
||||
@ -29,7 +30,7 @@
|
||||
"grunt-contrib-compress": "~0.5.0",
|
||||
"grunt-contrib-concat": "~0.3.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"grunt-contrib-watch": "~0.3.1",
|
||||
"grunt-contrib-watch": "~0.4.0",
|
||||
"grunt-shell": "~0.2.2"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@ -3,6 +3,9 @@ Filter =
|
||||
init: ->
|
||||
return if g.VIEW is 'catalog' or !Conf['Filter']
|
||||
|
||||
unless Conf['Filtered Backlinks']
|
||||
$.addClass doc, 'hide-backlinks'
|
||||
|
||||
for key of Config.filter
|
||||
@filters[key] = []
|
||||
for filter in Conf[key].split '\n'
|
||||
|
||||
@ -113,6 +113,10 @@ Config =
|
||||
true
|
||||
'Add buttons to hide single replies.'
|
||||
]
|
||||
'Filtered Backlinks': [
|
||||
true
|
||||
'When enabled, shows backlinks to filtered posts with a line-through decoration. Otherwise, hides the backlinks.'
|
||||
]
|
||||
'Stubs': [
|
||||
true
|
||||
'Show stubs of hidden threads / replies.'
|
||||
@ -295,6 +299,10 @@ Config =
|
||||
true
|
||||
'Inline quoted post on click.'
|
||||
]
|
||||
'Quote Hash Navigation': [
|
||||
false
|
||||
'Include an extra link after quotes for autoscrolling to quoted posts.'
|
||||
]
|
||||
'Forward Hiding': [
|
||||
true
|
||||
'Hide original posts of inlined backlinks.'
|
||||
@ -315,6 +323,10 @@ Config =
|
||||
true
|
||||
'Add \'(You)\' to quotes linking to your posts.'
|
||||
]
|
||||
'Highlight Posts Quoting You': [
|
||||
false
|
||||
'Highlights any posts that contain a quote to your post.'
|
||||
]
|
||||
'Highlight Own Posts': [
|
||||
false
|
||||
'Highlights own posts if Mark Quotes of You is enabled.'
|
||||
|
||||
@ -279,6 +279,13 @@ Main =
|
||||
obj.callback.isAddon = true
|
||||
Klass::callbacks.push obj.callback
|
||||
|
||||
message: (e) ->
|
||||
{version} = e.data
|
||||
if version and version isnt g.VERSION
|
||||
el = $.el 'span',
|
||||
innerHTML: "Update: <%= meta.name %> v#{version} is out, get it <a href=<%= meta.page %> target=_blank>here</a>."
|
||||
new Notification 'info', el, 120
|
||||
|
||||
checkUpdate: ->
|
||||
return unless Conf['Check for Updates'] and Main.isThisPageLegit()
|
||||
# Check for updates after:
|
||||
@ -293,18 +300,11 @@ Main =
|
||||
$.get items, (items) ->
|
||||
if items.lastupdate > now - freq or items.lastchecked > now - $.DAY
|
||||
return
|
||||
$.ajax '<%= meta.repo %>raw/<%= meta.mainBranch %>/<%= meta.buildsPath %>version', onload: ->
|
||||
return unless @status is 200
|
||||
version = @response
|
||||
return unless /^\d\.\d+\.\d+$/.test version
|
||||
if g.VERSION is version
|
||||
# Don't check for updates too frequently if there wasn't one in a 'long' time.
|
||||
$.set 'lastupdate', now
|
||||
return
|
||||
$.set 'lastchecked', now
|
||||
el = $.el 'span',
|
||||
innerHTML: "Update: <%= meta.name %> v#{version} is out, get it <a href=<%= meta.page %> target=_blank>here</a>."
|
||||
new Notification 'info', el, 120
|
||||
$.ready ->
|
||||
$.on window, 'message', Main.message
|
||||
$.set 'lastUpdate', now
|
||||
$.add d.head, $.el 'script',
|
||||
src: '<%= meta.repo %>raw/<%= meta.mainBranch %>/latest.js'
|
||||
|
||||
handleErrors: (errors) ->
|
||||
unless errors instanceof Array
|
||||
|
||||
@ -91,14 +91,10 @@ Settings =
|
||||
$.on $('.close', dialog), 'click', Settings.close
|
||||
$.on overlay, 'click', Settings.close
|
||||
|
||||
d.body.style.width = "#{d.body.clientWidth}px"
|
||||
$.addClass d.body, 'unscroll'
|
||||
$.add d.body, [overlay, dialog]
|
||||
|
||||
close: ->
|
||||
return unless Settings.dialog
|
||||
d.body.style.removeProperty 'width'
|
||||
$.rmClass d.body, 'unscroll'
|
||||
$.rm Settings.overlay
|
||||
$.rm Settings.dialog
|
||||
delete Settings.overlay
|
||||
@ -374,9 +370,10 @@ Settings =
|
||||
|
||||
$.get items, (items) ->
|
||||
for key, val of items
|
||||
continue if ['usercss', 'emojiPos', 'archiver'].contains key
|
||||
continue if ['emojiPos', 'archiver'].contains key
|
||||
input = inputs[key]
|
||||
input.value = val
|
||||
continue if key is 'usercss'
|
||||
$.on input, event, Settings[key]
|
||||
Settings[key].call input
|
||||
Rice.nodes sectionreturn
|
||||
|
||||
@ -227,7 +227,7 @@ UI = do ->
|
||||
isTouching: isTouching
|
||||
}
|
||||
|
||||
[o.topBorder, o.bottomBorder] = if Conf['Header auto-hide']
|
||||
[o.topBorder, o.bottomBorder] = if Conf['Header auto-hide'] or not Conf['Fixed Header']
|
||||
[0, 0]
|
||||
else if Conf['Bottom Header']
|
||||
[0, Header.bar.getBoundingClientRect().height]
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
class Notification
|
||||
constructor: (type, content, @timeout) ->
|
||||
@add = add.bind @
|
||||
@close = close.bind @
|
||||
|
||||
@el = $.el 'div',
|
||||
innerHTML: '<a href=javascript:; class=close title=Close>×</a><div class=message></div>'
|
||||
@el.style.opacity = 0
|
||||
@ -17,7 +14,7 @@ class Notification
|
||||
setType: (type) ->
|
||||
@el.className = "notification #{type}"
|
||||
|
||||
add = ->
|
||||
add: =>
|
||||
if d.hidden
|
||||
$.on d, 'visibilitychange', @add
|
||||
return
|
||||
@ -27,5 +24,5 @@ class Notification
|
||||
@el.style.opacity = 1
|
||||
setTimeout @close, @timeout * $.SECOND if @timeout
|
||||
|
||||
close = ->
|
||||
close: =>
|
||||
$.rm @el
|
||||
1
src/General/meta/latest.js
Normal file
1
src/General/meta/latest.js
Normal file
@ -0,0 +1 @@
|
||||
postMessage({version:'<%= version %>'},'*')
|
||||
@ -1 +0,0 @@
|
||||
<%= version %>
|
||||
@ -7,7 +7,7 @@ Fourchan =
|
||||
$.globalEval """
|
||||
window.addEventListener('prettyprint', function(e) {
|
||||
var pre = e.detail;
|
||||
pre.innerHTML = prettyPrintOne(pre.innerHTML);
|
||||
pre.innerHTML = prettyPrintOne(pre.innerHTML.replace(/\\s/g, ' '));
|
||||
}, false);
|
||||
"""
|
||||
Post::callbacks.push
|
||||
@ -33,7 +33,12 @@ Fourchan =
|
||||
code: ->
|
||||
return if @isClone
|
||||
for pre in $$ '.prettyprint', @nodes.comment
|
||||
$.event 'prettyprint', pre, window
|
||||
# Don't pretty print twice:
|
||||
# Might need a better way to detect if a .prettyprint
|
||||
# is already pretty-printed. We can't just look for spans
|
||||
# since 4chan inserts its quotes and whatnot inside.
|
||||
unless $ '.pln', pre
|
||||
$.event 'prettyprint', pre, window
|
||||
return
|
||||
math: ->
|
||||
return if @isClone or !$ '.math', @nodes.comment
|
||||
@ -44,4 +49,4 @@ Fourchan =
|
||||
$.event '4chanParsingDone',
|
||||
threadId: threadID
|
||||
offset: offset
|
||||
limit: limit
|
||||
limit: limit
|
||||
|
||||
@ -6,7 +6,8 @@ ThreadStats =
|
||||
@dialog = sc = $.el 'span',
|
||||
innerHTML: "<span id=post-count>0</span> / <span id=file-count>0</span>"
|
||||
id: 'thread-stats'
|
||||
Header.addShortcut sc
|
||||
$.ready ->
|
||||
Header.addShortcut sc
|
||||
else
|
||||
@dialog = sc = UI.dialog 'thread-stats', 'bottom: 0px; right: 0px;',
|
||||
"<div class=move><span id=post-count>0</span> / <span id=file-count>0</span></div>"
|
||||
|
||||
@ -8,7 +8,8 @@ ThreadUpdater =
|
||||
@dialog = sc = $.el 'span',
|
||||
innerHTML: "<span id=update-status></span><span id=update-timer title='Update now'></span>"
|
||||
id: 'updater'
|
||||
Header.addShortcut sc
|
||||
$.ready ->
|
||||
Header.addShortcut sc
|
||||
else
|
||||
@dialog = sc = UI.dialog 'updater', 'bottom: 0px; left: 0px;',
|
||||
"<div class=move></div><span id=update-status></span><span id=update-timer title='Update now'></span>"
|
||||
@ -97,9 +98,15 @@ ThreadUpdater =
|
||||
return unless e.detail.threadID is ThreadUpdater.thread.ID
|
||||
ThreadUpdater.outdateCount = 0
|
||||
setTimeout ThreadUpdater.update, 1000 if ThreadUpdater.seconds > 2
|
||||
checkpost: ->
|
||||
checkpost: (e) ->
|
||||
unless ThreadUpdater.checkPostCount
|
||||
return unless e.detail.threadID is ThreadUpdater.thread.ID
|
||||
ThreadUpdater.seconds = 0
|
||||
ThreadUpdater.outdateCount = 0
|
||||
ThreadUpdater.set 'timer', '...'
|
||||
unless g.DEAD or ThreadUpdater.foundPost or ThreadUpdater.checkPostCount >= 5
|
||||
return setTimeout ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND
|
||||
ThreadUpdater.set 'timer', ThreadUpdater.getInterval()
|
||||
ThreadUpdater.checkPostCount = 0
|
||||
delete ThreadUpdater.foundPost
|
||||
delete ThreadUpdater.postID
|
||||
|
||||
@ -1,12 +1,26 @@
|
||||
ThreadWatcher =
|
||||
init: ->
|
||||
return unless Conf['Thread Watcher']
|
||||
@shortcut = sc = $.el 'a',
|
||||
textContent: 'Watcher'
|
||||
id: 'watcher-link'
|
||||
href: 'javascript:;'
|
||||
className: 'disabled'
|
||||
|
||||
@dialog = UI.dialog 'watcher', 'top: 50px; left: 0px;',
|
||||
'<div class=move>Thread Watcher</div>'
|
||||
'<div class=move>Thread Watcher<a class=close href=javascript:;>×</a></div>'
|
||||
|
||||
$.on d, 'QRPostSuccessful', @cb.post
|
||||
$.on d, '4chanXInitFinished', @ready
|
||||
$.sync 'WatchedThreads', @refresh
|
||||
$.on sc, 'click', @toggleWatcher
|
||||
$.on $('.move>.close', ThreadWatcher.dialog), 'click', @toggleWatcher
|
||||
|
||||
Header.addShortcut sc
|
||||
|
||||
$.ready ->
|
||||
ThreadWatcher.refresh()
|
||||
$.add d.body, ThreadWatcher.dialog
|
||||
ThreadWatcher.dialog.hidden = true
|
||||
|
||||
Thread::callbacks.push
|
||||
name: 'Thread Watcher'
|
||||
@ -23,12 +37,6 @@ ThreadWatcher =
|
||||
ThreadWatcher.watch @
|
||||
$.delete 'AutoWatch'
|
||||
|
||||
ready: ->
|
||||
$.off d, '4chanXInitFinished', ThreadWatcher.ready
|
||||
return unless Main.isThisPageLegit()
|
||||
ThreadWatcher.refresh()
|
||||
$.add d.body, ThreadWatcher.dialog
|
||||
|
||||
refresh: (watched) ->
|
||||
unless watched
|
||||
$.get 'WatchedThreads', {}, (item) ->
|
||||
@ -61,6 +69,10 @@ ThreadWatcher =
|
||||
Favicon.empty
|
||||
return
|
||||
|
||||
toggleWatcher: ->
|
||||
$.toggleClass ThreadWatcher.shortcut, 'disabled'
|
||||
ThreadWatcher.dialog.hidden = !ThreadWatcher.dialog.hidden
|
||||
|
||||
cb:
|
||||
toggle: ->
|
||||
ThreadWatcher.toggle Get.postFromNode(@).thread
|
||||
|
||||
@ -22,6 +22,7 @@ Unread =
|
||||
$.on d, '4chanXInitFinished', Unread.ready
|
||||
$.on d, 'ThreadUpdate', Unread.onUpdate
|
||||
$.on d, 'scroll visibilitychange', Unread.read
|
||||
$.on d, 'visibilitychange', Unread.setLine if Conf['Unread Line']
|
||||
|
||||
ready: ->
|
||||
$.off d, '4chanXInitFinished', Unread.ready
|
||||
@ -29,8 +30,7 @@ Unread =
|
||||
for ID, post of Unread.thread.posts
|
||||
posts.push post if post.isReply
|
||||
Unread.addPosts posts
|
||||
Unread.setLine() if Conf['Unread Line']
|
||||
Unread.scroll() if Conf['Scroll to Last Read Post']
|
||||
Unread.scroll() if Conf['Scroll to Last Read Post']
|
||||
|
||||
scroll: ->
|
||||
# Let the header's onload callback handle it.
|
||||
|
||||
@ -161,6 +161,7 @@ QR =
|
||||
for type, arr of types
|
||||
QR.persona.loadPersonas type, arr
|
||||
return
|
||||
|
||||
parseItem: (item, types) ->
|
||||
return if item[0] is '#'
|
||||
return unless match = item.match /(name|email|subject|password):"(.*)"/i
|
||||
@ -170,7 +171,7 @@ QR =
|
||||
item = item.replace match, ''
|
||||
|
||||
boards = item.match(/boards:([^;]+)/i)?[1].toLowerCase() or 'global'
|
||||
if boards isnt 'global' and not (g.BOARD.ID in boards.split ',')
|
||||
if boards isnt 'global' and not ((boards.split ',').contains g.BOARD.ID)
|
||||
return
|
||||
|
||||
if type is 'password'
|
||||
@ -182,14 +183,16 @@ QR =
|
||||
if /always/i.test item
|
||||
QR.persona.always[type] = val
|
||||
|
||||
unless val in types[type]
|
||||
unless types[type].contains val
|
||||
types[type].push val
|
||||
|
||||
loadPersonas: (type, arr) ->
|
||||
list = $ "#list-#{type}", QR.nodes.el
|
||||
for val in arr
|
||||
$.add list, $.el 'option',
|
||||
textContent: val
|
||||
return
|
||||
|
||||
getPassword: ->
|
||||
unless QR.persona.pwd
|
||||
QR.persona.pwd = if m = d.cookie.match /4chan_pass=([^;]+)/
|
||||
@ -202,9 +205,11 @@ QR =
|
||||
# we'd rather use #postPassword when we can.
|
||||
$.id('delPassword').value
|
||||
return QR.persona.pwd
|
||||
|
||||
get: (cb) ->
|
||||
$.get 'QR.persona', {}, ({'QR.persona': persona}) ->
|
||||
cb persona
|
||||
|
||||
set: (post) ->
|
||||
$.get 'QR.persona', {}, ({'QR.persona': persona}) ->
|
||||
persona =
|
||||
@ -231,17 +236,20 @@ QR =
|
||||
QR.cooldown.cooldowns = item["cooldown.#{board}"]
|
||||
QR.cooldown.start()
|
||||
$.sync "cooldown.#{board}", QR.cooldown.sync
|
||||
|
||||
start: ->
|
||||
return unless Conf['Cooldown']
|
||||
return if QR.cooldown.isCounting
|
||||
QR.cooldown.isCounting = true
|
||||
QR.cooldown.count()
|
||||
|
||||
sync: (cooldowns) ->
|
||||
# Add each cooldowns, don't overwrite everything in case we
|
||||
# still need to prune one in the current tab to auto-post.
|
||||
for id of cooldowns
|
||||
QR.cooldown.cooldowns[id] = cooldowns[id]
|
||||
QR.cooldown.start()
|
||||
|
||||
set: (data) ->
|
||||
return unless Conf['Cooldown']
|
||||
{req, post, isReply, delay} = data
|
||||
@ -271,12 +279,14 @@ QR =
|
||||
QR.cooldown.cooldowns[start] = cooldown
|
||||
$.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns
|
||||
QR.cooldown.start()
|
||||
|
||||
unset: (id) ->
|
||||
delete QR.cooldown.cooldowns[id]
|
||||
if Object.keys(QR.cooldown.cooldowns).length
|
||||
$.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns
|
||||
else
|
||||
$.delete "cooldown.#{g.BOARD}"
|
||||
|
||||
count: ->
|
||||
unless Object.keys(QR.cooldown.cooldowns).length
|
||||
$.delete "#{g.BOARD}.cooldown"
|
||||
@ -382,11 +392,11 @@ QR =
|
||||
toggle = if e.type is 'dragstart' then $.off else $.on
|
||||
toggle d, 'dragover', QR.dragOver
|
||||
toggle d, 'drop', QR.dropFile
|
||||
|
||||
|
||||
dragOver: (e) ->
|
||||
e.preventDefault()
|
||||
e.dataTransfer.dropEffect = 'copy' # cursor feedback
|
||||
|
||||
|
||||
dropFile: (e) ->
|
||||
# Let it only handle files from the desktop.
|
||||
return unless e.dataTransfer.files.length
|
||||
@ -394,7 +404,7 @@ QR =
|
||||
QR.open()
|
||||
QR.fileInput e.dataTransfer.files
|
||||
$.addClass QR.nodes.el, 'dump'
|
||||
|
||||
|
||||
paste: (e) ->
|
||||
files = []
|
||||
for item in e.clipboardData.items
|
||||
@ -410,7 +420,7 @@ QR =
|
||||
openFileInput: (e) ->
|
||||
return if e.keyCode and e.keyCode isnt 32
|
||||
QR.nodes.fileInput.click()
|
||||
|
||||
|
||||
fileInput: (files) ->
|
||||
if @ instanceof Element #or files instanceof Event # file input
|
||||
files = [@files...]
|
||||
@ -448,7 +458,7 @@ QR =
|
||||
$.addClass QR.nodes.el, 'dump'
|
||||
|
||||
posts: []
|
||||
|
||||
|
||||
post: class
|
||||
constructor: (select) ->
|
||||
el = $.el 'a',
|
||||
@ -516,7 +526,7 @@ QR =
|
||||
@load() if QR.selected is @ # load persona
|
||||
@select() if select
|
||||
@unlock()
|
||||
|
||||
|
||||
rm: ->
|
||||
$.rm @nodes.el
|
||||
index = QR.posts.indexOf @
|
||||
@ -527,7 +537,7 @@ QR =
|
||||
QR.posts.splice index, 1
|
||||
return unless window.URL
|
||||
URL.revokeObjectURL @URL
|
||||
|
||||
|
||||
lock: (lock=true) ->
|
||||
@isLocked = lock
|
||||
return unless @ is QR.selected
|
||||
@ -538,10 +548,10 @@ QR =
|
||||
(if lock then $.off else $.on) QR.nodes.filename.parentNode, 'click', QR.openFileInput
|
||||
@nodes.spoiler.disabled = lock
|
||||
@nodes.el.draggable = !lock
|
||||
|
||||
|
||||
unlock: ->
|
||||
@lock false
|
||||
|
||||
|
||||
select: ->
|
||||
if QR.selected
|
||||
QR.selected.nodes.el.id = null
|
||||
@ -556,6 +566,7 @@ QR =
|
||||
@load()
|
||||
|
||||
$.event 'QRPostSelection', @
|
||||
|
||||
load: ->
|
||||
# Load this post's values.
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com']
|
||||
@ -564,7 +575,7 @@ QR =
|
||||
QR.tripcodeHider.call QR.nodes['name']
|
||||
@showFileData()
|
||||
QR.characterCount()
|
||||
|
||||
|
||||
save: (input) ->
|
||||
if input.type is 'checkbox'
|
||||
@spoiler = input.checked
|
||||
@ -578,7 +589,7 @@ QR =
|
||||
# during the last 5 seconds of the cooldown.
|
||||
if QR.cooldown.auto and @ is QR.posts[0] and 0 < QR.cooldown.seconds <= 5
|
||||
QR.cooldown.auto = false
|
||||
|
||||
|
||||
forceSave: ->
|
||||
return unless @ is QR.selected
|
||||
# Do this in case people use extensions
|
||||
@ -586,7 +597,7 @@ QR =
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com', 'spoiler']
|
||||
@save QR.nodes[name]
|
||||
return
|
||||
|
||||
|
||||
setFile: (@file) ->
|
||||
@filename = "#{file.name} (#{$.bytesToString file.size})"
|
||||
@nodes.el.title = @filename
|
||||
@ -597,7 +608,7 @@ QR =
|
||||
@nodes.el.style.backgroundImage = null
|
||||
return
|
||||
@setThumbnail()
|
||||
|
||||
|
||||
setThumbnail: (fileURL) ->
|
||||
# XXX Opera does not support blob URL
|
||||
# Create a redimensioned thumbnail.
|
||||
@ -657,7 +668,7 @@ QR =
|
||||
applyBlob new Blob [ui8a], type: 'image/png'
|
||||
|
||||
img.src = fileURL
|
||||
|
||||
|
||||
rmFile: ->
|
||||
delete @file
|
||||
delete @filename
|
||||
@ -676,7 +687,7 @@ QR =
|
||||
$.addClass QR.nodes.fileSubmit, 'has-file'
|
||||
else
|
||||
$.rmClass QR.nodes.fileSubmit, 'has-file'
|
||||
|
||||
|
||||
pasteText: (file) ->
|
||||
reader = new FileReader()
|
||||
reader.onload = (e) =>
|
||||
@ -689,7 +700,7 @@ QR =
|
||||
QR.nodes.com.value = @com
|
||||
@nodes.span.textContent = @com
|
||||
reader.readAsText file
|
||||
|
||||
|
||||
dragStart: ->
|
||||
$.addClass @, 'drag'
|
||||
|
||||
@ -705,7 +716,7 @@ QR =
|
||||
dragOver: (e) ->
|
||||
e.preventDefault()
|
||||
e.dataTransfer.dropEffect = 'move'
|
||||
|
||||
|
||||
drop: ->
|
||||
el = $ '.drag', @parentNode
|
||||
$.rmClass el, 'drag' # Opera doesn't fire dragEnd if we drop it on something else
|
||||
@ -723,7 +734,7 @@ QR =
|
||||
return if d.cookie.indexOf('pass_enabled=1') >= 0
|
||||
return unless @isEnabled = !!$.id 'captchaFormPart'
|
||||
$.asap (-> $.id 'recaptcha_challenge_field_holder'), @ready.bind @
|
||||
|
||||
|
||||
ready: ->
|
||||
setLifetime = (e) => @lifetime = e.detail
|
||||
$.on window, 'captcha:timeout', setLifetime
|
||||
@ -774,7 +785,7 @@ QR =
|
||||
|
||||
sync: (@captchas) ->
|
||||
QR.captcha.count()
|
||||
|
||||
|
||||
getOne: ->
|
||||
@clear()
|
||||
if captcha = @captchas.shift()
|
||||
@ -790,7 +801,7 @@ QR =
|
||||
# If there's only one word, duplicate it.
|
||||
response = "#{response} #{response}" unless /\s/.test response
|
||||
{challenge, response}
|
||||
|
||||
|
||||
save: ->
|
||||
return unless response = @nodes.input.value.trim()
|
||||
@captchas.push
|
||||
@ -800,7 +811,7 @@ QR =
|
||||
@count()
|
||||
@reload()
|
||||
$.set 'captchas', @captchas
|
||||
|
||||
|
||||
clear: ->
|
||||
now = Date.now()
|
||||
for captcha, i in @captchas
|
||||
@ -809,7 +820,7 @@ QR =
|
||||
@captchas = @captchas[i..]
|
||||
@count()
|
||||
$.set 'captchas', @captchas
|
||||
|
||||
|
||||
load: ->
|
||||
return unless @nodes.challenge.firstChild
|
||||
# -1 minute to give upload some time.
|
||||
@ -819,7 +830,7 @@ QR =
|
||||
@nodes.img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}"
|
||||
@nodes.input.value = null
|
||||
@clear()
|
||||
|
||||
|
||||
count: ->
|
||||
count = @captchas.length
|
||||
@nodes.input.placeholder = switch count
|
||||
@ -829,14 +840,15 @@ QR =
|
||||
'Verification (1 cached captcha)'
|
||||
else
|
||||
"Verification (#{count} cached captchas)"
|
||||
@nodes.input.alt = count # For XTRM RICE.
|
||||
|
||||
|
||||
@nodes.input.alt = count
|
||||
|
||||
reload: (focus) ->
|
||||
# the 't' argument prevents the input from being focused
|
||||
$.globalEval 'Recaptcha.reload("t")'
|
||||
# Focus if we meant to.
|
||||
@nodes.input.focus() if focus
|
||||
|
||||
|
||||
keydown: (e) ->
|
||||
if e.keyCode is 8 and not @nodes.input.value
|
||||
@reload()
|
||||
@ -975,6 +987,7 @@ QR =
|
||||
else if !check and @.className.match "\\btripped\\b" then $.rmClass @, 'tripped'
|
||||
|
||||
preSubmitHooks: []
|
||||
|
||||
submit: (e) ->
|
||||
e?.preventDefault()
|
||||
|
||||
|
||||
@ -36,12 +36,13 @@ QuoteBacklink =
|
||||
for clone in post.clones
|
||||
containers.push clone.nodes.backlinkContainer
|
||||
for container in containers
|
||||
link = a.cloneNode true
|
||||
frag = [$.tn(' '), link = a.cloneNode true]
|
||||
if Conf['Quote Previewing']
|
||||
$.on link, 'mouseover', QuotePreview.mouseover
|
||||
if Conf['Quote Inlining']
|
||||
$.on link, 'click', QuoteInline.toggle
|
||||
$.add container, [$.tn(' '), link]
|
||||
frag.pushArrays QuoteInline.qiQuote link, $.hasClass link, 'filtered' if Conf['Quote Hash Navigation']
|
||||
$.add container, frag
|
||||
return
|
||||
secondNode: ->
|
||||
if @isClone and (@origin.isReply or Conf['OP Backlinks'])
|
||||
|
||||
@ -5,14 +5,31 @@ QuoteInline =
|
||||
if Conf['Comment Expansion']
|
||||
ExpandComment.callbacks.push @node
|
||||
|
||||
if Conf['Quote Hash Navigation']
|
||||
@node = ->
|
||||
for link in @nodes.quotelinks.concat [@nodes.backlinks...]
|
||||
$.after link, QuoteInline.qiQuote link, $.hasClass link, 'filtered' unless @isClone
|
||||
$.on link, 'click', QuoteInline.toggle
|
||||
return
|
||||
|
||||
else
|
||||
@node = ->
|
||||
for link in @nodes.quotelinks.concat [@nodes.backlinks...]
|
||||
$.on link, 'click', QuoteInline.toggle
|
||||
return
|
||||
|
||||
Post::callbacks.push
|
||||
name: 'Quote Inlining'
|
||||
cb: @node
|
||||
|
||||
node: ->
|
||||
for link in @nodes.quotelinks.concat [@nodes.backlinks...]
|
||||
$.on link, 'click', QuoteInline.toggle
|
||||
return
|
||||
qiQuote: (link, hidden) ->
|
||||
[
|
||||
$.tn(' ')
|
||||
$.el 'a',
|
||||
className: if hidden then 'hashlink filtered' else 'hashlink'
|
||||
textContent: '#'
|
||||
href: link.href
|
||||
]
|
||||
|
||||
toggle: (e) ->
|
||||
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0
|
||||
|
||||
@ -17,6 +17,9 @@ QuoteYou =
|
||||
if Conf['Highlight Own Posts']
|
||||
$.addClass doc, 'highlight-own'
|
||||
|
||||
if Conf['Highlight Posts Quoting You']
|
||||
$.addClass doc, 'highlight-you'
|
||||
|
||||
# Stop there if there's no quotes in that post.
|
||||
return unless (quotes = @quotes).length
|
||||
{quotelinks} = @nodes
|
||||
@ -24,4 +27,5 @@ QuoteYou =
|
||||
for quotelink in quotelinks
|
||||
if QR.db.get Get.postDataFromLink quotelink
|
||||
$.add quotelink, $.tn QuoteYou.text
|
||||
$.addClass @nodes.root, 'quotesYou'
|
||||
return
|
||||
Loading…
x
Reference in New Issue
Block a user