Merge branch 'email-fix-reverted' into tests

This commit is contained in:
ccd0 2014-06-27 14:29:05 -07:00
commit 335ef45af3
43 changed files with 353 additions and 1150 deletions

View File

@ -1,3 +1,32 @@
### v1.8.1
*2014-06-19*
**MayhemYDG**
- More API changes:
- `ThreadUpdate`:
- `thread` field replaced with `threadID` containing `fullID` of thread (e.g. `"g.39894014"`)
- `newPosts` field changed from list of `Post` objects to list of post `fullID`s.
- `deletedPosts` and `deletedFiles` removed
- `QRPostSuccessful`:
- `board` field replaced with `boardID` containing name of board (e.g. `"g"`)
- `QRPostSuccessful_`:
- `boardID` added; is now identical to `QRPostSuccessful`
## v1.8.0
*2014-06-18*
**ccd0**
- Add compatibility with Greasemonkey 2.0.
- Much of Mayhem's [API](https://github.com/MayhemYDG/4chan-x/wiki) has been removed due to issues with Greasemonkey 2.0.
- The `AddCallback`, `QRPostSelection`, `QRGetSelectedPost`, and `QRAddPreSubmitHook` events are removed.
- Callback functions can no longer be passed via the `AddMenuEntry` and `CreateNotification` events.
- The information sent with `QRPostSuccessful` and `ThreadUpdate` events has been reduced:
- Board objects have been reduced to the form `{ID: "g"}`.
- Thread and post objects have been reduced to the form `{ID: 39894014, fullID: "g.39894014"}`.
- More fields may be added if requested.
- The `AddMenuEntry` and `AddSettingsSection` events continue to not work in Chromium should be considered deprecated. They are provided for backwards compatibility with existing scripts. Suggestions for replacements are welcome.
- The `4chanXInitFinished`, `CloseMenu`, `QRDialogCreation`, and `OpenSettings` events are unchanged, as is the undocumented `QRPostSuccessful_` (`QRPostSuccessful` without the board object, used by Name Sync on Chromium).
### v1.7.63 ### v1.7.63
*2014-06-16* *2014-06-16*

View File

@ -124,6 +124,9 @@ module.exports = (grunt) ->
command: """ command: """
git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>." git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>."
git tag -a <%= pkg.version %> -m "<%= pkg.meta.name %> v<%= pkg.version %>." git tag -a <%= pkg.version %> -m "<%= pkg.meta.name %> v<%= pkg.version %>."
"""
stable:
command: """
git tag -af stable -m "<%= pkg.meta.name %> v<%= pkg.version %>." git tag -af stable -m "<%= pkg.meta.name %> v<%= pkg.version %>."
git checkout gh-pages git checkout gh-pages
git merge --ff-only stable git merge --ff-only stable
@ -204,6 +207,16 @@ module.exports = (grunt) ->
'clean:tmpuserscript' 'clean:tmpuserscript'
] ]
grunt.registerTask 'testing', [
'build'
'shell:pack'
'compress:crx'
'concat:meta'
'copy:builds'
'shell:commit'
'shell:push'
]
grunt.registerTask 'release', [ grunt.registerTask 'release', [
'build' 'build'
'shell:pack' 'shell:pack'
@ -211,6 +224,7 @@ module.exports = (grunt) ->
'concat:meta' 'concat:meta'
'copy:builds' 'copy:builds'
'shell:commit' 'shell:commit'
'shell:stable'
'shell:push' 'shell:push'
] ]

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.7.63 - 2014-06-16 * 4chan X - Version 1.8.1 - 2014-06-19
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE

View File

