diff --git a/CHANGELOG.md b/CHANGELOG.md index b584e2d27..a72a0fbe8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ Sometimes the changelog has notes (not comprehensive) acknowledging people's work. This does not mean the changes are their fault, only that their code was used. All changes to the script are chosen by and the fault of the maintainer (ccd0). +### v1.11.28 + +**v1.11.28.0** *(2016-03-13)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.11.28.0/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.11.28.0/builds/4chan-X-noupdate.crx "Chromium version")] +- Based on v1.11.27.2. +- New sorting mode: `Last long reply` sorts threads by time of last visible reply over 100 characters, or time of creation if no such reply exists. +- More hash commands for the JSON Index: + - `#bump-order`, `#last-reply`, `#last-long-reply`, `#creation-date`, `#reply-count`, and `#file-count` set the sort mode of the index. + - `#infinite-scrolling` and `#all-threads` added as alternatives to `#infinite` and `#all-pages`. + - Multiple commands may now be separated by slashes (e.g. https://boards.4chan.org/g/#catalog/s=programming switches to catalog mode and searches for "programming"). +- New option `Per-board sort type`, added under `Index Navigation` in header menu, controls whether the sorting order you set applies to individual boards or for all boards. +- Add `mode` and `sort` options for custom header board links; for example, `g-mode:"infinite scrolling"` opens /g/ sorted in infinite scrolling mode. +- Remove `` tags from posts containing `[math]` or `[eqn]` tags so that the TeX equations aren't broken. + ### v1.11.27 **v1.11.27.2** *(2016-03-03)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.11.27.2/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.11.27.2/builds/4chan-X-noupdate.crx "Chromium version")] diff --git a/builds/4chan-X-beta.crx b/builds/4chan-X-beta.crx index 1ab4d92df..95a2feb50 100644 Binary files a/builds/4chan-X-beta.crx and b/builds/4chan-X-beta.crx differ diff --git a/builds/4chan-X-beta.meta.js b/builds/4chan-X-beta.meta.js index b79a32717..ba2ea5726 100644 --- a/builds/4chan-X-beta.meta.js +++ b/builds/4chan-X-beta.meta.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X beta -// @version 1.11.27.2 +// @version 1.11.28.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X diff --git a/builds/4chan-X-beta.user.js b/builds/4chan-X-beta.user.js index da9ead328..a084f1683 100644 --- a/builds/4chan-X-beta.user.js +++ b/builds/4chan-X-beta.user.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript // ==UserScript== // @name 4chan X beta -// @version 1.11.27.2 +// @version 1.11.28.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -321,7 +321,6 @@ Index: { 'Index Mode': 'paged', 'Previous Index Mode': 'paged', - 'Index Sort': 'bump', 'Index Size': 'small', 'Show Replies': true, 'Pin Watched Threads': false, @@ -440,7 +439,7 @@ doc = d.documentElement; g = { - VERSION: '1.11.27.2', + VERSION: '1.11.28.0', NAMESPACE: '4chan X.', boards: {} }; @@ -2884,7 +2883,7 @@ } boardnav = boardnav.replace(/(\r\n|\n|\r)/g, ' '); as = $$('#full-board-list a[title]', Header.boardList); - re = /[\w@]+(-(all|title|replace|full|index|catalog|archive|expired|text:"[^"]+"(,"[^"]+")?))*|[^\w@]+/g; + re = /[\w@]+(-(all|title|replace|full|index|catalog|archive|expired|(mode|sort|text):"[^"]+"(,"[^"]+")?))*|[^\w@]+/g; nodes = (function() { var k, len1, ref, results; ref = boardnav.match(re); @@ -2899,7 +2898,7 @@ return $.ready(CatalogLinks.initBoardList); }, mapCustomNavigation: function(t, as) { - var a, boardID, href, m, text, url; + var a, boardID, href, indexOptions, m, text, url; if (/^[^\w@]/.test(t)) { return $.tn(t); } @@ -2909,6 +2908,12 @@ url = m2; return ''; }); + indexOptions = []; + t = t.replace(/-(?:mode|sort):"([^"]+)"/g, function(m0, m1) { + indexOptions.push(m1.toLowerCase().replace(/\ /g, '-')); + return ''; + }); + indexOptions = indexOptions.join('/'); if (/^toggle-all/.test(t)) { a = $.el('a', { className: 'show-board-list-button', @@ -2969,6 +2974,12 @@ return a.firstChild; } } + if (Conf['JSON Index'] && indexOptions) { + a.dataset.indexOptions = indexOptions; + if (a.hostname === 'boards.4chan.org' && a.pathname.split('/')[2] === '') { + a.href += (a.hash ? '/' : '#') + indexOptions; + } + } if (/-archive/.test(t)) { if (href = Redirect.to('board', { boardID: boardID @@ -3132,26 +3143,26 @@ return $('[name=boardnav]', settings).focus(); }, hashScroll: function(e) { - var hash, post; - if (e.state) { - return; + var el, hash; + if (e) { + if (e.state) { + return; + } + if (!history.state) { + history.replaceState({}, ''); + } } - if (!history.state) { - history.replaceState({}, ''); + if ((hash = location.hash.slice(1)) && (el = $.id(hash))) { + return $.queueTask(function() { + return Header.scrollTo(el); + }); } - hash = this.location.hash.slice(1); - if (!(/^\d*p\d+$/.test(hash) && (post = $.id(hash)))) { - return; - } - if (!post.getBoundingClientRect().height) { - return; - } - return $.queueTask(function() { - return Header.scrollTo(post); - }); }, scrollTo: function(root, down, needed) { var height, x; + if (!root.offsetParent) { + return; + } if (down) { x = Header.getBottomOf(root); if (Conf['Fixed Header'] && Conf['Header auto-hide on scroll'] && Conf['Bottom header']) { @@ -3284,7 +3295,7 @@ showHiddenThreads: false, changed: {}, init: function() { - var anchorEntry, input, k, label, len1, len2, name, pinEntry, q, ref, ref1, ref2, ref3, ref4, ref5, refNavEntry, repliesEntry, select; + var anchorEntry, input, k, label, len1, len2, name, pinEntry, q, ref, ref1, ref2, ref3, ref4, ref5, ref6, refNavEntry, repliesEntry, select, sortEntry; if (g.BOARD.ID === 'f' || !Conf['JSON Index'] || g.VIEW !== 'index') { return; } @@ -3296,6 +3307,8 @@ if ((ref1 = history.state) != null ? ref1.mode : void 0) { Conf['Index Mode'] = (ref2 = history.state) != null ? ref2.mode : void 0; } + this.currentSort = (ref3 = history.state) != null ? ref3.sort : void 0; + this.currentSort || (this.currentSort = typeof Conf['Index Sort'] === 'object' ? Conf['Index Sort'][g.BOARD.ID] || 'bump' : Conf['Index Sort']); this.currentPage = this.getCurrentPage(); this.processHash(); $.addClass(doc, 'index-loading', (Conf['Index Mode'].replace(/\ /g, '-')) + "-mode"); @@ -3314,6 +3327,9 @@ repliesEntry = { el: UI.checkbox('Show Replies', 'Show replies') }; + sortEntry = { + el: UI.checkbox('Per-Board Sort Type', 'Per-board sort type', typeof Conf['Index Sort'] === 'object') + }; pinEntry = { el: UI.checkbox('Pin Watched Threads', 'Pin watched threads') }; @@ -3323,12 +3339,13 @@ refNavEntry = { el: UI.checkbox('Refreshed Navigation', 'Refreshed navigation') }; + sortEntry.el.title = 'Set the sorting order of each board independently.'; pinEntry.el.title = 'Move watched threads to the start of the index.'; anchorEntry.el.title = 'Move hidden threads to the end of the index.'; refNavEntry.el.title = 'Refresh index when navigating through pages.'; - ref3 = [repliesEntry, pinEntry, anchorEntry, refNavEntry]; - for (k = 0, len1 = ref3.length; k < len1; k++) { - label = ref3[k]; + ref4 = [repliesEntry, pinEntry, anchorEntry, refNavEntry]; + for (k = 0, len1 = ref4.length; k < len1; k++) { + label = ref4[k]; input = label.el.firstChild; name = input.name; $.on(input, 'change', $.cb.checked); @@ -3338,24 +3355,25 @@ break; case 'Pin Watched Threads': case 'Anchor Hidden Threads': - $.on(input, 'change', this.cb.sort); + $.on(input, 'change', this.cb.resort); } } + $.on(sortEntry.el.firstChild, 'change', this.cb.perBoardSort); Header.menu.addEntry({ el: $.el('span', { textContent: 'Index Navigation' }), order: 100, - subEntries: [repliesEntry, pinEntry, anchorEntry, refNavEntry] + subEntries: [repliesEntry, sortEntry, pinEntry, anchorEntry, refNavEntry] }); this.navLinks = $.el('div', { className: 'navLinks json-index' }); $.extend(this.navLinks, { - innerHTML: "Index Catalog Archive Bottom ×" + innerHTML: "Index Catalog Archive Bottom ×" }); $('.cataloglink a', this.navLinks).href = CatalogLinks.catalog(); - if ((ref4 = g.BOARD.ID) === 'b' || ref4 === 'trash') { + if ((ref5 = g.BOARD.ID) === 'b' || ref5 === 'trash') { $('.archlistlink', this.navLinks).hidden = true; } $.on($('#index-last-refresh a', this.navLinks), 'click', this.cb.refreshFront); @@ -3369,14 +3387,15 @@ this.selectSort = $('#index-sort', this.navLinks); this.selectSize = $('#index-size', this.navLinks); $.on(this.selectMode, 'change', this.cb.mode); - ref5 = [this.selectMode, this.selectSort, this.selectSize]; - for (q = 0, len2 = ref5.length; q < len2; q++) { - select = ref5[q]; - select.value = Conf[select.name]; - $.on(select, 'change', $.cb.value); - } $.on(this.selectSort, 'change', this.cb.sort); + $.on(this.selectSize, 'change', $.cb.value); $.on(this.selectSize, 'change', this.cb.size); + ref6 = [this.selectMode, this.selectSize]; + for (q = 0, len2 = ref6.length; q < len2; q++) { + select = ref6[q]; + select.value = Conf[select.name]; + } + this.selectSort.value = Index.currentSort; this.root = $.el('div', { className: 'board json-index' }); @@ -3394,13 +3413,13 @@ return d.title = d.title.replace(/\ -\ Page\ \d+/, ''); }); $.onExists(doc, '.board > .thread > .postContainer, .board + *', function() { - var board, el, len3, len4, ref6, ref7, threadRoot, topNavPos, u, v; + var board, el, len3, len4, ref7, ref8, threadRoot, topNavPos, u, v; Index.hat = $('.board > .thread > img:first-child'); if (Index.hat) { if (Index.nodes) { - ref6 = Index.nodes; - for (u = 0, len3 = ref6.length; u < len3; u++) { - threadRoot = ref6[u]; + ref7 = Index.nodes; + for (u = 0, len3 = ref7.length; u < len3; u++) { + threadRoot = ref7[u]; $.prepend(threadRoot, Index.hat.cloneNode(false)); } } @@ -3413,9 +3432,9 @@ try { d.implementation.createDocument(null, null, null).appendChild(board); } catch (_error) {} - ref7 = $$('.navLinks'); - for (v = 0, len4 = ref7.length; v < len4; v++) { - el = ref7[v]; + ref8 = $$('.navLinks'); + for (v = 0, len4 = ref8.length; v < len4; v++) { + el = ref8[v]; $.rm(el); } $.rm($.id('ctrl-top')); @@ -3549,21 +3568,25 @@ return Index.buildIndex(); }, mode: function() { - var mode; - mode = this.value; - if (mode !== 'catalog') { - Conf['Previous Index Mode'] = mode; - $.set('Previous Index Mode', mode); - } Index.pushState({ - mode: mode + mode: this.value }); return Index.pageLoad(false); }, sort: function() { + Index.pushState({ + sort: this.value + }); + return Index.pageLoad(false); + }, + resort: function() { Index.sort(); return Index.buildIndex(); }, + perBoardSort: function() { + Conf['Index Sort'] = this.checked ? {} : ''; + return Index.saveSort(); + }, size: function(e) { if (Conf['Index Mode'] !== 'catalog') { $.rmClass(Index.root, 'catalog-small'); @@ -3585,19 +3608,23 @@ return Index.buildIndex(); }, popstate: function(e) { - var mode, page, ref, searched; + var mode, nCommands, page, ref, searched, sort; if (e != null ? e.state : void 0) { - ref = e.state, searched = ref.searched, mode = ref.mode; + ref = e.state, searched = ref.searched, mode = ref.mode, sort = ref.sort; page = Index.getCurrentPage(); Index.setState({ search: searched, mode: mode, + sort: sort, page: page }); return Index.pageLoad(false); } else { - if (Index.processHash()) { - return Index[Conf['Refreshed Navigation'] ? 'update' : 'pageLoad'](); + nCommands = Index.processHash(); + if (Conf['Refreshed Navigation'] && nCommands) { + return Index.update(); + } else { + return Index.pageLoad(); } } }, @@ -3646,25 +3673,53 @@ return Index.pageLoad(); } }, + hashCommands: { + mode: { + 'paged': 'paged', + 'infinite-scrolling': 'infinite', + 'infinite': 'infinite', + 'all-threads': 'all pages', + 'all-pages': 'all pages', + 'catalog': 'catalog' + }, + sort: { + 'bump-order': 'bump', + 'last-reply': 'lastreply', + 'last-long-reply': 'lastlong', + 'creation-date': 'birth', + 'reply-count': 'replycount', + 'file-count': 'filecount' + } + }, processHash: function() { - var command, hash, ref, state; + var command, commands, hash, k, leftover, len1, mode, ref, sort, state; hash = ((ref = location.href.match(/#.*/)) != null ? ref[0] : void 0) || ''; - command = hash.slice(1); state = { replace: true }; - if (command === 'paged' || command === 'infinite' || command === 'all-pages' || command === 'catalog') { - state.mode = command.replace(/-/g, ' '); - } else if (command === 'index') { - state.mode = Conf['Previous Index Mode']; - state.page = 1; - } else if (/^s=/.test(command)) { - state.search = decodeURIComponent(command.slice(2)).replace(/\+/g, ' ').trim(); - } else { - state.hash = hash; + commands = hash.slice(1).split('/'); + leftover = []; + for (k = 0, len1 = commands.length; k < len1; k++) { + command = commands[k]; + if ((mode = Index.hashCommands.mode[command])) { + state.mode = mode; + } else if (command === 'index') { + state.mode = Conf['Previous Index Mode']; + state.page = 1; + } else if ((sort = Index.hashCommands.sort[command])) { + state.sort = sort; + } else if (/^s=/.test(command)) { + state.search = decodeURIComponent(command.slice(2)).replace(/\+/g, ' ').trim(); + } else { + leftover.push(command); + } + } + hash = leftover.join('/'); + if (hash) { + state.hash = "#" + hash; } Index.pushState(state); - return state.hash == null; + return commands.length - leftover.length; }, pushState: function(state) { var hash, pageBeforeSearch, pathname, ref, replace, search; @@ -3683,13 +3738,14 @@ hash || (hash = ''); return history[replace ? 'replaceState' : 'pushState']({ mode: Conf['Index Mode'], + sort: Index.currentSort, searched: Index.search, oldpage: pageBeforeSearch }, '', location.protocol + "//" + location.host + pathname + hash); }, setState: function(arg) { - var mode, page, ref, search; - search = arg.search, mode = arg.mode, page = arg.page; + var hash, mode, page, ref, search, sort; + search = arg.search, mode = arg.mode, sort = arg.sort, page = arg.page, hash = arg.hash; if ((search != null) && search !== Index.search) { Index.changed.search = true; Index.search = search; @@ -3703,43 +3759,69 @@ $.set('Previous Index Mode', mode); } } + if ((sort != null) && sort !== Index.currentSort) { + Index.changed.sort = true; + Index.currentSort = sort; + Index.saveSort(); + } if ((ref = Conf['Index Mode']) === 'all pages' || ref === 'catalog') { page = 1; } if ((page != null) && page !== Index.currentPage) { Index.changed.page = true; - return Index.currentPage = page; + Index.currentPage = page; + } + if (hash != null) { + return Index.changed.hash = true; } }, + saveSort: function() { + if (typeof Conf['Index Sort'] === 'object') { + Conf['Index Sort'][g.BOARD.ID] = Index.currentSort; + } else { + Conf['Index Sort'] = Index.currentSort; + } + return $.set('Index Sort', Conf['Index Sort']); + }, pageLoad: function(scroll) { - var mode, page, ref, search, threads; + var hash, mode, page, ref, search, sort, threads; if (scroll == null) { scroll = true; } if (!Index.liveThreadData) { return; } - ref = Index.changed, threads = ref.threads, search = ref.search, mode = ref.mode, page = ref.page; - if (threads || search) { + ref = Index.changed, threads = ref.threads, search = ref.search, mode = ref.mode, sort = ref.sort, page = ref.page, hash = ref.hash; + if (threads || search || sort) { Index.sort(); + } + if (threads || search) { Index.buildPagelist(); } if (search) { Index.setupSearch(); } if (mode) { - Index.applyMode(); + Index.setupMode(); + } + if (sort) { + Index.setupSort(); + } + if (threads || search || mode || page || sort) { + Index.buildIndex(); } if (threads || search || mode || page) { - Index.buildIndex(); Index.setPage(); } - if (scroll) { + if (scroll && !hash) { Index.scrollToIndex(); } + if (hash) { + Header.hashScroll(); + } return Index.changed = {}; }, - applyMode: function() { + setupMode: function() { var k, len1, mode, ref; ref = ['paged', 'infinite', 'all pages', 'catalog']; for (k = 0, len1 = ref.length; k < len1; k++) { @@ -3751,6 +3833,9 @@ Index.showHiddenThreads = false; return $('#hidden-toggle a', Index.navLinks).textContent = 'Show'; }, + setupSort: function() { + return Index.selectSort.value = Index.currentSort; + }, getPagesNum: function() { if (Index.search) { return Math.ceil(Index.sortedNodes.length / Index.threadsNumPerPage); @@ -4065,13 +4150,13 @@ } }, sort: function() { - var k, len1, liveThreadData, liveThreadIDs, nodes, sortedNodes, sortedThreadIDs, threadID; + var k, lastlong, len1, liveThreadData, liveThreadIDs, nodes, sortedNodes, sortedThreadIDs, threadID; liveThreadIDs = Index.liveThreadIDs, liveThreadData = Index.liveThreadData; if (!liveThreadData) { return; } sortedThreadIDs = (function() { - switch (Conf['Index Sort']) { + switch (Index.currentSort) { case 'lastreply': return slice.call(liveThreadData).sort(function(a, b) { var num; @@ -4085,6 +4170,23 @@ }).map(function(post) { return post.no; }); + case 'lastlong': + lastlong = function(thread) { + var i, k, r, ref; + ref = thread.last_replies || []; + for (i = k = ref.length - 1; k >= 0; i = k += -1) { + r = ref[i]; + if (r.com && Build.parseComment(r.com).replace(/[^a-z]/ig, '').length >= 100) { + return r; + } + } + return thread; + }; + return slice.call(liveThreadData).sort(function(a, b) { + return lastlong(b).no - lastlong(a).no; + }).map(function(post) { + return post.no; + }); case 'bump': return liveThreadIDs; case 'birth': @@ -15326,6 +15428,9 @@ continue; } a.href = useCatalog ? CatalogLinks.catalog(board) : "/" + board + "/"; + if (a.dataset.indexOptions && a.hostname === 'boards.4chan.org' && a.pathname.split('/')[2] === '') { + a.href += (a.hash ? '/' : '#') + a.dataset.indexOptions; + } } CatalogLinks.el.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + "."; return $('input', CatalogLinks.el).checked = useCatalog; @@ -15830,7 +15935,23 @@ }); } if (g.BOARD.ID === 'sci') { - $.globalEval('window.addEventListener(\'mathjax\', function(e) {\n if (window.MathJax) {\n window.MathJax.Hub.Queue(function() {\n if (!e.target.querySelector(\'.MathJax\')) {\n window.MathJax.Hub.Typeset(e.target);\n }\n });\n } else {\n if (!document.querySelector(\'script[src^="//cdn.mathjax.org/"]\')) {\n window.loadMathJax();\n window.loadMathJax = function() {};\n if (!e.target.classList.contains(\'postMessage\')) {\n document.querySelector(\'script[src^="//cdn.mathjax.org/"]\').addEventListener(\'load\', function() {\n window.MathJax.Hub.Queue([\'Typeset\', window.MathJax.Hub, e.target]);\n }, false);\n }\n }\n }\n}, false);'); + $.global(function() { + return window.addEventListener('mathjax', function(e) { + if (window.MathJax) { + return window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, e.target]); + } else { + if (!document.querySelector('script[src^="//cdn.mathjax.org/"]')) { + window.loadMathJax(); + window.loadMathJax = function() {}; + } + if (!e.target.classList.contains('postMessage')) { + return document.querySelector('script[src^="//cdn.mathjax.org/"]').addEventListener('load', function() { + return window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, e.target]); + }, false); + } + } + }, false); + }); Post.callbacks.push({ name: 'Parse /sci/ math', cb: this.math @@ -15874,10 +15995,17 @@ })(this)); }, math: function() { - var cb; - if (!(/\[(math|eqn)\]/.test(this.nodes.comment.textContent) || $('.math:not([id])', this.nodes.comment))) { + var cb, k, len1, wbr, wbrs; + if (!/\[(math|eqn)\]/.test(this.nodes.comment.textContent)) { return; } + if ((wbrs = $$('wbr', this.nodes.comment)).length) { + for (k = 0, len1 = wbrs.length; k < len1; k++) { + wbr = wbrs[k]; + $.rm(wbr); + } + this.nodes.comment.normalize(); + } cb = (function(_this) { return function() { if (!doc.contains(_this.nodes.comment)) { @@ -17560,7 +17688,7 @@ advanced: function(section) { var aa, ab, applyCSS, archBoards, archive, boardID, boardOptions, boardSelect, boards, customCSS, files, i, input, inputs, interval, item, items, k, len1, len2, len3, len4, len5, len6, len7, name, o, q, ref, ref1, ref2, ref3, ref4, ref5, ref6, row, rows, software, ta, table, u, uid, v, warning, withCredentials, z; $.extend(section, { - innerHTML: "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Captcha Language
Choose from list of language codes. Leave blank to autoselect.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
Board link: g
Archive link: g-archive
Internal archive link: g-expired
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:"Install Gentoo"
Index-only link: g-index
Catalog-only link: g-catalog
External link: external-text:"Google","http://www.google.com"
Combinations are possible: g-index-text:"Technology Index"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"]
will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
if you are on /g/.
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Literal %: %%
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (4chan filename)
Filename: %n (truncated), %N (untruncated), %t (4chan filename)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Tag: %g
Literal %: %%
Quick Reply Personas

