Merge branch 'mayhem' into v3

Conflicts:
	CHANGELOG.md
	package.json
	src/Archive/archives.json
	src/General/Config.coffee
	src/General/Header.coffee
	src/General/Main.coffee
	src/General/Settings.coffee
	src/General/UI.coffee
	src/Miscellaneous/Keybinds.coffee
	src/Monitoring/ThreadUpdater.coffee
	src/Monitoring/Unread.coffee
	src/Posting/QR.captcha.coffee
	src/Posting/QR.coffee
	src/Posting/QR.post.coffee
This commit is contained in:
Zixaphir 2014-06-22 07:04:25 -07:00
commit f103fd0301
38 changed files with 233 additions and 507 deletions

View File

@ -1,4 +1,7 @@
**MayhemYDG**:
- Compatibility fixes for Greasemonkey v2.
- The QR won't duplicate single-word captchas anymore if you've input numbers only (like a street address).
- Removed the `Download Link` feature on Chrome/Opera as it is not working as intended anymore.
- [Security fix](https://github.com/MayhemYDG/4chan-x/issues/1634).
### v1.7.33

View File

@ -1,5 +1,5 @@
/*
* 4chan X - Version 1.7.33 - 2014-05-29
* 4chan X - Version 1.7.33 - 2014-06-22
*
* Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE

View File

@ -24,7 +24,7 @@
// ==/UserScript==
/*
* 4chan X - Version 1.7.33 - 2014-05-29
* 4chan X - Version 1.7.33 - 2014-06-22
*
* Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE
@ -215,7 +215,6 @@
'Persistent QR': [true, 'The Quick reply won\'t disappear after posting.'],
'Auto Hide QR': [true, 'Automatically hide the quick reply when posting.'],
'Open Post in New Tab': [true, 'Open new threads or replies to a thread from the index in a new tab.'],
'Remember Subject': [false, 'Remember the subject field, instead of resetting after posting.'],
'Remember QR Size': [false, 'Remember the size of the Quick reply.'],
'Remember Spoiler': [false, 'Remember the spoiler state, instead of resetting after posting.'],
'Hide Original Post Form': [true, 'Hide the normal post form.'],
@ -655,6 +654,9 @@
if (root == null) {
root = d;
}
if ((detail != null) && typeof cloneInto === 'function') {
detail = cloneInto(detail, d.defaultView);
}
return root.dispatchEvent(new CustomEvent(event, {
bubbles: true,
detail: detail
@ -1961,8 +1963,8 @@
Header = {
init: function() {
var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler, linkJustifyToggler, menuButton, scrollHeaderToggler, shortcutToggler;
this.menu = new UI.Menu('header');
menuButton = $.el('span', {
this.menu = new UI.Menu();
menuButton = $.el('a', {
className: 'menu-button',
innerHTML: '<i></i>'
});
@ -2025,8 +2027,7 @@
$.sync('Header auto-hide', this.setBarVisibility);
$.sync('Centered links', this.setLinkJustify);
this.addShortcut(menuButton);
$.event('AddMenuEntry', {
type: 'header',
this.menu.addEntry({
el: $.el('span', {
textContent: 'Header'
}),
@ -2473,7 +2474,7 @@
className: 'shortcut brackets-wrap'
});
$.add(shortcut, el);
return $.prepend(Header.shortcuts, shortcut);
return $.add(Header.shortcuts, shortcut);
},
rmShortcut: function(el) {
return $.rm(el.parentElement);
@ -2482,12 +2483,9 @@
return Header.menu.toggle(e, this, g);
},
createNotification: function(e) {
var cb, content, lifetime, notice, type, _ref;
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
notice = new Notice(type, content, lifetime);
if (cb) {
return cb(notice);
}
var content, lifetime, notice, type, _ref;
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime;
return notice = new Notice(type, content, lifetime);
},
areNotificationsEnabled: false,
enableDesktopNotifications: function() {
@ -2630,8 +2628,7 @@
$.on(input, 'change', this.cb.replies);
}
}
$.event('AddMenuEntry', {
type: 'header',
Header.menu.addEntry({
el: $.el('span', {
textContent: 'Index Navigation'
}),
@ -2748,8 +2745,7 @@
if (g.VIEW !== 'index' || !Conf['Menu'] || g.BOARD.ID === 'f') {
return;
}
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: $.el('a', {
href: 'javascript:;'
}),
@ -3023,7 +3019,7 @@
}
onSameIndex = g.VIEW === 'index' && a.pathname.split('/')[1] === g.BOARD.ID;
needChange = Index.cb.indexNav(a, onSameIndex);
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || !onSameIndex) {
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || !onSameIndex || g.BOARD.ID === 'f') {
return;
}
e.preventDefault();
@ -3554,8 +3550,7 @@
if (!infinite) {
$.rmAll(Index.root);
}
$.add(Index.root, nodes);
return $.event('IndexBuild', nodes);
return $.add(Index.root, nodes);
},
isSearching: false,
clearSearch: function() {
@ -4216,15 +4211,11 @@
lastToggledButton = null;
function Menu(type) {
this.type = type;
function Menu() {
this.rmEntry = __bind(this.rmEntry, this);
this.addEntry = __bind(this.addEntry, this);
this.onFocus = __bind(this.onFocus, this);
this.keybinds = __bind(this.keybinds, this);
this.close = __bind(this.close, this);
$.on(d, 'AddMenuEntry', this.addEntry);
$.on(d, 'rmMenuEntry', this.rmEntry);
this.entries = [];
}
@ -4422,12 +4413,7 @@
return style.right = right;
};
Menu.prototype.addEntry = function(e) {
var entry;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
Menu.prototype.addEntry = function(entry) {
this.parseEntry(entry);
return this.entries.push(entry);
};
@ -4854,7 +4840,6 @@
textContent: 'Filter'
});
entry = {
type: 'post',
el: div,
order: 50,
open: function(post) {
@ -4868,7 +4853,7 @@
type = _ref[_i];
entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1]));
}
return $.event('AddMenuEntry', entry);
return Menu.menu.addEntry(entry);
},
createSubEntry: function(text, type) {
var el;
@ -5047,8 +5032,7 @@
innerHTML: "<input type=checkbox name=makeStub checked=" + Conf['Stubs'] + "> Make stub"
})
};
$.event('AddMenuEntry', {
type: 'post',
Menu.menu.addEntry({
el: $.el('div', {
textContent: 'Hide post',
className: 'hide-post-link'
@ -5099,8 +5083,7 @@
return true;
}
};
$.event('AddMenuEntry', {
type: 'post',
Menu.menu.addEntry({
el: $.el('div', {
textContent: 'Unhide post',
className: 'show-post-link'
@ -5124,8 +5107,7 @@
if (g.VIEW !== 'index') {
return;
}
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: $.el('a', {
href: 'javascript:;'
}),
@ -5716,8 +5698,7 @@
});
input = $('input', this.controls);
$.on(input, 'change', this.toggle);
$.event('AddMenuEntry', this.entry = {
type: 'header',
Header.menu.addEntry(this.entry = {
el: this.controls,
order: 98
});
@ -6024,16 +6005,6 @@
}
});
$.before($.id('togglePostFormLink'), link);
$.on(d, 'QRGetSelectedPost', function(_arg) {
var cb;
cb = _arg.detail;
return cb(QR.selected);
});
$.on(d, 'QRAddPreSubmitHook', function(_arg) {
var cb;
cb = _arg.detail;
return QR.preSubmitHooks.push(cb);
});
$.on(d, 'dragover', QR.dragOver);
$.on(d, 'drop', QR.dropFile);
$.on(d, 'dragstart dragend', QR.drag);
@ -6622,9 +6593,8 @@
return $.add(nodes.form, flag);
}
},
preSubmitHooks: [],
submit: function(e) {
var challenge, err, extra, filetag, formData, hook, options, post, response, textOnly, thread, threadID, _i, _len, _ref, _ref1;
var challenge, err, extra, filetag, formData, options, post, response, textOnly, thread, threadID, _ref;
if (e != null) {
e.preventDefault();
}
@ -6657,17 +6627,9 @@
err = 'No file selected.';
} else if (post.file && thread.fileLimit) {
err = 'Max limit of image replies has been reached.';
} else {
_ref = QR.preSubmitHooks;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
hook = _ref[_i];
if (err = hook(post, thread)) {
break;
}
}
}
if (QR.captcha.isEnabled && !err) {
_ref1 = QR.captcha.getOne(), challenge = _ref1.challenge, response = _ref1.response;
_ref = QR.captcha.getOne(), challenge = _ref.challenge, response = _ref.response;
if (!response) {
err = 'No valid captcha.';
}
@ -6802,11 +6764,12 @@
});
ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', {
board: g.BOARD,
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID
});
$.event('QRPostSuccessful_', {
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID
});
@ -6978,7 +6941,7 @@
}
if (response) {
response = response.trim();
if (!/\s/.test(response)) {
if (!/\s|^\d+$/.test(response)) {
response = "" + response + " " + response;
}
}
@ -7423,8 +7386,7 @@
rectEl = this.nodes.el.getBoundingClientRect();
rectList = this.nodes.el.parentNode.getBoundingClientRect();
this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2;
this.load();
return $.event('QRPostSelection', this);
return this.load();
};
_Class.prototype.load = function() {
@ -7719,8 +7681,7 @@
});
FappeTyme[lc] = input = el.firstElementChild;
$.on(input, 'change', FappeTyme.cb.toggle.bind(input));
$.event('AddMenuEntry', {
type: 'header',
Header.menu.addEntry({
el: el,
order: 97
});
@ -7806,7 +7767,7 @@
nodes[key] = $(value, dialog);
}
menuButton = $('.menu-button', dialog);
nodes.menu = new UI.Menu('gallery');
nodes.menu = new UI.Menu();
cb = Gallery.cb;
$.on(nodes.frame, 'click', cb.blank);
$.on(nodes.next, 'click', cb.advance);
@ -7819,8 +7780,7 @@
createSubEntry = Gallery.menu.createSubEntry;
for (name in Config.gallery) {
el = createSubEntry(name).el;
$.event('AddMenuEntry', {
type: 'gallery',
nodes.menu.addEntry({
el: el,
order: 0
});
@ -8049,8 +8009,7 @@
for (name in Config.gallery) {
subEntries.push(createSubEntry(name));
}
return $.event('AddMenuEntry', {
type: 'header',
return Header.menu.addEntry({
el: el,
order: 105,
subEntries: subEntries
@ -8423,8 +8382,7 @@
conf = _ref[name];
subEntries.push(createSubEntry(name, conf[1]));
}
return $.event('AddMenuEntry', {
type: 'header',
return Header.menu.addEntry({
el: el,
order: 105,
subEntries: subEntries
@ -8602,8 +8560,7 @@
});
this.el = prefetch.firstElementChild;
$.on(this.el, 'change', this.toggle);
return $.event('AddMenuEntry', {
type: 'header',
return Header.menu.addEntry({
el: prefetch,
order: 104
});
@ -9363,7 +9320,6 @@
textContent: 'Archive'
});
entry = {
type: 'post',
el: div,
order: 90,
open: function(_arg) {
@ -9382,7 +9338,7 @@
type = _ref[_i];
entry.subEntries.push(this.createSubEntry(type[0], type[1]));
}
return $.event('AddMenuEntry', entry);
return Menu.menu.addEntry(entry);
},
createSubEntry: function(text, type) {
var el, open;
@ -9459,8 +9415,7 @@
return true;
}
};
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: div,
order: 40,
open: function(post) {
@ -9568,8 +9523,7 @@
className: 'download-link',
textContent: 'Download file'
});
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: a,
order: 100,
open: function(_arg) {
@ -9591,8 +9545,7 @@
if (!Conf['Menu']) {
return;
}
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: $.el('div', {
textContent: 'Labels'
}),
@ -9630,7 +9583,7 @@
innerHTML: '<i class="fa fa-bars"></i>',
href: 'javascript:;'
});
this.menu = new UI.Menu('post');
this.menu = new UI.Menu();
Post.callbacks.push({
name: 'Menu',
cb: this.node
@ -9683,8 +9636,7 @@
textContent: 'Report this post'
});
$.on(a, 'click', ReportLink.report);
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: a,
order: 10,
open: function(post) {
@ -9945,8 +9897,7 @@
subEntries.push({
el: this.settings
});
$.event('AddMenuEntry', this.entry = {
type: 'header',
Header.menu.addEntry(this.entry = {
el: $.el('span', {
textContent: 'Updater'
}),
@ -10097,7 +10048,7 @@
ThreadUpdater.thread.kill();
$.event('ThreadUpdate', {
404: true,
thread: ThreadUpdater.thread
threadID: ThreadUpdater.thread.fullID
});
break;
default:
@ -10196,7 +10147,7 @@
return new Notice('info', "The thread is " + change + ".", 30);
},
parse: function(postObjects) {
var OP, count, deletedFiles, deletedPosts, files, index, node, num, post, postObject, posts, root, scroll, sendEvent, _i, _j, _len, _len1;
var OP, count, files, index, node, num, post, postObject, posts, root, scroll, sendEvent, _i, _j, _len, _len1;
OP = postObjects[0];
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
@ -10221,19 +10172,15 @@
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
}
deletedPosts = [];
deletedFiles = [];
ThreadUpdater.thread.posts.forEach(function(post) {
var ID;
ID = +post.ID;
if (__indexOf.call(index, ID) < 0) {
post.kill();
deletedPosts.push(post);
} else if (post.isDead) {
post.resurrect();
} else if (post.file && !(post.file.isDead || __indexOf.call(files, ID) >= 0)) {
} else if (post.file && !post.file.isDead && __indexOf.call(files, ID) < 0) {
post.kill(true);
deletedFiles.push(post);
}
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
return ThreadUpdater.foundPost = true;
@ -10242,10 +10189,10 @@
sendEvent = function() {
return $.event('ThreadUpdate', {
404: false,
thread: ThreadUpdater.thread,
newPosts: posts,
deletedPosts: deletedPosts,
deletedFiles: deletedFiles,
threadID: ThreadUpdater.thread.fullID,
newPosts: posts.map(function(post) {
return post.fullID;
}),
postCount: OP.replies + 1,
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
});
@ -10420,14 +10367,14 @@
return ThreadWatcher.rm(boardID, +threadID);
},
post: function(e) {
var board, postID, threadID, _ref;
_ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
var boardID, postID, threadID, _ref;
_ref = e.detail, boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
if (postID === threadID) {
if (Conf['Auto Watch']) {
return $.set('AutoWatch', threadID);
}
} else if (Conf['Auto Watch Reply']) {
return ThreadWatcher.add(board.threads[threadID]);
return ThreadWatcher.add(g.threads[boardID + '.' + threadID]);
}
},
onIndexRefresh: function() {
@ -10456,7 +10403,7 @@
},
onThreadRefresh: function(e) {
var thread;
thread = e.detail.thread;
thread = g.threads[e.detail.threadID];
if (!(e.detail[404] && ThreadWatcher.db.get({
boardID: thread.board.ID,
threadID: thread.ID
@ -10668,12 +10615,12 @@
if (!Conf['Thread Watcher']) {
return;
}
menu = new UI.Menu('thread watcher');
menu = new UI.Menu();
$.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) {
return menu.toggle(e, this, ThreadWatcher);
});
this.addHeaderMenuEntry();
return this.addMenuEntries();
return this.addMenuEntries(menu);
},
addHeaderMenuEntry: function() {
var entryEl;
@ -10683,8 +10630,7 @@
entryEl = $.el('a', {
href: 'javascript:;'
});
$.event('AddMenuEntry', {
type: 'header',
Header.menu.addEntry({
el: entryEl,
order: 60
});
@ -10699,13 +10645,12 @@
return entryEl.textContent = text;
});
},
addMenuEntries: function() {
addMenuEntries: function(menu) {
var cb, conf, entries, entry, name, refresh, subEntries, _i, _len, _ref, _ref1;
entries = [];
entries.push({
cb: ThreadWatcher.cb.openAll,
entry: {
type: 'thread watcher',
el: $.el('a', {
textContent: 'Open all threads'
})
@ -10717,7 +10662,6 @@
entries.push({
cb: ThreadWatcher.cb.checkThreads,
entry: {
type: 'thread watcher',
el: $.el('a', {
textContent: 'Check 404\'d threads'
})
@ -10729,7 +10673,6 @@
entries.push({
cb: ThreadWatcher.cb.pruneDeads,
entry: {
type: 'thread watcher',
el: $.el('a', {
textContent: 'Prune 404\'d threads'
})
@ -10746,7 +10689,6 @@
}
entries.push({
entry: {
type: 'thread watcher',
el: $.el('span', {
textContent: 'Settings'
}),
@ -10764,7 +10706,7 @@
if (refresh) {
this.refreshers.push(refresh.bind(entry));
}
$.event('AddMenuEntry', entry);
menu.addEntry(entry);
}
},
createSubEntry: function(name, desc) {
@ -10964,11 +10906,13 @@
onUpdate: function(e) {
if (e.detail[404]) {
return Unread.update();
} else if (!Conf['Quote Threading']) {
return Unread.addPosts(e.detail.newPosts);
} else {
} else if (Conf['Quote Threading']) {
Unread.read();
return Unread.update();
} else {
return Unread.addPosts(e.detail.newPosts.map(function(fullID) {
return g.posts[fullID];
}));
}
},
readSinglePost: function(post) {
@ -11114,7 +11058,7 @@
}
return Redirect.data = o;
},
archives: [{"uid":0,"name":"Foolz","domain":"archive.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["a","biz","co","diy","gd","jp","m","sci","sp","tg","tv","vg","vp","vr","wsg"],"files":["a","biz","diy","gd","jp","m","sci","tg","vg","vp","vr","wsg"]},{"uid":1,"name":"NSFW Foolz","domain":"nsfw.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["u"],"files":["u"]},{"uid":2,"name":"The Dark Cave","domain":"archive.thedarkcave.org","http":true,"https":true,"software":"foolfuuka","boards":["c","int","out","po"],"files":["c","po"]},{"uid":3,"name":"4plebs Archive","domain":"archive.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["adv","hr","o","pol","s4s","tg","trv","tv","x"],"files":["adv","hr","o","pol","s4s","tg","trv","tv","x"]},{"uid":18,"name":"4plebs Flash Archive","domain":"flash.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["f"],"files":["f"]},{"uid":4,"name":"Nyafuu","domain":"archive.nyafuu.org","http":true,"https":true,"software":"foolfuuka","boards":["c","e","w","wg"],"files":["c","e","w","wg"]},{"uid":5,"name":"Love is Over","domain":"archive.loveisover.me","http":true,"https":true,"software":"foolfuuka","boards":["d","i","lgbt"],"files":["d","i","lgbt"]},{"uid":8,"name":"Rebecca Black Tech","domain":"rbt.asia","http":false,"https":true,"software":"fuuka","boards":["cgl","g","mu","w"],"files":["cgl","g","mu","w"]},{"uid":9,"name":"Heinessen","domain":"archive.heinessen.com","http":true,"https":false,"software":"fuuka","boards":["an","fit","k","mlp","r9k","toy"],"files":["an","fit","k","mlp","r9k","toy"]},{"uid":10,"name":"warosu","domain":"fuuka.warosu.org","http":false,"https":true,"software":"fuuka","boards":["3","biz","cgl","ck","diy","fa","g","ic","jp","lit","sci","tg","vr"],"files":["3","biz","cgl","ck","diy","fa","ic","jp","lit","sci","tg","vr"]},{"uid":15,"name":"fgts","domain":"fgts.eu","http":true,"https":true,"software":"foolfuuka","boards":["asp","cm","h","hc","hm","n","p","r","s","soc","y"],"files":["asp","cm","h","hc","hm","n","p","r","s","soc","y"]},{"uid":16,"name":"maware","domain":"archive.mawa.re","http":true,"https":false,"software":"foolfuuka","boards":["t"],"files":["t"]},{"uid":17,"name":"installgentoo.com","domain":"chan.installgentoo.com","http":true,"https":false,"software":"foolfuuka","boards":["g","t"],"files":["g","t"]},{"uid":19,"name":"Innovandalism Archive","domain":"boards.innovandalism.eu","http":true,"https":false,"software":"foolfuuka","boards":["v"],"files":[]},{"uid":13,"name":"Foolz Beta","domain":"beta.foolz.us","http":true,"https":true,"withCredentials":true,"software":"foolfuuka","boards":["a","biz","co","d","diy","gd","jp","m","s4s","sci","sp","tg","tv","u","vg","vp","vr","wsg"],"files":["a","biz","d","diy","gd","jp","m","s4s","sci","tg","u","vg","vp","vr","wsg"]},{"uid":19,"name":"Innovandalism Archive","domain":"boards.innovandalism.eu","http":true,"https":false,"software":"foolfuuka","boards":["v"],"files":[]}],
archives: [{"uid":0,"name":"Foolz","domain":"archive.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["a","biz","c","co","diy","gd","int","jp","m","out","po","sci","sp","tg","tv","vg","vp","vr","wsg"],"files":["a","biz","c","co","diy","gd","jp","m","po","sci","tg","vg","vp","vr","wsg"]},{"uid":1,"name":"NSFW Foolz","domain":"nsfw.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["u"],"files":["u"]},{"uid":3,"name":"4plebs Archive","domain":"archive.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["adv","f","hr","o","pol","s4s","tg","trv","tv","x"],"files":["adv","f","hr","o","pol","s4s","tg","trv","tv","x"]},{"uid":4,"name":"Nyafuu","domain":"archive.nyafuu.org","http":true,"https":true,"software":"foolfuuka","boards":["c","e","w","wg"],"files":["c","e","w","wg"]},{"uid":5,"name":"Love is Over","domain":"archive.loveisover.me","http":true,"https":true,"software":"foolfuuka","boards":["d","i","lgbt"],"files":["d","i","lgbt"]},{"uid":8,"name":"Rebecca Black Tech","domain":"archive.rebeccablacktech.com","http":false,"https":true,"software":"fuuka","boards":["cgl","g","mu","w"],"files":["cgl","g","mu","w"]},{"uid":9,"name":"Heinessen","domain":"archive.heinessen.com","http":true,"https":false,"software":"fuuka","boards":["an","fit","k","mlp","r9k","toy"],"files":["an","fit","k","mlp","r9k","toy"]},{"uid":10,"name":"warosu","domain":"warosu.org","http":false,"https":true,"software":"fuuka","boards":["3","biz","cgl","ck","diy","fa","g","ic","jp","lit","sci","tg","vr"],"files":["3","biz","cgl","ck","diy","fa","ic","jp","lit","sci","tg","vr"]},{"uid":15,"name":"fgts","domain":"fgts.jp","http":true,"https":true,"software":"foolfuuka","boards":["asp","cm","h","hc","hm","n","p","r","s","soc","y"],"files":["asp","cm","h","hc","hm","n","p","r","s","soc","y"]},{"uid":16,"name":"maware","domain":"archive.mawa.re","http":true,"https":false,"software":"foolfuuka","boards":["t"],"files":["t"]},{"uid":19,"name":"Deniable Plausibility","domain":"boards.deniableplausibility.net","http":true,"https":false,"software":"foolfuuka","boards":["v","vg"],"files":["v","vg"]},{"uid":19,"name":"Innovandalism Archive","domain":"boards.innovandalism.eu","http":true,"https":false,"software":"foolfuuka","boards":["v"],"files":[]},{"uid":13,"name":"Foolz Beta","domain":"beta.foolz.us","http":true,"https":true,"withCredentials":true,"software":"foolfuuka","boards":["a","biz","c","co","d","diy","gd","int","jp","m","out","po","s4s","sci","sp","tg","tv","u","vg","vp","vr","wsg"],"files":["a","biz","c","co","d","diy","gd","jp","m","po","s4s","sci","tg","u","vg","vp","vr","wsg"]}],
to: function(dest, data) {
var archive;
archive = (dest === 'search' || dest === 'board' ? Redirect.data.thread : Redirect.data[dest])[data.boardID];
@ -11183,7 +11127,6 @@
return;
}
entry = {
type: 'header',
el: $.el('a', {
textContent: 'Show announcement',
className: 'show-announcement',
@ -11194,7 +11137,7 @@
return psa.hidden;
}
};
$.event('AddMenuEntry', entry);
Header.menu.addEntry(entry);
$.on(entry.el, 'click', PSAHiding.toggle);
PSAHiding.btn = btn = $.el('span', {
innerHTML: '[<a href=javascript:;>Dismiss</a>]',
@ -11352,8 +11295,7 @@
input = $('input', el);
$.on(input, 'change', this.toggle);
$.sync('Header catalog links', CatalogLinks.set);
$.event('AddMenuEntry', {
type: 'header',
Header.menu.addEntry({
el: el,
order: 95
});
@ -11885,7 +11827,7 @@
});
}
if (board === 'sci') {
$.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
$.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(document.getElementById(e.detail));\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
return Post.callbacks.push({
name: 'Parse /sci/ math',
cb: this.math
@ -11912,7 +11854,7 @@
if (this.isClone || !$('.math', this.nodes.comment)) {
return;
}
return $.event('jsmath', this.nodes.post, window);
return $.event('jsmath', this.nodes.post.id, window);
}
};
@ -12215,31 +12157,31 @@
}
break;
case Conf['Next thread']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
Nav.scroll(+1);
break;
case Conf['Previous thread']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
Nav.scroll(-1);
break;
case Conf['Expand thread']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
ExpandThread.toggle(thread);
break;
case Conf['Open thread']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
Keybinds.open(thread);
break;
case Conf['Open thread tab']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
Keybinds.open(thread, true);
@ -12628,7 +12570,7 @@
var response;
e.preventDefault();
response = field.value.trim();
if (!/\s/.test(response)) {
if (!/\s|^\d+$/.test(response)) {
field.value = "" + response + " " + response;
}
return this.submit();
@ -13174,7 +13116,6 @@
Settings.addSection('Sauce', Settings.sauce);
Settings.addSection('Advanced', Settings.advanced);
Settings.addSection('Keybinds', Settings.keybinds);
$.on(d, 'AddSettingsSection', Settings.addSection);
$.on(d, 'OpenSettings', function(e) {
return Settings.open(e.detail);
});
@ -13238,10 +13179,7 @@
},
sections: [],
addSection: function(title, open) {
var hyphenatedTitle, _ref;
if (typeof title !== 'string') {
_ref = title.detail, title = _ref.title, open = _ref.open;
}
var hyphenatedTitle;
hyphenatedTitle = title.toLowerCase().replace(/\s+/g, '-');
return Settings.sections.push({
title: title,
@ -13923,7 +13861,6 @@
init('Banner', Banner);
init('Navigate', Navigate);
init('Flash Features', Flash);
$.on(d, 'AddCallback', Main.addCallback);
return $.ready(Main.initReady);
},
initStyle: function() {
@ -14071,25 +14008,6 @@
return $.set('previousversion', g.VERSION);
});
},
addCallback: function(e) {
var Klass, obj;
obj = e.detail;
if (typeof obj.callback.name !== 'string') {
throw new Error("Invalid callback name: " + obj.callback.name);
}
switch (obj.type) {
case 'Post':
Klass = Post;
break;
case 'Thread':
Klass = Thread;
break;
default:
return;
}
obj.callback.isAddon = true;
return Klass.callbacks.push(obj.callback);
},
handleErrors: function(errors) {
var div, error, logs, _i, _len;
if (!(errors instanceof Array)) {

View File

@ -1,6 +1,6 @@
// Generated by CoffeeScript
/*
* 4chan X - Version 1.7.33 - 2014-05-29
* 4chan X - Version 1.7.33 - 2014-06-22
*
* Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE
@ -170,7 +170,6 @@
'Report Link': [true, 'Add a report link to the menu.'],
'Post Hiding Link': [true, 'Add a link to hide posts.'],
'Delete Link': [true, 'Add post and image deletion links to the menu.'],
'Download Link': [true, 'Add a download with original filename link to the menu. Chrome-only currently.'],
'Archive Link': [true, 'Add an archive link to the menu.']
},
'Monitoring': {
@ -192,7 +191,6 @@
'Persistent QR': [true, 'The Quick reply won\'t disappear after posting.'],
'Auto Hide QR': [true, 'Automatically hide the quick reply when posting.'],
'Open Post in New Tab': [true, 'Open new threads or replies to a thread from the index in a new tab.'],
'Remember Subject': [false, 'Remember the subject field, instead of resetting after posting.'],
'Remember Spoiler': [false, 'Remember the spoiler state, instead of resetting after posting.'],
'Hide Original Post Form': [true, 'Hide the normal post form.'],
'Cooldown': [true, 'Indicate the remaining time before posting again.'],
@ -2020,8 +2018,8 @@
Header = {
init: function() {
var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler, linkJustifyToggler, menuButton, scrollHeaderToggler, shortcutToggler;
this.menu = new UI.Menu('header');
menuButton = $.el('span', {
this.menu = new UI.Menu();
menuButton = $.el('a', {
className: 'menu-button',
innerHTML: '<i></i>'
});
@ -2084,8 +2082,7 @@
$.sync('Header auto-hide', this.setBarVisibility);
$.sync('Centered links', this.setLinkJustify);
this.addShortcut(menuButton);
$.event('AddMenuEntry', {
type: 'header',
this.menu.addEntry({
el: $.el('span', {
textContent: 'Header'
}),
@ -2532,7 +2529,7 @@
className: 'shortcut brackets-wrap'
});
$.add(shortcut, el);
return $.prepend(Header.shortcuts, shortcut);
return $.add(Header.shortcuts, shortcut);
},
rmShortcut: function(el) {
return $.rm(el.parentElement);
@ -2541,12 +2538,9 @@
return Header.menu.toggle(e, this, g);
},
createNotification: function(e) {
var cb, content, lifetime, notice, type, _ref;
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
notice = new Notice(type, content, lifetime);
if (cb) {
return cb(notice);
}
var content, lifetime, notice, type, _ref;
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime;
return notice = new Notice(type, content, lifetime);
},
areNotificationsEnabled: false,
enableDesktopNotifications: function() {
@ -2689,8 +2683,7 @@
$.on(input, 'change', this.cb.replies);
}
}
$.event('AddMenuEntry', {
type: 'header',
Header.menu.addEntry({
el: $.el('span', {
textContent: 'Index Navigation'
}),
@ -2807,8 +2800,7 @@
if (g.VIEW !== 'index' || !Conf['Menu'] || g.BOARD.ID === 'f') {
return;
}
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: $.el('a', {
href: 'javascript:;'
}),
@ -3082,7 +3074,7 @@
}
onSameIndex = g.VIEW === 'index' && a.pathname.split('/')[1] === g.BOARD.ID;
needChange = Index.cb.indexNav(a, onSameIndex);
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || !onSameIndex) {
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || !onSameIndex || g.BOARD.ID === 'f') {
return;
}
e.preventDefault();
@ -3613,8 +3605,7 @@
if (!infinite) {
$.rmAll(Index.root);
}
$.add(Index.root, nodes);
return $.event('IndexBuild', nodes);
return $.add(Index.root, nodes);
},
isSearching: false,
clearSearch: function() {
@ -4275,15 +4266,11 @@
lastToggledButton = null;
function Menu(type) {
this.type = type;
function Menu() {
this.rmEntry = __bind(this.rmEntry, this);
this.addEntry = __bind(this.addEntry, this);
this.onFocus = __bind(this.onFocus, this);
this.keybinds = __bind(this.keybinds, this);
this.close = __bind(this.close, this);
$.on(d, 'AddMenuEntry', this.addEntry);
$.on(d, 'rmMenuEntry', this.rmEntry);
this.entries = [];
}
@ -4481,12 +4468,7 @@
return style.right = right;
};
Menu.prototype.addEntry = function(e) {
var entry;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
Menu.prototype.addEntry = function(entry) {
this.parseEntry(entry);
return this.entries.push(entry);
};
@ -4906,7 +4888,6 @@
textContent: 'Filter'
});
entry = {
type: 'post',
el: div,
order: 50,
open: function(post) {
@ -4920,7 +4901,7 @@
type = _ref[_i];
entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1]));
}
return $.event('AddMenuEntry', entry);
return Menu.menu.addEntry(entry);
},
createSubEntry: function(text, type) {
var el;
@ -5099,8 +5080,7 @@
innerHTML: "<input type=checkbox name=makeStub checked=" + Conf['Stubs'] + "> Make stub"
})
};
$.event('AddMenuEntry', {
type: 'post',
Menu.menu.addEntry({
el: $.el('div', {
textContent: 'Hide post',
className: 'hide-post-link'
@ -5151,8 +5131,7 @@
return true;
}
};
$.event('AddMenuEntry', {
type: 'post',
Menu.menu.addEntry({
el: $.el('div', {
textContent: 'Unhide post',
className: 'show-post-link'
@ -5176,8 +5155,7 @@
if (g.VIEW !== 'index') {
return;
}
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: $.el('a', {
href: 'javascript:;'
}),
@ -5768,8 +5746,7 @@
});
input = $('input', this.controls);
$.on(input, 'change', this.toggle);
$.event('AddMenuEntry', this.entry = {
type: 'header',
Header.menu.addEntry(this.entry = {
el: this.controls,
order: 98
});
@ -6076,16 +6053,6 @@
}
});
$.before($.id('togglePostFormLink'), link);
$.on(d, 'QRGetSelectedPost', function(_arg) {
var cb;
cb = _arg.detail;
return cb(QR.selected);
});
$.on(d, 'QRAddPreSubmitHook', function(_arg) {
var cb;
cb = _arg.detail;
return QR.preSubmitHooks.push(cb);
});
$.on(d, 'paste', QR.paste);
$.on(d, 'dragover', QR.dragOver);
$.on(d, 'drop', QR.dropFile);
@ -6669,9 +6636,8 @@
return $.add(nodes.form, flag);
}
},
preSubmitHooks: [],
submit: function(e) {
var challenge, err, extra, filetag, formData, hook, options, post, response, textOnly, thread, threadID, _i, _len, _ref, _ref1;
var challenge, err, extra, filetag, formData, options, post, response, textOnly, thread, threadID, _ref;
if (e != null) {
e.preventDefault();
}
@ -6704,17 +6670,9 @@
err = 'No file selected.';
} else if (post.file && thread.fileLimit) {
err = 'Max limit of image replies has been reached.';
} else {
_ref = QR.preSubmitHooks;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
hook = _ref[_i];
if (err = hook(post, thread)) {
break;
}
}
}
if (QR.captcha.isEnabled && !err) {
_ref1 = QR.captcha.getOne(), challenge = _ref1.challenge, response = _ref1.response;
_ref = QR.captcha.getOne(), challenge = _ref.challenge, response = _ref.response;
if (!response) {
err = 'No valid captcha.';
}
@ -6849,11 +6807,12 @@
});
ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', {
board: g.BOARD,
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID
});
$.event('QRPostSuccessful_', {
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID
});
@ -7025,7 +6984,7 @@
}
if (response) {
response = response.trim();
if (!/\s/.test(response)) {
if (!/\s|^\d+$/.test(response)) {
response = "" + response + " " + response;
}
}
@ -7464,8 +7423,7 @@
rectEl = this.nodes.el.getBoundingClientRect();
rectList = this.nodes.el.parentNode.getBoundingClientRect();
this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2;
this.load();
return $.event('QRPostSelection', this);
return this.load();
};
_Class.prototype.load = function() {
@ -7757,8 +7715,7 @@
});
FappeTyme[lc] = input = el.firstElementChild;
$.on(input, 'change', FappeTyme.cb.toggle.bind(input));
$.event('AddMenuEntry', {
type: 'header',
Header.menu.addEntry({
el: el,
order: 97
});
@ -7844,7 +7801,7 @@
nodes[key] = $(value, dialog);
}
menuButton = $('.menu-button', dialog);
nodes.menu = new UI.Menu('gallery');
nodes.menu = new UI.Menu();
cb = Gallery.cb;
$.on(nodes.frame, 'click', cb.blank);
$.on(nodes.next, 'click', cb.advance);
@ -7857,8 +7814,7 @@
createSubEntry = Gallery.menu.createSubEntry;
for (name in Config.gallery) {
el = createSubEntry(name).el;
$.event('AddMenuEntry', {
type: 'gallery',
nodes.menu.addEntry({
el: el,
order: 0
});
@ -8087,8 +8043,7 @@
for (name in Config.gallery) {
subEntries.push(createSubEntry(name));
}
return $.event('AddMenuEntry', {
type: 'header',
return Header.menu.addEntry({
el: el,
order: 105,
subEntries: subEntries
@ -8450,8 +8405,7 @@
conf = _ref[name];
subEntries.push(createSubEntry(name, conf[1]));
}
return $.event('AddMenuEntry', {
type: 'header',
return Header.menu.addEntry({
el: el,
order: 105,
subEntries: subEntries
@ -8618,8 +8572,7 @@
});
this.el = prefetch.firstElementChild;
$.on(this.el, 'change', this.toggle);
return $.event('AddMenuEntry', {
type: 'header',
return Header.menu.addEntry({
el: prefetch,
order: 104
});
@ -9379,7 +9332,6 @@
textContent: 'Archive'
});
entry = {
type: 'post',
el: div,
order: 90,
open: function(_arg) {
@ -9398,7 +9350,7 @@
type = _ref[_i];
entry.subEntries.push(this.createSubEntry(type[0], type[1]));
}
return $.event('AddMenuEntry', entry);
return Menu.menu.addEntry(entry);
},
createSubEntry: function(text, type) {
var el, open;
@ -9475,8 +9427,7 @@
return true;
}
};
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: div,
order: 40,
open: function(post) {
@ -9584,8 +9535,7 @@
className: 'download-link',
textContent: 'Download file'
});
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: a,
order: 100,
open: function(_arg) {
@ -9607,8 +9557,7 @@
if (!Conf['Menu']) {
return;
}
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: $.el('div', {
textContent: 'Labels'
}),
@ -9646,7 +9595,7 @@
innerHTML: '<i class="fa fa-bars"></i>',
href: 'javascript:;'
});
this.menu = new UI.Menu('post');
this.menu = new UI.Menu();
Post.callbacks.push({
name: 'Menu',
cb: this.node
@ -9699,8 +9648,7 @@
textContent: 'Report this post'
});
$.on(a, 'click', ReportLink.report);
return $.event('AddMenuEntry', {
type: 'post',
return Menu.menu.addEntry({
el: a,
order: 10,
open: function(post) {
@ -9961,8 +9909,7 @@
subEntries.push({
el: this.settings
});
$.event('AddMenuEntry', this.entry = {
type: 'header',
Header.menu.addEntry(this.entry = {
el: $.el('span', {
textContent: 'Updater'
}),
@ -10113,7 +10060,7 @@
ThreadUpdater.thread.kill();
$.event('ThreadUpdate', {
404: true,
thread: ThreadUpdater.thread
threadID: ThreadUpdater.thread.fullID
});
break;
default:
@ -10212,7 +10159,7 @@
return new Notice('info', "The thread is " + change + ".", 30);
},
parse: function(postObjects) {
var OP, count, deletedFiles, deletedPosts, files, index, node, num, post, postObject, posts, root, scroll, sendEvent, _i, _j, _len, _len1;
var OP, count, files, index, node, num, post, postObject, posts, root, scroll, sendEvent, _i, _j, _len, _len1;
OP = postObjects[0];
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
@ -10237,19 +10184,15 @@
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
}
deletedPosts = [];
deletedFiles = [];
ThreadUpdater.thread.posts.forEach(function(post) {
var ID;
ID = +post.ID;
if (__indexOf.call(index, ID) < 0) {
post.kill();
deletedPosts.push(post);
} else if (post.isDead) {
post.resurrect();
} else if (post.file && !(post.file.isDead || __indexOf.call(files, ID) >= 0)) {
} else if (post.file && !post.file.isDead && __indexOf.call(files, ID) < 0) {
post.kill(true);
deletedFiles.push(post);
}
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
return ThreadUpdater.foundPost = true;
@ -10258,10 +10201,10 @@
sendEvent = function() {
return $.event('ThreadUpdate', {
404: false,
thread: ThreadUpdater.thread,
newPosts: posts,
deletedPosts: deletedPosts,
deletedFiles: deletedFiles,
threadID: ThreadUpdater.thread.fullID,
newPosts: posts.map(function(post) {
return post.fullID;
}),
postCount: OP.replies + 1,
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
});
@ -10436,14 +10379,14 @@
return ThreadWatcher.rm(boardID, +threadID);
},
post: function(e) {
var board, postID, threadID, _ref;
_ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
var boardID, postID, threadID, _ref;
_ref = e.detail, boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
if (postID === threadID) {
if (Conf['Auto Watch']) {
return $.set('AutoWatch', threadID);
}
} else if (Conf['Auto Watch Reply']) {
return ThreadWatcher.add(board.threads[threadID]);
return ThreadWatcher.add(g.threads[boardID + '.' + threadID]);
}
},
onIndexRefresh: function() {
@ -10472,7 +10415,7 @@
},
onThreadRefresh: function(e) {
var thread;
thread = e.detail.thread;
thread = g.threads[e.detail.threadID];
if (!(e.detail[404] && ThreadWatcher.db.get({
boardID: thread.board.ID,
threadID: thread.ID
@ -10684,12 +10627,12 @@
if (!Conf['Thread Watcher']) {
return;
}
menu = new UI.Menu('thread watcher');
menu = new UI.Menu();
$.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) {
return menu.toggle(e, this, ThreadWatcher);
});
this.addHeaderMenuEntry();
return this.addMenuEntries();
return this.addMenuEntries(menu);
},
addHeaderMenuEntry: function() {
var entryEl;
@ -10699,8 +10642,7 @@
entryEl = $.el('a', {
href: 'javascript:;'
});
$.event('AddMenuEntry', {
type: 'header',
Header.menu.addEntry({
el: entryEl,
order: 60
});
@ -10715,13 +10657,12 @@
return entryEl.textContent = text;
});
},
addMenuEntries: function() {
addMenuEntries: function(menu) {
var cb, conf, entries, entry, name, refresh, subEntries, _i, _len, _ref, _ref1;
entries = [];
entries.push({
cb: ThreadWatcher.cb.openAll,
entry: {
type: 'thread watcher',
el: $.el('a', {
textContent: 'Open all threads'
})
@ -10733,7 +10674,6 @@
entries.push({
cb: ThreadWatcher.cb.checkThreads,
entry: {
type: 'thread watcher',
el: $.el('a', {
textContent: 'Check 404\'d threads'
})
@ -10745,7 +10685,6 @@
entries.push({
cb: ThreadWatcher.cb.pruneDeads,
entry: {
type: 'thread watcher',
el: $.el('a', {
textContent: 'Prune 404\'d threads'
})
@ -10762,7 +10701,6 @@
}
entries.push({
entry: {
type: 'thread watcher',
el: $.el('span', {
textContent: 'Settings'
}),
@ -10780,7 +10718,7 @@
if (refresh) {
this.refreshers.push(refresh.bind(entry));
}
$.event('AddMenuEntry', entry);
menu.addEntry(entry);
}
},
createSubEntry: function(name, desc) {
@ -10980,11 +10918,13 @@
onUpdate: function(e) {
if (e.detail[404]) {
return Unread.update();
} else if (!Conf['Quote Threading']) {
return Unread.addPosts(e.detail.newPosts);
} else {
} else if (Conf['Quote Threading']) {
Unread.read();
return Unread.update();
} else {
return Unread.addPosts(e.detail.newPosts.map(function(fullID) {
return g.posts[fullID];
}));
}
},
readSinglePost: function(post) {
@ -11129,7 +11069,7 @@
}
return Redirect.data = o;
},
archives: [{"uid":0,"name":"Foolz","domain":"archive.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["a","biz","co","diy","gd","jp","m","sci","sp","tg","tv","vg","vp","vr","wsg"],"files":["a","biz","diy","gd","jp","m","sci","tg","vg","vp","vr","wsg"]},{"uid":1,"name":"NSFW Foolz","domain":"nsfw.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["u"],"files":["u"]},{"uid":2,"name":"The Dark Cave","domain":"archive.thedarkcave.org","http":true,"https":true,"software":"foolfuuka","boards":["c","int","out","po"],"files":["c","po"]},{"uid":3,"name":"4plebs Archive","domain":"archive.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["adv","hr","o","pol","s4s","tg","trv","tv","x"],"files":["adv","hr","o","pol","s4s","tg","trv","tv","x"]},{"uid":18,"name":"4plebs Flash Archive","domain":"flash.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["f"],"files":["f"]},{"uid":4,"name":"Nyafuu","domain":"archive.nyafuu.org","http":true,"https":true,"software":"foolfuuka","boards":["c","e","w","wg"],"files":["c","e","w","wg"]},{"uid":5,"name":"Love is Over","domain":"archive.loveisover.me","http":true,"https":true,"software":"foolfuuka","boards":["d","i","lgbt"],"files":["d","i","lgbt"]},{"uid":8,"name":"Rebecca Black Tech","domain":"rbt.asia","http":false,"https":true,"software":"fuuka","boards":["cgl","g","mu","w"],"files":["cgl","g","mu","w"]},{"uid":9,"name":"Heinessen","domain":"archive.heinessen.com","http":true,"https":false,"software":"fuuka","boards":["an","fit","k","mlp","r9k","toy"],"files":["an","fit","k","mlp","r9k","toy"]},{"uid":10,"name":"warosu","domain":"fuuka.warosu.org","http":false,"https":true,"software":"fuuka","boards":["3","biz","cgl","ck","diy","fa","g","ic","jp","lit","sci","tg","vr"],"files":["3","biz","cgl","ck","diy","fa","ic","jp","lit","sci","tg","vr"]},{"uid":15,"name":"fgts","domain":"fgts.eu","http":true,"https":true,"software":"foolfuuka","boards":["asp","cm","h","hc","hm","n","p","r","s","soc","y"],"files":["asp","cm","h","hc","hm","n","p","r","s","soc","y"]},{"uid":16,"name":"maware","domain":"archive.mawa.re","http":true,"https":false,"software":"foolfuuka","boards":["t"],"files":["t"]},{"uid":17,"name":"installgentoo.com","domain":"chan.installgentoo.com","http":true,"https":false,"software":"foolfuuka","boards":["g","t"],"files":["g","t"]},{"uid":19,"name":"Innovandalism Archive","domain":"boards.innovandalism.eu","http":true,"https":false,"software":"foolfuuka","boards":["v"],"files":[]},{"uid":13,"name":"Foolz Beta","domain":"beta.foolz.us","http":true,"https":true,"withCredentials":true,"software":"foolfuuka","boards":["a","biz","co","d","diy","gd","jp","m","s4s","sci","sp","tg","tv","u","vg","vp","vr","wsg"],"files":["a","biz","d","diy","gd","jp","m","s4s","sci","tg","u","vg","vp","vr","wsg"]},{"uid":19,"name":"Innovandalism Archive","domain":"boards.innovandalism.eu","http":true,"https":false,"software":"foolfuuka","boards":["v"],"files":[]}],
archives: [{"uid":0,"name":"Foolz","domain":"archive.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["a","biz","c","co","diy","gd","int","jp","m","out","po","sci","sp","tg","tv","vg","vp","vr","wsg"],"files":["a","biz","c","co","diy","gd","jp","m","po","sci","tg","vg","vp","vr","wsg"]},{"uid":1,"name":"NSFW Foolz","domain":"nsfw.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["u"],"files":["u"]},{"uid":3,"name":"4plebs Archive","domain":"archive.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["adv","f","hr","o","pol","s4s","tg","trv","tv","x"],"files":["adv","f","hr","o","pol","s4s","tg","trv","tv","x"]},{"uid":4,"name":"Nyafuu","domain":"archive.nyafuu.org","http":true,"https":true,"software":"foolfuuka","boards":["c","e","w","wg"],"files":["c","e","w","wg"]},{"uid":5,"name":"Love is Over","domain":"archive.loveisover.me","http":true,"https":true,"software":"foolfuuka","boards":["d","i","lgbt"],"files":["d","i","lgbt"]},{"uid":8,"name":"Rebecca Black Tech","domain":"archive.rebeccablacktech.com","http":false,"https":true,"software":"fuuka","boards":["cgl","g","mu","w"],"files":["cgl","g","mu","w"]},{"uid":9,"name":"Heinessen","domain":"archive.heinessen.com","http":true,"https":false,"software":"fuuka","boards":["an","fit","k","mlp","r9k","toy"],"files":["an","fit","k","mlp","r9k","toy"]},{"uid":10,"name":"warosu","domain":"warosu.org","http":false,"https":true,"software":"fuuka","boards":["3","biz","cgl","ck","diy","fa","g","ic","jp","lit","sci","tg","vr"],"files":["3","biz","cgl","ck","diy","fa","ic","jp","lit","sci","tg","vr"]},{"uid":15,"name":"fgts","domain":"fgts.jp","http":true,"https":true,"software":"foolfuuka","boards":["asp","cm","h","hc","hm","n","p","r","s","soc","y"],"files":["asp","cm","h","hc","hm","n","p","r","s","soc","y"]},{"uid":16,"name":"maware","domain":"archive.mawa.re","http":true,"https":false,"software":"foolfuuka","boards":["t"],"files":["t"]},{"uid":19,"name":"Deniable Plausibility","domain":"boards.deniableplausibility.net","http":true,"https":false,"software":"foolfuuka","boards":["v","vg"],"files":["v","vg"]},{"uid":19,"name":"Innovandalism Archive","domain":"boards.innovandalism.eu","http":true,"https":false,"software":"foolfuuka","boards":["v"],"files":[]},{"uid":13,"name":"Foolz Beta","domain":"beta.foolz.us","http":true,"https":true,"withCredentials":true,"software":"foolfuuka","boards":["a","biz","c","co","d","diy","gd","int","jp","m","out","po","s4s","sci","sp","tg","tv","u","vg","vp","vr","wsg"],"files":["a","biz","c","co","d","diy","gd","jp","m","po","s4s","sci","tg","u","vg","vp","vr","wsg"]}],
to: function(dest, data) {
var archive;
archive = (dest === 'search' || dest === 'board' ? Redirect.data.thread : Redirect.data[dest])[data.boardID];
@ -11198,7 +11138,6 @@
return;
}
entry = {
type: 'header',
el: $.el('a', {
textContent: 'Show announcement',
className: 'show-announcement',
@ -11209,7 +11148,7 @@
return psa.hidden;
}
};
$.event('AddMenuEntry', entry);
Header.menu.addEntry(entry);
$.on(entry.el, 'click', PSAHiding.toggle);
PSAHiding.btn = btn = $.el('span', {
innerHTML: '[<a href=javascript:;>Dismiss</a>]',
@ -11367,8 +11306,7 @@
input = $('input', el);
$.on(input, 'change', this.toggle);
$.sync('Header catalog links', CatalogLinks.set);
$.event('AddMenuEntry', {
type: 'header',
Header.menu.addEntry({
el: el,
order: 95
});
@ -11900,7 +11838,7 @@
});
}
if (board === 'sci') {
$.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
$.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(document.getElementById(e.detail));\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
return Post.callbacks.push({
name: 'Parse /sci/ math',
cb: this.math
@ -11927,7 +11865,7 @@
if (this.isClone || !$('.math', this.nodes.comment)) {
return;
}
return $.event('jsmath', this.nodes.post, window);
return $.event('jsmath', this.nodes.post.id, window);
}
};
@ -12230,31 +12168,31 @@
}
break;
case Conf['Next thread']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
Nav.scroll(+1);
break;
case Conf['Previous thread']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
Nav.scroll(-1);
break;
case Conf['Expand thread']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
ExpandThread.toggle(thread);
break;
case Conf['Open thread']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
Keybinds.open(thread);
break;
case Conf['Open thread tab']:
if (g.VIEW !== 'index') {
if (g.VIEW !== 'index' || Conf['Index Mode'] === 'catalog') {
return;
}
Keybinds.open(thread, true);
@ -12643,7 +12581,7 @@
var response;
e.preventDefault();
response = field.value.trim();
if (!/\s/.test(response)) {
if (!/\s|^\d+$/.test(response)) {
field.value = "" + response + " " + response;
}
return this.submit();
@ -13194,7 +13132,6 @@
Settings.addSection('Sauce', Settings.sauce);
Settings.addSection('Advanced', Settings.advanced);
Settings.addSection('Keybinds', Settings.keybinds);
$.on(d, 'AddSettingsSection', Settings.addSection);
$.on(d, 'OpenSettings', function(e) {
return Settings.open(e.detail);
});
@ -13258,10 +13195,7 @@
},
sections: [],
addSection: function(title, open) {
var hyphenatedTitle, _ref;
if (typeof title !== 'string') {
_ref = title.detail, title = _ref.title, open = _ref.open;
}
var hyphenatedTitle;
hyphenatedTitle = title.toLowerCase().replace(/\s+/g, '-');
return Settings.sections.push({
title: title,
@ -13941,7 +13875,6 @@
init('Banner', Banner);
init('Navigate', Navigate);
init('Flash Features', Flash);
$.on(d, 'AddCallback', Main.addCallback);
return $.ready(Main.initReady);
},
initStyle: function() {
@ -14074,25 +14007,6 @@
return $.set('previousversion', g.VERSION);
});
},
addCallback: function(e) {
var Klass, obj;
obj = e.detail;
if (typeof obj.callback.name !== 'string') {
throw new Error("Invalid callback name: " + obj.callback.name);
}
switch (obj.type) {
case 'Post':
Klass = Post;
break;
case 'Thread':
Klass = Thread;
break;
default:
return;
}
obj.callback.isAddon = true;
return Klass.callbacks.push(obj.callback);
},
handleErrors: function(errors) {
var div, error, logs, _i, _len;
if (!(errors instanceof Array)) {

View File

@ -8,7 +8,6 @@
.field {
background-color: #FFF;
border: 1px solid #CCC;
-moz-box-sizing: border-box;
box-sizing: border-box;
color: #333;
font-family: inherit;
@ -235,7 +234,6 @@ body > .desktop:not(hr):not(.navLinks):not(#boardNavDesktop):not(#boardNavDeskto
position: absolute;
}
.message {
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 6px 20px;
max-height: 200px;
@ -245,7 +243,6 @@ body > .desktop:not(hr):not(.navLinks):not(#boardNavDesktop):not(#boardNavDeskto
/* Settings */
:root.fourchan-x body {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#overlay {
@ -258,7 +255,6 @@ body > .desktop:not(hr):not(.navLinks):not(#boardNavDesktop):not(#boardNavDeskto
width: 100%;
}
#fourchanx-settings {
-moz-box-sizing: border-box;
box-sizing: border-box;
box-shadow: 0 0 15px rgba(0, 0, 0, .15);
height: 600px;
@ -400,16 +396,16 @@ body > .desktop:not(hr):not(.navLinks):not(#boardNavDesktop):not(#boardNavDeskto
text-decoration: none;
}
.catalog-mode .board {
text-align: center;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.catalog-thread {
display: inline-flex;
text-align: left;
flex-direction: column;
align-items: center;
margin: 0 2px 5px;
word-break: break-word;
vertical-align: top;
}
.catalog-small .catalog-thread {
width: 165px;
@ -682,7 +678,6 @@ a.hide-announcement {
clear: both;
}
#ihover {
-moz-box-sizing: border-box;
box-sizing: border-box;
max-height: 100%;
max-width: 75%;
@ -824,7 +819,6 @@ a.hide-announcement {
border: 1px solid #808080;
color: #FFF !important;
font-size: 12px;
-moz-box-sizing: border-box;
box-sizing: border-box;
cursor: move;
display: inline-block;

View File

@ -27,18 +27,18 @@
}
},
"devDependencies": {
"font-awesome": "~4.0.3",
"grunt": "~0.4.4",
"grunt-bump": "~0.0.13",
"font-awesome": "~4.1.0",
"grunt": "~0.4.5",
"grunt-bump": "~0.0.14",
"grunt-concurrent": "~0.5.0",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-coffee": "~0.10.1",
"grunt-contrib-compress": "~0.8.0",
"grunt-contrib-compress": "~0.9.1",
"grunt-contrib-concat": "~0.4.0",
"grunt-contrib-copy": "~0.5.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-shell": "~0.7.0",
"load-grunt-tasks": "~0.4.0"
"load-grunt-tasks": "~0.5.0"
},
"repository": {
"type": "git",

View File

@ -5,8 +5,8 @@
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["a", "biz", "co", "diy", "gd", "jp", "m", "sci", "sp", "tg", "tv", "vg", "vp", "vr", "wsg"],
"files": ["a", "biz", "diy", "gd", "jp", "m", "sci", "tg", "vg", "vp", "vr", "wsg"]
"boards": ["a", "biz", "c", "co", "diy", "gd", "int", "jp", "m", "out", "po", "sci", "sp", "tg", "tv", "vg", "vp", "vr", "wsg"],
"files": ["a", "biz", "c", "co", "diy", "gd", "jp", "m", "po", "sci", "tg", "vg", "vp", "vr", "wsg"]
}, {
"uid": 1,
"name": "NSFW Foolz",
@ -16,15 +16,6 @@
"software": "foolfuuka",
"boards": ["u"],
"files": ["u"]
}, {
"uid": 2,
"name": "The Dark Cave",
"domain": "archive.thedarkcave.org",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["c", "int", "out", "po"],
"files": ["c", "po"]
}, {
"uid": 3,
"name": "4plebs Archive",
@ -32,17 +23,8 @@
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["adv", "hr", "o", "pol", "s4s", "tg", "trv", "tv", "x"],
"files": ["adv", "hr", "o", "pol", "s4s", "tg", "trv", "tv", "x"]
}, {
"uid": 18,
"name": "4plebs Flash Archive",
"domain": "flash.4plebs.org",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["f"],
"files": ["f"]
"boards": ["adv", "f", "hr", "o", "pol", "s4s", "tg", "trv", "tv", "x"],
"files": ["adv", "f", "hr", "o", "pol", "s4s", "tg", "trv", "tv", "x"]
}, {
"uid": 4,
"name": "Nyafuu",
@ -64,7 +46,7 @@
}, {
"uid": 8,
"name": "Rebecca Black Tech",
"domain": "rbt.asia",
"domain": "archive.rebeccablacktech.com",
"http": false,
"https": true,
"software": "fuuka",
@ -82,7 +64,7 @@
}, {
"uid": 10,
"name": "warosu",
"domain": "fuuka.warosu.org",
"domain": "warosu.org",
"http": false,
"https": true,
"software": "fuuka",
@ -91,7 +73,7 @@
}, {
"uid": 15,
"name": "fgts",
"domain": "fgts.eu",
"domain": "fgts.jp",
"http": true,
"https": true,
"software": "foolfuuka",
@ -107,14 +89,14 @@
"boards": ["t"],
"files": ["t"]
}, {
"uid": 17,
"name": "installgentoo.com",
"domain": "chan.installgentoo.com",
"uid": 19,
"name": "Deniable Plausibility",
"domain": "boards.deniableplausibility.net",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": ["g", "t"],
"files": ["g", "t"]
"boards": ["v", "vg"],
"files": ["v", "vg"]
}, {
"uid": 19,
"name": "Innovandalism Archive",
@ -132,15 +114,6 @@
"https": true,
"withCredentials": true,
"software": "foolfuuka",
"boards": ["a", "biz", "co", "d", "diy", "gd", "jp", "m", "s4s", "sci", "sp", "tg", "tv", "u", "vg", "vp", "vr", "wsg"],
"files": ["a", "biz", "d", "diy", "gd", "jp", "m", "s4s", "sci", "tg", "u", "vg", "vp", "vr", "wsg"]
}, {
"uid": 19,
"name": "Innovandalism Archive",
"domain": "boards.innovandalism.eu",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": ["v"],
"files": []
"boards": ["a", "biz", "c", "co", "d", "diy", "gd", "int", "jp", "m", "out", "po", "s4s", "sci", "sp", "tg", "tv", "u", "vg", "vp", "vr", "wsg"],
"files": ["a", "biz", "c", "co", "d", "diy", "gd","jp", "m", "po", "s4s", "sci", "tg", "u", "vg", "vp", "vr", "wsg"]
}]

View File

@ -170,7 +170,6 @@ Filter =
textContent: 'Filter'
entry =
type: 'post'
el: div
order: 50
open: (post) ->
@ -195,7 +194,7 @@ Filter =
# Add a sub entry for each filter type.
entry.subEntries.push Filter.menu.createSubEntry type[0], type[1]
$.event 'AddMenuEntry', entry
Menu.menu.addEntry entry
createSubEntry: (text, type) ->
el = $.el 'a',

View File

@ -88,8 +88,7 @@ PostHiding =
makeStub =
el: $.el 'label', innerHTML: "<input type=checkbox name=makeStub checked=#{Conf['Stubs']}> Make stub"
$.event 'AddMenuEntry',
type: 'post'
Menu.menu.addEntry
el: $.el 'div',
textContent: 'Hide post'
className: 'hide-post-link'
@ -117,8 +116,7 @@ PostHiding =
@el.firstChild.checked = if 'hideRecursively' of data then data.hideRecursively else Conf['Recursive Hiding']
true
$.event 'AddMenuEntry',
type: 'post'
Menu.menu.addEntry
el: $.el 'div',
textContent: 'Unhide post'
className: 'show-post-link'
@ -132,8 +130,7 @@ PostHiding =
subEntries: [apply, thisPost, replies]
return if g.VIEW isnt 'index'
$.event 'AddMenuEntry',
type: 'post'
Menu.menu.addEntry
el: $.el 'a', href: 'javascript:;'
order: 20
open: (post) ->

View File

@ -229,12 +229,6 @@ Config =
true
'Add post and image deletion links to the menu.'
]
<% if (type === 'crx') { %>
'Download Link': [
true
'Add a download with original filename link to the menu. Chrome-only currently.'
]
<% } %>
'Archive Link': [
true
'Add an archive link to the menu.'
@ -307,10 +301,6 @@ Config =
true
'Open new threads or replies to a thread from the index in a new tab.'
]
'Remember Subject': [
false
'Remember the subject field, instead of resetting after posting.'
]
<% if (type === 'userscript') { %>
'Remember QR Size': [
false

View File

@ -1,8 +1,8 @@
Header =
init: ->
@menu = new UI.Menu 'header'
@menu = new UI.Menu()
menuButton = $.el 'span',
menuButton = $.el 'a',
className: 'menu-button'
innerHTML: '<i></i>'
@ -62,10 +62,8 @@ Header =
@addShortcut menuButton
$.event 'AddMenuEntry',
type: 'header'
el: $.el 'span',
textContent: 'Header'
@menu.addEntry
el: $.el 'span', textContent: 'Header'
order: 107
subEntries: [
el: barFixedToggler
@ -436,7 +434,7 @@ Header =
shortcut = $.el 'span',
className: 'shortcut brackets-wrap'
$.add shortcut, el
$.prepend Header.shortcuts, shortcut
$.add Header.shortcuts, shortcut
rmShortcut: (el) ->
$.rm el.parentElement
@ -445,9 +443,8 @@ Header =
Header.menu.toggle e, @, g
createNotification: (e) ->
{type, content, lifetime, cb} = e.detail
{type, content, lifetime} = e.detail
notice = new Notice type, content, lifetime
cb notice if cb
areNotificationsEnabled: false
enableDesktopNotifications: ->

View File

@ -73,8 +73,7 @@ Index =
when 'Show Replies'
$.on input, 'change', @cb.replies
$.event 'AddMenuEntry',
type: 'header'
Header.menu.addEntry
el: $.el 'span',
textContent: 'Index Navigation'
order: 98
@ -171,8 +170,7 @@ Index =
init: ->
return if g.VIEW isnt 'index' or !Conf['Menu'] or g.BOARD.ID is 'f'
$.event 'AddMenuEntry',
type: 'post'
Menu.menu.addEntry
el: $.el 'a', href: 'javascript:;'
order: 19
open: ({thread}) ->
@ -372,7 +370,7 @@ Index =
onSameIndex = g.VIEW is 'index' and a.pathname.split('/')[1] is g.BOARD.ID
needChange = Index.cb.indexNav a, onSameIndex
# Do nav if this isn't a simple click, or different board.
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or !onSameIndex
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or !onSameIndex or g.BOARD.ID is 'f'
e.preventDefault()
Index.update() unless needChange
@ -781,7 +779,6 @@ Index =
$.rmAll Index.root unless infinite
$.add Index.root, nodes
$.event 'IndexBuild', nodes
isSearching: false

View File

@ -142,7 +142,6 @@ Main =
init 'Navigate', Navigate
init 'Flash Features', Flash
$.on d, 'AddCallback', Main.addCallback
$.ready Main.initReady
initStyle: ->
@ -260,20 +259,6 @@ Main =
Settings.open()
$.set 'previousversion', g.VERSION
addCallback: (e) ->
obj = e.detail
unless typeof obj.callback.name is 'string'
throw new Error "Invalid callback name: #{obj.callback.name}"
switch obj.type
when 'Post'
Klass = Post
when 'Thread'
Klass = Thread
else
return
obj.callback.isAddon = true
Klass.callbacks.push obj.callback
handleErrors: (errors) ->
unless errors instanceof Array
error = errors

View File

@ -16,8 +16,7 @@ Settings =
Settings.addSection 'Advanced', Settings.advanced
Settings.addSection 'Keybinds', Settings.keybinds
$.on d, 'AddSettingsSection', Settings.addSection
$.on d, 'OpenSettings', (e) -> Settings.open e.detail
$.on d, 'OpenSettings', (e) -> Settings.open e.detail
settings = JSON.parse(localStorage.getItem '4chan-settings') or {}
return if settings.disableAll
@ -72,8 +71,6 @@ Settings =
sections: []
addSection: (title, open) ->
if typeof title isnt 'string'
{title, open} = title.detail
hyphenatedTitle = title.toLowerCase().replace /\s+/g, '-'
Settings.sections.push {title, hyphenatedTitle, open}
openSection: ->

View File

@ -21,10 +21,7 @@ UI = do ->
currentMenu = null
lastToggledButton = null
constructor: (@type) ->
# Doc here: https://github.com/MayhemYDG/4chan-x/wiki/Menu-API
$.on d, 'AddMenuEntry', @addEntry
$.on d, 'rmMenuEntry', @rmEntry
constructor: ->
@entries = []
makeMenu: ->
@ -190,9 +187,7 @@ UI = do ->
style.left = left
style.right = right
addEntry: (e) =>
entry = e.detail
return if entry.type isnt @type
addEntry: (entry) ->
@parseEntry entry
@entries.push entry

View File

@ -179,6 +179,10 @@ $.off = (el, events, handler) ->
return
$.event = (event, detail, root=d) ->
<% if (type === 'userscript') { %>
if detail? and typeof cloneInto is 'function'
detail = cloneInto detail, d.defaultView
<% } %>
root.dispatchEvent new CustomEvent event, {bubbles: true, detail}
$.open =

View File

@ -11,8 +11,7 @@ FappeTyme =
FappeTyme[lc] = input = el.firstElementChild
$.on input, 'change', FappeTyme.cb.toggle.bind input
$.event 'AddMenuEntry',
type: 'header'
Header.menu.addEntry
el: el
order: 97

View File

@ -60,7 +60,7 @@ Gallery =
}
menuButton = $ '.menu-button', dialog
nodes.menu = new UI.Menu 'gallery'
nodes.menu = new UI.Menu()
{cb} = Gallery
$.on nodes.frame, 'click', cb.blank
@ -76,8 +76,7 @@ Gallery =
for name of Config.gallery
{el} = createSubEntry name
$.event 'AddMenuEntry',
type: 'gallery'
nodes.menu.addEntry
el: el
order: 0
@ -251,8 +250,7 @@ Gallery =
for name of Config.gallery
subEntries.push createSubEntry name
$.event 'AddMenuEntry',
type: 'header'
Header.menu.addEntry
el: el
order: 105
subEntries: subEntries

View File

@ -266,8 +266,7 @@ ImageExpand =
for name, conf of Config.imageExpansion
subEntries.push createSubEntry name, conf[1]
$.event 'AddMenuEntry',
type: 'header'
Header.menu.addEntry
el: el
order: 105
subEntries: subEntries

View File

@ -16,8 +16,7 @@ ImageLoader =
@el = prefetch.firstElementChild
$.on @el, 'change', @toggle
$.event 'AddMenuEntry',
type: 'header'
Header.menu.addEntry
el: prefetch
order: 104

View File

@ -6,7 +6,6 @@ ArchiveLink =
textContent: 'Archive'
entry =
type: 'post'
el: div
order: 90
open: ({ID, thread, board}) ->
@ -25,7 +24,7 @@ ArchiveLink =
# Add a sub entry for each type.
entry.subEntries.push @createSubEntry type[0], type[1]
$.event 'AddMenuEntry', entry
Menu.menu.addEntry entry
createSubEntry: (text, type) ->
el = $.el 'a',

View File

@ -26,8 +26,7 @@ DeleteLink =
$.on fileEl, 'click', DeleteLink.delete
true
$.event 'AddMenuEntry',
type: 'post'
Menu.menu.addEntry
el: div
order: 40
open: (post) ->

View File

@ -5,8 +5,7 @@ DownloadLink =
a = $.el 'a',
className: 'download-link'
textContent: 'Download file'
$.event 'AddMenuEntry',
type: 'post'
Menu.menu.addEntry
el: a
order: 100
open: ({file}) ->

View File

@ -2,8 +2,7 @@ Labels =
init: ->
return if !Conf['Menu']
$.event 'AddMenuEntry',
type: 'post'
Menu.menu.addEntry
el: $.el 'div', textContent: 'Labels'
order: 60
open: (post, addSubEntry) ->

View File

@ -7,7 +7,7 @@ Menu =
innerHTML: '<i class="fa fa-bars"></i>'
href: 'javascript:;'
@menu = new UI.Menu 'post'
@menu = new UI.Menu()
Post.callbacks.push
name: 'Menu'
cb: @node

View File

@ -7,8 +7,7 @@ ReportLink =
href: 'javascript:;'
textContent: 'Report this post'
$.on a, 'click', ReportLink.report
$.event 'AddMenuEntry',
type: 'post'
Menu.menu.addEntry
el: a
order: 10
open: (post) ->

View File

@ -11,14 +11,13 @@ PSAHiding =
return
entry =
type: 'header'
el: $.el 'a',
textContent: 'Show announcement'
className: 'show-announcement'
href: 'javascript:;'
order: 50
open: -> psa.hidden
$.event 'AddMenuEntry', entry
Header.menu.addEntry entry
$.on entry.el, 'click', PSAHiding.toggle
PSAHiding.btn = btn = $.el 'span',

View File

@ -10,8 +10,7 @@ CatalogLinks =
$.on input, 'change', @toggle
$.sync 'Header catalog links', CatalogLinks.set
$.event 'AddMenuEntry',
type: 'header'
Header.menu.addEntry
el: el
order: 95

View File

@ -18,7 +18,7 @@ Fourchan =
window.addEventListener('jsmath', function(e) {
if (jsMath.loaded) {
// process one post
jsMath.ProcessBeforeShowing(e.detail);
jsMath.ProcessBeforeShowing(document.getElementById(e.detail));
} else {
// load jsMath and process whole document
jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);
@ -39,4 +39,4 @@ Fourchan =
return
math: ->
return if @isClone or !$ '.math', @nodes.comment
$.event 'jsmath', @nodes.post, window
$.event 'jsmath', @nodes.post.id, window

View File

@ -144,19 +144,19 @@ Keybinds =
Index.setIndexMode 'catalog'
# Thread Navigation
when Conf['Next thread']
return if g.VIEW isnt 'index'
return if g.VIEW isnt 'index' or Conf['Index Mode'] is 'catalog'
Nav.scroll +1
when Conf['Previous thread']
return if g.VIEW isnt 'index'
return if g.VIEW isnt 'index' or Conf['Index Mode'] is 'catalog'
Nav.scroll -1
when Conf['Expand thread']
return if g.VIEW isnt 'index'
return if g.VIEW isnt 'index' or Conf['Index Mode'] is 'catalog'
ExpandThread.toggle thread
when Conf['Open thread']
return if g.VIEW isnt 'index'
return if g.VIEW isnt 'index' or Conf['Index Mode'] is 'catalog'
Keybinds.open thread
when Conf['Open thread tab']
return if g.VIEW isnt 'index'
return if g.VIEW isnt 'index' or Conf['Index Mode'] is 'catalog'
Keybinds.open thread, true
# Reply Navigation
when Conf['Next reply']

View File

@ -9,5 +9,5 @@ Report =
$.on $('form'), 'submit', (e) ->
e.preventDefault()
response = field.value.trim()
field.value = "#{response} #{response}" unless /\s/.test response
field.value = "#{response} #{response}" unless /\s|^\d+$/.test response
@submit()

View File

@ -47,8 +47,7 @@ ThreadUpdater =
subEntries.push el: @settings
$.event 'AddMenuEntry', @entry =
type: 'header'
Header.menu.addEntry @entry =
el: $.el 'span',
textContent: 'Updater'
order: 110
@ -169,7 +168,7 @@ ThreadUpdater =
ThreadUpdater.thread.kill()
$.event 'ThreadUpdate',
404: true
thread: ThreadUpdater.thread
threadID: ThreadUpdater.thread.fullID
else
ThreadUpdater.outdateCount++
ThreadUpdater.setInterval()
@ -292,9 +291,6 @@ ThreadUpdater =
node = Build.postFromObject postObject, ThreadUpdater.thread.board.ID
posts.push new Post node, ThreadUpdater.thread, ThreadUpdater.thread.board
deletedPosts = []
deletedFiles = []
# Check for deleted posts/files.
ThreadUpdater.thread.posts.forEach (post) ->
# XXX tmp fix for 4chan's racing condition
@ -304,12 +300,10 @@ ThreadUpdater =
unless ID in index
post.kill()
deletedPosts.push post
else if post.isDead
post.resurrect()
else if post.file and not (post.file.isDead or ID in files)
else if post.file and !post.file.isDead and ID not in files
post.kill true
deletedFiles.push post
# Fetching your own posts after posting
if ThreadUpdater.postID and ThreadUpdater.postID is ID
@ -318,10 +312,8 @@ ThreadUpdater =
sendEvent = ->
$.event 'ThreadUpdate',
404: false
thread: ThreadUpdater.thread
newPosts: posts
deletedPosts: deletedPosts
deletedFiles: deletedFiles
threadID: ThreadUpdater.thread.fullID
newPosts: posts.map (post) -> post.fullID
postCount: OP.replies + 1
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file and !ThreadUpdater.thread.OP.file.isDead)

View File

@ -88,12 +88,12 @@ ThreadWatcher =
[boardID, threadID] = @parentNode.dataset.fullID.split '.'
ThreadWatcher.rm boardID, +threadID
post: (e) ->
{board, postID, threadID} = e.detail
{boardID, threadID, postID} = e.detail
if postID is threadID
if Conf['Auto Watch']
$.set 'AutoWatch', threadID
else if Conf['Auto Watch Reply']
ThreadWatcher.add board.threads[threadID]
ThreadWatcher.add g.threads[boardID + '.' + threadID]
onIndexRefresh: ->
boardID = g.BOARD.ID
for threadID, data of ThreadWatcher.db.data.boards[boardID] when not data.isDead and threadID not of g.BOARD.threads
@ -104,7 +104,7 @@ ThreadWatcher =
ThreadWatcher.db.set {boardID, threadID, val: data}
ThreadWatcher.refresh()
onThreadRefresh: (e) ->
{thread} = e.detail
thread = g.threads[e.detail.threadID]
return unless e.detail[404] and ThreadWatcher.db.get {boardID: thread.board.ID, threadID: thread.ID}
# Update 404 status.
ThreadWatcher.add thread
@ -227,18 +227,17 @@ ThreadWatcher =
refreshers: []
init: ->
return if !Conf['Thread Watcher']
menu = new UI.Menu 'thread watcher'
menu = new UI.Menu()
$.on $('.menu-button', ThreadWatcher.dialog), 'click', (e) ->
menu.toggle e, @, ThreadWatcher
@addHeaderMenuEntry()
@addMenuEntries()
@addMenuEntries menu
addHeaderMenuEntry: ->
return if g.VIEW isnt 'thread'
entryEl = $.el 'a',
href: 'javascript:;'
$.event 'AddMenuEntry',
type: 'header'
Header.menu.addEntry
el: entryEl
order: 60
$.on entryEl, 'click', -> ThreadWatcher.toggle g.threads["#{g.BOARD}.#{g.THREADID}"]
@ -251,14 +250,13 @@ ThreadWatcher =
$.rmClass entryEl, rmClass
entryEl.textContent = text
addMenuEntries: ->
addMenuEntries: (menu) ->
entries = []
# `Open all` entry
entries.push
cb: ThreadWatcher.cb.openAll
entry:
type: 'thread watcher'
el: $.el 'a',
textContent: 'Open all threads'
refresh: -> (if ThreadWatcher.list.firstElementChild then $.rmClass else $.addClass) @el, 'disabled'
@ -267,7 +265,6 @@ ThreadWatcher =
entries.push
cb: ThreadWatcher.cb.checkThreads
entry:
type: 'thread watcher'
el: $.el 'a',
textContent: 'Check 404\'d threads'
refresh: -> (if $('div:not(.dead-thread)', ThreadWatcher.list) then $.rmClass else $.addClass) @el, 'disabled'
@ -276,7 +273,6 @@ ThreadWatcher =
entries.push
cb: ThreadWatcher.cb.pruneDeads
entry:
type: 'thread watcher'
el: $.el 'a',
textContent: 'Prune 404\'d threads'
refresh: -> (if $('.dead-thread', ThreadWatcher.list) then $.rmClass else $.addClass) @el, 'disabled'
@ -287,7 +283,6 @@ ThreadWatcher =
subEntries.push @createSubEntry name, conf[1]
entries.push
entry:
type: 'thread watcher'
el: $.el 'span',
textContent: 'Settings'
subEntries: subEntries
@ -296,7 +291,7 @@ ThreadWatcher =
entry.el.href = 'javascript:;' if entry.el.nodeName is 'A'
$.on entry.el, 'click', cb if cb
@refreshers.push refresh.bind entry if refresh
$.event 'AddMenuEntry', entry
menu.addEntry entry
return
createSubEntry: (name, desc) ->
entry =

View File

@ -122,11 +122,11 @@ Unread =
onUpdate: (e) ->
if e.detail[404]
Unread.update()
else if !Conf['Quote Threading']
Unread.addPosts e.detail.newPosts
else
else if Conf['Quote Threading']
Unread.read()
Unread.update()
else
Unread.addPosts e.detail.newPosts.map (fullID) -> g.posts[fullID]
readSinglePost: (post) ->
{ID} = post

View File

@ -93,7 +93,7 @@ QR.captcha =
response = response.trim()
# one-word-captcha:
# If there's only one word, duplicate it.
response = "#{response} #{response}" unless /\s/.test response
response = "#{response} #{response}" unless /\s|^\d+$/.test response
{challenge, response}
save: ->

View File

@ -53,11 +53,6 @@ QR =
$.before $.id('togglePostFormLink'), link
$.on d, 'QRGetSelectedPost', ({detail: cb}) ->
cb QR.selected
$.on d, 'QRAddPreSubmitHook', ({detail: cb}) ->
QR.preSubmitHooks.push cb
<% if (type === 'crx') { %>
$.on d, 'paste', QR.paste
<% } %>
@ -580,8 +575,6 @@ QR =
nodes.flag = flag
$.add nodes.form, flag
preSubmitHooks: []
submit: (e) ->
e?.preventDefault()
@ -614,9 +607,6 @@ QR =
err = 'No file selected.'
else if post.file and thread.fileLimit
err = 'Max limit of image replies has been reached.'
else for hook in QR.preSubmitHooks
if err = hook post, thread
break
if QR.captcha.isEnabled and !err
{challenge, response} = QR.captcha.getOne()
@ -775,11 +765,11 @@ QR =
# Post/upload confirmed as successful.
$.event 'QRPostSuccessful', {
board: g.BOARD
boardID: g.BOARD.ID
threadID
postID
}
$.event 'QRPostSuccessful_', {threadID, postID}
$.event 'QRPostSuccessful_', {boardID: g.BOARD.ID, threadID, postID}
# Enable auto-posting if we have stuff left to post, disable it otherwise.
postsCount = QR.posts.length - 1

View File

@ -112,7 +112,6 @@ QR.post = class
rectList = @nodes.el.parentNode.getBoundingClientRect()
@nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width/2 - rectList.left - rectList.width/2
@load()
$.event 'QRPostSelection', @
load: ->
# Load this post's values.

View File

@ -13,8 +13,7 @@ QuoteThreading =
input = $ 'input', @controls
$.on input, 'change', @toggle
$.event 'AddMenuEntry', @entry =
type: 'header'
Header.menu.addEntry @entry =
el: @controls
order: 98