@ -3,8 +3,6 @@ Fork of [Spittie's 4chan X](https://github.com/Spittie/4chan-x) (itself a fork o
Note: If you're looking for a maintained fork of OneeChan, try Note: If you're looking for a maintained fork of OneeChan, try
https://github.com/Nebukazar/OneeChan https://github.com/Nebukazar/OneeChan
#### [Why 4chan X needs to access data on every site?](https://github.com/ccd0/4chan-x/wiki/Why-4chan-X-needs-to-access-data-from-every-website%3F)
## [Install](https://ccd0.github.io/4chan-x/builds/4chan-X.user.js) (Firefox) ## [Install](https://ccd0.github.io/4chan-x/builds/4chan-X.user.js) (Firefox)
Install [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/), then click the link above to install. Install [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/), then click the link above to install.
@ -25,29 +23,7 @@ This fork of 4chan X is not guaranteed to work correctly in other browsers, but
5. Download 4chanX with `wget https://ccd0.github.io/4chan-x/builds/4chan-X.user.js` 5. Download 4chanX with `wget https://ccd0.github.io/4chan-x/builds/4chan-X.user.js`
6. Start dwb 6. Start dwb
## If you have any problems, try resetting your 4chan X settings ## [Frequently Asked Questions](https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions)
## Forking ## [Reporting Bugs and Contributing](https://github.com/ccd0/4chan-x/blob/master/CONTRIBUTING.md)
### Get started
- Get started by reading through the [Help link](https://help.github.com/) on how to fork a Github project.
- Click the "Fork" button on this page.
- Install [node.js](http://nodejs.org/).
- Install [Grunt's CLI](http://gruntjs.com/) with `npm install -g grunt-cli`.
- Clone your fork of 4chan X.
- `cd` into it.
- Install/Update 4chan X dependencies with `npm install`.
### Build
- Build with `grunt`.
- Continuously build with `grunt watch`.
### Release
- Update the version with `grunt patch`, `grunt minor` or `grunt major`.
- Release with `grunt release`.
Note: this is only used to release new 4chan X versions, ignore as you see fit.

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.7.63 // @version 1.8.1
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript // Generated by CoffeeScript
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.7.63 // @version 1.8.1
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X
@ -24,7 +24,7 @@
// ==/UserScript== // ==/UserScript==
/* /*
* 4chan X - Version 1.7.63 - 2014-06-16 * 4chan X - Version 1.8.1 - 2014-06-19
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE
@ -374,7 +374,7 @@
doc = d.documentElement; doc = d.documentElement;
g = { g = {
VERSION: '1.7.63', VERSION: '1.8.1',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
boards: {} boards: {}
}; };
@ -386,16 +386,6 @@
return root.querySelector(selector); return root.querySelector(selector);
}; };
$.extend = function(obj, prop) {
var key, val;
for (key in prop) {
val = prop[key];
if (prop.hasOwnProperty(key)) {
obj[key] = val;
}
}
};
$.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000))); $.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000)));
$.id = function(id) { $.id = function(id) {
@ -659,6 +649,9 @@
if (root == null) { if (root == null) {
root = d; root = d;
} }
if ((detail != null) && typeof cloneInto === 'function') {
detail = cloneInto(detail, document.defaultView);
}
return root.dispatchEvent(new CustomEvent(event, { return root.dispatchEvent(new CustomEvent(event, {
bubbles: true, bubbles: true,
detail: detail detail: detail
@ -840,36 +833,19 @@
Callbacks.prototype.push = function(_arg) { Callbacks.prototype.push = function(_arg) {
var cb, name; var cb, name;
name = _arg.name, cb = _arg.cb; name = _arg.name, cb = _arg.cb;
if (this[name]) {
this.connect(name);
}
if (!this[name]) { if (!this[name]) {
this.keys.push(name); this.keys.push(name);
} }
return this[name] = cb; return this[name] = cb;
}; };
Callbacks.prototype.connect = function(name) {
if (this[name].disconnected) {
return delete this[name].disconnected;
}
};
Callbacks.prototype.disconnect = function(name) {
if (this[name]) {
return this[name].disconnected = true;
}
};
Callbacks.prototype.execute = function(node) { Callbacks.prototype.execute = function(node) {
var err, errors, name, _i, _len, _ref; var err, errors, name, _i, _len, _ref;
_ref = this.keys; _ref = this.keys;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
name = _ref[_i]; name = _ref[_i];
try { try {
if (!this[name].disconnected) { this[name].call(node);
this[name].call(node);
}
} catch (_error) { } catch (_error) {
err = _error; err = _error;
if (!errors) { if (!errors) {
@ -1515,12 +1491,6 @@
return typeof this.sync === "function" ? this.sync() : void 0; return typeof this.sync === "function" ? this.sync() : void 0;
}; };
DataBoard.prototype.disconnect = function() {
$.desync(this.key);
delete this.sync;
return delete this.data;
};
return DataBoard; return DataBoard;
})(); })();
@ -1843,8 +1813,7 @@
$.sync('Header auto-hide', this.setBarVisibility); $.sync('Header auto-hide', this.setBarVisibility);
$.sync('Centered links', this.setLinkJustify); $.sync('Centered links', this.setLinkJustify);
this.addShortcut(menuButton); this.addShortcut(menuButton);
$.event('AddMenuEntry', { this.menu.addEntry({
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Header' textContent: 'Header'
}), }),
@ -2251,12 +2220,9 @@
return Header.menu.toggle(e, this, g); return Header.menu.toggle(e, this, g);
}, },
createNotification: function(e) { createNotification: function(e) {
var cb, content, lifetime, notice, type, _ref; var content, lifetime, notice, type, _ref;
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb; _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime;
notice = new Notice(type, content, lifetime); return notice = new Notice(type, content, lifetime);
if (cb) {
return cb(notice);
}
}, },
areNotificationsEnabled: false, areNotificationsEnabled: false,
enableDesktopNotifications: function() { enableDesktopNotifications: function() {
@ -2396,8 +2362,7 @@
$.on(input, 'change', this.cb.sort); $.on(input, 'change', this.cb.sort);
} }
} }
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Index Navigation' textContent: 'Index Navigation'
}), }),
@ -2922,14 +2887,12 @@
return nodes; return nodes;
}, },
buildStructure: function(nodes) { buildStructure: function(nodes) {
var i, node, result; var node, _i, _len;
result = $.frag(); for (_i = 0, _len = nodes.length; _i < _len; _i++) {
i = 0; node = nodes[_i];
while (node = nodes[i++]) { $.add(Index.root, [node, $.el('hr')]);
$.add(result, [node, $.el('hr')]);
} }
$.event('IndexBuild', result.children); return ThreadHiding.onIndexBuild(nodes);
return $.add(Index.root, result);
}, },
isSearching: false, isSearching: false,
clearSearch: function() { clearSearch: function() {
@ -3107,7 +3070,7 @@
This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS). This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
@license: https://github.com/4chan/4chan-JS/blob/master/LICENSE @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
*/ */
var E, boardID, capcode, container, date, dateUTC, email, file, fileSize, fileThumb, flagCode, flagName, h_capcodeClass, h_capcodeIcon, h_capcodeStart, h_closed, h_comment, h_emailEnd, h_emailStart, h_file, h_fileDims, h_fileInfo, h_fileTitle1, h_fileTitle2, h_flag, h_gifIcon, h_imgSrc, h_pageIcon, h_postClass, h_quoteLink, h_replyLink, h_sideArrows, h_staticPath, h_sticky, h_tripcode, h_userID, href, isClosed, isOP, isSticky, name, pageNum, postID, quote, shortFilename, spoilerRange, subject, threadID, tripcode, uniqueID, _i, _len, _ref; var E, boardID, capcode, container, date, dateUTC, email, email_processed, file, fileSize, fileThumb, flagCode, flagName, h_capcodeClass, h_capcodeIcon, h_capcodeStart, h_closed, h_comment, h_emailEnd, h_emailStart, h_file, h_fileDims, h_fileInfo, h_fileTitle1, h_fileTitle2, h_flag, h_gifIcon, h_imgSrc, h_pageIcon, h_postClass, h_quoteLink, h_replyLink, h_sideArrows, h_staticPath, h_sticky, h_tripcode, h_userID, href, isClosed, isOP, isSticky, name, pageNum, postID, quote, shortFilename, spoilerRange, subject, threadID, tripcode, uniqueID, _i, _len, _ref;
E = Build.h_escape; E = Build.h_escape;
postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, h_comment = o.h_comment, file = o.file; postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, h_comment = o.h_comment, file = o.file;
name || (name = ''); name || (name = '');
@ -3125,8 +3088,9 @@
} else { } else {
h_tripcode = ''; h_tripcode = '';
} }
email_processed = encodeURIComponent(email).replace(/%40/g, '@');
if (email) { if (email) {
h_emailStart = "<a href='mailto:" + (E(encodeURIComponent(email))) + "' class='useremail'>"; h_emailStart = "<a href='mailto:" + (E(email_processed)) + "' class='useremail'>";
h_emailEnd = '</a>'; h_emailEnd = '</a>';
} else { } else {
h_emailStart = ''; h_emailStart = '';
@ -3573,7 +3537,7 @@
}; };
UI = (function() { UI = (function() {
var Menu, checkbox, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove; var Menu, checkbox, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, menus, touchend, touchmove;
dialog = function(id, position, properties) { dialog = function(id, position, properties) {
var child, el, move, _i, _len, _ref; var child, el, move, _i, _len, _ref;
el = $.el('div', { el = $.el('div', {
@ -3599,6 +3563,7 @@
} }
return el; return el;
}; };
menus = {};
Menu = (function() { Menu = (function() {
var currentMenu, lastToggledButton; var currentMenu, lastToggledButton;
@ -3608,14 +3573,23 @@
function Menu(type) { function Menu(type) {
this.type = type; this.type = type;
this.rmEntry = __bind(this.rmEntry, this);
this.addEntry = __bind(this.addEntry, this); this.addEntry = __bind(this.addEntry, this);
this.onFocus = __bind(this.onFocus, this); this.onFocus = __bind(this.onFocus, this);
this.keybinds = __bind(this.keybinds, this); this.keybinds = __bind(this.keybinds, this);
this.close = __bind(this.close, this); this.close = __bind(this.close, this);
$.on(d, 'AddMenuEntry', this.addEntry); $.on(d, 'AddMenuEntry', (function(_this) {
$.on(d, 'rmMenuEntry', this.rmEntry); return function(_arg) {
var detail;
detail = _arg.detail;
if (detail.type !== _this.type) {
return;
}
delete detail.open;
return _this.addEntry(detail);
};
})(this));
this.entries = []; this.entries = [];
menus[this.type] = this;
} }
Menu.prototype.makeMenu = function() { Menu.prototype.makeMenu = function() {
@ -3806,26 +3780,11 @@
return style.right = right; return style.right = right;
}; };
Menu.prototype.addEntry = function(e) { Menu.prototype.addEntry = function(entry) {
var entry;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
this.parseEntry(entry); this.parseEntry(entry);
return this.entries.push(entry); return this.entries.push(entry);
}; };
Menu.prototype.rmEntry = function(e) {
var entry, index;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
index = this.entries.indexOf(entry);
return this.entries.splice(index, 1);
};
Menu.prototype.parseEntry = function(entry) { Menu.prototype.parseEntry = function(entry) {
var el, subEntries, subEntry, _i, _len; var el, subEntries, subEntry, _i, _len;
el = entry.el, subEntries = entry.subEntries; el = entry.el, subEntries = entry.subEntries;
@ -4295,7 +4254,6 @@
textContent: 'Filter' textContent: 'Filter'
}); });
entry = { entry = {
type: 'post',
el: div, el: div,
order: 50, order: 50,
open: function(post) { open: function(post) {
@ -4309,7 +4267,7 @@
type = _ref[_i]; type = _ref[_i];
entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1])); entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1]));
} }
return $.event('AddMenuEntry', entry); return Menu.menu.addEntry(entry);
}, },
createSubEntry: function(text, type) { createSubEntry: function(text, type) {
var el; var el;
@ -4415,8 +4373,7 @@
thisPost = UI.checkbox('thisPost', ' This post', true); thisPost = UI.checkbox('thisPost', ' This post', true);
replies = UI.checkbox('replies', ' Hide replies', Conf['Recursive Hiding']); replies = UI.checkbox('replies', ' Hide replies', Conf['Recursive Hiding']);
makeStub = UI.checkbox('makeStub', ' Make stub', Conf['Stubs']); makeStub = UI.checkbox('makeStub', ' Make stub', Conf['Stubs']);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(post) { open: function(post) {
@ -4454,8 +4411,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(hideStubLink, 'click', PostHiding.menu.hideStub); $.on(hideStubLink, 'click', PostHiding.menu.hideStub);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(post) { open: function(post) {
@ -4485,8 +4441,7 @@
} }
] ]
}); });
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: hideStubLink, el: hideStubLink,
order: 15, order: 15,
open: function(post) { open: function(post) {
@ -4723,7 +4678,6 @@
} }
this.db = new DataBoard('hiddenThreads'); this.db = new DataBoard('hiddenThreads');
this.syncCatalog(); this.syncCatalog();
$.on(d, 'IndexBuild', this.onIndexBuild);
return Thread.callbacks.push({ return Thread.callbacks.push({
name: 'Thread Hiding', name: 'Thread Hiding',
cb: this.node cb: this.node
@ -4742,16 +4696,12 @@
} }
return $.prepend(this.OP.nodes.root, ThreadHiding.makeButton(this, 'hide')); return $.prepend(this.OP.nodes.root, ThreadHiding.makeButton(this, 'hide'));
}, },
onIndexBuild: function(_arg) { onIndexBuild: function(nodes) {
var i, nodes, root, thread, _i, _len; var root, thread, _i, _len;
nodes = _arg.detail; for (_i = 0, _len = nodes.length; _i < _len; _i++) {
for (i = _i = 0, _len = nodes.length; _i < _len; i = _i += 2) { root = nodes[_i];
root = nodes[i];
thread = Get.threadFromRoot(root); thread = Get.threadFromRoot(root);
if (!thread.isHidden) { if (thread.isHidden && thread.stub && !root.contains(thread.stub)) {
continue;
}
if (thread.stub && root.contains(thread.stub)) {
ThreadHiding.makeStub(thread, root); ThreadHiding.makeStub(thread, root);
} }
} }
@ -4822,8 +4772,7 @@
}); });
$.on(apply, 'click', ThreadHiding.menu.hide); $.on(apply, 'click', ThreadHiding.menu.hide);
makeStub = UI.checkbox('Stubs', ' Make stub'); makeStub = UI.checkbox('Stubs', ' Make stub');
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(_arg) { open: function(_arg) {
@ -4849,8 +4798,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(div, 'click', ThreadHiding.menu.show); $.on(div, 'click', ThreadHiding.menu.show);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(_arg) { open: function(_arg) {
@ -4868,8 +4816,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(hideStubLink, 'click', ThreadHiding.menu.hideStub); $.on(hideStubLink, 'click', ThreadHiding.menu.hideStub);
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: hideStubLink, el: hideStubLink,
order: 15, order: 15,
open: function(_arg) { open: function(_arg) {
@ -5396,8 +5343,7 @@
}); });
input = $('input', this.controls); input = $('input', this.controls);
$.on(input, 'change', this.toggle); $.on(input, 'change', this.toggle);
$.event('AddMenuEntry', this.entry = { Header.menu.addEntry(this.entry = {
type: 'header',
el: this.controls, el: this.controls,
order: 98 order: 98
}); });
@ -5409,19 +5355,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var input;
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
input = $('input', this.controls);
$.off(input, 'change', this.toggle);
$.event('rmMenuEntry', this.entry);
delete this.enabled;
delete this.controls;
delete this.entry;
return Post.callbacks.disconnect('Quote Threading');
},
ready: function() { ready: function() {
$.off(d, '4chanXInitFinished', QuoteThreading.ready); $.off(d, '4chanXInitFinished', QuoteThreading.ready);
return QuoteThreading.force(); return QuoteThreading.force();
@ -5824,16 +5757,6 @@
$.prepend($('.navLinksBot'), linkBot); $.prepend($('.navLinksBot'), linkBot);
} }
$.before($.id('togglePostFormLink'), link); $.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, 'paste', QR.paste);
$.on(d, 'dragover', QR.dragOver); $.on(d, 'dragover', QR.dragOver);
$.on(d, 'drop', QR.dropFile); $.on(d, 'drop', QR.dropFile);
@ -6455,9 +6378,8 @@
return $.add(nodes.form, flag); return $.add(nodes.form, flag);
} }
}, },
preSubmitHooks: [],
submit: function(e) { 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) { if (e != null) {
e.preventDefault(); e.preventDefault();
} }
@ -6490,17 +6412,9 @@
err = 'No file selected.'; err = 'No file selected.';
} else if (post.file && thread.fileLimit) { } else if (post.file && thread.fileLimit) {
err = 'Max limit of image replies has been reached.'; 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) { 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) { if (!response) {
err = 'No valid captcha.'; err = 'No valid captcha.';
} }
@ -6633,11 +6547,12 @@
}); });
ThreadUpdater.postID = postID; ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', { $.event('QRPostSuccessful', {
board: g.BOARD, boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
postID: postID postID: postID
}); });
$.event('QRPostSuccessful_', { $.event('QRPostSuccessful_', {
boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
postID: postID postID: postID
}); });
@ -7260,8 +7175,7 @@
rectEl = this.nodes.el.getBoundingClientRect(); rectEl = this.nodes.el.getBoundingClientRect();
rectList = this.nodes.el.parentNode.getBoundingClientRect(); rectList = this.nodes.el.parentNode.getBoundingClientRect();
this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2; this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2;
this.load(); return this.load();
return $.event('QRPostSelection', this);
}; };
_Class.prototype.load = function() { _Class.prototype.load = function() {
@ -7533,8 +7447,7 @@
el.title = "" + type + " Tyme"; el.title = "" + type + " Tyme";
FappeTyme[lc] = input = el.firstElementChild; FappeTyme[lc] = input = el.firstElementChild;
$.on(input, 'change', FappeTyme.cb.toggle.bind(input)); $.on(input, 'change', FappeTyme.cb.toggle.bind(input));
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 97 order: 97
}); });
@ -7633,8 +7546,7 @@
createSubEntry = Gallery.menu.createSubEntry; createSubEntry = Gallery.menu.createSubEntry;
for (name in Config.gallery) { for (name in Config.gallery) {
el = createSubEntry(name).el; el = createSubEntry(name).el;
$.event('AddMenuEntry', { nodes.menu.addEntry({
type: 'gallery',
el: el, el: el,
order: 0 order: 0
}); });
@ -7868,8 +7780,7 @@
for (name in Config.gallery) { for (name in Config.gallery) {
subEntries.push(createSubEntry(name)); subEntries.push(createSubEntry(name));
} }
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 105, order: 105,
subEntries: subEntries subEntries: subEntries
@ -8213,8 +8124,7 @@
conf = _ref[name]; conf = _ref[name];
subEntries.push(createSubEntry(name, conf[1])); subEntries.push(createSubEntry(name, conf[1]));
} }
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 105, order: 105,
subEntries: subEntries subEntries: subEntries
@ -8386,8 +8296,7 @@
}); });
this.el = prefetch.firstElementChild; this.el = prefetch.firstElementChild;
$.on(this.el, 'change', this.toggle); $.on(this.el, 'change', this.toggle);
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: prefetch, el: prefetch,
order: 104 order: 104
}); });
@ -9144,7 +9053,6 @@
textContent: 'Archive' textContent: 'Archive'
}); });
entry = { entry = {
type: 'post',
el: div, el: div,
order: 90, order: 90,
open: function(_arg) { open: function(_arg) {
@ -9163,7 +9071,7 @@
type = _ref[_i]; type = _ref[_i];
entry.subEntries.push(this.createSubEntry(type[0], type[1])); entry.subEntries.push(this.createSubEntry(type[0], type[1]));
} }
return $.event('AddMenuEntry', entry); return Menu.menu.addEntry(entry);
}, },
createSubEntry: function(text, type) { createSubEntry: function(text, type) {
var el, open; var el, open;
@ -9240,8 +9148,7 @@
return true; return true;
} }
}; };
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 40, order: 40,
open: function(post) { open: function(post) {
@ -9365,8 +9272,7 @@
}; };
})(this)); })(this));
}); });
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: a, el: a,
order: 100, order: 100,
open: function(_arg) { open: function(_arg) {
@ -9434,8 +9340,7 @@
textContent: 'Report this post' textContent: 'Report this post'
}); });
$.on(a, 'click', ReportLink.report); $.on(a, 'click', ReportLink.report);
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: a, el: a,
order: 10, order: 10,
open: function(post) { open: function(post) {
@ -9512,12 +9417,6 @@
}, },
node: function() { node: function() {
return d.title = Get.threadExcerpt(this); return d.title = Get.threadExcerpt(this);
},
disconnect: function() {
if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
return;
}
return Thread.callbacks.disconnect('Thread Excerpt');
} }
}; };
@ -9569,25 +9468,6 @@
ThreadStats.update(postCount, fileCount); ThreadStats.update(postCount, fileCount);
return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate); return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
}, },
disconnect: function() {
if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
return;
}
if (Conf['Updater and Stats in Header']) {
Header.rmShortcut(this.dialog);
} else {
$.rm(this.dialog);
}
clearTimeout(this.timeout);
delete this.timeout;
delete this.thread;
delete this.postCountEl;
delete this.fileCountEl;
delete this.pageCountEl;
delete this.dialog;
Thread.callbacks.disconnect('Thread Stats');
return $.off(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
onUpdate: function(e) { onUpdate: function(e) {
var fileCount, postCount, _ref; var fileCount, postCount, _ref;
if (e.detail[404]) { if (e.detail[404]) {
@ -9707,8 +9587,7 @@
subEntries.push({ subEntries.push({
el: this.settings el: this.settings
}); });
$.event('AddMenuEntry', this.entry = { Header.menu.addEntry(this.entry = {
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Updater' textContent: 'Updater'
}), }),
@ -9720,45 +9599,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var el, entry, input, name, _i, _j, _len, _len1, _ref, _ref1;
if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
return;
}
$.off(this.timer, 'click', this.update);
$.off(this.status, 'click', this.update);
if (this.timeoutID) {
clearTimeout(this.timeoutID);
}
_ref = this.entry.subEntries;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
entry = _ref[_i];
el = entry.el;
input = el.firstElementChild;
$.off(input, 'change', $.cb.checked);
$.off(input, 'change', this.cb.scrollBG);
$.off(input, 'change', this.cb.update);
}
$.off(this.settings, 'click', this.intervalShortcut);
$.off(window, 'online offline', this.cb.online);
$.off(d, 'QRPostSuccessful', this.cb.checkpost);
$.off(d, 'visibilitychange', this.cb.visibility);
this.set('timer', null);
this.set('status', 'Offline');
$.event('rmMenuEntry', this.entry);
if (Conf['Updater and Stats in Header']) {
Header.rmShortcut(this.dialog);
} else {
$.rmClass(doc, 'float');
$.rm(this.dialog);
}
_ref1 = ['checkPostCount', 'timer', 'status', 'isUpdating', 'entry', 'dialog', 'thread', 'root', 'lastPost', 'outdateCount', 'online', 'seconds', 'timeoutID'];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
name = _ref1[_j];
delete this[name];
}
return Thread.callbacks.disconnect('Thread Updater');
},
node: function() { node: function() {
ThreadUpdater.thread = this; ThreadUpdater.thread = this;
ThreadUpdater.root = this.OP.nodes.root.parentNode; ThreadUpdater.root = this.OP.nodes.root.parentNode;
@ -9857,7 +9697,7 @@
ThreadUpdater.thread.kill(); ThreadUpdater.thread.kill();
$.event('ThreadUpdate', { $.event('ThreadUpdate', {
404: true, 404: true,
thread: ThreadUpdater.thread threadID: ThreadUpdater.thread.fullID
}); });
break; break;
default: default:
@ -9951,7 +9791,7 @@
return new Notice('info', "The thread is " + change + ".", 30); return new Notice('info', "The thread is " + change + ".", 30);
}, },
parse: function(postObjects) { parse: function(postObjects) {
var OP, count, deletedFiles, deletedPosts, files, index, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1; var OP, count, files, index, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1;
OP = postObjects[0]; OP = postObjects[0];
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
@ -9976,19 +9816,15 @@
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID); node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board)); posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
} }
deletedPosts = [];
deletedFiles = [];
ThreadUpdater.thread.posts.forEach(function(post) { ThreadUpdater.thread.posts.forEach(function(post) {
var ID; var ID;
ID = +post.ID; ID = +post.ID;
if (__indexOf.call(index, ID) < 0) { if (__indexOf.call(index, ID) < 0) {
post.kill(); post.kill();
deletedPosts.push(post);
} else if (post.isDead) { } else if (post.isDead) {
post.resurrect(); 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); post.kill(true);
deletedFiles.push(post);
} }
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) { if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
return ThreadUpdater.foundPost = true; return ThreadUpdater.foundPost = true;
@ -10040,10 +9876,10 @@
} }
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: false, 404: false,
thread: ThreadUpdater.thread, threadID: ThreadUpdater.thread.fullID,
newPosts: posts, newPosts: posts.map(function(post) {
deletedPosts: deletedPosts, return post.fullID;
deletedFiles: deletedFiles, }),
postCount: OP.replies + 1, postCount: OP.replies + 1,
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead) fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
}); });
@ -10070,9 +9906,6 @@
this.status = $('#watcher-status', this.dialog); this.status = $('#watcher-status', this.dialog);
this.list = this.dialog.lastElementChild; this.list = this.dialog.lastElementChild;
$.on(d, 'QRPostSuccessful', this.cb.post); $.on(d, 'QRPostSuccessful', this.cb.post);
if (g.VIEW === 'thread') {
$.on(d, 'ThreadUpdate', this.cb.threadUpdate);
}
$.on(sc, 'click', this.toggleWatcher); $.on(sc, 'click', this.toggleWatcher);
$.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher); $.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher);
$.on(d, '4chanXInitFinished', this.ready); $.on(d, '4chanXInitFinished', this.ready);
@ -10181,14 +10014,14 @@
return ThreadWatcher.rm(boardID, +threadID); return ThreadWatcher.rm(boardID, +threadID);
}, },
post: function(e) { post: function(e) {
var board, postID, threadID, _ref; var boardID, postID, threadID, _ref;
_ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID; _ref = e.detail, boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
if (postID === threadID) { if (postID === threadID) {
if (Conf['Auto Watch']) { if (Conf['Auto Watch']) {
return $.set('AutoWatch', threadID); return $.set('AutoWatch', threadID);
} }
} else if (Conf['Auto Watch Reply']) { } else if (Conf['Auto Watch Reply']) {
return ThreadWatcher.add(board.threads[threadID]); return ThreadWatcher.add(g.threads[boardID + '.' + threadID]);
} }
}, },
onIndexRefresh: function() { onIndexRefresh: function() {
@ -10218,7 +10051,7 @@
}, },
onThreadRefresh: function(e) { onThreadRefresh: function(e) {
var thread; var thread;
thread = e.detail.thread; thread = g.threads[e.detail.threadID];
if (!(e.detail[404] && ThreadWatcher.db.get({ if (!(e.detail[404] && ThreadWatcher.db.get({
boardID: thread.board.ID, boardID: thread.board.ID,
threadID: thread.ID threadID: thread.ID
@ -10430,7 +10263,7 @@
if (!Conf['Thread Watcher']) { if (!Conf['Thread Watcher']) {
return; return;
} }
menu = new UI.Menu('thread watcher'); menu = this.menu = new UI.Menu('thread watcher');
$.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) { $.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) {
return menu.toggle(e, this, ThreadWatcher); return menu.toggle(e, this, ThreadWatcher);
}); });
@ -10445,8 +10278,7 @@
entryEl = $.el('a', { entryEl = $.el('a', {
href: 'javascript:;' href: 'javascript:;'
}); });
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: entryEl, el: entryEl,
order: 60 order: 60
}); });
@ -10467,7 +10299,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.openAll, cb: ThreadWatcher.cb.openAll,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Open all threads' textContent: 'Open all threads'
}) })
@ -10479,7 +10310,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.checkThreads, cb: ThreadWatcher.cb.checkThreads,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Check 404\'d threads' textContent: 'Check 404\'d threads'
}) })
@ -10491,7 +10321,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.pruneDeads, cb: ThreadWatcher.cb.pruneDeads,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Prune 404\'d threads' textContent: 'Prune 404\'d threads'
}) })
@ -10508,7 +10337,6 @@
} }
entries.push({ entries.push({
entry: { entry: {
type: 'thread watcher',
el: $.el('span', { el: $.el('span', {
textContent: 'Settings' textContent: 'Settings'
}), }),
@ -10526,7 +10354,7 @@
if (refresh) { if (refresh) {
this.refreshers.push(refresh.bind(entry)); this.refreshers.push(refresh.bind(entry));
} }
$.event('AddMenuEntry', entry); this.menu.addEntry(entry);
} }
}, },
createSubEntry: function(name, desc) { createSubEntry: function(name, desc) {
@ -10562,28 +10390,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var hr, name, _i, _len, _ref;
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Desktop Notifications']) {
return;
}
Unread.db.disconnect();
if (hr = Unread.hr, Unread) {
$.rm(hr);
}
_ref = ['db', 'hr', 'posts', 'postsQuotingYou', 'thread', 'title', 'lastReadPost'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
name = _ref[_i];
delete this[name];
}
$.off(d, '4chanXInitFinished', this.ready);
$.off(d, 'ThreadUpdate', this.onUpdate);
$.off(d, 'scroll visibilitychange', this.read);
if (Conf['Unread Line'] && !Conf['Quote Threading']) {
$.off(d, 'visibilitychange', this.setLine);
}
return Thread.callbacks.disconnect('Unread');
},
node: function() { node: function() {
Unread.thread = this; Unread.thread = this;
Unread.title = d.title; Unread.title = d.title;
@ -10728,7 +10534,9 @@
if (e.detail[404]) { if (e.detail[404]) {
return Unread.update(); return Unread.update();
} else if (!QuoteThreading.enabled) { } else if (!QuoteThreading.enabled) {
return Unread.addPosts(e.detail.newPosts); return Unread.addPosts(e.detail.newPosts.map(function(fullID) {
return g.posts[fullID];
}));
} else { } else {
Unread.read(); Unread.read();
return Unread.update(); return Unread.update();
@ -10937,7 +10745,6 @@
return; return;
} }
entry = { entry = {
type: 'header',
el: $.el('a', { el: $.el('a', {
textContent: 'Show announcement', textContent: 'Show announcement',
className: 'show-announcement', className: 'show-announcement',
@ -10948,7 +10755,7 @@
return psa.hidden; return psa.hidden;
} }
}; };
$.event('AddMenuEntry', entry); Header.menu.addEntry(entry);
$.on(entry.el, 'click', PSAHiding.toggle); $.on(entry.el, 'click', PSAHiding.toggle);
PSAHiding.btn = btn = $.el('span', { PSAHiding.btn = btn = $.el('span', {
innerHTML: '[<a href="javascript:;">Dismiss</a>]', innerHTML: '[<a href="javascript:;">Dismiss</a>]',
@ -11101,8 +10908,7 @@
input = $('input', el); input = $('input', el);
$.on(input, 'change', this.toggle); $.on(input, 'change', this.toggle);
$.sync('Header catalog links', CatalogLinks.set); $.sync('Header catalog links', CatalogLinks.set);
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 95 order: 95
}); });
@ -11599,7 +11405,7 @@
}); });
} }
if (board === 'sci') { if (board === 'sci') {
$.globalEval('window.addEventListener(\'jsmath\', function(e) {\n if (!jsMath) return;\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else if (jsMath.Autoload && jsMath.Autoload.checked) {\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) return;\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(document.getElementById(e.detail));\n } else if (jsMath.Autoload && jsMath.Autoload.checked) {\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({ return Post.callbacks.push({
name: 'Parse /sci/ math', name: 'Parse /sci/ math',
cb: this.math cb: this.math
@ -11632,7 +11438,7 @@
}; };
})(this)), (function(_this) { })(this)), (function(_this) {
return function() { return function() {
return $.event('jsmath', _this.nodes.post, window); return $.event('jsmath', _this.nodes.post.id, window);
}; };
})(this)); })(this));
}, },
@ -12480,7 +12286,7 @@
Settings.dialog = dialog = $.el('div', { Settings.dialog = dialog = $.el('div', {
id: 'fourchanx-settings', id: 'fourchanx-settings',
className: 'dialog', className: 'dialog',
innerHTML: '<nav><div class=sections-list></div><p class=\'imp-exp-result warning\'></p><div class=credits><a class=export>Export</a>&nbsp|&nbsp<a class=import>Import</a>&nbsp|&nbsp<a class=reset>Reset Settings</a>&nbsp|&nbsp<input type=file hidden><a href=\'https://github.com/ccd0/4chan-x\' target=_blank>4chan X</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md\' target=_blank>1.7.63</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/issues\' target=_blank>Issues</a>&nbsp|&nbsp<a href=javascript:; class=\'close fa fa-times\' title=Close></a></div></nav><div class=section-container><section></section></div>' innerHTML: '<nav><div class=sections-list></div><p class=\'imp-exp-result warning\'></p><div class=credits><a class=export>Export</a>&nbsp|&nbsp<a class=import>Import</a>&nbsp|&nbsp<a class=reset>Reset Settings</a>&nbsp|&nbsp<input type=file hidden><a href=\'https://github.com/ccd0/4chan-x\' target=_blank>4chan X</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md\' target=_blank>1.8.1</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/issues\' target=_blank>Issues</a>&nbsp|&nbsp<a href=javascript:; class=\'close fa fa-times\' title=Close></a></div></nav><div class=section-container><section></section></div>'
}); });
$.on($('.export', Settings.dialog), 'click', Settings["export"]); $.on($('.export', Settings.dialog), 'click', Settings["export"]);
$.on($('.import', Settings.dialog), 'click', Settings["import"]); $.on($('.import', Settings.dialog), 'click', Settings["import"]);
@ -13185,7 +12991,6 @@
}); });
} }
} }
$.on(d, 'AddCallback', Main.addCallback);
return $.ready(Main.initReady); return $.ready(Main.initReady);
}, },
initStyle: function() { initStyle: function() {
@ -13325,7 +13130,7 @@
} }
if (previousversion) { if (previousversion) {
el = $.el('span', { el = $.el('span', {
innerHTML: '4chan X has been updated to <a href="https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md" target="_blank">version 1.7.63</a>.' innerHTML: '4chan X has been updated to <a href="https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md" target="_blank">version 1.8.1</a>.'
}); });
new Notice('info', el, 15); new Notice('info', el, 15);
} else { } else {
@ -13368,25 +13173,6 @@
}; };
return softTask(); return softTask();
}, },
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) { handleErrors: function(errors) {
var div, error, logs, _i, _len; var div, error, logs, _i, _len;
if (!(errors instanceof Array)) { if (!(errors instanceof Array)) {

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,6 @@
{ {
"name": "4chan X", "name": "4chan X",
"version": "1.7.63", "version": "1.8.1",
"manifest_version": 2, "manifest_version": 2,
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"icons": { "icons": {

View File

@ -1,6 +1,6 @@
// Generated by CoffeeScript // Generated by CoffeeScript
/* /*
* 4chan X - Version 1.7.63 - 2014-06-16 * 4chan X - Version 1.8.1 - 2014-06-19
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE
@ -349,7 +349,7 @@
doc = d.documentElement; doc = d.documentElement;
g = { g = {
VERSION: '1.7.63', VERSION: '1.8.1',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
boards: {} boards: {}
}; };
@ -361,16 +361,6 @@
return root.querySelector(selector); return root.querySelector(selector);
}; };
$.extend = function(obj, prop) {
var key, val;
for (key in prop) {
val = prop[key];
if (prop.hasOwnProperty(key)) {
obj[key] = val;
}
}
};
$.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000))); $.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000)));
$.id = function(id) { $.id = function(id) {
@ -875,36 +865,19 @@
Callbacks.prototype.push = function(_arg) { Callbacks.prototype.push = function(_arg) {
var cb, name; var cb, name;
name = _arg.name, cb = _arg.cb; name = _arg.name, cb = _arg.cb;
if (this[name]) {
this.connect(name);
}
if (!this[name]) { if (!this[name]) {
this.keys.push(name); this.keys.push(name);
} }
return this[name] = cb; return this[name] = cb;
}; };
Callbacks.prototype.connect = function(name) {
if (this[name].disconnected) {
return delete this[name].disconnected;
}
};
Callbacks.prototype.disconnect = function(name) {
if (this[name]) {
return this[name].disconnected = true;
}
};
Callbacks.prototype.execute = function(node) { Callbacks.prototype.execute = function(node) {
var err, errors, name, _i, _len, _ref; var err, errors, name, _i, _len, _ref;
_ref = this.keys; _ref = this.keys;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
name = _ref[_i]; name = _ref[_i];
try { try {
if (!this[name].disconnected) { this[name].call(node);
this[name].call(node);
}
} catch (_error) { } catch (_error) {
err = _error; err = _error;
if (!errors) { if (!errors) {
@ -1550,12 +1523,6 @@
return typeof this.sync === "function" ? this.sync() : void 0; return typeof this.sync === "function" ? this.sync() : void 0;
}; };
DataBoard.prototype.disconnect = function() {
$.desync(this.key);
delete this.sync;
return delete this.data;
};
return DataBoard; return DataBoard;
})(); })();
@ -1878,8 +1845,7 @@
$.sync('Header auto-hide', this.setBarVisibility); $.sync('Header auto-hide', this.setBarVisibility);
$.sync('Centered links', this.setLinkJustify); $.sync('Centered links', this.setLinkJustify);
this.addShortcut(menuButton); this.addShortcut(menuButton);
$.event('AddMenuEntry', { this.menu.addEntry({
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Header' textContent: 'Header'
}), }),
@ -2286,12 +2252,9 @@
return Header.menu.toggle(e, this, g); return Header.menu.toggle(e, this, g);
}, },
createNotification: function(e) { createNotification: function(e) {
var cb, content, lifetime, notice, type, _ref; var content, lifetime, notice, type, _ref;
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb; _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime;
notice = new Notice(type, content, lifetime); return notice = new Notice(type, content, lifetime);
if (cb) {
return cb(notice);
}
}, },
areNotificationsEnabled: false, areNotificationsEnabled: false,
enableDesktopNotifications: function() { enableDesktopNotifications: function() {
@ -2431,8 +2394,7 @@
$.on(input, 'change', this.cb.sort); $.on(input, 'change', this.cb.sort);
} }
} }
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Index Navigation' textContent: 'Index Navigation'
}), }),
@ -2957,14 +2919,12 @@
return nodes; return nodes;
}, },
buildStructure: function(nodes) { buildStructure: function(nodes) {
var i, node, result; var node, _i, _len;
result = $.frag(); for (_i = 0, _len = nodes.length; _i < _len; _i++) {
i = 0; node = nodes[_i];
while (node = nodes[i++]) { $.add(Index.root, [node, $.el('hr')]);
$.add(result, [node, $.el('hr')]);
} }
$.event('IndexBuild', result.children); return ThreadHiding.onIndexBuild(nodes);
return $.add(Index.root, result);
}, },
isSearching: false, isSearching: false,
clearSearch: function() { clearSearch: function() {
@ -3142,7 +3102,7 @@
This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS). This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
@license: https://github.com/4chan/4chan-JS/blob/master/LICENSE @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
*/ */
var E, boardID, capcode, container, date, dateUTC, email, file, fileSize, fileThumb, flagCode, flagName, h_capcodeClass, h_capcodeIcon, h_capcodeStart, h_closed, h_comment, h_emailEnd, h_emailStart, h_file, h_fileDims, h_fileInfo, h_fileTitle1, h_fileTitle2, h_flag, h_gifIcon, h_imgSrc, h_pageIcon, h_postClass, h_quoteLink, h_replyLink, h_sideArrows, h_staticPath, h_sticky, h_tripcode, h_userID, href, isClosed, isOP, isSticky, name, pageNum, postID, quote, shortFilename, spoilerRange, subject, threadID, tripcode, uniqueID, _i, _len, _ref; var E, boardID, capcode, container, date, dateUTC, email, email_processed, file, fileSize, fileThumb, flagCode, flagName, h_capcodeClass, h_capcodeIcon, h_capcodeStart, h_closed, h_comment, h_emailEnd, h_emailStart, h_file, h_fileDims, h_fileInfo, h_fileTitle1, h_fileTitle2, h_flag, h_gifIcon, h_imgSrc, h_pageIcon, h_postClass, h_quoteLink, h_replyLink, h_sideArrows, h_staticPath, h_sticky, h_tripcode, h_userID, href, isClosed, isOP, isSticky, name, pageNum, postID, quote, shortFilename, spoilerRange, subject, threadID, tripcode, uniqueID, _i, _len, _ref;
E = Build.h_escape; E = Build.h_escape;
postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, h_comment = o.h_comment, file = o.file; postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, h_comment = o.h_comment, file = o.file;
name || (name = ''); name || (name = '');
@ -3160,8 +3120,9 @@
} else { } else {
h_tripcode = ''; h_tripcode = '';
} }
email_processed = encodeURIComponent(email).replace(/%40/g, '@');
if (email) { if (email) {
h_emailStart = "<a href='mailto:" + (E(encodeURIComponent(email))) + "' class='useremail'>"; h_emailStart = "<a href='mailto:" + (E(email_processed)) + "' class='useremail'>";
h_emailEnd = '</a>'; h_emailEnd = '</a>';
} else { } else {
h_emailStart = ''; h_emailStart = '';
@ -3608,7 +3569,7 @@
}; };
UI = (function() { UI = (function() {
var Menu, checkbox, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove; var Menu, checkbox, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, menus, touchend, touchmove;
dialog = function(id, position, properties) { dialog = function(id, position, properties) {
var child, el, move, _i, _len, _ref; var child, el, move, _i, _len, _ref;
el = $.el('div', { el = $.el('div', {
@ -3634,6 +3595,7 @@
} }
return el; return el;
}; };
menus = {};
Menu = (function() { Menu = (function() {
var currentMenu, lastToggledButton; var currentMenu, lastToggledButton;
@ -3643,14 +3605,23 @@
function Menu(type) { function Menu(type) {
this.type = type; this.type = type;
this.rmEntry = __bind(this.rmEntry, this);
this.addEntry = __bind(this.addEntry, this); this.addEntry = __bind(this.addEntry, this);
this.onFocus = __bind(this.onFocus, this); this.onFocus = __bind(this.onFocus, this);
this.keybinds = __bind(this.keybinds, this); this.keybinds = __bind(this.keybinds, this);
this.close = __bind(this.close, this); this.close = __bind(this.close, this);
$.on(d, 'AddMenuEntry', this.addEntry); $.on(d, 'AddMenuEntry', (function(_this) {
$.on(d, 'rmMenuEntry', this.rmEntry); return function(_arg) {
var detail;
detail = _arg.detail;
if (detail.type !== _this.type) {
return;
}
delete detail.open;
return _this.addEntry(detail);
};
})(this));
this.entries = []; this.entries = [];
menus[this.type] = this;
} }
Menu.prototype.makeMenu = function() { Menu.prototype.makeMenu = function() {
@ -3841,26 +3812,11 @@
return style.right = right; return style.right = right;
}; };
Menu.prototype.addEntry = function(e) { Menu.prototype.addEntry = function(entry) {
var entry;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
this.parseEntry(entry); this.parseEntry(entry);
return this.entries.push(entry); return this.entries.push(entry);
}; };
Menu.prototype.rmEntry = function(e) {
var entry, index;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
index = this.entries.indexOf(entry);
return this.entries.splice(index, 1);
};
Menu.prototype.parseEntry = function(entry) { Menu.prototype.parseEntry = function(entry) {
var el, subEntries, subEntry, _i, _len; var el, subEntries, subEntry, _i, _len;
el = entry.el, subEntries = entry.subEntries; el = entry.el, subEntries = entry.subEntries;
@ -4320,7 +4276,6 @@
textContent: 'Filter' textContent: 'Filter'
}); });
entry = { entry = {
type: 'post',
el: div, el: div,
order: 50, order: 50,
open: function(post) { open: function(post) {
@ -4334,7 +4289,7 @@
type = _ref[_i]; type = _ref[_i];
entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1])); entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1]));
} }
return $.event('AddMenuEntry', entry); return Menu.menu.addEntry(entry);
}, },
createSubEntry: function(text, type) { createSubEntry: function(text, type) {
var el; var el;
@ -4440,8 +4395,7 @@
thisPost = UI.checkbox('thisPost', ' This post', true); thisPost = UI.checkbox('thisPost', ' This post', true);
replies = UI.checkbox('replies', ' Hide replies', Conf['Recursive Hiding']); replies = UI.checkbox('replies', ' Hide replies', Conf['Recursive Hiding']);
makeStub = UI.checkbox('makeStub', ' Make stub', Conf['Stubs']); makeStub = UI.checkbox('makeStub', ' Make stub', Conf['Stubs']);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(post) { open: function(post) {
@ -4479,8 +4433,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(hideStubLink, 'click', PostHiding.menu.hideStub); $.on(hideStubLink, 'click', PostHiding.menu.hideStub);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(post) { open: function(post) {
@ -4510,8 +4463,7 @@
} }
] ]
}); });
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: hideStubLink, el: hideStubLink,
order: 15, order: 15,
open: function(post) { open: function(post) {
@ -4748,7 +4700,6 @@
} }
this.db = new DataBoard('hiddenThreads'); this.db = new DataBoard('hiddenThreads');
this.syncCatalog(); this.syncCatalog();
$.on(d, 'IndexBuild', this.onIndexBuild);
return Thread.callbacks.push({ return Thread.callbacks.push({
name: 'Thread Hiding', name: 'Thread Hiding',
cb: this.node cb: this.node
@ -4767,16 +4718,12 @@
} }
return $.prepend(this.OP.nodes.root, ThreadHiding.makeButton(this, 'hide')); return $.prepend(this.OP.nodes.root, ThreadHiding.makeButton(this, 'hide'));
}, },
onIndexBuild: function(_arg) { onIndexBuild: function(nodes) {
var i, nodes, root, thread, _i, _len; var root, thread, _i, _len;
nodes = _arg.detail; for (_i = 0, _len = nodes.length; _i < _len; _i++) {
for (i = _i = 0, _len = nodes.length; _i < _len; i = _i += 2) { root = nodes[_i];
root = nodes[i];
thread = Get.threadFromRoot(root); thread = Get.threadFromRoot(root);
if (!thread.isHidden) { if (thread.isHidden && thread.stub && !root.contains(thread.stub)) {
continue;
}
if (thread.stub && root.contains(thread.stub)) {
ThreadHiding.makeStub(thread, root); ThreadHiding.makeStub(thread, root);
} }
} }
@ -4847,8 +4794,7 @@
}); });
$.on(apply, 'click', ThreadHiding.menu.hide); $.on(apply, 'click', ThreadHiding.menu.hide);
makeStub = UI.checkbox('Stubs', ' Make stub'); makeStub = UI.checkbox('Stubs', ' Make stub');
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(_arg) { open: function(_arg) {
@ -4874,8 +4820,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(div, 'click', ThreadHiding.menu.show); $.on(div, 'click', ThreadHiding.menu.show);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(_arg) { open: function(_arg) {
@ -4893,8 +4838,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(hideStubLink, 'click', ThreadHiding.menu.hideStub); $.on(hideStubLink, 'click', ThreadHiding.menu.hideStub);
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: hideStubLink, el: hideStubLink,
order: 15, order: 15,
open: function(_arg) { open: function(_arg) {
@ -5421,8 +5365,7 @@
}); });
input = $('input', this.controls); input = $('input', this.controls);
$.on(input, 'change', this.toggle); $.on(input, 'change', this.toggle);
$.event('AddMenuEntry', this.entry = { Header.menu.addEntry(this.entry = {
type: 'header',
el: this.controls, el: this.controls,
order: 98 order: 98
}); });
@ -5434,19 +5377,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var input;
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
input = $('input', this.controls);
$.off(input, 'change', this.toggle);
$.event('rmMenuEntry', this.entry);
delete this.enabled;
delete this.controls;
delete this.entry;
return Post.callbacks.disconnect('Quote Threading');
},
ready: function() { ready: function() {
$.off(d, '4chanXInitFinished', QuoteThreading.ready); $.off(d, '4chanXInitFinished', QuoteThreading.ready);
return QuoteThreading.force(); return QuoteThreading.force();
@ -5849,16 +5779,6 @@
$.prepend($('.navLinksBot'), linkBot); $.prepend($('.navLinksBot'), linkBot);
} }
$.before($.id('togglePostFormLink'), link); $.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, 'paste', QR.paste);
$.on(d, 'dragover', QR.dragOver); $.on(d, 'dragover', QR.dragOver);
$.on(d, 'drop', QR.dropFile); $.on(d, 'drop', QR.dropFile);
@ -6478,9 +6398,8 @@
return $.add(nodes.form, flag); return $.add(nodes.form, flag);
} }
}, },
preSubmitHooks: [],
submit: function(e) { 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) { if (e != null) {
e.preventDefault(); e.preventDefault();
} }
@ -6513,17 +6432,9 @@
err = 'No file selected.'; err = 'No file selected.';
} else if (post.file && thread.fileLimit) { } else if (post.file && thread.fileLimit) {
err = 'Max limit of image replies has been reached.'; 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) { 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) { if (!response) {
err = 'No valid captcha.'; err = 'No valid captcha.';
} }
@ -6656,11 +6567,12 @@
}); });
ThreadUpdater.postID = postID; ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', { $.event('QRPostSuccessful', {
board: g.BOARD, boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
postID: postID postID: postID
}); });
$.event('QRPostSuccessful_', { $.event('QRPostSuccessful_', {
boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
postID: postID postID: postID
}); });
@ -7277,8 +7189,7 @@
rectEl = this.nodes.el.getBoundingClientRect(); rectEl = this.nodes.el.getBoundingClientRect();
rectList = this.nodes.el.parentNode.getBoundingClientRect(); rectList = this.nodes.el.parentNode.getBoundingClientRect();
this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2; this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2;
this.load(); return this.load();
return $.event('QRPostSelection', this);
}; };
_Class.prototype.load = function() { _Class.prototype.load = function() {
@ -7550,8 +7461,7 @@
el.title = "" + type + " Tyme"; el.title = "" + type + " Tyme";
FappeTyme[lc] = input = el.firstElementChild; FappeTyme[lc] = input = el.firstElementChild;
$.on(input, 'change', FappeTyme.cb.toggle.bind(input)); $.on(input, 'change', FappeTyme.cb.toggle.bind(input));
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 97 order: 97
}); });
@ -7650,8 +7560,7 @@
createSubEntry = Gallery.menu.createSubEntry; createSubEntry = Gallery.menu.createSubEntry;
for (name in Config.gallery) { for (name in Config.gallery) {
el = createSubEntry(name).el; el = createSubEntry(name).el;
$.event('AddMenuEntry', { nodes.menu.addEntry({
type: 'gallery',
el: el, el: el,
order: 0 order: 0
}); });
@ -7885,8 +7794,7 @@
for (name in Config.gallery) { for (name in Config.gallery) {
subEntries.push(createSubEntry(name)); subEntries.push(createSubEntry(name));
} }
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 105, order: 105,
subEntries: subEntries subEntries: subEntries
@ -8219,8 +8127,7 @@
conf = _ref[name]; conf = _ref[name];
subEntries.push(createSubEntry(name, conf[1])); subEntries.push(createSubEntry(name, conf[1]));
} }
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 105, order: 105,
subEntries: subEntries subEntries: subEntries
@ -8381,8 +8288,7 @@
}); });
this.el = prefetch.firstElementChild; this.el = prefetch.firstElementChild;
$.on(this.el, 'change', this.toggle); $.on(this.el, 'change', this.toggle);
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: prefetch, el: prefetch,
order: 104 order: 104
}); });
@ -9139,7 +9045,6 @@
textContent: 'Archive' textContent: 'Archive'
}); });
entry = { entry = {
type: 'post',
el: div, el: div,
order: 90, order: 90,
open: function(_arg) { open: function(_arg) {
@ -9158,7 +9063,7 @@
type = _ref[_i]; type = _ref[_i];
entry.subEntries.push(this.createSubEntry(type[0], type[1])); entry.subEntries.push(this.createSubEntry(type[0], type[1]));
} }
return $.event('AddMenuEntry', entry); return Menu.menu.addEntry(entry);
}, },
createSubEntry: function(text, type) { createSubEntry: function(text, type) {
var el, open; var el, open;
@ -9235,8 +9140,7 @@
return true; return true;
} }
}; };
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 40, order: 40,
open: function(post) { open: function(post) {
@ -9360,8 +9264,7 @@
}; };
})(this)); })(this));
}); });
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: a, el: a,
order: 100, order: 100,
open: function(_arg) { open: function(_arg) {
@ -9429,8 +9332,7 @@
textContent: 'Report this post' textContent: 'Report this post'
}); });
$.on(a, 'click', ReportLink.report); $.on(a, 'click', ReportLink.report);
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: a, el: a,
order: 10, order: 10,
open: function(post) { open: function(post) {
@ -9507,12 +9409,6 @@
}, },
node: function() { node: function() {
return d.title = Get.threadExcerpt(this); return d.title = Get.threadExcerpt(this);
},
disconnect: function() {
if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
return;
}
return Thread.callbacks.disconnect('Thread Excerpt');
} }
}; };
@ -9564,25 +9460,6 @@
ThreadStats.update(postCount, fileCount); ThreadStats.update(postCount, fileCount);
return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate); return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
}, },
disconnect: function() {
if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
return;
}
if (Conf['Updater and Stats in Header']) {
Header.rmShortcut(this.dialog);
} else {
$.rm(this.dialog);
}
clearTimeout(this.timeout);
delete this.timeout;
delete this.thread;
delete this.postCountEl;
delete this.fileCountEl;
delete this.pageCountEl;
delete this.dialog;
Thread.callbacks.disconnect('Thread Stats');
return $.off(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
onUpdate: function(e) { onUpdate: function(e) {
var fileCount, postCount, _ref; var fileCount, postCount, _ref;
if (e.detail[404]) { if (e.detail[404]) {
@ -9702,8 +9579,7 @@
subEntries.push({ subEntries.push({
el: this.settings el: this.settings
}); });
$.event('AddMenuEntry', this.entry = { Header.menu.addEntry(this.entry = {
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Updater' textContent: 'Updater'
}), }),
@ -9715,45 +9591,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var el, entry, input, name, _i, _j, _len, _len1, _ref, _ref1;
if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
return;
}
$.off(this.timer, 'click', this.update);
$.off(this.status, 'click', this.update);
if (this.timeoutID) {
clearTimeout(this.timeoutID);
}
_ref = this.entry.subEntries;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
entry = _ref[_i];
el = entry.el;
input = el.firstElementChild;
$.off(input, 'change', $.cb.checked);
$.off(input, 'change', this.cb.scrollBG);
$.off(input, 'change', this.cb.update);
}
$.off(this.settings, 'click', this.intervalShortcut);
$.off(window, 'online offline', this.cb.online);
$.off(d, 'QRPostSuccessful', this.cb.checkpost);
$.off(d, 'visibilitychange', this.cb.visibility);
this.set('timer', null);
this.set('status', 'Offline');
$.event('rmMenuEntry', this.entry);
if (Conf['Updater and Stats in Header']) {
Header.rmShortcut(this.dialog);
} else {
$.rmClass(doc, 'float');
$.rm(this.dialog);
}
_ref1 = ['checkPostCount', 'timer', 'status', 'isUpdating', 'entry', 'dialog', 'thread', 'root', 'lastPost', 'outdateCount', 'online', 'seconds', 'timeoutID'];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
name = _ref1[_j];
delete this[name];
}
return Thread.callbacks.disconnect('Thread Updater');
},
node: function() { node: function() {
ThreadUpdater.thread = this; ThreadUpdater.thread = this;
ThreadUpdater.root = this.OP.nodes.root.parentNode; ThreadUpdater.root = this.OP.nodes.root.parentNode;
@ -9852,7 +9689,7 @@
ThreadUpdater.thread.kill(); ThreadUpdater.thread.kill();
$.event('ThreadUpdate', { $.event('ThreadUpdate', {
404: true, 404: true,
thread: ThreadUpdater.thread threadID: ThreadUpdater.thread.fullID
}); });
break; break;
default: default:
@ -9946,7 +9783,7 @@
return new Notice('info', "The thread is " + change + ".", 30); return new Notice('info', "The thread is " + change + ".", 30);
}, },
parse: function(postObjects) { parse: function(postObjects) {
var OP, count, deletedFiles, deletedPosts, files, index, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1; var OP, count, files, index, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1;
OP = postObjects[0]; OP = postObjects[0];
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
@ -9971,19 +9808,15 @@
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID); node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board)); posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
} }
deletedPosts = [];
deletedFiles = [];
ThreadUpdater.thread.posts.forEach(function(post) { ThreadUpdater.thread.posts.forEach(function(post) {
var ID; var ID;
ID = +post.ID; ID = +post.ID;
if (__indexOf.call(index, ID) < 0) { if (__indexOf.call(index, ID) < 0) {
post.kill(); post.kill();
deletedPosts.push(post);
} else if (post.isDead) { } else if (post.isDead) {
post.resurrect(); 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); post.kill(true);
deletedFiles.push(post);
} }
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) { if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
return ThreadUpdater.foundPost = true; return ThreadUpdater.foundPost = true;
@ -10035,10 +9868,10 @@
} }
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: false, 404: false,
thread: ThreadUpdater.thread, threadID: ThreadUpdater.thread.fullID,
newPosts: posts, newPosts: posts.map(function(post) {
deletedPosts: deletedPosts, return post.fullID;
deletedFiles: deletedFiles, }),
postCount: OP.replies + 1, postCount: OP.replies + 1,
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead) fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
}); });
@ -10065,9 +9898,6 @@
this.status = $('#watcher-status', this.dialog); this.status = $('#watcher-status', this.dialog);
this.list = this.dialog.lastElementChild; this.list = this.dialog.lastElementChild;
$.on(d, 'QRPostSuccessful', this.cb.post); $.on(d, 'QRPostSuccessful', this.cb.post);
if (g.VIEW === 'thread') {
$.on(d, 'ThreadUpdate', this.cb.threadUpdate);
}
$.on(sc, 'click', this.toggleWatcher); $.on(sc, 'click', this.toggleWatcher);
$.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher); $.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher);
$.on(d, '4chanXInitFinished', this.ready); $.on(d, '4chanXInitFinished', this.ready);
@ -10176,14 +10006,14 @@
return ThreadWatcher.rm(boardID, +threadID); return ThreadWatcher.rm(boardID, +threadID);
}, },
post: function(e) { post: function(e) {
var board, postID, threadID, _ref; var boardID, postID, threadID, _ref;
_ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID; _ref = e.detail, boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
if (postID === threadID) { if (postID === threadID) {
if (Conf['Auto Watch']) { if (Conf['Auto Watch']) {
return $.set('AutoWatch', threadID); return $.set('AutoWatch', threadID);
} }
} else if (Conf['Auto Watch Reply']) { } else if (Conf['Auto Watch Reply']) {
return ThreadWatcher.add(board.threads[threadID]); return ThreadWatcher.add(g.threads[boardID + '.' + threadID]);
} }
}, },
onIndexRefresh: function() { onIndexRefresh: function() {
@ -10213,7 +10043,7 @@
}, },
onThreadRefresh: function(e) { onThreadRefresh: function(e) {
var thread; var thread;
thread = e.detail.thread; thread = g.threads[e.detail.threadID];
if (!(e.detail[404] && ThreadWatcher.db.get({ if (!(e.detail[404] && ThreadWatcher.db.get({
boardID: thread.board.ID, boardID: thread.board.ID,
threadID: thread.ID threadID: thread.ID
@ -10425,7 +10255,7 @@
if (!Conf['Thread Watcher']) { if (!Conf['Thread Watcher']) {
return; return;
} }
menu = new UI.Menu('thread watcher'); menu = this.menu = new UI.Menu('thread watcher');
$.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) { $.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) {
return menu.toggle(e, this, ThreadWatcher); return menu.toggle(e, this, ThreadWatcher);
}); });
@ -10440,8 +10270,7 @@
entryEl = $.el('a', { entryEl = $.el('a', {
href: 'javascript:;' href: 'javascript:;'
}); });
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: entryEl, el: entryEl,
order: 60 order: 60
}); });
@ -10462,7 +10291,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.openAll, cb: ThreadWatcher.cb.openAll,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Open all threads' textContent: 'Open all threads'
}) })
@ -10474,7 +10302,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.checkThreads, cb: ThreadWatcher.cb.checkThreads,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Check 404\'d threads' textContent: 'Check 404\'d threads'
}) })
@ -10486,7 +10313,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.pruneDeads, cb: ThreadWatcher.cb.pruneDeads,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Prune 404\'d threads' textContent: 'Prune 404\'d threads'
}) })
@ -10503,7 +10329,6 @@
} }
entries.push({ entries.push({
entry: { entry: {
type: 'thread watcher',
el: $.el('span', { el: $.el('span', {
textContent: 'Settings' textContent: 'Settings'
}), }),
@ -10521,7 +10346,7 @@
if (refresh) { if (refresh) {
this.refreshers.push(refresh.bind(entry)); this.refreshers.push(refresh.bind(entry));
} }
$.event('AddMenuEntry', entry); this.menu.addEntry(entry);
} }
}, },
createSubEntry: function(name, desc) { createSubEntry: function(name, desc) {
@ -10557,28 +10382,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var hr, name, _i, _len, _ref;
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Desktop Notifications']) {
return;
}
Unread.db.disconnect();
if (hr = Unread.hr, Unread) {
$.rm(hr);
}
_ref = ['db', 'hr', 'posts', 'postsQuotingYou', 'thread', 'title', 'lastReadPost'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
name = _ref[_i];
delete this[name];
}
$.off(d, '4chanXInitFinished', this.ready);
$.off(d, 'ThreadUpdate', this.onUpdate);
$.off(d, 'scroll visibilitychange', this.read);
if (Conf['Unread Line'] && !Conf['Quote Threading']) {
$.off(d, 'visibilitychange', this.setLine);
}
return Thread.callbacks.disconnect('Unread');
},
node: function() { node: function() {
Unread.thread = this; Unread.thread = this;
Unread.title = d.title; Unread.title = d.title;
@ -10723,7 +10526,9 @@
if (e.detail[404]) { if (e.detail[404]) {
return Unread.update(); return Unread.update();
} else if (!QuoteThreading.enabled) { } else if (!QuoteThreading.enabled) {
return Unread.addPosts(e.detail.newPosts); return Unread.addPosts(e.detail.newPosts.map(function(fullID) {
return g.posts[fullID];
}));
} else { } else {
Unread.read(); Unread.read();
return Unread.update(); return Unread.update();
@ -10931,7 +10736,6 @@
return; return;
} }
entry = { entry = {
type: 'header',
el: $.el('a', { el: $.el('a', {
textContent: 'Show announcement', textContent: 'Show announcement',
className: 'show-announcement', className: 'show-announcement',
@ -10942,7 +10746,7 @@
return psa.hidden; return psa.hidden;
} }
}; };
$.event('AddMenuEntry', entry); Header.menu.addEntry(entry);
$.on(entry.el, 'click', PSAHiding.toggle); $.on(entry.el, 'click', PSAHiding.toggle);
PSAHiding.btn = btn = $.el('span', { PSAHiding.btn = btn = $.el('span', {
innerHTML: '[<a href="javascript:;">Dismiss</a>]', innerHTML: '[<a href="javascript:;">Dismiss</a>]',
@ -11095,8 +10899,7 @@
input = $('input', el); input = $('input', el);
$.on(input, 'change', this.toggle); $.on(input, 'change', this.toggle);
$.sync('Header catalog links', CatalogLinks.set); $.sync('Header catalog links', CatalogLinks.set);
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 95 order: 95
}); });
@ -11593,7 +11396,7 @@
}); });
} }
if (board === 'sci') { if (board === 'sci') {
$.globalEval('window.addEventListener(\'jsmath\', function(e) {\n if (!jsMath) return;\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else if (jsMath.Autoload && jsMath.Autoload.checked) {\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) return;\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(document.getElementById(e.detail));\n } else if (jsMath.Autoload && jsMath.Autoload.checked) {\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({ return Post.callbacks.push({
name: 'Parse /sci/ math', name: 'Parse /sci/ math',
cb: this.math cb: this.math
@ -11626,7 +11429,7 @@
}; };
})(this)), (function(_this) { })(this)), (function(_this) {
return function() { return function() {
return $.event('jsmath', _this.nodes.post, window); return $.event('jsmath', _this.nodes.post.id, window);
}; };
})(this)); })(this));
}, },
@ -12474,7 +12277,7 @@
Settings.dialog = dialog = $.el('div', { Settings.dialog = dialog = $.el('div', {
id: 'fourchanx-settings', id: 'fourchanx-settings',
className: 'dialog', className: 'dialog',
innerHTML: '<nav><div class=sections-list></div><p class=\'imp-exp-result warning\'></p><div class=credits><a class=export>Export</a>&nbsp|&nbsp<a class=import>Import</a>&nbsp|&nbsp<a class=reset>Reset Settings</a>&nbsp|&nbsp<input type=file hidden><a href=\'https://github.com/ccd0/4chan-x\' target=_blank>4chan X</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md\' target=_blank>1.7.63</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/issues\' target=_blank>Issues</a>&nbsp|&nbsp<a href=javascript:; class=\'close fa fa-times\' title=Close></a></div></nav><div class=section-container><section></section></div>' innerHTML: '<nav><div class=sections-list></div><p class=\'imp-exp-result warning\'></p><div class=credits><a class=export>Export</a>&nbsp|&nbsp<a class=import>Import</a>&nbsp|&nbsp<a class=reset>Reset Settings</a>&nbsp|&nbsp<input type=file hidden><a href=\'https://github.com/ccd0/4chan-x\' target=_blank>4chan X</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md\' target=_blank>1.8.1</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/issues\' target=_blank>Issues</a>&nbsp|&nbsp<a href=javascript:; class=\'close fa fa-times\' title=Close></a></div></nav><div class=section-container><section></section></div>'
}); });
$.on($('.export', Settings.dialog), 'click', Settings["export"]); $.on($('.export', Settings.dialog), 'click', Settings["export"]);
$.on($('.import', Settings.dialog), 'click', Settings["import"]); $.on($('.import', Settings.dialog), 'click', Settings["import"]);
@ -13176,7 +12979,6 @@
}); });
} }
} }
$.on(d, 'AddCallback', Main.addCallback);
return $.ready(Main.initReady); return $.ready(Main.initReady);
}, },
initStyle: function() { initStyle: function() {
@ -13306,7 +13108,7 @@
} }
if (previousversion) { if (previousversion) {
el = $.el('span', { el = $.el('span', {
innerHTML: '4chan X has been updated to <a href="https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md" target="_blank">version 1.7.63</a>.' innerHTML: '4chan X has been updated to <a href="https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md" target="_blank">version 1.8.1</a>.'
}); });
new Notice('info', el, 15); new Notice('info', el, 15);
} else { } else {
@ -13349,25 +13151,6 @@
}; };
return softTask(); return softTask();
}, },
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) { handleErrors: function(errors) {
var div, error, logs, _i, _len; var div, error, logs, _i, _len;
if (!(errors instanceof Array)) { if (!(errors instanceof Array)) {

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'> <app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/crx.crx' version='1.7.63' /> <updatecheck codebase='https://ccd0.github.io/4chan-x/builds/crx.crx' version='1.8.1' />
</app> </app>
</gupdate> </gupdate>

View File

@ -1,6 +1,6 @@
{ {
"name": "4chan X", "name": "4chan X",
"version": "1.7.63", "version": "1.8.1",
"manifest_version": 2, "manifest_version": 2,
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"icons": { "icons": {

View File

@ -1,6 +1,6 @@
// Generated by CoffeeScript // Generated by CoffeeScript
/* /*
* 4chan X - Version 1.7.63 - 2014-06-16 * 4chan X - Version 1.8.1 - 2014-06-19
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE
@ -349,7 +349,7 @@
doc = d.documentElement; doc = d.documentElement;
g = { g = {
VERSION: '1.7.63', VERSION: '1.8.1',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
boards: {} boards: {}
}; };
@ -361,16 +361,6 @@
return root.querySelector(selector); return root.querySelector(selector);
}; };
$.extend = function(obj, prop) {
var key, val;
for (key in prop) {
val = prop[key];
if (prop.hasOwnProperty(key)) {
obj[key] = val;
}
}
};
$.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000))); $.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000)));
$.id = function(id) { $.id = function(id) {
@ -875,36 +865,19 @@
Callbacks.prototype.push = function(_arg) { Callbacks.prototype.push = function(_arg) {
var cb, name; var cb, name;
name = _arg.name, cb = _arg.cb; name = _arg.name, cb = _arg.cb;
if (this[name]) {
this.connect(name);
}
if (!this[name]) { if (!this[name]) {
this.keys.push(name); this.keys.push(name);
} }
return this[name] = cb; return this[name] = cb;
}; };
Callbacks.prototype.connect = function(name) {
if (this[name].disconnected) {
return delete this[name].disconnected;
}
};
Callbacks.prototype.disconnect = function(name) {
if (this[name]) {
return this[name].disconnected = true;
}
};
Callbacks.prototype.execute = function(node) { Callbacks.prototype.execute = function(node) {
var err, errors, name, _i, _len, _ref; var err, errors, name, _i, _len, _ref;
_ref = this.keys; _ref = this.keys;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
name = _ref[_i]; name = _ref[_i];
try { try {
if (!this[name].disconnected) { this[name].call(node);
this[name].call(node);
}
} catch (_error) { } catch (_error) {
err = _error; err = _error;
if (!errors) { if (!errors) {
@ -1550,12 +1523,6 @@
return typeof this.sync === "function" ? this.sync() : void 0; return typeof this.sync === "function" ? this.sync() : void 0;
}; };
DataBoard.prototype.disconnect = function() {
$.desync(this.key);
delete this.sync;
return delete this.data;
};
return DataBoard; return DataBoard;
})(); })();
@ -1878,8 +1845,7 @@
$.sync('Header auto-hide', this.setBarVisibility); $.sync('Header auto-hide', this.setBarVisibility);
$.sync('Centered links', this.setLinkJustify); $.sync('Centered links', this.setLinkJustify);
this.addShortcut(menuButton); this.addShortcut(menuButton);
$.event('AddMenuEntry', { this.menu.addEntry({
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Header' textContent: 'Header'
}), }),
@ -2286,12 +2252,9 @@
return Header.menu.toggle(e, this, g); return Header.menu.toggle(e, this, g);
}, },
createNotification: function(e) { createNotification: function(e) {
var cb, content, lifetime, notice, type, _ref; var content, lifetime, notice, type, _ref;
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb; _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime;
notice = new Notice(type, content, lifetime); return notice = new Notice(type, content, lifetime);
if (cb) {
return cb(notice);
}
}, },
areNotificationsEnabled: false, areNotificationsEnabled: false,
enableDesktopNotifications: function() { enableDesktopNotifications: function() {
@ -2431,8 +2394,7 @@
$.on(input, 'change', this.cb.sort); $.on(input, 'change', this.cb.sort);
} }
} }
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Index Navigation' textContent: 'Index Navigation'
}), }),
@ -2957,14 +2919,12 @@
return nodes; return nodes;
}, },
buildStructure: function(nodes) { buildStructure: function(nodes) {
var i, node, result; var node, _i, _len;
result = $.frag(); for (_i = 0, _len = nodes.length; _i < _len; _i++) {
i = 0; node = nodes[_i];
while (node = nodes[i++]) { $.add(Index.root, [node, $.el('hr')]);
$.add(result, [node, $.el('hr')]);
} }
$.event('IndexBuild', result.children); return ThreadHiding.onIndexBuild(nodes);
return $.add(Index.root, result);
}, },
isSearching: false, isSearching: false,
clearSearch: function() { clearSearch: function() {
@ -3142,7 +3102,7 @@
This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS). This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
@license: https://github.com/4chan/4chan-JS/blob/master/LICENSE @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
*/ */
var E, boardID, capcode, container, date, dateUTC, email, file, fileSize, fileThumb, flagCode, flagName, h_capcodeClass, h_capcodeIcon, h_capcodeStart, h_closed, h_comment, h_emailEnd, h_emailStart, h_file, h_fileDims, h_fileInfo, h_fileTitle1, h_fileTitle2, h_flag, h_gifIcon, h_imgSrc, h_pageIcon, h_postClass, h_quoteLink, h_replyLink, h_sideArrows, h_staticPath, h_sticky, h_tripcode, h_userID, href, isClosed, isOP, isSticky, name, pageNum, postID, quote, shortFilename, spoilerRange, subject, threadID, tripcode, uniqueID, _i, _len, _ref; var E, boardID, capcode, container, date, dateUTC, email, email_processed, file, fileSize, fileThumb, flagCode, flagName, h_capcodeClass, h_capcodeIcon, h_capcodeStart, h_closed, h_comment, h_emailEnd, h_emailStart, h_file, h_fileDims, h_fileInfo, h_fileTitle1, h_fileTitle2, h_flag, h_gifIcon, h_imgSrc, h_pageIcon, h_postClass, h_quoteLink, h_replyLink, h_sideArrows, h_staticPath, h_sticky, h_tripcode, h_userID, href, isClosed, isOP, isSticky, name, pageNum, postID, quote, shortFilename, spoilerRange, subject, threadID, tripcode, uniqueID, _i, _len, _ref;
E = Build.h_escape; E = Build.h_escape;
postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, h_comment = o.h_comment, file = o.file; postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, h_comment = o.h_comment, file = o.file;
name || (name = ''); name || (name = '');
@ -3160,8 +3120,9 @@
} else { } else {
h_tripcode = ''; h_tripcode = '';
} }
email_processed = encodeURIComponent(email).replace(/%40/g, '@');
if (email) { if (email) {
h_emailStart = "<a href='mailto:" + (E(encodeURIComponent(email))) + "' class='useremail'>"; h_emailStart = "<a href='mailto:" + (E(email_processed)) + "' class='useremail'>";
h_emailEnd = '</a>'; h_emailEnd = '</a>';
} else { } else {
h_emailStart = ''; h_emailStart = '';
@ -3608,7 +3569,7 @@
}; };
UI = (function() { UI = (function() {
var Menu, checkbox, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove; var Menu, checkbox, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, menus, touchend, touchmove;
dialog = function(id, position, properties) { dialog = function(id, position, properties) {
var child, el, move, _i, _len, _ref; var child, el, move, _i, _len, _ref;
el = $.el('div', { el = $.el('div', {
@ -3634,6 +3595,7 @@
} }
return el; return el;
}; };
menus = {};
Menu = (function() { Menu = (function() {
var currentMenu, lastToggledButton; var currentMenu, lastToggledButton;
@ -3643,14 +3605,23 @@
function Menu(type) { function Menu(type) {
this.type = type; this.type = type;
this.rmEntry = __bind(this.rmEntry, this);
this.addEntry = __bind(this.addEntry, this); this.addEntry = __bind(this.addEntry, this);
this.onFocus = __bind(this.onFocus, this); this.onFocus = __bind(this.onFocus, this);
this.keybinds = __bind(this.keybinds, this); this.keybinds = __bind(this.keybinds, this);
this.close = __bind(this.close, this); this.close = __bind(this.close, this);
$.on(d, 'AddMenuEntry', this.addEntry); $.on(d, 'AddMenuEntry', (function(_this) {
$.on(d, 'rmMenuEntry', this.rmEntry); return function(_arg) {
var detail;
detail = _arg.detail;
if (detail.type !== _this.type) {
return;
}
delete detail.open;
return _this.addEntry(detail);
};
})(this));
this.entries = []; this.entries = [];
menus[this.type] = this;
} }
Menu.prototype.makeMenu = function() { Menu.prototype.makeMenu = function() {
@ -3841,26 +3812,11 @@
return style.right = right; return style.right = right;
}; };
Menu.prototype.addEntry = function(e) { Menu.prototype.addEntry = function(entry) {
var entry;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
this.parseEntry(entry); this.parseEntry(entry);
return this.entries.push(entry); return this.entries.push(entry);
}; };
Menu.prototype.rmEntry = function(e) {
var entry, index;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
index = this.entries.indexOf(entry);
return this.entries.splice(index, 1);
};
Menu.prototype.parseEntry = function(entry) { Menu.prototype.parseEntry = function(entry) {
var el, subEntries, subEntry, _i, _len; var el, subEntries, subEntry, _i, _len;
el = entry.el, subEntries = entry.subEntries; el = entry.el, subEntries = entry.subEntries;
@ -4320,7 +4276,6 @@
textContent: 'Filter' textContent: 'Filter'
}); });
entry = { entry = {
type: 'post',
el: div, el: div,
order: 50, order: 50,
open: function(post) { open: function(post) {
@ -4334,7 +4289,7 @@
type = _ref[_i]; type = _ref[_i];
entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1])); entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1]));
} }
return $.event('AddMenuEntry', entry); return Menu.menu.addEntry(entry);
}, },
createSubEntry: function(text, type) { createSubEntry: function(text, type) {
var el; var el;
@ -4440,8 +4395,7 @@
thisPost = UI.checkbox('thisPost', ' This post', true); thisPost = UI.checkbox('thisPost', ' This post', true);
replies = UI.checkbox('replies', ' Hide replies', Conf['Recursive Hiding']); replies = UI.checkbox('replies', ' Hide replies', Conf['Recursive Hiding']);
makeStub = UI.checkbox('makeStub', ' Make stub', Conf['Stubs']); makeStub = UI.checkbox('makeStub', ' Make stub', Conf['Stubs']);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(post) { open: function(post) {
@ -4479,8 +4433,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(hideStubLink, 'click', PostHiding.menu.hideStub); $.on(hideStubLink, 'click', PostHiding.menu.hideStub);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(post) { open: function(post) {
@ -4510,8 +4463,7 @@
} }
] ]
}); });
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: hideStubLink, el: hideStubLink,
order: 15, order: 15,
open: function(post) { open: function(post) {
@ -4748,7 +4700,6 @@
} }
this.db = new DataBoard('hiddenThreads'); this.db = new DataBoard('hiddenThreads');
this.syncCatalog(); this.syncCatalog();
$.on(d, 'IndexBuild', this.onIndexBuild);
return Thread.callbacks.push({ return Thread.callbacks.push({
name: 'Thread Hiding', name: 'Thread Hiding',
cb: this.node cb: this.node
@ -4767,16 +4718,12 @@
} }
return $.prepend(this.OP.nodes.root, ThreadHiding.makeButton(this, 'hide')); return $.prepend(this.OP.nodes.root, ThreadHiding.makeButton(this, 'hide'));
}, },
onIndexBuild: function(_arg) { onIndexBuild: function(nodes) {
var i, nodes, root, thread, _i, _len; var root, thread, _i, _len;
nodes = _arg.detail; for (_i = 0, _len = nodes.length; _i < _len; _i++) {
for (i = _i = 0, _len = nodes.length; _i < _len; i = _i += 2) { root = nodes[_i];
root = nodes[i];
thread = Get.threadFromRoot(root); thread = Get.threadFromRoot(root);
if (!thread.isHidden) { if (thread.isHidden && thread.stub && !root.contains(thread.stub)) {
continue;
}
if (thread.stub && root.contains(thread.stub)) {
ThreadHiding.makeStub(thread, root); ThreadHiding.makeStub(thread, root);
} }
} }
@ -4847,8 +4794,7 @@
}); });
$.on(apply, 'click', ThreadHiding.menu.hide); $.on(apply, 'click', ThreadHiding.menu.hide);
makeStub = UI.checkbox('Stubs', ' Make stub'); makeStub = UI.checkbox('Stubs', ' Make stub');
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(_arg) { open: function(_arg) {
@ -4874,8 +4820,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(div, 'click', ThreadHiding.menu.show); $.on(div, 'click', ThreadHiding.menu.show);
$.event('AddMenuEntry', { Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 20, order: 20,
open: function(_arg) { open: function(_arg) {
@ -4893,8 +4838,7 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(hideStubLink, 'click', ThreadHiding.menu.hideStub); $.on(hideStubLink, 'click', ThreadHiding.menu.hideStub);
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: hideStubLink, el: hideStubLink,
order: 15, order: 15,
open: function(_arg) { open: function(_arg) {
@ -5421,8 +5365,7 @@
}); });
input = $('input', this.controls); input = $('input', this.controls);
$.on(input, 'change', this.toggle); $.on(input, 'change', this.toggle);
$.event('AddMenuEntry', this.entry = { Header.menu.addEntry(this.entry = {
type: 'header',
el: this.controls, el: this.controls,
order: 98 order: 98
}); });
@ -5434,19 +5377,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var input;
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
input = $('input', this.controls);
$.off(input, 'change', this.toggle);
$.event('rmMenuEntry', this.entry);
delete this.enabled;
delete this.controls;
delete this.entry;
return Post.callbacks.disconnect('Quote Threading');
},
ready: function() { ready: function() {
$.off(d, '4chanXInitFinished', QuoteThreading.ready); $.off(d, '4chanXInitFinished', QuoteThreading.ready);
return QuoteThreading.force(); return QuoteThreading.force();
@ -5849,16 +5779,6 @@
$.prepend($('.navLinksBot'), linkBot); $.prepend($('.navLinksBot'), linkBot);
} }
$.before($.id('togglePostFormLink'), link); $.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, 'paste', QR.paste);
$.on(d, 'dragover', QR.dragOver); $.on(d, 'dragover', QR.dragOver);
$.on(d, 'drop', QR.dropFile); $.on(d, 'drop', QR.dropFile);
@ -6478,9 +6398,8 @@
return $.add(nodes.form, flag); return $.add(nodes.form, flag);
} }
}, },
preSubmitHooks: [],
submit: function(e) { 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) { if (e != null) {
e.preventDefault(); e.preventDefault();
} }
@ -6513,17 +6432,9 @@
err = 'No file selected.'; err = 'No file selected.';
} else if (post.file && thread.fileLimit) { } else if (post.file && thread.fileLimit) {
err = 'Max limit of image replies has been reached.'; 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) { 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) { if (!response) {
err = 'No valid captcha.'; err = 'No valid captcha.';
} }
@ -6656,11 +6567,12 @@
}); });
ThreadUpdater.postID = postID; ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', { $.event('QRPostSuccessful', {
board: g.BOARD, boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
postID: postID postID: postID
}); });
$.event('QRPostSuccessful_', { $.event('QRPostSuccessful_', {
boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
postID: postID postID: postID
}); });
@ -7277,8 +7189,7 @@
rectEl = this.nodes.el.getBoundingClientRect(); rectEl = this.nodes.el.getBoundingClientRect();
rectList = this.nodes.el.parentNode.getBoundingClientRect(); rectList = this.nodes.el.parentNode.getBoundingClientRect();
this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2; this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2;
this.load(); return this.load();
return $.event('QRPostSelection', this);
}; };
_Class.prototype.load = function() { _Class.prototype.load = function() {
@ -7550,8 +7461,7 @@
el.title = "" + type + " Tyme"; el.title = "" + type + " Tyme";
FappeTyme[lc] = input = el.firstElementChild; FappeTyme[lc] = input = el.firstElementChild;
$.on(input, 'change', FappeTyme.cb.toggle.bind(input)); $.on(input, 'change', FappeTyme.cb.toggle.bind(input));
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 97 order: 97
}); });
@ -7650,8 +7560,7 @@
createSubEntry = Gallery.menu.createSubEntry; createSubEntry = Gallery.menu.createSubEntry;
for (name in Config.gallery) { for (name in Config.gallery) {
el = createSubEntry(name).el; el = createSubEntry(name).el;
$.event('AddMenuEntry', { nodes.menu.addEntry({
type: 'gallery',
el: el, el: el,
order: 0 order: 0
}); });
@ -7885,8 +7794,7 @@
for (name in Config.gallery) { for (name in Config.gallery) {
subEntries.push(createSubEntry(name)); subEntries.push(createSubEntry(name));
} }
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 105, order: 105,
subEntries: subEntries subEntries: subEntries
@ -8219,8 +8127,7 @@
conf = _ref[name]; conf = _ref[name];
subEntries.push(createSubEntry(name, conf[1])); subEntries.push(createSubEntry(name, conf[1]));
} }
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 105, order: 105,
subEntries: subEntries subEntries: subEntries
@ -8381,8 +8288,7 @@
}); });
this.el = prefetch.firstElementChild; this.el = prefetch.firstElementChild;
$.on(this.el, 'change', this.toggle); $.on(this.el, 'change', this.toggle);
return $.event('AddMenuEntry', { return Header.menu.addEntry({
type: 'header',
el: prefetch, el: prefetch,
order: 104 order: 104
}); });
@ -9139,7 +9045,6 @@
textContent: 'Archive' textContent: 'Archive'
}); });
entry = { entry = {
type: 'post',
el: div, el: div,
order: 90, order: 90,
open: function(_arg) { open: function(_arg) {
@ -9158,7 +9063,7 @@
type = _ref[_i]; type = _ref[_i];
entry.subEntries.push(this.createSubEntry(type[0], type[1])); entry.subEntries.push(this.createSubEntry(type[0], type[1]));
} }
return $.event('AddMenuEntry', entry); return Menu.menu.addEntry(entry);
}, },
createSubEntry: function(text, type) { createSubEntry: function(text, type) {
var el, open; var el, open;
@ -9235,8 +9140,7 @@
return true; return true;
} }
}; };
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: div, el: div,
order: 40, order: 40,
open: function(post) { open: function(post) {
@ -9360,8 +9264,7 @@
}; };
})(this)); })(this));
}); });
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: a, el: a,
order: 100, order: 100,
open: function(_arg) { open: function(_arg) {
@ -9429,8 +9332,7 @@
textContent: 'Report this post' textContent: 'Report this post'
}); });
$.on(a, 'click', ReportLink.report); $.on(a, 'click', ReportLink.report);
return $.event('AddMenuEntry', { return Menu.menu.addEntry({
type: 'post',
el: a, el: a,
order: 10, order: 10,
open: function(post) { open: function(post) {
@ -9507,12 +9409,6 @@
}, },
node: function() { node: function() {
return d.title = Get.threadExcerpt(this); return d.title = Get.threadExcerpt(this);
},
disconnect: function() {
if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
return;
}
return Thread.callbacks.disconnect('Thread Excerpt');
} }
}; };
@ -9564,25 +9460,6 @@
ThreadStats.update(postCount, fileCount); ThreadStats.update(postCount, fileCount);
return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate); return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
}, },
disconnect: function() {
if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
return;
}
if (Conf['Updater and Stats in Header']) {
Header.rmShortcut(this.dialog);
} else {
$.rm(this.dialog);
}
clearTimeout(this.timeout);
delete this.timeout;
delete this.thread;
delete this.postCountEl;
delete this.fileCountEl;
delete this.pageCountEl;
delete this.dialog;
Thread.callbacks.disconnect('Thread Stats');
return $.off(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
onUpdate: function(e) { onUpdate: function(e) {
var fileCount, postCount, _ref; var fileCount, postCount, _ref;
if (e.detail[404]) { if (e.detail[404]) {
@ -9702,8 +9579,7 @@
subEntries.push({ subEntries.push({
el: this.settings el: this.settings
}); });
$.event('AddMenuEntry', this.entry = { Header.menu.addEntry(this.entry = {
type: 'header',
el: $.el('span', { el: $.el('span', {
textContent: 'Updater' textContent: 'Updater'
}), }),
@ -9715,45 +9591,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var el, entry, input, name, _i, _j, _len, _len1, _ref, _ref1;
if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
return;
}
$.off(this.timer, 'click', this.update);
$.off(this.status, 'click', this.update);
if (this.timeoutID) {
clearTimeout(this.timeoutID);
}
_ref = this.entry.subEntries;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
entry = _ref[_i];
el = entry.el;
input = el.firstElementChild;
$.off(input, 'change', $.cb.checked);
$.off(input, 'change', this.cb.scrollBG);
$.off(input, 'change', this.cb.update);
}
$.off(this.settings, 'click', this.intervalShortcut);
$.off(window, 'online offline', this.cb.online);
$.off(d, 'QRPostSuccessful', this.cb.checkpost);
$.off(d, 'visibilitychange', this.cb.visibility);
this.set('timer', null);
this.set('status', 'Offline');
$.event('rmMenuEntry', this.entry);
if (Conf['Updater and Stats in Header']) {
Header.rmShortcut(this.dialog);
} else {
$.rmClass(doc, 'float');
$.rm(this.dialog);
}
_ref1 = ['checkPostCount', 'timer', 'status', 'isUpdating', 'entry', 'dialog', 'thread', 'root', 'lastPost', 'outdateCount', 'online', 'seconds', 'timeoutID'];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
name = _ref1[_j];
delete this[name];
}
return Thread.callbacks.disconnect('Thread Updater');
},
node: function() { node: function() {
ThreadUpdater.thread = this; ThreadUpdater.thread = this;
ThreadUpdater.root = this.OP.nodes.root.parentNode; ThreadUpdater.root = this.OP.nodes.root.parentNode;
@ -9852,7 +9689,7 @@
ThreadUpdater.thread.kill(); ThreadUpdater.thread.kill();
$.event('ThreadUpdate', { $.event('ThreadUpdate', {
404: true, 404: true,
thread: ThreadUpdater.thread threadID: ThreadUpdater.thread.fullID
}); });
break; break;
default: default:
@ -9946,7 +9783,7 @@
return new Notice('info', "The thread is " + change + ".", 30); return new Notice('info', "The thread is " + change + ".", 30);
}, },
parse: function(postObjects) { parse: function(postObjects) {
var OP, count, deletedFiles, deletedPosts, files, index, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1; var OP, count, files, index, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1;
OP = postObjects[0]; OP = postObjects[0];
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
@ -9971,19 +9808,15 @@
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID); node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board)); posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
} }
deletedPosts = [];
deletedFiles = [];
ThreadUpdater.thread.posts.forEach(function(post) { ThreadUpdater.thread.posts.forEach(function(post) {
var ID; var ID;
ID = +post.ID; ID = +post.ID;
if (__indexOf.call(index, ID) < 0) { if (__indexOf.call(index, ID) < 0) {
post.kill(); post.kill();
deletedPosts.push(post);
} else if (post.isDead) { } else if (post.isDead) {
post.resurrect(); 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); post.kill(true);
deletedFiles.push(post);
} }
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) { if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
return ThreadUpdater.foundPost = true; return ThreadUpdater.foundPost = true;
@ -10035,10 +9868,10 @@
} }
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: false, 404: false,
thread: ThreadUpdater.thread, threadID: ThreadUpdater.thread.fullID,
newPosts: posts, newPosts: posts.map(function(post) {
deletedPosts: deletedPosts, return post.fullID;
deletedFiles: deletedFiles, }),
postCount: OP.replies + 1, postCount: OP.replies + 1,
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead) fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
}); });
@ -10065,9 +9898,6 @@
this.status = $('#watcher-status', this.dialog); this.status = $('#watcher-status', this.dialog);
this.list = this.dialog.lastElementChild; this.list = this.dialog.lastElementChild;
$.on(d, 'QRPostSuccessful', this.cb.post); $.on(d, 'QRPostSuccessful', this.cb.post);
if (g.VIEW === 'thread') {
$.on(d, 'ThreadUpdate', this.cb.threadUpdate);
}
$.on(sc, 'click', this.toggleWatcher); $.on(sc, 'click', this.toggleWatcher);
$.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher); $.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher);
$.on(d, '4chanXInitFinished', this.ready); $.on(d, '4chanXInitFinished', this.ready);
@ -10176,14 +10006,14 @@
return ThreadWatcher.rm(boardID, +threadID); return ThreadWatcher.rm(boardID, +threadID);
}, },
post: function(e) { post: function(e) {
var board, postID, threadID, _ref; var boardID, postID, threadID, _ref;
_ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID; _ref = e.detail, boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
if (postID === threadID) { if (postID === threadID) {
if (Conf['Auto Watch']) { if (Conf['Auto Watch']) {
return $.set('AutoWatch', threadID); return $.set('AutoWatch', threadID);
} }
} else if (Conf['Auto Watch Reply']) { } else if (Conf['Auto Watch Reply']) {
return ThreadWatcher.add(board.threads[threadID]); return ThreadWatcher.add(g.threads[boardID + '.' + threadID]);
} }
}, },
onIndexRefresh: function() { onIndexRefresh: function() {
@ -10213,7 +10043,7 @@
}, },
onThreadRefresh: function(e) { onThreadRefresh: function(e) {
var thread; var thread;
thread = e.detail.thread; thread = g.threads[e.detail.threadID];
if (!(e.detail[404] && ThreadWatcher.db.get({ if (!(e.detail[404] && ThreadWatcher.db.get({
boardID: thread.board.ID, boardID: thread.board.ID,
threadID: thread.ID threadID: thread.ID
@ -10425,7 +10255,7 @@
if (!Conf['Thread Watcher']) { if (!Conf['Thread Watcher']) {
return; return;
} }
menu = new UI.Menu('thread watcher'); menu = this.menu = new UI.Menu('thread watcher');
$.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) { $.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) {
return menu.toggle(e, this, ThreadWatcher); return menu.toggle(e, this, ThreadWatcher);
}); });
@ -10440,8 +10270,7 @@
entryEl = $.el('a', { entryEl = $.el('a', {
href: 'javascript:;' href: 'javascript:;'
}); });
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: entryEl, el: entryEl,
order: 60 order: 60
}); });
@ -10462,7 +10291,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.openAll, cb: ThreadWatcher.cb.openAll,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Open all threads' textContent: 'Open all threads'
}) })
@ -10474,7 +10302,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.checkThreads, cb: ThreadWatcher.cb.checkThreads,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Check 404\'d threads' textContent: 'Check 404\'d threads'
}) })
@ -10486,7 +10313,6 @@
entries.push({ entries.push({
cb: ThreadWatcher.cb.pruneDeads, cb: ThreadWatcher.cb.pruneDeads,
entry: { entry: {
type: 'thread watcher',
el: $.el('a', { el: $.el('a', {
textContent: 'Prune 404\'d threads' textContent: 'Prune 404\'d threads'
}) })
@ -10503,7 +10329,6 @@
} }
entries.push({ entries.push({
entry: { entry: {
type: 'thread watcher',
el: $.el('span', { el: $.el('span', {
textContent: 'Settings' textContent: 'Settings'
}), }),
@ -10521,7 +10346,7 @@
if (refresh) { if (refresh) {
this.refreshers.push(refresh.bind(entry)); this.refreshers.push(refresh.bind(entry));
} }
$.event('AddMenuEntry', entry); this.menu.addEntry(entry);
} }
}, },
createSubEntry: function(name, desc) { createSubEntry: function(name, desc) {
@ -10557,28 +10382,6 @@
cb: this.node cb: this.node
}); });
}, },
disconnect: function() {
var hr, name, _i, _len, _ref;
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Desktop Notifications']) {
return;
}
Unread.db.disconnect();
if (hr = Unread.hr, Unread) {
$.rm(hr);
}
_ref = ['db', 'hr', 'posts', 'postsQuotingYou', 'thread', 'title', 'lastReadPost'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
name = _ref[_i];
delete this[name];
}
$.off(d, '4chanXInitFinished', this.ready);
$.off(d, 'ThreadUpdate', this.onUpdate);
$.off(d, 'scroll visibilitychange', this.read);
if (Conf['Unread Line'] && !Conf['Quote Threading']) {
$.off(d, 'visibilitychange', this.setLine);
}
return Thread.callbacks.disconnect('Unread');
},
node: function() { node: function() {
Unread.thread = this; Unread.thread = this;
Unread.title = d.title; Unread.title = d.title;
@ -10723,7 +10526,9 @@
if (e.detail[404]) { if (e.detail[404]) {
return Unread.update(); return Unread.update();
} else if (!QuoteThreading.enabled) { } else if (!QuoteThreading.enabled) {
return Unread.addPosts(e.detail.newPosts); return Unread.addPosts(e.detail.newPosts.map(function(fullID) {
return g.posts[fullID];
}));
} else { } else {
Unread.read(); Unread.read();
return Unread.update(); return Unread.update();
@ -10931,7 +10736,6 @@
return; return;
} }
entry = { entry = {
type: 'header',
el: $.el('a', { el: $.el('a', {
textContent: 'Show announcement', textContent: 'Show announcement',
className: 'show-announcement', className: 'show-announcement',
@ -10942,7 +10746,7 @@
return psa.hidden; return psa.hidden;
} }
}; };
$.event('AddMenuEntry', entry); Header.menu.addEntry(entry);
$.on(entry.el, 'click', PSAHiding.toggle); $.on(entry.el, 'click', PSAHiding.toggle);
PSAHiding.btn = btn = $.el('span', { PSAHiding.btn = btn = $.el('span', {
innerHTML: '[<a href="javascript:;">Dismiss</a>]', innerHTML: '[<a href="javascript:;">Dismiss</a>]',
@ -11095,8 +10899,7 @@
input = $('input', el); input = $('input', el);
$.on(input, 'change', this.toggle); $.on(input, 'change', this.toggle);
$.sync('Header catalog links', CatalogLinks.set); $.sync('Header catalog links', CatalogLinks.set);
$.event('AddMenuEntry', { Header.menu.addEntry({
type: 'header',
el: el, el: el,
order: 95 order: 95
}); });
@ -11593,7 +11396,7 @@
}); });
} }
if (board === 'sci') { if (board === 'sci') {
$.globalEval('window.addEventListener(\'jsmath\', function(e) {\n if (!jsMath) return;\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else if (jsMath.Autoload && jsMath.Autoload.checked) {\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) return;\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(document.getElementById(e.detail));\n } else if (jsMath.Autoload && jsMath.Autoload.checked) {\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({ return Post.callbacks.push({
name: 'Parse /sci/ math', name: 'Parse /sci/ math',
cb: this.math cb: this.math
@ -11626,7 +11429,7 @@
}; };
})(this)), (function(_this) { })(this)), (function(_this) {
return function() { return function() {
return $.event('jsmath', _this.nodes.post, window); return $.event('jsmath', _this.nodes.post.id, window);
}; };
})(this)); })(this));
}, },
@ -12474,7 +12277,7 @@
Settings.dialog = dialog = $.el('div', { Settings.dialog = dialog = $.el('div', {
id: 'fourchanx-settings', id: 'fourchanx-settings',
className: 'dialog', className: 'dialog',
innerHTML: '<nav><div class=sections-list></div><p class=\'imp-exp-result warning\'></p><div class=credits><a class=export>Export</a>&nbsp|&nbsp<a class=import>Import</a>&nbsp|&nbsp<a class=reset>Reset Settings</a>&nbsp|&nbsp<input type=file hidden><a href=\'https://github.com/ccd0/4chan-x\' target=_blank>4chan X</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md\' target=_blank>1.7.63</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/issues\' target=_blank>Issues</a>&nbsp|&nbsp<a href=javascript:; class=\'close fa fa-times\' title=Close></a></div></nav><div class=section-container><section></section></div>' innerHTML: '<nav><div class=sections-list></div><p class=\'imp-exp-result warning\'></p><div class=credits><a class=export>Export</a>&nbsp|&nbsp<a class=import>Import</a>&nbsp|&nbsp<a class=reset>Reset Settings</a>&nbsp|&nbsp<input type=file hidden><a href=\'https://github.com/ccd0/4chan-x\' target=_blank>4chan X</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md\' target=_blank>1.8.1</a>&nbsp|&nbsp<a href=\'https://github.com/ccd0/4chan-x/issues\' target=_blank>Issues</a>&nbsp|&nbsp<a href=javascript:; class=\'close fa fa-times\' title=Close></a></div></nav><div class=section-container><section></section></div>'
}); });
$.on($('.export', Settings.dialog), 'click', Settings["export"]); $.on($('.export', Settings.dialog), 'click', Settings["export"]);
$.on($('.import', Settings.dialog), 'click', Settings["import"]); $.on($('.import', Settings.dialog), 'click', Settings["import"]);
@ -13176,7 +12979,6 @@
}); });
} }
} }
$.on(d, 'AddCallback', Main.addCallback);
return $.ready(Main.initReady); return $.ready(Main.initReady);
}, },
initStyle: function() { initStyle: function() {
@ -13306,7 +13108,7 @@
} }
if (previousversion) { if (previousversion) {
el = $.el('span', { el = $.el('span', {
innerHTML: '4chan X has been updated to <a href="https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md" target="_blank">version 1.7.63</a>.' innerHTML: '4chan X has been updated to <a href="https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md" target="_blank">version 1.8.1</a>.'
}); });
new Notice('info', el, 15); new Notice('info', el, 15);
} else { } else {
@ -13349,25 +13151,6 @@
}; };
return softTask(); return softTask();
}, },
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) { handleErrors: function(errors) {
var div, error, logs, _i, _len; var div, error, logs, _i, _len;
if (!(errors instanceof Array)) { if (!(errors instanceof Array)) {

View File

@ -1,6 +1,6 @@
{ {
"name": "4chan-X", "name": "4chan-X",
"version": "1.7.63", "version": "1.8.1",
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": { "meta": {
"name": "4chan X", "name": "4chan X",

View File

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

View File

@ -39,8 +39,7 @@ PostHiding =
replies = UI.checkbox 'replies', ' Hide replies', Conf['Recursive Hiding'] replies = UI.checkbox 'replies', ' Hide replies', Conf['Recursive Hiding']
makeStub = UI.checkbox 'makeStub', ' Make stub', Conf['Stubs'] makeStub = UI.checkbox 'makeStub', ' Make stub', Conf['Stubs']
$.event 'AddMenuEntry', Menu.menu.addEntry
type: 'post'
el: div el: div
order: 20 order: 20
open: (post) -> open: (post) ->
@ -75,8 +74,7 @@ PostHiding =
href: 'javascript:;' href: 'javascript:;'
$.on hideStubLink, 'click', PostHiding.menu.hideStub $.on hideStubLink, 'click', PostHiding.menu.hideStub
$.event 'AddMenuEntry', Menu.menu.addEntry
type: 'post'
el: div el: div
order: 20 order: 20
open: (post) -> open: (post) ->
@ -96,8 +94,7 @@ PostHiding =
el: replies el: replies
] ]
$.event 'AddMenuEntry', Menu.menu.addEntry
type: 'post'
el: hideStubLink el: hideStubLink
order: 15 order: 15
open: (post) -> open: (post) ->

View File

@ -4,7 +4,6 @@ ThreadHiding =
@db = new DataBoard 'hiddenThreads' @db = new DataBoard 'hiddenThreads'
@syncCatalog() @syncCatalog()
$.on d, 'IndexBuild', @onIndexBuild
Thread.callbacks.push Thread.callbacks.push
name: 'Thread Hiding' name: 'Thread Hiding'
cb: @node cb: @node
@ -15,12 +14,10 @@ ThreadHiding =
return unless Conf['Thread Hiding Buttons'] return unless Conf['Thread Hiding Buttons']
$.prepend @OP.nodes.root, ThreadHiding.makeButton @, 'hide' $.prepend @OP.nodes.root, ThreadHiding.makeButton @, 'hide'
onIndexBuild: ({detail: nodes}) -> onIndexBuild: (nodes) ->
for root, i in nodes by 2 for root in nodes
thread = Get.threadFromRoot root thread = Get.threadFromRoot root
continue unless thread.isHidden if thread.isHidden and thread.stub and !root.contains thread.stub
if thread.stub and root.contains thread.stub
# When we come back to a page, the stub is already there.
ThreadHiding.makeStub thread, root ThreadHiding.makeStub thread, root
return return
@ -80,8 +77,7 @@ ThreadHiding =
makeStub = UI.checkbox 'Stubs', ' Make stub' makeStub = UI.checkbox 'Stubs', ' Make stub'
$.event 'AddMenuEntry', Menu.menu.addEntry
type: 'post'
el: div el: div
order: 20 order: 20
open: ({thread, isReply}) -> open: ({thread, isReply}) ->
@ -97,8 +93,7 @@ ThreadHiding =
href: 'javascript:;' href: 'javascript:;'
$.on div, 'click', ThreadHiding.menu.show $.on div, 'click', ThreadHiding.menu.show
$.event 'AddMenuEntry', Menu.menu.addEntry
type: 'post'
el: div el: div
order: 20 order: 20
open: ({thread, isReply}) -> open: ({thread, isReply}) ->
@ -112,8 +107,7 @@ ThreadHiding =
href: 'javascript:;' href: 'javascript:;'
$.on hideStubLink, 'click', ThreadHiding.menu.hideStub $.on hideStubLink, 'click', ThreadHiding.menu.hideStub
$.event 'AddMenuEntry', Menu.menu.addEntry
type: 'post'
el: hideStubLink el: hideStubLink
order: 15 order: 15
open: ({thread, isReply}) -> open: ({thread, isReply}) ->

View File

@ -54,8 +54,7 @@ Header =
@addShortcut menuButton @addShortcut menuButton
$.event 'AddMenuEntry', @menu.addEntry
type: 'header'
el: $.el 'span', el: $.el 'span',
textContent: 'Header' textContent: 'Header'
order: 107 order: 107
@ -427,9 +426,8 @@ Header =
Header.menu.toggle e, @, g Header.menu.toggle e, @, g
createNotification: (e) -> createNotification: (e) ->
{type, content, lifetime, cb} = e.detail {type, content, lifetime} = e.detail
notice = new Notice type, content, lifetime notice = new Notice type, content, lifetime
cb notice if cb
areNotificationsEnabled: false areNotificationsEnabled: false
enableDesktopNotifications: -> enableDesktopNotifications: ->

View File

@ -55,8 +55,7 @@ Index =
when 'Anchor Hidden Threads' when 'Anchor Hidden Threads'
$.on input, 'change', @cb.sort $.on input, 'change', @cb.sort
$.event 'AddMenuEntry', Header.menu.addEntry
type: 'header'
el: $.el 'span', el: $.el 'span',
textContent: 'Index Navigation' textContent: 'Index Navigation'
order: 98 order: 98
@ -438,11 +437,9 @@ Index =
nodes nodes
buildStructure: (nodes) -> buildStructure: (nodes) ->
result = $.frag() for node in nodes
i = 0 $.add Index.root, [node, $.el 'hr']
$.add result, [node, $.el 'hr'] while node = nodes[i++] ThreadHiding.onIndexBuild nodes
$.event 'IndexBuild', result.children
$.add Index.root, result
isSearching: false isSearching: false

View File

@ -78,7 +78,6 @@ Main =
# c.timeEnd "#{name} initialization" # c.timeEnd "#{name} initialization"
# c.timeEnd 'All initializations' # c.timeEnd 'All initializations'
$.on d, 'AddCallback', Main.addCallback
$.ready Main.initReady $.ready Main.initReady
initStyle: -> initStyle: ->
@ -218,20 +217,6 @@ Main =
softTask() softTask()
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) -> handleErrors: (errors) ->
unless errors instanceof Array unless errors instanceof Array
error = errors error = errors

View File

@ -23,8 +23,10 @@ UI = do ->
constructor: (@type) -> constructor: (@type) ->
# Doc here: https://github.com/MayhemYDG/4chan-x/wiki/Menu-API # Doc here: https://github.com/MayhemYDG/4chan-x/wiki/Menu-API
$.on d, 'AddMenuEntry', @addEntry $.on d, 'AddMenuEntry', ({detail}) =>
$.on d, 'rmMenuEntry', @rmEntry return if detail.type isnt @type
delete detail.open
@addEntry detail
@entries = [] @entries = []
makeMenu: -> makeMenu: ->
@ -187,18 +189,10 @@ UI = do ->
style.left = left style.left = left
style.right = right style.right = right
addEntry: (e) => addEntry: (entry) =>
entry = e.detail
return if entry.type isnt @type
@parseEntry entry @parseEntry entry
@entries.push entry @entries.push entry
rmEntry: (e) =>
entry = e.detail
return if entry.type isnt @type
index = @entries.indexOf entry
@entries.splice index, 1
parseEntry: (entry) -> parseEntry: (entry) ->
{el, subEntries} = entry {el, subEntries} = entry
$.addClass el, 'entry' $.addClass el, 'entry'

View File

@ -4,10 +4,6 @@
$ = (selector, root=d.body) -> $ = (selector, root=d.body) ->
root.querySelector selector root.querySelector selector
$.extend = (obj, prop) ->
obj[key] = val for key, val of prop when prop.hasOwnProperty key
return
$.DAY = 24 * $.DAY = 24 *
$.HOUR = 60 * $.HOUR = 60 *
$.MINUTE = 60 * $.MINUTE = 60 *
@ -181,6 +177,10 @@ $.off = (el, events, handler) ->
return return
$.event = (event, detail, root=d) -> $.event = (event, detail, root=d) ->
<% if (type === 'userscript') { %>
if detail? and typeof cloneInto is 'function'
detail = cloneInto detail, document.defaultView
<% } %>
root.dispatchEvent new CustomEvent event, {bubbles: true, detail} root.dispatchEvent new CustomEvent event, {bubbles: true, detail}
$.open = $.open =

View File

@ -3,17 +3,13 @@ class Callbacks
@keys = [] @keys = []
push: ({name, cb}) -> push: ({name, cb}) ->
@connect name if @[name]
@keys.push name unless @[name] @keys.push name unless @[name]
@[name] = cb @[name] = cb
connect: (name) -> delete @[name].disconnected if @[name].disconnected
disconnect: (name) -> @[name].disconnected = true if @[name]
execute: (node) -> execute: (node) ->
for name in @keys for name in @keys
try try
@[name].call node unless @[name].disconnected @[name].call node
catch err catch err
errors = [] unless errors errors = [] unless errors
errors.push errors.push

View File

@ -89,8 +89,3 @@ class DataBoard
onSync: (data) => onSync: (data) =>
@data = data or boards: {} @data = data or boards: {}
@sync?() @sync?()
disconnect: ->
$.desync @key
delete @sync
delete @data

View File

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

View File

@ -61,8 +61,7 @@ Gallery =
for name of Config.gallery for name of Config.gallery
{el} = createSubEntry name {el} = createSubEntry name
$.event 'AddMenuEntry', nodes.menu.addEntry
type: 'gallery'
el: el el: el
order: 0 order: 0
@ -235,8 +234,7 @@ Gallery =
for name of Config.gallery for name of Config.gallery
subEntries.push createSubEntry name subEntries.push createSubEntry name
$.event 'AddMenuEntry', Header.menu.addEntry
type: 'header'
el: el el: el
order: 105 order: 105
subEntries: subEntries subEntries: subEntries

View File

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

View File

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

View File

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

View File

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

View File

@ -17,8 +17,7 @@ DownloadLink =
else else
new Notice 'error', "Could not download #{file.URL}", 30 new Notice 'error', "Could not download #{file.URL}", 30
$.event 'AddMenuEntry', Menu.menu.addEntry
type: 'post'
el: a el: a
order: 100 order: 100
open: ({file}) -> open: ({file}) ->

View File

@ -7,8 +7,7 @@ ReportLink =
href: 'javascript:;' href: 'javascript:;'
textContent: 'Report this post' textContent: 'Report this post'
$.on a, 'click', ReportLink.report $.on a, 'click', ReportLink.report
$.event 'AddMenuEntry', Menu.menu.addEntry
type: 'post'
el: a el: a
order: 10 order: 10
open: (post) -> open: (post) ->
@ -19,4 +18,4 @@ ReportLink =
url = "//sys.4chan.org/#{post.board}/imgboard.php?mode=report&no=#{post}" url = "//sys.4chan.org/#{post.board}/imgboard.php?mode=report&no=#{post}"
id = Date.now() id = Date.now()
set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200" set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200"
window.open url, id, set window.open url, id, set

View File

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

View File

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

View File

@ -21,7 +21,7 @@ Fourchan =
if (!jsMath) return; if (!jsMath) return;
if (jsMath.loaded) { if (jsMath.loaded) {
// process one post // process one post
jsMath.ProcessBeforeShowing(e.detail); jsMath.ProcessBeforeShowing(document.getElementById(e.detail));
} else if (jsMath.Autoload && jsMath.Autoload.checked) { } else if (jsMath.Autoload && jsMath.Autoload.checked) {
// load jsMath and process whole document // load jsMath and process whole document
jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]); jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);
@ -43,7 +43,7 @@ Fourchan =
math: -> math: ->
return if (@isClone and doc.contains @origin.nodes.root) or !$ '.math', @nodes.comment return if (@isClone and doc.contains @origin.nodes.root) or !$ '.math', @nodes.comment
$.asap (=> doc.contains @nodes.post), => $.asap (=> doc.contains @nodes.post), =>
$.event 'jsmath', @nodes.post, window $.event 'jsmath', @nodes.post.id, window
parseThread: (threadID, offset, limit) -> parseThread: (threadID, offset, limit) ->
# Fix /sci/ # Fix /sci/
# Fix /g/ # Fix /g/

View File

@ -6,6 +6,3 @@ ThreadExcerpt =
name: 'Thread Excerpt' name: 'Thread Excerpt'
cb: @node cb: @node
node: -> d.title = Get.threadExcerpt @ node: -> d.title = Get.threadExcerpt @
disconnect: ->
return if g.VIEW isnt 'thread' or !Conf['Thread Excerpt']
Thread.callbacks.disconnect 'Thread Excerpt'

View File

@ -34,26 +34,6 @@ ThreadStats =
ThreadStats.update postCount, fileCount ThreadStats.update postCount, fileCount
$.on d, 'ThreadUpdate', ThreadStats.onUpdate $.on d, 'ThreadUpdate', ThreadStats.onUpdate
disconnect: ->
return if g.VIEW isnt 'thread' or !Conf['Thread Stats']
if Conf['Updater and Stats in Header']
Header.rmShortcut @dialog
else
$.rm @dialog
clearTimeout @timeout # a possible race condition might be that this won't clear in time, but the resulting error will prevent issues anyways.
delete @timeout
delete @thread
delete @postCountEl
delete @fileCountEl
delete @pageCountEl
delete @dialog
Thread.callbacks.disconnect 'Thread Stats'
$.off d, 'ThreadUpdate', ThreadStats.onUpdate
onUpdate: (e) -> onUpdate: (e) ->
return if e.detail[404] return if e.detail[404]
{postCount, fileCount} = e.detail {postCount, fileCount} = e.detail

View File

@ -52,8 +52,7 @@ ThreadUpdater =
subEntries.push el: @settings subEntries.push el: @settings
$.event 'AddMenuEntry', @entry = Header.menu.addEntry @entry =
type: 'header'
el: $.el 'span', el: $.el 'span',
textContent: 'Updater' textContent: 'Updater'
order: 110 order: 110
@ -63,40 +62,6 @@ ThreadUpdater =
name: 'Thread Updater' name: 'Thread Updater'
cb: @node cb: @node
disconnect: ->
return if g.VIEW isnt 'thread' or !Conf['Thread Updater']
$.off @timer, 'click', @update
$.off @status, 'click', @update
clearTimeout @timeoutID if @timeoutID
for entry in @entry.subEntries
{el} = entry
input = el.firstElementChild
$.off input, 'change', $.cb.checked
$.off input, 'change', @cb.scrollBG
$.off input, 'change', @cb.update
$.off @settings, 'click', @intervalShortcut
$.off window, 'online offline', @cb.online
$.off d, 'QRPostSuccessful', @cb.checkpost
$.off d, 'visibilitychange', @cb.visibility
@set 'timer', null
@set 'status', 'Offline'
$.event 'rmMenuEntry', @entry
if Conf['Updater and Stats in Header']
Header.rmShortcut @dialog
else
$.rmClass doc, 'float'
$.rm @dialog
delete @[name] for name in ['checkPostCount', 'timer', 'status', 'isUpdating', 'entry', 'dialog', 'thread', 'root', 'lastPost', 'outdateCount', 'online', 'seconds', 'timeoutID']
Thread.callbacks.disconnect 'Thread Updater'
node: -> node: ->
ThreadUpdater.thread = @ ThreadUpdater.thread = @
ThreadUpdater.root = @OP.nodes.root.parentNode ThreadUpdater.root = @OP.nodes.root.parentNode
@ -173,7 +138,7 @@ ThreadUpdater =
ThreadUpdater.thread.kill() ThreadUpdater.thread.kill()
$.event 'ThreadUpdate', $.event 'ThreadUpdate',
404: true 404: true
thread: ThreadUpdater.thread threadID: ThreadUpdater.thread.fullID
else else
ThreadUpdater.outdateCount++ ThreadUpdater.outdateCount++
ThreadUpdater.setInterval() ThreadUpdater.setInterval()
@ -291,9 +256,6 @@ ThreadUpdater =
node = Build.postFromObject postObject, ThreadUpdater.thread.board.ID node = Build.postFromObject postObject, ThreadUpdater.thread.board.ID
posts.push new Post node, ThreadUpdater.thread, ThreadUpdater.thread.board posts.push new Post node, ThreadUpdater.thread, ThreadUpdater.thread.board
deletedPosts = []
deletedFiles = []
# Check for deleted posts/files. # Check for deleted posts/files.
ThreadUpdater.thread.posts.forEach (post) -> ThreadUpdater.thread.posts.forEach (post) ->
# XXX tmp fix for 4chan's racing condition # XXX tmp fix for 4chan's racing condition
@ -303,12 +265,10 @@ ThreadUpdater =
unless ID in index unless ID in index
post.kill() post.kill()
deletedPosts.push post
else if post.isDead else if post.isDead
post.resurrect() post.resurrect()
else if post.file and not (post.file.isDead or ID in files) else if post.file and not (post.file.isDead or ID in files)
post.kill true post.kill true
deletedFiles.push post
# Fetching your own posts after posting # Fetching your own posts after posting
if ThreadUpdater.postID and ThreadUpdater.postID is ID if ThreadUpdater.postID and ThreadUpdater.postID is ID
@ -353,9 +313,7 @@ ThreadUpdater =
$.event 'ThreadUpdate', $.event 'ThreadUpdate',
404: false 404: false
thread: ThreadUpdater.thread threadID: ThreadUpdater.thread.fullID
newPosts: posts newPosts: posts.map (post) -> post.fullID
deletedPosts: deletedPosts
deletedFiles: deletedFiles
postCount: OP.replies + 1 postCount: OP.replies + 1
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file and !ThreadUpdater.thread.OP.file.isDead) fileCount: OP.images + (!!ThreadUpdater.thread.OP.file and !ThreadUpdater.thread.OP.file.isDead)

View File

@ -15,7 +15,6 @@ ThreadWatcher =
@list = @dialog.lastElementChild @list = @dialog.lastElementChild
$.on d, 'QRPostSuccessful', @cb.post $.on d, 'QRPostSuccessful', @cb.post
$.on d, 'ThreadUpdate', @cb.threadUpdate if g.VIEW is 'thread'
$.on sc, 'click', @toggleWatcher $.on sc, 'click', @toggleWatcher
$.on $('.move>.close', ThreadWatcher.dialog), 'click', @toggleWatcher $.on $('.move>.close', ThreadWatcher.dialog), 'click', @toggleWatcher
@ -88,12 +87,12 @@ ThreadWatcher =
[boardID, threadID] = @parentNode.dataset.fullID.split '.' [boardID, threadID] = @parentNode.dataset.fullID.split '.'
ThreadWatcher.rm boardID, +threadID ThreadWatcher.rm boardID, +threadID
post: (e) -> post: (e) ->
{board, postID, threadID} = e.detail {boardID, threadID, postID} = e.detail
if postID is threadID if postID is threadID
if Conf['Auto Watch'] if Conf['Auto Watch']
$.set 'AutoWatch', threadID $.set 'AutoWatch', threadID
else if Conf['Auto Watch Reply'] else if Conf['Auto Watch Reply']
ThreadWatcher.add board.threads[threadID] ThreadWatcher.add g.threads[boardID + '.' + threadID]
onIndexRefresh: -> onIndexRefresh: ->
{db} = ThreadWatcher {db} = ThreadWatcher
boardID = g.BOARD.ID boardID = g.BOARD.ID
@ -105,7 +104,7 @@ ThreadWatcher =
ThreadWatcher.db.set {boardID, threadID, val: data} ThreadWatcher.db.set {boardID, threadID, val: data}
ThreadWatcher.refresh() ThreadWatcher.refresh()
onThreadRefresh: (e) -> 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} return unless e.detail[404] and ThreadWatcher.db.get {boardID: thread.board.ID, threadID: thread.ID}
# Update 404 status. # Update 404 status.
ThreadWatcher.add thread ThreadWatcher.add thread
@ -228,7 +227,7 @@ ThreadWatcher =
refreshers: [] refreshers: []
init: -> init: ->
return if !Conf['Thread Watcher'] return if !Conf['Thread Watcher']
menu = new UI.Menu 'thread watcher' menu = @menu = new UI.Menu 'thread watcher'
$.on $('.menu-button', ThreadWatcher.dialog), 'click', (e) -> $.on $('.menu-button', ThreadWatcher.dialog), 'click', (e) ->
menu.toggle e, @, ThreadWatcher menu.toggle e, @, ThreadWatcher
@addHeaderMenuEntry() @addHeaderMenuEntry()
@ -238,8 +237,7 @@ ThreadWatcher =
return if g.VIEW isnt 'thread' return if g.VIEW isnt 'thread'
entryEl = $.el 'a', entryEl = $.el 'a',
href: 'javascript:;' href: 'javascript:;'
$.event 'AddMenuEntry', Header.menu.addEntry
type: 'header'
el: entryEl el: entryEl
order: 60 order: 60
$.on entryEl, 'click', -> ThreadWatcher.toggle g.threads["#{g.BOARD}.#{g.THREADID}"] $.on entryEl, 'click', -> ThreadWatcher.toggle g.threads["#{g.BOARD}.#{g.THREADID}"]
@ -259,7 +257,6 @@ ThreadWatcher =
entries.push entries.push
cb: ThreadWatcher.cb.openAll cb: ThreadWatcher.cb.openAll
entry: entry:
type: 'thread watcher'
el: $.el 'a', el: $.el 'a',
textContent: 'Open all threads' textContent: 'Open all threads'
refresh: -> (if ThreadWatcher.list.firstElementChild then $.rmClass else $.addClass) @el, 'disabled' refresh: -> (if ThreadWatcher.list.firstElementChild then $.rmClass else $.addClass) @el, 'disabled'
@ -268,7 +265,6 @@ ThreadWatcher =
entries.push entries.push
cb: ThreadWatcher.cb.checkThreads cb: ThreadWatcher.cb.checkThreads
entry: entry:
type: 'thread watcher'
el: $.el 'a', el: $.el 'a',
textContent: 'Check 404\'d threads' textContent: 'Check 404\'d threads'
refresh: -> (if $('div:not(.dead-thread)', ThreadWatcher.list) then $.rmClass else $.addClass) @el, 'disabled' refresh: -> (if $('div:not(.dead-thread)', ThreadWatcher.list) then $.rmClass else $.addClass) @el, 'disabled'
@ -277,7 +273,6 @@ ThreadWatcher =
entries.push entries.push
cb: ThreadWatcher.cb.pruneDeads cb: ThreadWatcher.cb.pruneDeads
entry: entry:
type: 'thread watcher'
el: $.el 'a', el: $.el 'a',
textContent: 'Prune 404\'d threads' textContent: 'Prune 404\'d threads'
refresh: -> (if $('.dead-thread', ThreadWatcher.list) then $.rmClass else $.addClass) @el, 'disabled' refresh: -> (if $('.dead-thread', ThreadWatcher.list) then $.rmClass else $.addClass) @el, 'disabled'
@ -288,7 +283,6 @@ ThreadWatcher =
subEntries.push @createSubEntry name, conf[1] subEntries.push @createSubEntry name, conf[1]
entries.push entries.push
entry: entry:
type: 'thread watcher'
el: $.el 'span', el: $.el 'span',
textContent: 'Settings' textContent: 'Settings'
subEntries: subEntries subEntries: subEntries
@ -297,7 +291,7 @@ ThreadWatcher =
entry.el.href = 'javascript:;' if entry.el.nodeName is 'A' entry.el.href = 'javascript:;' if entry.el.nodeName is 'A'
$.on entry.el, 'click', cb if cb $.on entry.el, 'click', cb if cb
@refreshers.push refresh.bind entry if refresh @refreshers.push refresh.bind entry if refresh
$.event 'AddMenuEntry', entry @menu.addEntry entry
return return
createSubEntry: (name, desc) -> createSubEntry: (name, desc) ->
entry = entry =

