Conflicts:
	CHANGELOG.md
	LICENSE
	builds/4chan-X.meta.js
	builds/4chan-X.user.js
	builds/crx/script.js
	json/archives.json
This commit is contained in:
Zixaphir 2013-11-23 11:17:11 -07:00
commit 7fb48b93d4
10 changed files with 667 additions and 69 deletions

View File

@ -1,18 +1,9 @@
<<<<<<< HEAD
**Zixaphir**:
- Better MediaCru.sh embedding
- Infinite Scrolling
### v1.2.41
*2013-10-03*
=======
## 3.14.0 - *2013-11-21*
**MayhemYDG**:
- Tiny posting cooldown adjustment:
- You can post an image reply immediately after a non-image reply.
- **New option**: `Auto-hide header on scroll`.
- Added support for `4cdn.org`.
## 3.13.0 - *2013-11-16*
- More index navigation improvements:
- Searching in the index is now possible and will show matched OPs by:
<ul>
@ -31,14 +22,7 @@
</ul>
- The elapsed time since the last index refresh is now indicated at the top of the index.
- New setting: `Show replies`, enabled by default. Disable it to only show OPs in the index.
### 3.12.1 - *2013-11-04*
- The index refreshing notification will now only appear on initial page load with slow connections.
- Minor fixes.
## 3.12.0 - *2013-11-03*
- Index navigation improvements:
- You can now refresh the index page you are on with the refresh shortcut in the header bar or the same keybind for refreshing threads.
- You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu:<br>
@ -53,48 +37,43 @@
</ul>
- Navigating across index pages is now instantaneous.
- Added a keybind to open the catalog search field on index pages.
- Various minor fixes
### 3.11.5 - *2013-10-03*
### v1.2.43
*2013-11-10*
- Minor Chrome 30 fix.
>>>>>>> ce0c0c1623702e7931908183160fa04a31b26897
**noface**:
- Strawpoll.me embedding support (as usual, only works on HTTP 4chan due to lack of HTTPS)
### v1.2.42
*2013-10-22*
**Zixaphir**:
- Better MediaCru.sh embedding
- Infinite Scrolling
### v1.2.41
*2013-10-03*
**MayhemYDG**:
- Minor Chrome 30 fix
<<<<<<< HEAD
### v1.2.40
*2013-09-22*
=======
- Tiny posting cooldown adjustment:
- You can post an image reply immediately after a non-image reply.
>>>>>>> ce0c0c1623702e7931908183160fa04a31b26897
**MayhemYDG**:
- /pol/ flag selector
<<<<<<< HEAD
**seaweedchan**:
- Delete cooldown update
- Small bug fixes
- Don't show warnings AND desktop notifications at the same time, and prefer QR warnings unless the document is hidden
=======
- Update posting cooldown timers to match 4chan settings:
- Cooldown may vary between inter-thread and intra-thread replies.
- Cooldown may vary when posting a file or not.
- Cooldown does not take sageing into account anymore.
- Timers vary across boards.
>>>>>>> ce0c0c1623702e7931908183160fa04a31b26897
### v1.2.39
*2013-09-19*
<<<<<<< HEAD
**seaweedchan**:
- Fix thread updater bug introduced in last version
=======
- Updated post and deletion cooldown timers to match 4chan changes: they are now twice as long.
>>>>>>> ce0c0c1623702e7931908183160fa04a31b26897
### v1.2.38
*2013-09-19*
@ -436,17 +415,8 @@
### v1.2.3
*2013-05-14*
<<<<<<< HEAD
**MayhemYDG**:
- Add new archive selection
=======
- **New feature**: `Archive selection`
- Select which archive you want for specific boards and redirection type.
- Access it in the `Archives` tab of the Settings window.
- The list of archived boards will now update automatically, independently from 4chan X updates.
- If you're an archiver and want [data](https://github.com/MayhemYDG/4chan-x/blob/v3/json/archives.json) about your archive to be updated, added or removed: send a PR or open an issue.
- Fix quote previews getting 'stuck' in Opera.
>>>>>>> ce0c0c1623702e7931908183160fa04a31b26897
**seaweedchan**:
- Change watcher favicon to a heart. Change class name from `.favicon` to `.watch-thread-link`. Add `.watched` if thread is watched.