One item per line.
Items will be added in the relevant input's auto-completion list.
Password items will always be used, since there is no password input.
Lines starting with a # will be ignored.

Unread Favicon is disabled.
Thread Updater is disabled.
Interval: seconds
Custom Cooldown Time
Seconds:
" + innerHTML: "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Captcha Language
Choose from list of language codes. Leave blank to autoselect.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
Board link: g
Archive link: g-archive
Internal archive link: g-expired
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:"Install Gentoo"
Index-only link: g-index
Catalog-only link: g-catalog
Index mode: g-mode:"infinite scrolling"
Index sort: g-sort:"creation date"
External link: external-text:"Google","http://www.google.com"
Combinations are possible: g-index-text:"Technology Index"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"]
will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
if you are on /g/.
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Literal %: %%
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (4chan filename)
Filename: %n (truncated), %N (untruncated), %t (4chan filename)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Tag: %g
Literal %: %%
Quick Reply Personas

One item per line.
Items will be added in the relevant input's auto-completion list.
Password items will always be used, since there is no password input.
Lines starting with a # will be ignored.

Unread Favicon is disabled.
Thread Updater is disabled.
Interval: seconds
Custom Cooldown Time
Seconds:
" }); ref = $$('.warning', section); for (k = 0, len1 = ref.length; k < len1; k++) { @@ -17915,6 +18043,7 @@ } Conf['selectedArchives'] = {}; Conf['cooldowns'] = {}; + Conf['Index Sort'] = {}; Conf['Except Archives from Encryption'] = false; Conf['JSON Navigation'] = true; Conf['Oekaki Links'] = true; diff --git a/builds/4chan-X-noupdate.crx b/builds/4chan-X-noupdate.crx index 89d1fefb4..e050c2196 100644 Binary files a/builds/4chan-X-noupdate.crx and b/builds/4chan-X-noupdate.crx differ diff --git a/builds/4chan-X-noupdate.user.js b/builds/4chan-X-noupdate.user.js index a304f6fca..548381dcd 100644 --- a/builds/4chan-X-noupdate.user.js +++ b/builds/4chan-X-noupdate.user.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript // ==UserScript== // @name 4chan X -// @version 1.11.27.2 +// @version 1.11.28.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -321,7 +321,6 @@ Index: { 'Index Mode': 'paged', 'Previous Index Mode': 'paged', - 'Index Sort': 'bump', 'Index Size': 'small', 'Show Replies': true, 'Pin Watched Threads': false, @@ -440,7 +439,7 @@ doc = d.documentElement; g = { - VERSION: '1.11.27.2', + VERSION: '1.11.28.0', NAMESPACE: '4chan X.', boards: {} }; @@ -2884,7 +2883,7 @@ } boardnav = boardnav.replace(/(\r\n|\n|\r)/g, ' '); as = $$('#full-board-list a[title]', Header.boardList); - re = /[\w@]+(-(all|title|replace|full|index|catalog|archive|expired|text:"[^"]+"(,"[^"]+")?))*|[^\w@]+/g; + re = /[\w@]+(-(all|title|replace|full|index|catalog|archive|expired|(mode|sort|text):"[^"]+"(,"[^"]+")?))*|[^\w@]+/g; nodes = (function() { var k, len1, ref, results; ref = boardnav.match(re); @@ -2899,7 +2898,7 @@ return $.ready(CatalogLinks.initBoardList); }, mapCustomNavigation: function(t, as) { - var a, boardID, href, m, text, url; + var a, boardID, href, indexOptions, m, text, url; if (/^[^\w@]/.test(t)) { return $.tn(t); } @@ -2909,6 +2908,12 @@ url = m2; return ''; }); + indexOptions = []; + t = t.replace(/-(?:mode|sort):"([^"]+)"/g, function(m0, m1) { + indexOptions.push(m1.toLowerCase().replace(/\ /g, '-')); + return ''; + }); + indexOptions = indexOptions.join('/'); if (/^toggle-all/.test(t)) { a = $.el('a', { className: 'show-board-list-button', @@ -2969,6 +2974,12 @@ return a.firstChild; } } + if (Conf['JSON Index'] && indexOptions) { + a.dataset.indexOptions = indexOptions; + if (a.hostname === 'boards.4chan.org' && a.pathname.split('/')[2] === '') { + a.href += (a.hash ? '/' : '#') + indexOptions; + } + } if (/-archive/.test(t)) { if (href = Redirect.to('board', { boardID: boardID @@ -3132,26 +3143,26 @@ return $('[name=boardnav]', settings).focus(); }, hashScroll: function(e) { - var hash, post; - if (e.state) { - return; + var el, hash; + if (e) { + if (e.state) { + return; + } + if (!history.state) { + history.replaceState({}, ''); + } } - if (!history.state) { - history.replaceState({}, ''); + if ((hash = location.hash.slice(1)) && (el = $.id(hash))) { + return $.queueTask(function() { + return Header.scrollTo(el); + }); } - hash = this.location.hash.slice(1); - if (!(/^\d*p\d+$/.test(hash) && (post = $.id(hash)))) { - return; - } - if (!post.getBoundingClientRect().height) { - return; - } - return $.queueTask(function() { - return Header.scrollTo(post); - }); }, scrollTo: function(root, down, needed) { var height, x; + if (!root.offsetParent) { + return; + } if (down) { x = Header.getBottomOf(root); if (Conf['Fixed Header'] && Conf['Header auto-hide on scroll'] && Conf['Bottom header']) { @@ -3284,7 +3295,7 @@ showHiddenThreads: false, changed: {}, init: function() { - var anchorEntry, input, k, label, len1, len2, name, pinEntry, q, ref, ref1, ref2, ref3, ref4, ref5, refNavEntry, repliesEntry, select; + var anchorEntry, input, k, label, len1, len2, name, pinEntry, q, ref, ref1, ref2, ref3, ref4, ref5, ref6, refNavEntry, repliesEntry, select, sortEntry; if (g.BOARD.ID === 'f' || !Conf['JSON Index'] || g.VIEW !== 'index') { return; } @@ -3296,6 +3307,8 @@ if ((ref1 = history.state) != null ? ref1.mode : void 0) { Conf['Index Mode'] = (ref2 = history.state) != null ? ref2.mode : void 0; } + this.currentSort = (ref3 = history.state) != null ? ref3.sort : void 0; + this.currentSort || (this.currentSort = typeof Conf['Index Sort'] === 'object' ? Conf['Index Sort'][g.BOARD.ID] || 'bump' : Conf['Index Sort']); this.currentPage = this.getCurrentPage(); this.processHash(); $.addClass(doc, 'index-loading', (Conf['Index Mode'].replace(/\ /g, '-')) + "-mode"); @@ -3314,6 +3327,9 @@ repliesEntry = { el: UI.checkbox('Show Replies', 'Show replies') }; + sortEntry = { + el: UI.checkbox('Per-Board Sort Type', 'Per-board sort type', typeof Conf['Index Sort'] === 'object') + }; pinEntry = { el: UI.checkbox('Pin Watched Threads', 'Pin watched threads') }; @@ -3323,12 +3339,13 @@ refNavEntry = { el: UI.checkbox('Refreshed Navigation', 'Refreshed navigation') }; + sortEntry.el.title = 'Set the sorting order of each board independently.'; pinEntry.el.title = 'Move watched threads to the start of the index.'; anchorEntry.el.title = 'Move hidden threads to the end of the index.'; refNavEntry.el.title = 'Refresh index when navigating through pages.'; - ref3 = [repliesEntry, pinEntry, anchorEntry, refNavEntry]; - for (k = 0, len1 = ref3.length; k < len1; k++) { - label = ref3[k]; + ref4 = [repliesEntry, pinEntry, anchorEntry, refNavEntry]; + for (k = 0, len1 = ref4.length; k < len1; k++) { + label = ref4[k]; input = label.el.firstChild; name = input.name; $.on(input, 'change', $.cb.checked); @@ -3338,24 +3355,25 @@ break; case 'Pin Watched Threads': case 'Anchor Hidden Threads': - $.on(input, 'change', this.cb.sort); + $.on(input, 'change', this.cb.resort); } } + $.on(sortEntry.el.firstChild, 'change', this.cb.perBoardSort); Header.menu.addEntry({ el: $.el('span', { textContent: 'Index Navigation' }), order: 100, - subEntries: [repliesEntry, pinEntry, anchorEntry, refNavEntry] + subEntries: [repliesEntry, sortEntry, pinEntry, anchorEntry, refNavEntry] }); this.navLinks = $.el('div', { className: 'navLinks json-index' }); $.extend(this.navLinks, { - innerHTML: "Index Catalog Archive Bottom ×" + innerHTML: "Index Catalog Archive Bottom ×" }); $('.cataloglink a', this.navLinks).href = CatalogLinks.catalog(); - if ((ref4 = g.BOARD.ID) === 'b' || ref4 === 'trash') { + if ((ref5 = g.BOARD.ID) === 'b' || ref5 === 'trash') { $('.archlistlink', this.navLinks).hidden = true; } $.on($('#index-last-refresh a', this.navLinks), 'click', this.cb.refreshFront); @@ -3369,14 +3387,15 @@ this.selectSort = $('#index-sort', this.navLinks); this.selectSize = $('#index-size', this.navLinks); $.on(this.selectMode, 'change', this.cb.mode); - ref5 = [this.selectMode, this.selectSort, this.selectSize]; - for (q = 0, len2 = ref5.length; q < len2; q++) { - select = ref5[q]; - select.value = Conf[select.name]; - $.on(select, 'change', $.cb.value); - } $.on(this.selectSort, 'change', this.cb.sort); + $.on(this.selectSize, 'change', $.cb.value); $.on(this.selectSize, 'change', this.cb.size); + ref6 = [this.selectMode, this.selectSize]; + for (q = 0, len2 = ref6.length; q < len2; q++) { + select = ref6[q]; + select.value = Conf[select.name]; + } + this.selectSort.value = Index.currentSort; this.root = $.el('div', { className: 'board json-index' }); @@ -3394,13 +3413,13 @@ return d.title = d.title.replace(/\ -\ Page\ \d+/, ''); }); $.onExists(doc, '.board > .thread > .postContainer, .board + *', function() { - var board, el, len3, len4, ref6, ref7, threadRoot, topNavPos, u, v; + var board, el, len3, len4, ref7, ref8, threadRoot, topNavPos, u, v; Index.hat = $('.board > .thread > img:first-child'); if (Index.hat) { if (Index.nodes) { - ref6 = Index.nodes; - for (u = 0, len3 = ref6.length; u < len3; u++) { - threadRoot = ref6[u]; + ref7 = Index.nodes; + for (u = 0, len3 = ref7.length; u < len3; u++) { + threadRoot = ref7[u]; $.prepend(threadRoot, Index.hat.cloneNode(false)); } } @@ -3413,9 +3432,9 @@ try { d.implementation.createDocument(null, null, null).appendChild(board); } catch (_error) {} - ref7 = $$('.navLinks'); - for (v = 0, len4 = ref7.length; v < len4; v++) { - el = ref7[v]; + ref8 = $$('.navLinks'); + for (v = 0, len4 = ref8.length; v < len4; v++) { + el = ref8[v]; $.rm(el); } $.rm($.id('ctrl-top')); @@ -3549,21 +3568,25 @@ return Index.buildIndex(); }, mode: function() { - var mode; - mode = this.value; - if (mode !== 'catalog') { - Conf['Previous Index Mode'] = mode; - $.set('Previous Index Mode', mode); - } Index.pushState({ - mode: mode + mode: this.value }); return Index.pageLoad(false); }, sort: function() { + Index.pushState({ + sort: this.value + }); + return Index.pageLoad(false); + }, + resort: function() { Index.sort(); return Index.buildIndex(); }, + perBoardSort: function() { + Conf['Index Sort'] = this.checked ? {} : ''; + return Index.saveSort(); + }, size: function(e) { if (Conf['Index Mode'] !== 'catalog') { $.rmClass(Index.root, 'catalog-small'); @@ -3585,19 +3608,23 @@ return Index.buildIndex(); }, popstate: function(e) { - var mode, page, ref, searched; + var mode, nCommands, page, ref, searched, sort; if (e != null ? e.state : void 0) { - ref = e.state, searched = ref.searched, mode = ref.mode; + ref = e.state, searched = ref.searched, mode = ref.mode, sort = ref.sort; page = Index.getCurrentPage(); Index.setState({ search: searched, mode: mode, + sort: sort, page: page }); return Index.pageLoad(false); } else { - if (Index.processHash()) { - return Index[Conf['Refreshed Navigation'] ? 'update' : 'pageLoad'](); + nCommands = Index.processHash(); + if (Conf['Refreshed Navigation'] && nCommands) { + return Index.update(); + } else { + return Index.pageLoad(); } } }, @@ -3646,25 +3673,53 @@ return Index.pageLoad(); } }, + hashCommands: { + mode: { + 'paged': 'paged', + 'infinite-scrolling': 'infinite', + 'infinite': 'infinite', + 'all-threads': 'all pages', + 'all-pages': 'all pages', + 'catalog': 'catalog' + }, + sort: { + 'bump-order': 'bump', + 'last-reply': 'lastreply', + 'last-long-reply': 'lastlong', + 'creation-date': 'birth', + 'reply-count': 'replycount', + 'file-count': 'filecount' + } + }, processHash: function() { - var command, hash, ref, state; + var command, commands, hash, k, leftover, len1, mode, ref, sort, state; hash = ((ref = location.href.match(/#.*/)) != null ? ref[0] : void 0) || ''; - command = hash.slice(1); state = { replace: true }; - if (command === 'paged' || command === 'infinite' || command === 'all-pages' || command === 'catalog') { - state.mode = command.replace(/-/g, ' '); - } else if (command === 'index') { - state.mode = Conf['Previous Index Mode']; - state.page = 1; - } else if (/^s=/.test(command)) { - state.search = decodeURIComponent(command.slice(2)).replace(/\+/g, ' ').trim(); - } else { - state.hash = hash; + commands = hash.slice(1).split('/'); + leftover = []; + for (k = 0, len1 = commands.length; k < len1; k++) { + command = commands[k]; + if ((mode = Index.hashCommands.mode[command])) { + state.mode = mode; + } else if (command === 'index') { + state.mode = Conf['Previous Index Mode']; + state.page = 1; + } else if ((sort = Index.hashCommands.sort[command])) { + state.sort = sort; + } else if (/^s=/.test(command)) { + state.search = decodeURIComponent(command.slice(2)).replace(/\+/g, ' ').trim(); + } else { + leftover.push(command); + } + } + hash = leftover.join('/'); + if (hash) { + state.hash = "#" + hash; } Index.pushState(state); - return state.hash == null; + return commands.length - leftover.length; }, pushState: function(state) { var hash, pageBeforeSearch, pathname, ref, replace, search; @@ -3683,13 +3738,14 @@ hash || (hash = ''); return history[replace ? 'replaceState' : 'pushState']({ mode: Conf['Index Mode'], + sort: Index.currentSort, searched: Index.search, oldpage: pageBeforeSearch }, '', location.protocol + "//" + location.host + pathname + hash); }, setState: function(arg) { - var mode, page, ref, search; - search = arg.search, mode = arg.mode, page = arg.page; + var hash, mode, page, ref, search, sort; + search = arg.search, mode = arg.mode, sort = arg.sort, page = arg.page, hash = arg.hash; if ((search != null) && search !== Index.search) { Index.changed.search = true; Index.search = search; @@ -3703,43 +3759,69 @@ $.set('Previous Index Mode', mode); } } + if ((sort != null) && sort !== Index.currentSort) { + Index.changed.sort = true; + Index.currentSort = sort; + Index.saveSort(); + } if ((ref = Conf['Index Mode']) === 'all pages' || ref === 'catalog') { page = 1; } if ((page != null) && page !== Index.currentPage) { Index.changed.page = true; - return Index.currentPage = page; + Index.currentPage = page; + } + if (hash != null) { + return Index.changed.hash = true; } }, + saveSort: function() { + if (typeof Conf['Index Sort'] === 'object') { + Conf['Index Sort'][g.BOARD.ID] = Index.currentSort; + } else { + Conf['Index Sort'] = Index.currentSort; + } + return $.set('Index Sort', Conf['Index Sort']); + }, pageLoad: function(scroll) { - var mode, page, ref, search, threads; + var hash, mode, page, ref, search, sort, threads; if (scroll == null) { scroll = true; } if (!Index.liveThreadData) { return; } - ref = Index.changed, threads = ref.threads, search = ref.search, mode = ref.mode, page = ref.page; - if (threads || search) { + ref = Index.changed, threads = ref.threads, search = ref.search, mode = ref.mode, sort = ref.sort, page = ref.page, hash = ref.hash; + if (threads || search || sort) { Index.sort(); + } + if (threads || search) { Index.buildPagelist(); } if (search) { Index.setupSearch(); } if (mode) { - Index.applyMode(); + Index.setupMode(); + } + if (sort) { + Index.setupSort(); + } + if (threads || search || mode || page || sort) { + Index.buildIndex(); } if (threads || search || mode || page) { - Index.buildIndex(); Index.setPage(); } - if (scroll) { + if (scroll && !hash) { Index.scrollToIndex(); } + if (hash) { + Header.hashScroll(); + } return Index.changed = {}; }, - applyMode: function() { + setupMode: function() { var k, len1, mode, ref; ref = ['paged', 'infinite', 'all pages', 'catalog']; for (k = 0, len1 = ref.length; k < len1; k++) { @@ -3751,6 +3833,9 @@ Index.showHiddenThreads = false; return $('#hidden-toggle a', Index.navLinks).textContent = 'Show'; }, + setupSort: function() { + return Index.selectSort.value = Index.currentSort; + }, getPagesNum: function() { if (Index.search) { return Math.ceil(Index.sortedNodes.length / Index.threadsNumPerPage); @@ -4065,13 +4150,13 @@ } }, sort: function() { - var k, len1, liveThreadData, liveThreadIDs, nodes, sortedNodes, sortedThreadIDs, threadID; + var k, lastlong, len1, liveThreadData, liveThreadIDs, nodes, sortedNodes, sortedThreadIDs, threadID; liveThreadIDs = Index.liveThreadIDs, liveThreadData = Index.liveThreadData; if (!liveThreadData) { return; } sortedThreadIDs = (function() { - switch (Conf['Index Sort']) { + switch (Index.currentSort) { case 'lastreply': return slice.call(liveThreadData).sort(function(a, b) { var num; @@ -4085,6 +4170,23 @@ }).map(function(post) { return post.no; }); + case 'lastlong': + lastlong = function(thread) { + var i, k, r, ref; + ref = thread.last_replies || []; + for (i = k = ref.length - 1; k >= 0; i = k += -1) { + r = ref[i]; + if (r.com && Build.parseComment(r.com).replace(/[^a-z]/ig, '').length >= 100) { + return r; + } + } + return thread; + }; + return slice.call(liveThreadData).sort(function(a, b) { + return lastlong(b).no - lastlong(a).no; + }).map(function(post) { + return post.no; + }); case 'bump': return liveThreadIDs; case 'birth': @@ -15326,6 +15428,9 @@ continue; } a.href = useCatalog ? CatalogLinks.catalog(board) : "/" + board + "/"; + if (a.dataset.indexOptions && a.hostname === 'boards.4chan.org' && a.pathname.split('/')[2] === '') { + a.href += (a.hash ? '/' : '#') + a.dataset.indexOptions; + } } CatalogLinks.el.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + "."; return $('input', CatalogLinks.el).checked = useCatalog; @@ -15830,7 +15935,23 @@ }); } if (g.BOARD.ID === 'sci') { - $.globalEval('window.addEventListener(\'mathjax\', function(e) {\n if (window.MathJax) {\n window.MathJax.Hub.Queue(function() {\n if (!e.target.querySelector(\'.MathJax\')) {\n window.MathJax.Hub.Typeset(e.target);\n }\n });\n } else {\n if (!document.querySelector(\'script[src^="//cdn.mathjax.org/"]\')) {\n window.loadMathJax();\n window.loadMathJax = function() {};\n if (!e.target.classList.contains(\'postMessage\')) {\n document.querySelector(\'script[src^="//cdn.mathjax.org/"]\').addEventListener(\'load\', function() {\n window.MathJax.Hub.Queue([\'Typeset\', window.MathJax.Hub, e.target]);\n }, false);\n }\n }\n }\n}, false);'); + $.global(function() { + return window.addEventListener('mathjax', function(e) { + if (window.MathJax) { + return window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, e.target]); + } else { + if (!document.querySelector('script[src^="//cdn.mathjax.org/"]')) { + window.loadMathJax(); + window.loadMathJax = function() {}; + } + if (!e.target.classList.contains('postMessage')) { + return document.querySelector('script[src^="//cdn.mathjax.org/"]').addEventListener('load', function() { + return window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, e.target]); + }, false); + } + } + }, false); + }); Post.callbacks.push({ name: 'Parse /sci/ math', cb: this.math @@ -15874,10 +15995,17 @@ })(this)); }, math: function() { - var cb; - if (!(/\[(math|eqn)\]/.test(this.nodes.comment.textContent) || $('.math:not([id])', this.nodes.comment))) { + var cb, k, len1, wbr, wbrs; + if (!/\[(math|eqn)\]/.test(this.nodes.comment.textContent)) { return; } + if ((wbrs = $$('wbr', this.nodes.comment)).length) { + for (k = 0, len1 = wbrs.length; k < len1; k++) { + wbr = wbrs[k]; + $.rm(wbr); + } + this.nodes.comment.normalize(); + } cb = (function(_this) { return function() { if (!doc.contains(_this.nodes.comment)) { @@ -17560,7 +17688,7 @@ advanced: function(section) { var aa, ab, applyCSS, archBoards, archive, boardID, boardOptions, boardSelect, boards, customCSS, files, i, input, inputs, interval, item, items, k, len1, len2, len3, len4, len5, len6, len7, name, o, q, ref, ref1, ref2, ref3, ref4, ref5, ref6, row, rows, software, ta, table, u, uid, v, warning, withCredentials, z; $.extend(section, { - innerHTML: "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Captcha Language
Choose from list of language codes. Leave blank to autoselect.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
Board link: g
Archive link: g-archive
Internal archive link: g-expired
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:"Install Gentoo"
Index-only link: g-index
Catalog-only link: g-catalog
External link: external-text:"Google","http://www.google.com"
Combinations are possible: g-index-text:"Technology Index"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"]
will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
if you are on /g/.
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Literal %: %%
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (4chan filename)
Filename: %n (truncated), %N (untruncated), %t (4chan filename)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Tag: %g
Literal %: %%
Quick Reply Personas

One item per line.
Items will be added in the relevant input's auto-completion list.
Password items will always be used, since there is no password input.
Lines starting with a # will be ignored.

Unread Favicon is disabled.
Thread Updater is disabled.
Interval: seconds
Custom Cooldown Time
Seconds:
" + innerHTML: "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Captcha Language
Choose from list of language codes. Leave blank to autoselect.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
Board link: g
Archive link: g-archive
Internal archive link: g-expired
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:"Install Gentoo"
Index-only link: g-index
Catalog-only link: g-catalog
Index mode: g-mode:"infinite scrolling"
Index sort: g-sort:"creation date"
External link: external-text:"Google","http://www.google.com"
Combinations are possible: g-index-text:"Technology Index"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"]
will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
if you are on /g/.
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Literal %: %%
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (4chan filename)
Filename: %n (truncated), %N (untruncated), %t (4chan filename)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Tag: %g
Literal %: %%
Quick Reply Personas

One item per line.
Items will be added in the relevant input's auto-completion list.
Password items will always be used, since there is no password input.
Lines starting with a # will be ignored.

Unread Favicon is disabled.
Thread Updater is disabled.
Interval: seconds
Custom Cooldown Time
Seconds:
" }); ref = $$('.warning', section); for (k = 0, len1 = ref.length; k < len1; k++) { @@ -17915,6 +18043,7 @@ } Conf['selectedArchives'] = {}; Conf['cooldowns'] = {}; + Conf['Index Sort'] = {}; Conf['Except Archives from Encryption'] = false; Conf['JSON Navigation'] = true; Conf['Oekaki Links'] = true; diff --git a/builds/4chan-X.crx b/builds/4chan-X.crx index 1bf039602..aaf1cbf03 100644 Binary files a/builds/4chan-X.crx and b/builds/4chan-X.crx differ diff --git a/builds/4chan-X.meta.js b/builds/4chan-X.meta.js index deb81e61c..fecac547c 100644 --- a/builds/4chan-X.meta.js +++ b/builds/4chan-X.meta.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X -// @version 1.11.27.2 +// @version 1.11.28.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 779ce2763..000461ebe 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript // ==UserScript== // @name 4chan X -// @version 1.11.27.2 +// @version 1.11.28.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -321,7 +321,6 @@ Index: { 'Index Mode': 'paged', 'Previous Index Mode': 'paged', - 'Index Sort': 'bump', 'Index Size': 'small', 'Show Replies': true, 'Pin Watched Threads': false, @@ -440,7 +439,7 @@ doc = d.documentElement; g = { - VERSION: '1.11.27.2', + VERSION: '1.11.28.0', NAMESPACE: '4chan X.', boards: {} }; @@ -2884,7 +2883,7 @@ } boardnav = boardnav.replace(/(\r\n|\n|\r)/g, ' '); as = $$('#full-board-list a[title]', Header.boardList); - re = /[\w@]+(-(all|title|replace|full|index|catalog|archive|expired|text:"[^"]+"(,"[^"]+")?))*|[^\w@]+/g; + re = /[\w@]+(-(all|title|replace|full|index|catalog|archive|expired|(mode|sort|text):"[^"]+"(,"[^"]+")?))*|[^\w@]+/g; nodes = (function() { var k, len1, ref, results; ref = boardnav.match(re); @@ -2899,7 +2898,7 @@ return $.ready(CatalogLinks.initBoardList); }, mapCustomNavigation: function(t, as) { - var a, boardID, href, m, text, url; + var a, boardID, href, indexOptions, m, text, url; if (/^[^\w@]/.test(t)) { return $.tn(t); } @@ -2909,6 +2908,12 @@ url = m2; return ''; }); + indexOptions = []; + t = t.replace(/-(?:mode|sort):"([^"]+)"/g, function(m0, m1) { + indexOptions.push(m1.toLowerCase().replace(/\ /g, '-')); + return ''; + }); + indexOptions = indexOptions.join('/'); if (/^toggle-all/.test(t)) { a = $.el('a', { className: 'show-board-list-button', @@ -2969,6 +2974,12 @@ return a.firstChild; } } + if (Conf['JSON Index'] && indexOptions) { + a.dataset.indexOptions = indexOptions; + if (a.hostname === 'boards.4chan.org' && a.pathname.split('/')[2] === '') { + a.href += (a.hash ? '/' : '#') + indexOptions; + } + } if (/-archive/.test(t)) { if (href = Redirect.to('board', { boardID: boardID @@ -3132,26 +3143,26 @@ return $('[name=boardnav]', settings).focus(); }, hashScroll: function(e) { - var hash, post; - if (e.state) { - return; + var el, hash; + if (e) { + if (e.state) { + return; + } + if (!history.state) { + history.replaceState({}, ''); + } } - if (!history.state) { - history.replaceState({}, ''); + if ((hash = location.hash.slice(1)) && (el = $.id(hash))) { + return $.queueTask(function() { + return Header.scrollTo(el); + }); } - hash = this.location.hash.slice(1); - if (!(/^\d*p\d+$/.test(hash) && (post = $.id(hash)))) { - return; - } - if (!post.getBoundingClientRect().height) { - return; - } - return $.queueTask(function() { - return Header.scrollTo(post); - }); }, scrollTo: function(root, down, needed) { var height, x; + if (!root.offsetParent) { + return; + } if (down) { x = Header.getBottomOf(root); if (Conf['Fixed Header'] && Conf['Header auto-hide on scroll'] && Conf['Bottom header']) { @@ -3284,7 +3295,7 @@ showHiddenThreads: false, changed: {}, init: function() { - var anchorEntry, input, k, label, len1, len2, name, pinEntry, q, ref, ref1, ref2, ref3, ref4, ref5, refNavEntry, repliesEntry, select; + var anchorEntry, input, k, label, len1, len2, name, pinEntry, q, ref, ref1, ref2, ref3, ref4, ref5, ref6, refNavEntry, repliesEntry, select, sortEntry; if (g.BOARD.ID === 'f' || !Conf['JSON Index'] || g.VIEW !== 'index') { return; } @@ -3296,6 +3307,8 @@ if ((ref1 = history.state) != null ? ref1.mode : void 0) { Conf['Index Mode'] = (ref2 = history.state) != null ? ref2.mode : void 0; } + this.currentSort = (ref3 = history.state) != null ? ref3.sort : void 0; + this.currentSort || (this.currentSort = typeof Conf['Index Sort'] === 'object' ? Conf['Index Sort'][g.BOARD.ID] || 'bump' : Conf['Index Sort']); this.currentPage = this.getCurrentPage(); this.processHash(); $.addClass(doc, 'index-loading', (Conf['Index Mode'].replace(/\ /g, '-')) + "-mode"); @@ -3314,6 +3327,9 @@ repliesEntry = { el: UI.checkbox('Show Replies', 'Show replies') }; + sortEntry = { + el: UI.checkbox('Per-Board Sort Type', 'Per-board sort type', typeof Conf['Index Sort'] === 'object') + }; pinEntry = { el: UI.checkbox('Pin Watched Threads', 'Pin watched threads') }; @@ -3323,12 +3339,13 @@ refNavEntry = { el: UI.checkbox('Refreshed Navigation', 'Refreshed navigation') }; + sortEntry.el.title = 'Set the sorting order of each board independently.'; pinEntry.el.title = 'Move watched threads to the start of the index.'; anchorEntry.el.title = 'Move hidden threads to the end of the index.'; refNavEntry.el.title = 'Refresh index when navigating through pages.'; - ref3 = [repliesEntry, pinEntry, anchorEntry, refNavEntry]; - for (k = 0, len1 = ref3.length; k < len1; k++) { - label = ref3[k]; + ref4 = [repliesEntry, pinEntry, anchorEntry, refNavEntry]; + for (k = 0, len1 = ref4.length; k < len1; k++) { + label = ref4[k]; input = label.el.firstChild; name = input.name; $.on(input, 'change', $.cb.checked); @@ -3338,24 +3355,25 @@ break; case 'Pin Watched Threads': case 'Anchor Hidden Threads': - $.on(input, 'change', this.cb.sort); + $.on(input, 'change', this.cb.resort); } } + $.on(sortEntry.el.firstChild, 'change', this.cb.perBoardSort); Header.menu.addEntry({ el: $.el('span', { textContent: 'Index Navigation' }), order: 100, - subEntries: [repliesEntry, pinEntry, anchorEntry, refNavEntry] + subEntries: [repliesEntry, sortEntry, pinEntry, anchorEntry, refNavEntry] }); this.navLinks = $.el('div', { className: 'navLinks json-index' }); $.extend(this.navLinks, { - innerHTML: "Index Catalog Archive Bottom ×" + innerHTML: "Index Catalog Archive Bottom ×" }); $('.cataloglink a', this.navLinks).href = CatalogLinks.catalog(); - if ((ref4 = g.BOARD.ID) === 'b' || ref4 === 'trash') { + if ((ref5 = g.BOARD.ID) === 'b' || ref5 === 'trash') { $('.archlistlink', this.navLinks).hidden = true; } $.on($('#index-last-refresh a', this.navLinks), 'click', this.cb.refreshFront); @@ -3369,14 +3387,15 @@ this.selectSort = $('#index-sort', this.navLinks); this.selectSize = $('#index-size', this.navLinks); $.on(this.selectMode, 'change', this.cb.mode); - ref5 = [this.selectMode, this.selectSort, this.selectSize]; - for (q = 0, len2 = ref5.length; q < len2; q++) { - select = ref5[q]; - select.value = Conf[select.name]; - $.on(select, 'change', $.cb.value); - } $.on(this.selectSort, 'change', this.cb.sort); + $.on(this.selectSize, 'change', $.cb.value); $.on(this.selectSize, 'change', this.cb.size); + ref6 = [this.selectMode, this.selectSize]; + for (q = 0, len2 = ref6.length; q < len2; q++) { + select = ref6[q]; + select.value = Conf[select.name]; + } + this.selectSort.value = Index.currentSort; this.root = $.el('div', { className: 'board json-index' }); @@ -3394,13 +3413,13 @@ return d.title = d.title.replace(/\ -\ Page\ \d+/, ''); }); $.onExists(doc, '.board > .thread > .postContainer, .board + *', function() { - var board, el, len3, len4, ref6, ref7, threadRoot, topNavPos, u, v; + var board, el, len3, len4, ref7, ref8, threadRoot, topNavPos, u, v; Index.hat = $('.board > .thread > img:first-child'); if (Index.hat) { if (Index.nodes) { - ref6 = Index.nodes; - for (u = 0, len3 = ref6.length; u < len3; u++) { - threadRoot = ref6[u]; + ref7 = Index.nodes; + for (u = 0, len3 = ref7.length; u < len3; u++) { + threadRoot = ref7[u]; $.prepend(threadRoot, Index.hat.cloneNode(false)); } } @@ -3413,9 +3432,9 @@ try { d.implementation.createDocument(null, null, null).appendChild(board); } catch (_error) {} - ref7 = $$('.navLinks'); - for (v = 0, len4 = ref7.length; v < len4; v++) { - el = ref7[v]; + ref8 = $$('.navLinks'); + for (v = 0, len4 = ref8.length; v < len4; v++) { + el = ref8[v]; $.rm(el); } $.rm($.id('ctrl-top')); @@ -3549,21 +3568,25 @@ return Index.buildIndex(); }, mode: function() { - var mode; - mode = this.value; - if (mode !== 'catalog') { - Conf['Previous Index Mode'] = mode; - $.set('Previous Index Mode', mode); - } Index.pushState({ - mode: mode + mode: this.value }); return Index.pageLoad(false); }, sort: function() { + Index.pushState({ + sort: this.value + }); + return Index.pageLoad(false); + }, + resort: function() { Index.sort(); return Index.buildIndex(); }, + perBoardSort: function() { + Conf['Index Sort'] = this.checked ? {} : ''; + return Index.saveSort(); + }, size: function(e) { if (Conf['Index Mode'] !== 'catalog') { $.rmClass(Index.root, 'catalog-small'); @@ -3585,19 +3608,23 @@ return Index.buildIndex(); }, popstate: function(e) { - var mode, page, ref, searched; + var mode, nCommands, page, ref, searched, sort; if (e != null ? e.state : void 0) { - ref = e.state, searched = ref.searched, mode = ref.mode; + ref = e.state, searched = ref.searched, mode = ref.mode, sort = ref.sort; page = Index.getCurrentPage(); Index.setState({ search: searched, mode: mode, + sort: sort, page: page }); return Index.pageLoad(false); } else { - if (Index.processHash()) { - return Index[Conf['Refreshed Navigation'] ? 'update' : 'pageLoad'](); + nCommands = Index.processHash(); + if (Conf['Refreshed Navigation'] && nCommands) { + return Index.update(); + } else { + return Index.pageLoad(); } } }, @@ -3646,25 +3673,53 @@ return Index.pageLoad(); } }, + hashCommands: { + mode: { + 'paged': 'paged', + 'infinite-scrolling': 'infinite', + 'infinite': 'infinite', + 'all-threads': 'all pages', + 'all-pages': 'all pages', + 'catalog': 'catalog' + }, + sort: { + 'bump-order': 'bump', + 'last-reply': 'lastreply', + 'last-long-reply': 'lastlong', + 'creation-date': 'birth', + 'reply-count': 'replycount', + 'file-count': 'filecount' + } + }, processHash: function() { - var command, hash, ref, state; + var command, commands, hash, k, leftover, len1, mode, ref, sort, state; hash = ((ref = location.href.match(/#.*/)) != null ? ref[0] : void 0) || ''; - command = hash.slice(1); state = { replace: true }; - if (command === 'paged' || command === 'infinite' || command === 'all-pages' || command === 'catalog') { - state.mode = command.replace(/-/g, ' '); - } else if (command === 'index') { - state.mode = Conf['Previous Index Mode']; - state.page = 1; - } else if (/^s=/.test(command)) { - state.search = decodeURIComponent(command.slice(2)).replace(/\+/g, ' ').trim(); - } else { - state.hash = hash; + commands = hash.slice(1).split('/'); + leftover = []; + for (k = 0, len1 = commands.length; k < len1; k++) { + command = commands[k]; + if ((mode = Index.hashCommands.mode[command])) { + state.mode = mode; + } else if (command === 'index') { + state.mode = Conf['Previous Index Mode']; + state.page = 1; + } else if ((sort = Index.hashCommands.sort[command])) { + state.sort = sort; + } else if (/^s=/.test(command)) { + state.search = decodeURIComponent(command.slice(2)).replace(/\+/g, ' ').trim(); + } else { + leftover.push(command); + } + } + hash = leftover.join('/'); + if (hash) { + state.hash = "#" + hash; } Index.pushState(state); - return state.hash == null; + return commands.length - leftover.length; }, pushState: function(state) { var hash, pageBeforeSearch, pathname, ref, replace, search; @@ -3683,13 +3738,14 @@ hash || (hash = ''); return history[replace ? 'replaceState' : 'pushState']({ mode: Conf['Index Mode'], + sort: Index.currentSort, searched: Index.search, oldpage: pageBeforeSearch }, '', location.protocol + "//" + location.host + pathname + hash); }, setState: function(arg) { - var mode, page, ref, search; - search = arg.search, mode = arg.mode, page = arg.page; + var hash, mode, page, ref, search, sort; + search = arg.search, mode = arg.mode, sort = arg.sort, page = arg.page, hash = arg.hash; if ((search != null) && search !== Index.search) { Index.changed.search = true; Index.search = search; @@ -3703,43 +3759,69 @@ $.set('Previous Index Mode', mode); } } + if ((sort != null) && sort !== Index.currentSort) { + Index.changed.sort = true; + Index.currentSort = sort; + Index.saveSort(); + } if ((ref = Conf['Index Mode']) === 'all pages' || ref === 'catalog') { page = 1; } if ((page != null) && page !== Index.currentPage) { Index.changed.page = true; - return Index.currentPage = page; + Index.currentPage = page; + } + if (hash != null) { + return Index.changed.hash = true; } }, + saveSort: function() { + if (typeof Conf['Index Sort'] === 'object') { + Conf['Index Sort'][g.BOARD.ID] = Index.currentSort; + } else { + Conf['Index Sort'] = Index.currentSort; + } + return $.set('Index Sort', Conf['Index Sort']); + }, pageLoad: function(scroll) { - var mode, page, ref, search, threads; + var hash, mode, page, ref, search, sort, threads; if (scroll == null) { scroll = true; } if (!Index.liveThreadData) { return; } - ref = Index.changed, threads = ref.threads, search = ref.search, mode = ref.mode, page = ref.page; - if (threads || search) { + ref = Index.changed, threads = ref.threads, search = ref.search, mode = ref.mode, sort = ref.sort, page = ref.page, hash = ref.hash; + if (threads || search || sort) { Index.sort(); + } + if (threads || search) { Index.buildPagelist(); } if (search) { Index.setupSearch(); } if (mode) { - Index.applyMode(); + Index.setupMode(); + } + if (sort) { + Index.setupSort(); + } + if (threads || search || mode || page || sort) { + Index.buildIndex(); } if (threads || search || mode || page) { - Index.buildIndex(); Index.setPage(); } - if (scroll) { + if (scroll && !hash) { Index.scrollToIndex(); } + if (hash) { + Header.hashScroll(); + } return Index.changed = {}; }, - applyMode: function() { + setupMode: function() { var k, len1, mode, ref; ref = ['paged', 'infinite', 'all pages', 'catalog']; for (k = 0, len1 = ref.length; k < len1; k++) { @@ -3751,6 +3833,9 @@ Index.showHiddenThreads = false; return $('#hidden-toggle a', Index.navLinks).textContent = 'Show'; }, + setupSort: function() { + return Index.selectSort.value = Index.currentSort; + }, getPagesNum: function() { if (Index.search) { return Math.ceil(Index.sortedNodes.length / Index.threadsNumPerPage); @@ -4065,13 +4150,13 @@ } }, sort: function() { - var k, len1, liveThreadData, liveThreadIDs, nodes, sortedNodes, sortedThreadIDs, threadID; + var k, lastlong, len1, liveThreadData, liveThreadIDs, nodes, sortedNodes, sortedThreadIDs, threadID; liveThreadIDs = Index.liveThreadIDs, liveThreadData = Index.liveThreadData; if (!liveThreadData) { return; } sortedThreadIDs = (function() { - switch (Conf['Index Sort']) { + switch (Index.currentSort) { case 'lastreply': return slice.call(liveThreadData).sort(function(a, b) { var num; @@ -4085,6 +4170,23 @@ }).map(function(post) { return post.no; }); + case 'lastlong': + lastlong = function(thread) { + var i, k, r, ref; + ref = thread.last_replies || []; + for (i = k = ref.length - 1; k >= 0; i = k += -1) { + r = ref[i]; + if (r.com && Build.parseComment(r.com).replace(/[^a-z]/ig, '').length >= 100) { + return r; + } + } + return thread; + }; + return slice.call(liveThreadData).sort(function(a, b) { + return lastlong(b).no - lastlong(a).no; + }).map(function(post) { + return post.no; + }); case 'bump': return liveThreadIDs; case 'birth': @@ -15326,6 +15428,9 @@ continue; } a.href = useCatalog ? CatalogLinks.catalog(board) : "/" + board + "/"; + if (a.dataset.indexOptions && a.hostname === 'boards.4chan.org' && a.pathname.split('/')[2] === '') { + a.href += (a.hash ? '/' : '#') + a.dataset.indexOptions; + } } CatalogLinks.el.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + "."; return $('input', CatalogLinks.el).checked = useCatalog; @@ -15830,7 +15935,23 @@ }); } if (g.BOARD.ID === 'sci') { - $.globalEval('window.addEventListener(\'mathjax\', function(e) {\n if (window.MathJax) {\n window.MathJax.Hub.Queue(function() {\n if (!e.target.querySelector(\'.MathJax\')) {\n window.MathJax.Hub.Typeset(e.target);\n }\n });\n } else {\n if (!document.querySelector(\'script[src^="//cdn.mathjax.org/"]\')) {\n window.loadMathJax();\n window.loadMathJax = function() {};\n if (!e.target.classList.contains(\'postMessage\')) {\n document.querySelector(\'script[src^="//cdn.mathjax.org/"]\').addEventListener(\'load\', function() {\n window.MathJax.Hub.Queue([\'Typeset\', window.MathJax.Hub, e.target]);\n }, false);\n }\n }\n }\n}, false);'); + $.global(function() { + return window.addEventListener('mathjax', function(e) { + if (window.MathJax) { + return window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, e.target]); + } else { + if (!document.querySelector('script[src^="//cdn.mathjax.org/"]')) { + window.loadMathJax(); + window.loadMathJax = function() {}; + } + if (!e.target.classList.contains('postMessage')) { + return document.querySelector('script[src^="//cdn.mathjax.org/"]').addEventListener('load', function() { + return window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, e.target]); + }, false); + } + } + }, false); + }); Post.callbacks.push({ name: 'Parse /sci/ math', cb: this.math @@ -15874,10 +15995,17 @@ })(this)); }, math: function() { - var cb; - if (!(/\[(math|eqn)\]/.test(this.nodes.comment.textContent) || $('.math:not([id])', this.nodes.comment))) { + var cb, k, len1, wbr, wbrs; + if (!/\[(math|eqn)\]/.test(this.nodes.comment.textContent)) { return; } + if ((wbrs = $$('wbr', this.nodes.comment)).length) { + for (k = 0, len1 = wbrs.length; k < len1; k++) { + wbr = wbrs[k]; + $.rm(wbr); + } + this.nodes.comment.normalize(); + } cb = (function(_this) { return function() { if (!doc.contains(_this.nodes.comment)) { @@ -17560,7 +17688,7 @@ advanced: function(section) { var aa, ab, applyCSS, archBoards, archive, boardID, boardOptions, boardSelect, boards, customCSS, files, i, input, inputs, interval, item, items, k, len1, len2, len3, len4, len5, len6, len7, name, o, q, ref, ref1, ref2, ref3, ref4, ref5, ref6, row, rows, software, ta, table, u, uid, v, warning, withCredentials, z; $.extend(section, { - innerHTML: "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Captcha Language
Choose from list of language codes. Leave blank to autoselect.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
Board link: g
Archive link: g-archive
Internal archive link: g-expired
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:"Install Gentoo"
Index-only link: g-index
Catalog-only link: g-catalog
External link: external-text:"Google","http://www.google.com"
Combinations are possible: g-index-text:"Technology Index"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"]
will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
if you are on /g/.
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Literal %: %%
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (4chan filename)
Filename: %n (truncated), %N (untruncated), %t (4chan filename)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Tag: %g
Literal %: %%
Quick Reply Personas

One item per line.
Items will be added in the relevant input's auto-completion list.
Password items will always be used, since there is no password input.
Lines starting with a # will be ignored.

Unread Favicon is disabled.
Thread Updater is disabled.
Interval: seconds
Custom Cooldown Time
Seconds:
" + innerHTML: "
Archiver
404 Redirect is disabled.
Thread redirectionPost fetchingFile redirection
Captcha Language
Choose from list of language codes. Leave blank to autoselect.
Custom Board Navigation
New lines will be converted into spaces.

In the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
Board link: g
Archive link: g-archive
Internal archive link: g-expired
Title link: g-title
Board link (Replace with title when on that board): g-replace
Full text link: g-full
Custom text link: g-text:"Install Gentoo"
Index-only link: g-index
Catalog-only link: g-catalog
Index mode: g-mode:"infinite scrolling"
Index sort: g-sort:"creation date"
External link: external-text:"Google","http://www.google.com"
Combinations are possible: g-index-text:"Technology Index"
Full board list toggle: toggle-all

[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"]
will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
if you are on /g/.
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Literal %: %%
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (4chan filename)
Filename: %n (truncated), %N (untruncated), %t (4chan filename)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Tag: %g
Literal %: %%
Quick Reply Personas

One item per line.
Items will be added in the relevant input's auto-completion list.
Password items will always be used, since there is no password input.
Lines starting with a # will be ignored.

Unread Favicon is disabled.
Thread Updater is disabled.
Interval: seconds
Custom Cooldown Time
Seconds:
" }); ref = $$('.warning', section); for (k = 0, len1 = ref.length; k < len1; k++) { @@ -17915,6 +18043,7 @@ } Conf['selectedArchives'] = {}; Conf['cooldowns'] = {}; + Conf['Index Sort'] = {}; Conf['Except Archives from Encryption'] = false; Conf['JSON Navigation'] = true; Conf['Oekaki Links'] = true; diff --git a/builds/4chan-X.zip b/builds/4chan-X.zip index 32112a504..d7795b399 100644 Binary files a/builds/4chan-X.zip and b/builds/4chan-X.zip differ diff --git a/builds/updates-beta.xml b/builds/updates-beta.xml index 029d1bd71..ff0f3aae1 100644 --- a/builds/updates-beta.xml +++ b/builds/updates-beta.xml @@ -1,7 +1,7 @@ - + diff --git a/builds/updates.xml b/builds/updates.xml index 1dc31f313..4572e8b5d 100644 --- a/builds/updates.xml +++ b/builds/updates.xml @@ -1,7 +1,7 @@ - + diff --git a/version.json b/version.json index 884892f88..560741dee 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "version": "1.11.27.2", - "date": "2016-03-04T05:31:24.593Z" + "version": "1.11.28.0", + "date": "2016-03-13T22:50:13.404Z" }