View File

@ -12,21 +12,6 @@ Unread =
name: 'Unread' name: 'Unread'
cb: @node cb: @node
disconnect: ->
return if g.VIEW isnt 'thread' or !Conf['Unread Count'] and !Conf['Unread Favicon'] and !Conf['Desktop Notifications']
Unread.db.disconnect()
$.rm hr if {hr} = Unread
delete @[name] for name in ['db', 'hr', 'posts', 'postsQuotingYou', 'thread', 'title', 'lastReadPost']
$.off d, '4chanXInitFinished', @ready
$.off d, 'ThreadUpdate', @onUpdate
$.off d, 'scroll visibilitychange', @read
$.off d, 'visibilitychange', @setLine if Conf['Unread Line'] and not Conf['Quote Threading']
Thread.callbacks.disconnect 'Unread'
node: -> node: ->
Unread.thread = @ Unread.thread = @
Unread.title = d.title Unread.title = d.title
@ -129,7 +114,7 @@ Unread =
if e.detail[404] if e.detail[404]
Unread.update() Unread.update()
else if !QuoteThreading.enabled else if !QuoteThreading.enabled
Unread.addPosts e.detail.newPosts Unread.addPosts e.detail.newPosts.map (fullID) -> g.posts[fullID]
else else
Unread.read() Unread.read()
Unread.update() Unread.update()