View File

@ -1,5 +1,5 @@
/*
* 4chan X - Version 1.2.41 - 2013-11-22
* 4chan X - Version 1.2.43 - 2013-11-23
*
* Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
// @version 1.2.41
// @version 1.2.43
// @minGMVer 1.12
// @minFFVer 22
// @namespace 4chan-X

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X
// @version 1.2.41
// @version 1.2.43
// @minGMVer 1.12
// @minFFVer 22
// @namespace 4chan-X
@ -22,7 +22,7 @@
// ==/UserScript==
/*
* 4chan X - Version 1.2.41 - 2013-11-22
* 4chan X - Version 1.2.43 - 2013-11-23
*
* Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
@ -340,7 +340,7 @@
doc = d.documentElement;
g = {
VERSION: '1.2.41',
VERSION: '1.2.43',
NAMESPACE: '4chan X.',
boards: {},
threads: {},
@ -5718,6 +5718,15 @@
}
}
},
StrawPoll: {
regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+)/,
style: 'border: 0; width: 600px; height: 406px;',
el: function(a) {
return $.el('iframe', {
src: "http://strawpoll.me/embed_1/" + a.dataset.uid
});
}
},
TwitchTV: {
regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/,
style: "border: none; width: 640px; height: 360px;",

View File

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

View File

@ -1,6 +1,6 @@
// Generated by CoffeeScript
/*
* 4chan X - Version 1.2.41 - 2013-11-22
* 4chan X - Version 1.2.43 - 2013-11-23
*
* Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
@ -82,7 +82,7 @@
'use strict';
(function() {
var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Gallery, Get, Header, IDColor, ImageExpand, ImageHover, ImageLoader, InfiniScroll, Keybinds, Linkify, Main, Menu, Nav, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g,
var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Gallery, Get, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, InfiniScroll, Keybinds, Linkify, Main, Menu, Nav, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g,
__slice = [].slice,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__hasProp = {}.hasOwnProperty,
@ -233,6 +233,11 @@
'sageEmoji': '4chan SS',
'emojiPos': 'before',
'Custom CSS': false,
Index: {
'Index Mode': 'paged',
'Index Sort': 'bump',
'Show Replies': true
},
Header: {
'Fixed Header': true,
'Header auto-hide': false,
@ -313,7 +318,7 @@
doc = d.documentElement;
g = {
VERSION: '1.2.41',
VERSION: '1.2.43',
NAMESPACE: '4chan X.',
boards: {},
threads: {},
@ -2054,6 +2059,610 @@
}
};
Index = {
init: function() {
var input, label, modeEntry, repliesEntry, sortEntry, _i, _j, _len, _len1, _ref, _ref1;
if (g.VIEW !== 'index' || g.BOARD.ID === 'f') {
return;
}
this.button = $.el('a', {
className: 'index-refresh-shortcut fa fa-refresh',
title: 'Refresh Index',
href: 'javascript:;'
});
$.on(this.button, 'click', this.update);
Header.addShortcut(this.button, 1);
modeEntry = {
el: $.el('span', {
textContent: 'Index mode'
}),
subEntries: [
{
el: $.el('label', {
innerHTML: '<input type=radio name="Index Mode" value="paged"> Paged'
})
}, {
el: $.el('label', {
innerHTML: '<input type=radio name="Index Mode" value="all pages"> All threads'
})
}
]
};
_ref = modeEntry.subEntries;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
label = _ref[_i];
input = label.el.firstChild;
input.checked = Conf['Index Mode'] === input.value;
$.on(input, 'change', $.cb.value);
$.on(input, 'change', this.cb.mode);
}
sortEntry = {
el: $.el('span', {
textContent: 'Sort by'
}),
subEntries: [
{
el: $.el('label', {
innerHTML: '<input type=radio name="Index Sort" value="bump"> Bump order'
})
}, {
el: $.el('label', {
innerHTML: '<input type=radio name="Index Sort" value="lastreply"> Last reply'
})
}, {
el: $.el('label', {
innerHTML: '<input type=radio name="Index Sort" value="birth"> Creation date'
})
}, {
el: $.el('label', {
innerHTML: '<input type=radio name="Index Sort" value="replycount"> Reply count'
})
}, {
el: $.el('label', {
innerHTML: '<input type=radio name="Index Sort" value="filecount"> File count'
})
}
]
};
_ref1 = sortEntry.subEntries;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
label = _ref1[_j];
input = label.el.firstChild;
input.checked = Conf['Index Sort'] === input.value;
$.on(input, 'change', $.cb.value);
$.on(input, 'change', this.cb.sort);
}
repliesEntry = {
el: $.el('label', {
innerHTML: '<input type=checkbox name="Show Replies"> Show replies'
})
};
input = repliesEntry.el.firstChild;
input.checked = Conf['Show Replies'];
$.on(input, 'change', $.cb.checked);
$.on(input, 'change', this.cb.replies);
$.event('AddMenuEntry', {
type: 'header',
el: $.el('span', {
textContent: 'Index Navigation'
}),
order: 90,
subEntries: [modeEntry, sortEntry, repliesEntry]
});
$.addClass(doc, 'index-loading');
this.update();
this.root = $.el('div', {
className: 'board'
});
this.pagelist = $.el('div', {
className: 'pagelist',
hidden: true,
innerHTML: "<div class=\"prev\"><a><button disabled>Previous</button></a></div><div class=\"pages\"></div><div class=\"next\"><a><button disabled>Next</button></a></div><div class=\"pages cataloglink\"><a href=\"./catalog\">Catalog</a></div>"
});
this.navLinks = $.el('div', {
className: 'navLinks',
innerHTML: "[<a href=\"./catalog\">Catalog</a>]&nbsp;[<time id=\"index-last-refresh\" title=\"Last index refresh\">...</time>]&nbsp;<input type=\"search\" id=\"index-search\" class=\"field\" placeholder=\"Search\"><a id=\"index-search-clear\" class=\"fa fa-times-circle\" href=\"javascript:;\"></a>"
});
this.searchInput = $('#index-search', this.navLinks);
this.currentPage = this.getCurrentPage();
$.on(window, 'popstate', this.cb.popstate);
$.on(this.pagelist, 'click', this.cb.pageNav);
$.on(this.searchInput, 'input', this.onSearchInput);
$.on($('#index-search-clear', this.navLinks), 'click', this.clearSearch);
return $.asap((function() {
return $('.board', doc) || d.readyState !== 'loading';
}), function() {
var board, navLink, _k, _len2, _ref2;
board = $('.board');
$.replace(board, Index.root);
d.implementation.createDocument(null, null, null).appendChild(board);
_ref2 = $$('.navLinks');
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
navLink = _ref2[_k];
$.rm(navLink);
}
$.after($.x('child::form/preceding-sibling::hr[1]'), Index.navLinks);
$.rmClass(doc, 'index-loading');
return $.asap((function() {
return $('.pagelist') || d.readyState !== 'loading';
}), function() {
return $.replace($('.pagelist'), Index.pagelist);
});
});
},
cb: {
mode: function() {
Index.togglePagelist();
return Index.buildIndex();
},
sort: function() {
Index.sort();
return Index.buildIndex();
},
replies: function() {
Index.buildThreads();
Index.sort();
return Index.buildIndex();
},
popstate: function(e) {
var pageNum;
pageNum = Index.getCurrentPage();
if (Index.currentPage !== pageNum) {
return Index.pageLoad(pageNum);
}
},
pageNav: function(e) {
var a;
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
return;
}
switch (e.target.nodeName) {
case 'BUTTON':
a = e.target.parentNode;
break;
case 'A':
a = e.target;
break;
default:
return;
}
if (a.textContent === 'Catalog') {
return;
}
e.preventDefault();
return Index.pageNav(+a.pathname.split('/')[2]);
}
},
scrollToIndex: function() {
return Header.scrollToIfNeeded(Index.root);
},
getCurrentPage: function() {
return +window.location.pathname.split('/')[2];
},
pageNav: function(pageNum) {
if (Index.currentPage === pageNum) {
return;
}
history.pushState(null, '', pageNum === 0 ? './' : pageNum);
return Index.pageLoad(pageNum);
},
pageLoad: function(pageNum) {
Index.currentPage = pageNum;
if (Conf['Index Mode'] !== 'paged') {
return;
}
Index.buildIndex();
Index.setPage();
return Index.scrollToIndex();
},
getPagesNum: function() {
if (Index.isSearching) {
return Math.ceil((Index.sortedNodes.length / 2) / Index.threadsNumPerPage);
} else {
return Index.pagesNum;
}
},
getMaxPageNum: function() {
return Math.max(0, Index.getPagesNum() - 1);
},
togglePagelist: function() {
return Index.pagelist.hidden = Conf['Index Mode'] !== 'paged';
},
buildPagelist: function() {
var a, i, maxPageNum, nodes, pagesRoot, _i;
pagesRoot = $('.pages', Index.pagelist);
maxPageNum = Index.getMaxPageNum();
if (pagesRoot.childElementCount !== maxPageNum + 1) {
nodes = [];
for (i = _i = 0; _i <= maxPageNum; i = _i += 1) {
a = $.el('a', {
textContent: i,
href: i ? i : './'
});
nodes.push($.tn('['), a, $.tn('] '));
}
$.rmAll(pagesRoot);
$.add(pagesRoot, nodes);
}
return Index.togglePagelist();
},
setPage: function() {
var a, href, maxPageNum, next, pageNum, pagesRoot, prev, strong;
pageNum = Index.getCurrentPage();
maxPageNum = Index.getMaxPageNum();
pagesRoot = $('.pages', Index.pagelist);
prev = pagesRoot.previousSibling.firstChild;
next = pagesRoot.nextSibling.firstChild;
href = Math.max(pageNum - 1, 0);
prev.href = href === 0 ? './' : href;
prev.firstChild.disabled = href === pageNum;
href = Math.min(pageNum + 1, maxPageNum);
next.href = href === 0 ? './' : href;
next.firstChild.disabled = href === pageNum;
if (strong = $('strong', pagesRoot)) {
if (+strong.textContent === pageNum) {
return;
}
$.replace(strong, strong.firstChild);
} else {
strong = $.el('strong');
}
a = pagesRoot.children[pageNum];
$.before(a, strong);
return $.add(strong, a);
},
update: function() {
var now, _ref, _ref1;
if (!navigator.onLine) {
return;
}
if ((_ref = Index.req) != null) {
_ref.abort();
}
if ((_ref1 = Index.notice) != null) {
_ref1.close();
}
if (d.readyState !== 'loading') {
Index.notice = new Notice('info', 'Refreshing index...');
} else {
now = Date.now();
$.ready(function() {
return setTimeout((function() {
if (!(Index.req && !Index.notice)) {
return;
}
return Index.notice = new Notice('info', 'Refreshing index...');
}), 5 * $.SECOND - (Date.now() - now));
});
}
Index.req = $.ajax("//a.4cdn.org/" + g.BOARD + "/catalog.json", {
onabort: Index.load,
onloadend: Index.load
}, {
whenModified: true
});
return $.addClass(Index.button, 'fa-spin');
},
load: function(e) {
var err, notice, req, timeEl;
$.rmClass(Index.button, 'fa-spin');
req = Index.req, notice = Index.notice;
delete Index.req;
delete Index.notice;
if (e.type === 'abort') {
req.onloadend = null;
notice.close();
return;
}
try {
if (req.status === 200) {
Index.parse(JSON.parse(req.response));
}
} catch (_error) {
err = _error;
c.error('Index failure:', err.stack);
if (notice) {
notice.setType('error');
notice.el.lastElementChild.textContent = 'Index refresh failed.';
setTimeout(notice.close, 2 * $.SECOND);
} else {
new Notice('error', 'Index refresh failed.', 2);
}
return;
}
if (notice) {
notice.setType('success');
notice.el.lastElementChild.textContent = 'Index refreshed!';
setTimeout(notice.close, $.SECOND);
}
timeEl = $('#index-last-refresh', Index.navLinks);
timeEl.dataset.utc = e.timeStamp;
RelativeDates.update(timeEl);
return Index.scrollToIndex();
},
parse: function(pages) {
Index.parseThreadList(pages);
Index.buildThreads();
Index.sort();
Index.buildIndex();
Index.buildPagelist();
return Index.setPage();
},
parseThreadList: function(pages) {
var thread, threadID, _ref, _ref1;
Index.pagesNum = pages.length;
Index.threadsNumPerPage = pages[0].threads.length;
Index.liveThreadData = pages.reduce((function(arr, next) {
return arr.concat(next.threads);
}), []);
Index.liveThreadIDs = Index.liveThreadData.map(function(data) {
return data.no;
});
_ref = g.BOARD.threads;
for (threadID in _ref) {
thread = _ref[threadID];
if (_ref1 = thread.ID, __indexOf.call(Index.liveThreadIDs, _ref1) < 0) {
thread.collect();
}
}
},
buildThreads: function() {
var err, errors, i, posts, thread, threadData, threadRoot, threads, _i, _len, _ref;
Index.nodes = [];
threads = [];
posts = [];
_ref = Index.liveThreadData;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
threadData = _ref[i];
threadRoot = Build.thread(g.BOARD, threadData);
Index.nodes.push(threadRoot, $.el('hr'));
if (thread = g.BOARD.threads[threadData.no]) {
thread.setPage(Math.floor(i / Index.threadsNumPerPage));
thread.setStatus('Sticky', !!threadData.sticky);
thread.setStatus('Closed', !!threadData.closed);
} else {
thread = new Thread(threadData.no, g.BOARD);
threads.push(thread);
}
if (thread.ID in thread.posts) {
continue;
}
try {
posts.push(new Post($('.opContainer', threadRoot), thread, g.BOARD));
} catch (_error) {
err = _error;
if (!errors) {
errors = [];
}
errors.push({
message: "Parsing of Post No." + thread + " failed. Post will be skipped.",
error: err
});
}
}
if (errors) {
Main.handleErrors(errors);
}
$.nodes(Index.nodes);
Main.callbackNodes(Thread, threads);
Main.callbackNodes(Post, posts);
return $.event('IndexRefresh');
},
buildReplies: function(threadRoots) {
var data, err, errors, i, lastReplies, node, nodes, post, posts, thread, threadRoot, _i, _j, _len, _len1;
posts = [];
for (_i = 0, _len = threadRoots.length; _i < _len; _i += 2) {
threadRoot = threadRoots[_i];
thread = Get.threadFromRoot(threadRoot);
i = Index.liveThreadIDs.indexOf(thread.ID);
if (!(lastReplies = Index.liveThreadData[i].last_replies)) {
continue;
}
nodes = [];
for (_j = 0, _len1 = lastReplies.length; _j < _len1; _j++) {
data = lastReplies[_j];
if (post = thread.posts[data.no]) {
nodes.push(post.nodes.root);
continue;
}
nodes.push(node = Build.postFromObject(data, thread.board.ID));
try {
posts.push(new Post(node, thread, thread.board));
} catch (_error) {
err = _error;
if (!errors) {
errors = [];
}
errors.push({
message: "Parsing of Post No." + data.no + " failed. Post will be skipped.",
error: err
});
}
}
$.add(threadRoot, nodes);
}
if (errors) {
Main.handleErrors(errors);
}
return Main.callbackNodes(Post, posts);
},
sort: function() {
var i, offset, sortedThreadIDs, threadID, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3;
switch (Conf['Index Sort']) {
case 'bump':
sortedThreadIDs = Index.liveThreadIDs;
break;
case 'lastreply':
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) {
if ('last_replies' in a) {
a = a.last_replies[a.last_replies.length - 1];
}
if ('last_replies' in b) {
b = b.last_replies[b.last_replies.length - 1];
}
return b.no - a.no;
}).map(function(data) {
return data.no;
});
break;
case 'birth':
sortedThreadIDs = __slice.call(Index.liveThreadIDs).sort(function(a, b) {
return b - a;
});
break;
case 'replycount':
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) {
return b.replies - a.replies;
}).map(function(data) {
return data.no;
});
break;
case 'filecount':
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) {
return b.images - a.images;
}).map(function(data) {
return data.no;
});
}
Index.sortedNodes = [];
for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) {
threadID = sortedThreadIDs[_i];
i = Index.liveThreadIDs.indexOf(threadID) * 2;
Index.sortedNodes.push(Index.nodes[i], Index.nodes[i + 1]);
}
if (Index.isSearching) {
Index.sortedNodes = Index.querySearch(Index.searchInput.value) || Index.sortedNodes;
}
offset = 0;
_ref = Index.sortedNodes;
for (i = _j = 0, _len1 = _ref.length; _j < _len1; i = _j += 2) {
threadRoot = _ref[i];
if (Get.threadFromRoot(threadRoot).isSticky) {
(_ref1 = Index.sortedNodes).splice.apply(_ref1, [offset++ * 2, 0].concat(__slice.call(Index.sortedNodes.splice(i, 2))));
}
}
if (!Conf['Filter']) {
return;
}
offset = 0;
_ref2 = Index.sortedNodes;
for (i = _k = 0, _len2 = _ref2.length; _k < _len2; i = _k += 2) {
threadRoot = _ref2[i];
if (Get.threadFromRoot(threadRoot).isOnTop) {
(_ref3 = Index.sortedNodes).splice.apply(_ref3, [offset++ * 2, 0].concat(__slice.call(Index.sortedNodes.splice(i, 2))));
}
}
},
buildIndex: function() {
var nodes, nodesPerPage, pageNum;
if (Conf['Index Mode'] === 'paged') {
pageNum = Index.getCurrentPage();
nodesPerPage = Index.threadsNumPerPage * 2;
nodes = Index.sortedNodes.slice(nodesPerPage * pageNum, nodesPerPage * (pageNum + 1));
} else {
nodes = Index.sortedNodes;
}
$.rmAll(Index.root);
if (Conf['Show Replies']) {
Index.buildReplies(nodes);
}
$.event('IndexBuild', nodes);
return $.add(Index.root, nodes);
},
isSearching: false,
clearSearch: function() {
Index.searchInput.value = null;
Index.onSearchInput();
return Index.searchInput.focus();
},
onSearchInput: function() {
var pageNum;
if (Index.isSearching = !!Index.searchInput.value.trim()) {
if (!Index.searchInput.dataset.searching) {
Index.searchInput.dataset.searching = 1;
Index.pageBeforeSearch = Index.getCurrentPage();
pageNum = 0;
} else {
pageNum = Index.getCurrentPage();
}
} else {
pageNum = Index.pageBeforeSearch;
delete Index.pageBeforeSearch;
delete Index.searchInput.dataset.searching;
}
Index.sort();
if (Conf['Index Mode'] === 'paged') {
pageNum = Math.min(pageNum, Index.getMaxPageNum());
}
Index.buildPagelist();
if (Index.currentPage === pageNum) {
Index.buildIndex();
return Index.setPage();
} else {
return Index.pageNav(pageNum);
}
},
querySearch: function(query) {
var keywords;
if (!(keywords = query.toLowerCase().match(/\S+/g))) {
return;
}
return Index.search(keywords);
},
search: function(keywords) {
var found, i, threadRoot, _i, _len, _ref;
found = [];
_ref = Index.sortedNodes;
for (i = _i = 0, _len = _ref.length; _i < _len; i = _i += 2) {
threadRoot = _ref[i];
if (Index.searchMatch(Get.threadFromRoot(threadRoot), keywords)) {
found.push(Index.sortedNodes[i], Index.sortedNodes[i + 1]);
}
}
return found;
},
searchMatch: function(thread, keywords) {
var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1;
_ref = thread.OP, info = _ref.info, file = _ref.file;
text = [];
_ref1 = ['comment', 'subject', 'name', 'tripcode', 'email'];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
key = _ref1[_i];
if (key in info) {
text.push(info[key]);
}
}
if (file) {
text.push(file.name);
}
text = text.join(' ').toLowerCase();
for (_j = 0, _len1 = keywords.length; _j < _len1; _j++) {
keyword = keywords[_j];
if (-1 === text.indexOf(keyword)) {
return false;
}
}
return true;
}
};
Build = {
spoilerRange: {},
shortFilename: function(filename, isReply) {
@ -2198,7 +2807,7 @@
container = $.el('div', {
id: "pc" + postID,
className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
innerHTML: ""
innerHTML: "" + (isOP ? '' : "<div class=sideArrows id=sa" + postID + ">&gt;&gt;</div>") + "<div id=p" + postID + " class='post " + (isOP ? 'op' : 'reply') + (capcode === 'admin_highlight' ? ' highlightPost' : '') + "'><div class='postInfoM mobile' id=pim" + postID + "><span class='nameBlock" + capcodeClass + "'><span class=name>" + (name || '') + "</span>" + (tripcode + capcodeStart + capcode + userID + flag + sticky + closed) + "<br>" + subject + "</span><span class='dateTime postNum' data-utc=" + dateUTC + ">" + date + "<a href=" + ("/" + boardID + "/res/" + threadID + "#p" + postID) + ">No.</a><a href='" + (g.VIEW === 'thread' && g.THREADID === +threadID ? "javascript:quote(" + postID + ")" : "/" + boardID + "/res/" + threadID + "#q" + postID) + "'>" + postID + "</a></span></div>" + (isOP ? fileHTML : '') + "<div class='postInfo desktop' id=pi" + postID + "><input type=checkbox name=" + postID + " value=delete>" + subject + "<span class='nameBlock" + capcodeClass + "'>" + emailStart + "<span class=name>" + (name || '') + "</span>" + (tripcode + capcodeStart + emailEnd + capcode + userID + flag) + "</span>" + " " + "<span class=dateTime data-utc=" + dateUTC + ">" + date + "</span>" + " " + "<span class='postNum desktop'><a href=" + ("/" + boardID + "/res/" + threadID + "#p" + postID) + " title='Highlight this post'>No.</a><a href='" + (g.VIEW === 'thread' && g.THREADID === +threadID ? "javascript:quote(" + postID + ")" : "/" + boardID + "/res/" + threadID + "#q" + postID) + "' title='Quote this post'>" + postID + "</a>" + (pageIcon + sticky + closed + replyLink) + "</span></div>" + (isOP ? '' : fileHTML) + "<blockquote class=postMessage id=m" + postID + ">" + (comment || '') + "</blockquote>" + " " + "</div>"
});
_ref = $$('.quotelink', container);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@ -5114,6 +5723,15 @@
}
}
},
StrawPoll: {
regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+)/,
style: 'border: 0; width: 600px; height: 406px;',
el: function(a) {
return $.el('iframe', {
src: "http://strawpoll.me/embed_1/" + a.dataset.uid
});
}
},
TwitchTV: {
regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/,
style: "border: none; width: 640px; height: 360px;",
@ -11994,8 +12612,7 @@
'Index Navigation': Nav,
'Keybinds': Keybinds,
'Show Dice Roll': Dice,
'Banner': Banner,
'Infinite Scrolling': InfiniScroll
'Banner': Banner
});
$.on(d, 'AddCallback', Main.addCallback);
return $.ready(Main.initReady);
@ -12209,7 +12826,7 @@
return Klass.callbacks.push(obj.callback);
},
handleErrors: function(errors) {
var div, err, error, logs, _i, _len;
var div, error, logs, _i, _len;
if (!(errors instanceof Array)) {
error = errors;
@ -12233,12 +12850,7 @@
});
for (_i = 0, _len = errors.length; _i < _len; _i++) {
error = errors[_i];
try {
$.add(logs, Main.parseError(error));
} catch (_error) {
err = _error;
c.error(error.message, error.stack);
}
$.add(logs, Main.parseError(error));
}
return new Notice('error', [div, logs], 30);
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

View File

@ -1 +1 @@
postMessage({version:'1.2.41'},'*')
postMessage({version:'1.2.43'},'*')

View File

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

View File

@ -346,6 +346,13 @@ Linkify =
api: (uid) -> "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/#{uid}"
text: (_) -> _.title
StrawPoll:
regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+)/
style: 'border: 0; width: 600px; height: 406px;'
el: (a) ->
$.el 'iframe',
src: "http://strawpoll.me/embed_1/#{a.dataset.uid}"
TwitchTV:
regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/
style: "border: none; width: 640px; height: 360px;"