View File

@ -72,12 +72,6 @@ QR =
$.before $.id('togglePostFormLink'), link $.before $.id('togglePostFormLink'), link
$.on d, 'QRGetSelectedPost', ({detail: cb}) ->
cb QR.selected
$.on d, 'QRAddPreSubmitHook', ({detail: cb}) ->
QR.preSubmitHooks.push cb
$.on d, 'paste', QR.paste $.on d, 'paste', QR.paste
$.on d, 'dragover', QR.dragOver $.on d, 'dragover', QR.dragOver
$.on d, 'drop', QR.dropFile $.on d, 'drop', QR.dropFile
@ -606,8 +600,6 @@ QR =
nodes.flag = flag nodes.flag = flag
$.add nodes.form, flag $.add nodes.form, flag
preSubmitHooks: []
submit: (e) -> submit: (e) ->
e?.preventDefault() e?.preventDefault()
@ -640,9 +632,6 @@ QR =
err = 'No file selected.' err = 'No file selected.'
else if post.file and thread.fileLimit else if post.file and thread.fileLimit
err = 'Max limit of image replies has been reached.' 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 if QR.captcha.isEnabled and !err
{challenge, response} = QR.captcha.getOne() {challenge, response} = QR.captcha.getOne()
@ -793,11 +782,11 @@ QR =
# Post/upload confirmed as successful. # Post/upload confirmed as successful.
$.event 'QRPostSuccessful', { $.event 'QRPostSuccessful', {
board: g.BOARD boardID: g.BOARD.ID
threadID threadID
postID 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. # Enable auto-posting if we have stuff left to post, disable it otherwise.
postsCount = QR.posts.length - 1 postsCount = QR.posts.length - 1

View File

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

View File

@ -13,8 +13,7 @@ QuoteThreading =
input = $ 'input', @controls input = $ 'input', @controls
$.on input, 'change', @toggle $.on input, 'change', @toggle
$.event 'AddMenuEntry', @entry = Header.menu.addEntry @entry =
type: 'header'
el: @controls el: @controls
order: 98 order: 98
@ -24,19 +23,6 @@ QuoteThreading =
name: 'Quote Threading' name: 'Quote Threading'
cb: @node cb: @node
disconnect: ->
return unless Conf['Quote Threading'] and g.VIEW is 'thread'
input = $ 'input', @controls
$.off input, 'change', @toggle
$.event 'rmMenuEntry', @entry
delete @enabled
delete @controls
delete @entry
Post.callbacks.disconnect 'Quote Threading'
ready: -> ready: ->
$.off d, '4chanXInitFinished', QuoteThreading.ready $.off d, '4chanXInitFinished', QuoteThreading.ready
QuoteThreading.force() QuoteThreading.force()