diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 2508d1ea0..2fac6fa9a 100755 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -95,10 +95,6 @@ module.exports = (grunt) -> push: false shell: - options: - stdout: true - stderr: true - failOnError: true checkout: command: 'git checkout <%= pkg.meta.mainBranch %>' commit: diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index eb809cc8c..6ffe0e39f 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1175,7 +1175,7 @@ Post.prototype.parseQuote = function(quotelink) { var fullID, match; - if (!(match = quotelink.href.match(/boards\.4chan\.org\/([^\/]+)\/(?:res|thread)\/\d+#p(\d+)$/))) { + if (!(match = quotelink.href.match(/boards\.4chan\.org\/([^\/]+)\/(res|thread)\/\d+(.*)?\#p(\d+)$/))) { return; } this.nodes.quotelinks.push(quotelink); @@ -1189,7 +1189,7 @@ }; Post.prototype.parseFile = function(that) { - var anchor, fileEl, fileText, nameNode, size, thumb, unit, _ref; + var anchor, fileEl, fileText, nameNode, size, thumb, unit; if (!((fileEl = $('.file', this.nodes.post)) && (thumb = $('img[data-md5]', fileEl)))) { return; } @@ -1213,7 +1213,7 @@ this.file.isImage = /(jpg|png|gif)$/i.test(this.file.URL); this.file.isVideo = /webm$/i.test(this.file.URL); if (this.file.isImage || this.file.isVideo) { - this.file.dimensions = (_ref = fileText.childNodes[2].textContent.match(/\d+x\d+/)) != null ? _ref[0] : void 0; + this.file.dimensions = fileText.childNodes[2].data.match(/\d+x\d+/)[0]; } return this.file.name = !this.file.isSpoiler && (nameNode = $('a', fileText)) ? nameNode.title || nameNode.textContent : fileText.title; }; @@ -1225,7 +1225,7 @@ node = _ref[_i]; $.rm(node); } - _ref1 = $$('[id]', post); + _ref1 = $$('[id]:not(.exif)', post); for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { node = _ref1[_j]; node.removeAttribute('id'); @@ -2926,8 +2926,8 @@ toggleHiddenThreads: function() { $('#hidden-toggle a', Index.navLinks).textContent = (Index.showHiddenThreads = !Index.showHiddenThreads) ? 'Hide' : 'Show'; Index.sort(); - if (Conf['Index Mode'] === 'paged' && Index.getCurrentPage() > 0) { - return Index.pageNav(0); + if (Conf['Index Mode'] === 'paged' && Index.getCurrentPage() > 1) { + return Index.pageNav(1); } else { return Index.buildIndex(); } @@ -3010,7 +3010,7 @@ if (Index.cb.indexNav(a, true)) { return; } - return Index.userPageNav(+a.pathname.split('/')[2]); + return Index.userPageNav(+a.pathname.split('/')[2] || 1); }, headerNav: function(e) { var a, needChange, onSameIndex; @@ -3077,7 +3077,7 @@ if (Index.currentPage === pageNum && !Index.root.parentElement) { return; } - Navigate.pushState(pageNum === 0 ? './' : pageNum); + Navigate.pushState(pageNum === 1 ? './' : pageNum); return Index.pageLoad(pageNum); }, pageLoad: function(pageNum) { @@ -3322,7 +3322,7 @@ var err, thread, threadRoot; threadRoot = Build.thread(g.BOARD, threadData); if (thread = g.BOARD.threads[threadData.no]) { - thread.setPage(Math.floor(i / Index.threadsNumPerPage)); + thread.setPage(Math.floor(i / Index.threadsNumPerPage) + 1); thread.setCount('post', threadData.replies + 1, threadData.bumplimit); thread.setCount('file', threadData.images + !!threadData.ext, threadData.imagelimit); thread.setStatus('Sticky', !!threadData.sticky); @@ -3517,7 +3517,7 @@ switch (Conf['Index Mode']) { case 'paged': case 'infinite': - pageNum = Index.getCurrentPage(); + pageNum = Index.getCurrentPage() - 1; threadsPerPage = Index.getThreadsNumPerPage(); threads = []; i = threadsPerPage * pageNum; @@ -3645,6 +3645,17 @@ return n = (n + 1) % 3; }; })(), + path: function(boardID, threadID, postID, fragment) { + var path; + path = "/" + boardID + "/thread/" + threadID; + if ((g.SLUG != null) && threadID === g.THREADID) { + path += "/" + g.SLUG; + } + if (postID) { + path += "#" + (fragment || 'p') + postID; + } + return path; + }, postFromObject: function(data, boardID) { var o; o = { @@ -3759,9 +3770,9 @@ sticky = isSticky ? " " : ''; closed = isClosed ? " " : ''; if (isOP && g.VIEW === 'index') { - pageNum = Math.floor(Index.liveThreadData.keys.indexOf("" + postID) / Index.threadsNumPerPage); + pageNum = Math.floor(Index.liveThreadData.keys.indexOf("" + postID) / Index.threadsNumPerPage) + 1; pageIcon = " Page " + pageNum + ""; - replyLink = "   [Reply]"; + replyLink = "   [Reply]"; } else { pageIcon = ''; replyLink = ''; @@ -3769,19 +3780,16 @@ container = $.el('div', { id: "pc" + postID, className: "postContainer " + (isOP ? 'op' : 'reply') + "Container", - innerHTML: (isOP ? '' : "
>>
") + ("
") + (isOP ? fileHTML : '') + "
" + (" ") + ("" + (subject || '') + " ") + ("") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcodeIcon + userID + flag + ' ' + ("" + date + " ") + "" + ("No.") + ("" + postID + "") + pageIcon + sticky + closed + replyLink + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
' + innerHTML: (isOP ? '' : "
>>
") + ("
") + (isOP ? fileHTML : '') + "
" + (" ") + ("" + (subject || '') + " ") + ("") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcodeIcon + userID + flag + ' ' + ("" + date + " ") + "" + ("No.") + ("" + postID + "") + pageIcon + sticky + closed + replyLink + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
' }); _ref = $$('.quotelink', container); for (_i = 0, _len = _ref.length; _i < _len; _i++) { quote = _ref[_i]; href = quote.getAttribute('href'); - if (href[0] === '/') { + if (href[0] !== '#') { continue; } - if (href[0] === '#') { - href = "" + threadID + href; - } - quote.href = "/" + boardID + "/thread/" + href; + quote.href = Build.path(boardID, threadID, href.slice(2)); } return container; }, @@ -3796,7 +3804,7 @@ return $.el('a', { className: 'summary', textContent: text.join(' '), - href: "/" + boardID + "/thread/" + threadID + href: Build.path(boardID, threadID) }); }, thread: function(board, data, full) { @@ -3832,12 +3840,12 @@ data = Index.liveThreadData[thread.ID]; postCount = data.replies + 1; fileCount = data.images + !!data.ext; - pageCount = Math.floor(Index.liveThreadData.keys.indexOf("" + thread.ID) / Index.threadsNumPerPage); + pageCount = Math.floor(Index.liveThreadData.keys.indexOf("" + thread.ID) / Index.threadsNumPerPage) + 1; subject = thread.OP.info.subject ? "
" + thread.OP.info.subject + "
" : ''; comment = thread.OP.nodes.comment.innerHTML.replace(/(
\s*){2,}/g, '
'); root = $.el('div', { className: 'catalog-thread', - innerHTML: "
" + postCount + " / " + fileCount + " / " + pageCount + "
" + subject + "
" + comment + "
" + innerHTML: "
" + postCount + " / " + fileCount + " / " + pageCount + "
" + subject + "
" + comment + "
" }); root.dataset.fullID = thread.fullID; if (thread.isPinned) { @@ -5316,7 +5324,7 @@ var a, frag, hash, text; frag = QuoteBacklink.frag.cloneNode(true); a = frag.lastElementChild; - a.href = "/" + quoter.board + "/thread/" + quoter.thread + "#p" + quoter; + a.href = Build.path(quoter.board.ID, quoter.thread.ID, quoter.ID); a.textContent = text = QuoteBacklink.funk(quoter.ID); if (quoter.isDead) { $.addClass(a, 'deadlink'); @@ -5888,7 +5896,7 @@ quoteID = "" + boardID + "." + postID; if (post = g.posts[quoteID]) { a = $.el('a', { - href: "/" + boardID + "/thread/" + post.thread + "#p" + postID, + href: Build.path(boardID, post.thread.ID, postID), className: post.isDead ? 'quotelink deadlink' : 'quotelink', textContent: quote }); @@ -6222,7 +6230,7 @@ _ref = $$('br', frag); for (_i = 0, _len = _ref.length; _i < _len; _i++) { node = _ref[_i]; - if (node !== frag.lastElementChild) { + if (node !== frag.lastChild) { $.replace(node, $.tn('\n>')); } } @@ -6910,7 +6918,7 @@ isReply: isReply, threadID: threadID }); - URL = threadID === postID ? "/" + g.BOARD + "/thread/" + threadID : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? "/" + g.BOARD + "/thread/" + threadID + "#p" + postID : void 0; + URL = threadID === postID ? Build.path(g.BOARD.ID, threadID) : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? Build.path(g.BOARD.ID, threadID, postID) : void 0; if (URL) { if (Conf['Open Post in New Tab']) { $.open(URL); @@ -11120,7 +11128,7 @@ } return Redirect.data = o; }, - archives: [{"uid":0,"name":"Foolz","domain":"archive.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["a","biz","co","diy","gd","jp","m","sci","sp","tg","tv","vg","vp","vr","wsg"],"files":["a","biz","gd","diy","jp","m","sci","tg","vg","vp","vr","wsg"]},{"uid":1,"name":"NSFW Foolz","domain":"nsfw.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["u"],"files":["u"]},{"uid":2,"name":"The Dark Cave","domain":"archive.thedarkcave.org","http":true,"https":true,"software":"foolfuuka","boards":["c","int","out","po"],"files":["c","po"]},{"uid":3,"name":"4plebs Archive","domain":"archive.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["adv","hr","o","pol","s4s","tg","trv","tv","x"],"files":["adv","hr","o","pol","s4s","tg","trv","tv","x"]},{"uid":18,"name":"4plebs Flash Archive","domain":"flash.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["f"],"files":["f"]},{"uid":4,"name":"Nyafuu","domain":"archive.nyafuu.org","http":true,"https":true,"software":"foolfuuka","boards":["c","e","w","wg"],"files":["c","e","w","wg"]},{"uid":5,"name":"Love is Over","domain":"loveisover.me","http":true,"https":true,"software":"foolfuuka","boards":["d","i"],"files":["d","i"]},{"uid":8,"name":"Rebecca Black Tech","domain":"rbt.asia","http":true,"https":true,"software":"fuuka","boards":["cgl","g","mu","w"],"files":["cgl","g","mu","w"]},{"uid":9,"name":"Heinessen","domain":"archive.heinessen.com","http":true,"https":false,"software":"fuuka","boards":["an","fit","k","mlp","r9k","toy"],"files":["an","fit","k","r9k","toy"]},{"uid":10,"name":"warosu","domain":"fuuka.warosu.org","http":false,"https":true,"software":"fuuka","boards":["3","biz","cgl","ck","diy","fa","g","ic","jp","lit","sci","tg","vr"],"files":["3","biz","cgl","ck","diy","fa","ic","jp","lit","sci","tg","vr"]},{"uid":15,"name":"fgts","domain":"fgts.eu","http":true,"https":true,"software":"foolfuuka","boards":["asp","cm","h","hc","hm","n","p","r","s","soc","y"],"files":["asp","cm","h","hc","hm","n","p","r","s","soc","y"]},{"uid":16,"name":"maware","domain":"archive.mawa.re","http":true,"https":false,"software":"foolfuuka","boards":["t"],"files":["t"]},{"uid":17,"name":"installgentoo.com","domain":"chan.installgentoo.com","http":true,"https":false,"software":"foolfuuka","boards":["g","t"],"files":["g","t"]},{"uid":13,"name":"Foolz Beta","domain":"beta.foolz.us","http":true,"https":true,"withCredentials":true,"software":"foolfuuka","boards":["a","biz","co","d","diy","gd","jp","m","s4s","sci","sp","tg","tv","u","v","vg","vp","vr","wsg"],"files":["a","biz","d","diy","gd","jp","m","s4s","sci","tg","u","vg","vp","vr","wsg"]}], + archives: [{"uid":0,"name":"Foolz","domain":"archive.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["a","biz","co","diy","gd","jp","m","sci","sp","tg","tv","vg","vp","vr","wsg"],"files":["a","biz","gd","diy","jp","m","sci","tg","vg","vp","vr","wsg"]},{"uid":1,"name":"NSFW Foolz","domain":"nsfw.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["u"],"files":["u"]},{"uid":2,"name":"The Dark Cave","domain":"archive.thedarkcave.org","http":true,"https":true,"software":"foolfuuka","boards":["c","int","out","po"],"files":["c","po"]},{"uid":3,"name":"4plebs Archive","domain":"archive.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["adv","hr","o","pol","s4s","tg","trv","tv","x"],"files":["adv","hr","o","pol","s4s","tg","trv","tv","x"]},{"uid":18,"name":"4plebs Flash Archive","domain":"flash.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["f"],"files":["f"]},{"uid":4,"name":"Nyafuu","domain":"archive.nyafuu.org","http":true,"https":true,"software":"foolfuuka","boards":["c","e","w","wg"],"files":["c","e","w","wg"]},{"uid":5,"name":"Love is Over","domain":"loveisover.me","http":true,"https":true,"software":"foolfuuka","boards":["d","i"],"files":["d","i"]},{"uid":8,"name":"Rebecca Black Tech","domain":"rbt.asia","http":true,"https":true,"software":"fuuka","boards":["cgl","g","mu","w"],"files":["cgl","g","mu","w"]},{"uid":9,"name":"Heinessen","domain":"archive.heinessen.com","http":true,"https":false,"software":"fuuka","boards":["an","fit","k","mlp","r9k","toy"],"files":["an","fit","k","r9k","toy"]},{"uid":10,"name":"warosu","domain":"fuuka.warosu.org","http":false,"https":true,"software":"fuuka","boards":["3","biz","cgl","ck","diy","fa","g","ic","jp","lit","sci","tg","vr"],"files":["3","biz","cgl","ck","diy","fa","ic","jp","lit","sci","tg","vr"]},{"uid":15,"name":"fgts","domain":"fgts.eu","http":true,"https":true,"software":"foolfuuka","boards":["asp","cm","h","hc","hm","n","p","r","s","soc","y"],"files":["asp","cm","h","hc","hm","n","p","r","s","soc","y"]},{"uid":16,"name":"maware","domain":"archive.mawa.re","http":true,"https":false,"software":"foolfuuka","boards":["t"],"files":["t"]},{"uid":17,"name":"installgentoo.com","domain":"chan.installgentoo.com","http":true,"https":false,"software":"foolfuuka","boards":["g","t"],"files":["g","t"]},{"uid":13,"name":"Foolz Beta","domain":"beta.foolz.us","http":true,"https":true,"withCredentials":true,"software":"foolfuuka","boards":["a","biz","co","d","diy","gd","jp","m","s4s","sci","sp","tg","tv","u","vg","vp","vr","wsg"],"files":["a","biz","d","diy","gd","jp","m","s4s","sci","tg","u","vg","vp","vr","wsg"]}], to: function(dest, data) { var archive; archive = (dest === 'search' || dest === 'board' ? Redirect.data.thread : Redirect.data[dest])[data.boardID]; @@ -12419,7 +12427,7 @@ if (g.VIEW !== 'index') { return; } - url = "/" + thread.board + "/thread/" + thread; + url = Build.path(thread.board.ID, thread.ID); if (tab) { return $.open(url); } else { @@ -13825,7 +13833,10 @@ } if (g.VIEW === 'thread') { g.THREADID = +pathname[3]; - if (pathname[2] !== 'thread' || pathname.length > 4) { + if (pathname[4] != null) { + g.SLUG = pathname[4]; + } + if (pathname[2] !== 'thread') { pathname[2] = 'thread'; history.replaceState(null, '', pathname.slice(0, 4).join('/') + location.hash); } diff --git a/builds/crx/script.js b/builds/crx/script.js index c9781e7d5..9823e7bff 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1231,7 +1231,7 @@ Post.prototype.parseQuote = function(quotelink) { var fullID, match; - if (!(match = quotelink.href.match(/boards\.4chan\.org\/([^\/]+)\/(?:res|thread)\/\d+#p(\d+)$/))) { + if (!(match = quotelink.href.match(/boards\.4chan\.org\/([^\/]+)\/(res|thread)\/\d+(.*)?\#p(\d+)$/))) { return; } this.nodes.quotelinks.push(quotelink); @@ -1245,7 +1245,7 @@ }; Post.prototype.parseFile = function(that) { - var anchor, fileEl, fileText, nameNode, size, thumb, unit, _ref, _ref1; + var anchor, fileEl, fileText, nameNode, size, thumb, unit, _ref; if (!((fileEl = $('.file', this.nodes.post)) && (thumb = $('img[data-md5]', fileEl)))) { return; } @@ -1269,10 +1269,10 @@ this.file.isImage = /(jpg|png|gif)$/i.test(this.file.URL); this.file.isVideo = /webm$/i.test(this.file.URL); if (this.file.isImage || this.file.isVideo) { - this.file.dimensions = (_ref = fileText.childNodes[2].textContent.match(/\d+x\d+/)) != null ? _ref[0] : void 0; + this.file.dimensions = fileText.childNodes[2].data.match(/\d+x\d+/)[0]; } this.file.name = !this.file.isSpoiler && (nameNode = $('a', fileText)) ? nameNode.title || nameNode.textContent : fileText.title; - return this.file.name = (_ref1 = this.file.name) != null ? _ref1.replace(/%22/g, '"') : void 0; + return this.file.name = (_ref = this.file.name) != null ? _ref.replace(/%22/g, '"') : void 0; }; Post.prototype.cleanup = function(root, post) { @@ -1282,7 +1282,7 @@ node = _ref[_i]; $.rm(node); } - _ref1 = $$('[id]', post); + _ref1 = $$('[id]:not(.exif)', post); for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { node = _ref1[_j]; node.removeAttribute('id'); @@ -2985,8 +2985,8 @@ toggleHiddenThreads: function() { $('#hidden-toggle a', Index.navLinks).textContent = (Index.showHiddenThreads = !Index.showHiddenThreads) ? 'Hide' : 'Show'; Index.sort(); - if (Conf['Index Mode'] === 'paged' && Index.getCurrentPage() > 0) { - return Index.pageNav(0); + if (Conf['Index Mode'] === 'paged' && Index.getCurrentPage() > 1) { + return Index.pageNav(1); } else { return Index.buildIndex(); } @@ -3069,7 +3069,7 @@ if (Index.cb.indexNav(a, true)) { return; } - return Index.userPageNav(+a.pathname.split('/')[2]); + return Index.userPageNav(+a.pathname.split('/')[2] || 1); }, headerNav: function(e) { var a, needChange, onSameIndex; @@ -3136,7 +3136,7 @@ if (Index.currentPage === pageNum && !Index.root.parentElement) { return; } - Navigate.pushState(pageNum === 0 ? './' : pageNum); + Navigate.pushState(pageNum === 1 ? './' : pageNum); return Index.pageLoad(pageNum); }, pageLoad: function(pageNum) { @@ -3381,7 +3381,7 @@ var err, thread, threadRoot; threadRoot = Build.thread(g.BOARD, threadData); if (thread = g.BOARD.threads[threadData.no]) { - thread.setPage(Math.floor(i / Index.threadsNumPerPage)); + thread.setPage(Math.floor(i / Index.threadsNumPerPage) + 1); thread.setCount('post', threadData.replies + 1, threadData.bumplimit); thread.setCount('file', threadData.images + !!threadData.ext, threadData.imagelimit); thread.setStatus('Sticky', !!threadData.sticky); @@ -3576,7 +3576,7 @@ switch (Conf['Index Mode']) { case 'paged': case 'infinite': - pageNum = Index.getCurrentPage(); + pageNum = Index.getCurrentPage() - 1; threadsPerPage = Index.getThreadsNumPerPage(); threads = []; i = threadsPerPage * pageNum; @@ -3704,6 +3704,17 @@ return n = (n + 1) % 3; }; })(), + path: function(boardID, threadID, postID, fragment) { + var path; + path = "/" + boardID + "/thread/" + threadID; + if ((g.SLUG != null) && threadID === g.THREADID) { + path += "/" + g.SLUG; + } + if (postID) { + path += "#" + (fragment || 'p') + postID; + } + return path; + }, postFromObject: function(data, boardID) { var o; o = { @@ -3818,9 +3829,9 @@ sticky = isSticky ? " " : ''; closed = isClosed ? " " : ''; if (isOP && g.VIEW === 'index') { - pageNum = Math.floor(Index.liveThreadData.keys.indexOf("" + postID) / Index.threadsNumPerPage); + pageNum = Math.floor(Index.liveThreadData.keys.indexOf("" + postID) / Index.threadsNumPerPage) + 1; pageIcon = " Page " + pageNum + ""; - replyLink = "   [Reply]"; + replyLink = "   [Reply]"; } else { pageIcon = ''; replyLink = ''; @@ -3828,19 +3839,16 @@ container = $.el('div', { id: "pc" + postID, className: "postContainer " + (isOP ? 'op' : 'reply') + "Container", - innerHTML: (isOP ? '' : "
>>
") + ("
") + (isOP ? fileHTML : '') + "
" + (" ") + ("" + (subject || '') + " ") + ("") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcodeIcon + userID + flag + ' ' + ("" + date + " ") + "" + ("No.") + ("" + postID + "") + pageIcon + sticky + closed + replyLink + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
' + innerHTML: (isOP ? '' : "
>>
") + ("
") + (isOP ? fileHTML : '') + "
" + (" ") + ("" + (subject || '') + " ") + ("") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcodeIcon + userID + flag + ' ' + ("" + date + " ") + "" + ("No.") + ("" + postID + "") + pageIcon + sticky + closed + replyLink + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
' }); _ref = $$('.quotelink', container); for (_i = 0, _len = _ref.length; _i < _len; _i++) { quote = _ref[_i]; href = quote.getAttribute('href'); - if (href[0] === '/') { + if (href[0] !== '#') { continue; } - if (href[0] === '#') { - href = "" + threadID + href; - } - quote.href = "/" + boardID + "/thread/" + href; + quote.href = Build.path(boardID, threadID, href.slice(2)); } return container; }, @@ -3855,7 +3863,7 @@ return $.el('a', { className: 'summary', textContent: text.join(' '), - href: "/" + boardID + "/thread/" + threadID + href: Build.path(boardID, threadID) }); }, thread: function(board, data, full) { @@ -3891,12 +3899,12 @@ data = Index.liveThreadData[thread.ID]; postCount = data.replies + 1; fileCount = data.images + !!data.ext; - pageCount = Math.floor(Index.liveThreadData.keys.indexOf("" + thread.ID) / Index.threadsNumPerPage); + pageCount = Math.floor(Index.liveThreadData.keys.indexOf("" + thread.ID) / Index.threadsNumPerPage) + 1; subject = thread.OP.info.subject ? "
" + thread.OP.info.subject + "
" : ''; comment = thread.OP.nodes.comment.innerHTML.replace(/(
\s*){2,}/g, '
'); root = $.el('div', { className: 'catalog-thread', - innerHTML: "
" + postCount + " / " + fileCount + " / " + pageCount + "
" + subject + "
" + comment + "
" + innerHTML: "
" + postCount + " / " + fileCount + " / " + pageCount + "
" + subject + "
" + comment + "
" }); root.dataset.fullID = thread.fullID; if (thread.isPinned) { @@ -5368,7 +5376,7 @@ var a, frag, hash, text; frag = QuoteBacklink.frag.cloneNode(true); a = frag.lastElementChild; - a.href = "/" + quoter.board + "/thread/" + quoter.thread + "#p" + quoter; + a.href = Build.path(quoter.board.ID, quoter.thread.ID, quoter.ID); a.textContent = text = QuoteBacklink.funk(quoter.ID); if (quoter.isDead) { $.addClass(a, 'deadlink'); @@ -5940,7 +5948,7 @@ quoteID = "" + boardID + "." + postID; if (post = g.posts[quoteID]) { a = $.el('a', { - href: "/" + boardID + "/thread/" + post.thread + "#p" + postID, + href: Build.path(boardID, post.thread.ID, postID), className: post.isDead ? 'quotelink deadlink' : 'quotelink', textContent: quote }); @@ -6284,7 +6292,7 @@ _ref = $$('br', frag); for (_i = 0, _len = _ref.length; _i < _len; _i++) { node = _ref[_i]; - if (node !== frag.lastElementChild) { + if (node !== frag.lastChild) { $.replace(node, $.tn('\n>')); } } @@ -6953,7 +6961,7 @@ isReply: isReply, threadID: threadID }); - URL = threadID === postID ? "/" + g.BOARD + "/thread/" + threadID : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? "/" + g.BOARD + "/thread/" + threadID + "#p" + postID : void 0; + URL = threadID === postID ? Build.path(g.BOARD.ID, threadID) : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? Build.path(g.BOARD.ID, threadID, postID) : void 0; if (URL) { if (Conf['Open Post in New Tab']) { $.open(URL); @@ -11134,7 +11142,7 @@ } return Redirect.data = o; }, - archives: [{"uid":0,"name":"Foolz","domain":"archive.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["a","biz","co","diy","gd","jp","m","sci","sp","tg","tv","vg","vp","vr","wsg"],"files":["a","biz","gd","diy","jp","m","sci","tg","vg","vp","vr","wsg"]},{"uid":1,"name":"NSFW Foolz","domain":"nsfw.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["u"],"files":["u"]},{"uid":2,"name":"The Dark Cave","domain":"archive.thedarkcave.org","http":true,"https":true,"software":"foolfuuka","boards":["c","int","out","po"],"files":["c","po"]},{"uid":3,"name":"4plebs Archive","domain":"archive.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["adv","hr","o","pol","s4s","tg","trv","tv","x"],"files":["adv","hr","o","pol","s4s","tg","trv","tv","x"]},{"uid":18,"name":"4plebs Flash Archive","domain":"flash.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["f"],"files":["f"]},{"uid":4,"name":"Nyafuu","domain":"archive.nyafuu.org","http":true,"https":true,"software":"foolfuuka","boards":["c","e","w","wg"],"files":["c","e","w","wg"]},{"uid":5,"name":"Love is Over","domain":"loveisover.me","http":true,"https":true,"software":"foolfuuka","boards":["d","i"],"files":["d","i"]},{"uid":8,"name":"Rebecca Black Tech","domain":"rbt.asia","http":true,"https":true,"software":"fuuka","boards":["cgl","g","mu","w"],"files":["cgl","g","mu","w"]},{"uid":9,"name":"Heinessen","domain":"archive.heinessen.com","http":true,"https":false,"software":"fuuka","boards":["an","fit","k","mlp","r9k","toy"],"files":["an","fit","k","r9k","toy"]},{"uid":10,"name":"warosu","domain":"fuuka.warosu.org","http":false,"https":true,"software":"fuuka","boards":["3","biz","cgl","ck","diy","fa","g","ic","jp","lit","sci","tg","vr"],"files":["3","biz","cgl","ck","diy","fa","ic","jp","lit","sci","tg","vr"]},{"uid":15,"name":"fgts","domain":"fgts.eu","http":true,"https":true,"software":"foolfuuka","boards":["asp","cm","h","hc","hm","n","p","r","s","soc","y"],"files":["asp","cm","h","hc","hm","n","p","r","s","soc","y"]},{"uid":16,"name":"maware","domain":"archive.mawa.re","http":true,"https":false,"software":"foolfuuka","boards":["t"],"files":["t"]},{"uid":17,"name":"installgentoo.com","domain":"chan.installgentoo.com","http":true,"https":false,"software":"foolfuuka","boards":["g","t"],"files":["g","t"]},{"uid":13,"name":"Foolz Beta","domain":"beta.foolz.us","http":true,"https":true,"withCredentials":true,"software":"foolfuuka","boards":["a","biz","co","d","diy","gd","jp","m","s4s","sci","sp","tg","tv","u","v","vg","vp","vr","wsg"],"files":["a","biz","d","diy","gd","jp","m","s4s","sci","tg","u","vg","vp","vr","wsg"]}], + archives: [{"uid":0,"name":"Foolz","domain":"archive.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["a","biz","co","diy","gd","jp","m","sci","sp","tg","tv","vg","vp","vr","wsg"],"files":["a","biz","gd","diy","jp","m","sci","tg","vg","vp","vr","wsg"]},{"uid":1,"name":"NSFW Foolz","domain":"nsfw.foolz.us","http":true,"https":true,"software":"foolfuuka","boards":["u"],"files":["u"]},{"uid":2,"name":"The Dark Cave","domain":"archive.thedarkcave.org","http":true,"https":true,"software":"foolfuuka","boards":["c","int","out","po"],"files":["c","po"]},{"uid":3,"name":"4plebs Archive","domain":"archive.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["adv","hr","o","pol","s4s","tg","trv","tv","x"],"files":["adv","hr","o","pol","s4s","tg","trv","tv","x"]},{"uid":18,"name":"4plebs Flash Archive","domain":"flash.4plebs.org","http":true,"https":true,"software":"foolfuuka","boards":["f"],"files":["f"]},{"uid":4,"name":"Nyafuu","domain":"archive.nyafuu.org","http":true,"https":true,"software":"foolfuuka","boards":["c","e","w","wg"],"files":["c","e","w","wg"]},{"uid":5,"name":"Love is Over","domain":"loveisover.me","http":true,"https":true,"software":"foolfuuka","boards":["d","i"],"files":["d","i"]},{"uid":8,"name":"Rebecca Black Tech","domain":"rbt.asia","http":true,"https":true,"software":"fuuka","boards":["cgl","g","mu","w"],"files":["cgl","g","mu","w"]},{"uid":9,"name":"Heinessen","domain":"archive.heinessen.com","http":true,"https":false,"software":"fuuka","boards":["an","fit","k","mlp","r9k","toy"],"files":["an","fit","k","r9k","toy"]},{"uid":10,"name":"warosu","domain":"fuuka.warosu.org","http":false,"https":true,"software":"fuuka","boards":["3","biz","cgl","ck","diy","fa","g","ic","jp","lit","sci","tg","vr"],"files":["3","biz","cgl","ck","diy","fa","ic","jp","lit","sci","tg","vr"]},{"uid":15,"name":"fgts","domain":"fgts.eu","http":true,"https":true,"software":"foolfuuka","boards":["asp","cm","h","hc","hm","n","p","r","s","soc","y"],"files":["asp","cm","h","hc","hm","n","p","r","s","soc","y"]},{"uid":16,"name":"maware","domain":"archive.mawa.re","http":true,"https":false,"software":"foolfuuka","boards":["t"],"files":["t"]},{"uid":17,"name":"installgentoo.com","domain":"chan.installgentoo.com","http":true,"https":false,"software":"foolfuuka","boards":["g","t"],"files":["g","t"]},{"uid":13,"name":"Foolz Beta","domain":"beta.foolz.us","http":true,"https":true,"withCredentials":true,"software":"foolfuuka","boards":["a","biz","co","d","diy","gd","jp","m","s4s","sci","sp","tg","tv","u","vg","vp","vr","wsg"],"files":["a","biz","d","diy","gd","jp","m","s4s","sci","tg","u","vg","vp","vr","wsg"]}], to: function(dest, data) { var archive; archive = (dest === 'search' || dest === 'board' ? Redirect.data.thread : Redirect.data[dest])[data.boardID]; @@ -12433,7 +12441,7 @@ if (g.VIEW !== 'index') { return; } - url = "/" + thread.board + "/thread/" + thread; + url = Build.path(thread.board.ID, thread.ID); if (tab) { return $.open(url); } else { @@ -13842,7 +13850,10 @@ } if (g.VIEW === 'thread') { g.THREADID = +pathname[3]; - if (pathname[2] !== 'thread' || pathname.length > 4) { + if (pathname[4] != null) { + g.SLUG = pathname[4]; + } + if (pathname[2] !== 'thread') { pathname[2] = 'thread'; history.replaceState(null, '', pathname.slice(0, 4).join('/') + location.hash); } diff --git a/css/style.css b/css/style.css index c65b2076c..feeb2444e 100644 --- a/css/style.css +++ b/css/style.css @@ -105,7 +105,7 @@ a[href="javascript:;"] { :root.bottom-header body { margin-bottom: 2em; } -body > .desktop:not(#boardNavDesktop):not(#boardNavDesktopFoot), +body > .desktop:not(hr):not(.navLinks):not(#boardNavDesktop):not(#boardNavDesktopFoot), :root.fourchan-x #navtopright, :root.fourchan-x #navbotright, :root.fourchan-x:not(.show-original-top-board-list) #boardNavDesktop, diff --git a/package.json b/package.json index e58de9eac..d3d740263 100755 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "grunt-contrib-concat": "~0.4.0", "grunt-contrib-copy": "~0.5.0", "grunt-contrib-watch": "~0.6.1", - "grunt-shell": "~0.6.4", + "grunt-shell": "~0.7.0", "load-grunt-tasks": "~0.4.0" }, "repository": { diff --git a/src/Archive/archives.json b/src/Archive/archives.json index f7aa7e1e1..ca1cabd60 100644 --- a/src/Archive/archives.json +++ b/src/Archive/archives.json @@ -123,6 +123,6 @@ "https": true, "withCredentials": true, "software": "foolfuuka", - "boards": ["a", "biz", "co", "d", "diy", "gd", "jp", "m", "s4s", "sci", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"], + "boards": ["a", "biz", "co", "d", "diy", "gd", "jp", "m", "s4s", "sci", "sp", "tg", "tv", "u", "vg", "vp", "vr", "wsg"], "files": ["a", "biz", "d", "diy", "gd", "jp", "m", "s4s", "sci", "tg", "u", "vg", "vp", "vr", "wsg"] }] diff --git a/src/General/Build.coffee b/src/General/Build.coffee index cb8293132..04b0a7824 100755 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -15,6 +15,11 @@ Build = thumbRotate: do -> n = 0 -> n = (n + 1) % 3 + path: (boardID, threadID, postID, fragment) -> + path = "/#{boardID}/thread/#{threadID}" + path += "/#{g.SLUG}" if g.SLUG? and threadID is g.THREADID + path += "##{fragment or 'p'}#{postID}" if postID + path postFromObject: (data, boardID) -> o = # id @@ -178,9 +183,9 @@ Build = '' if isOP and g.VIEW is 'index' - pageNum = Index.liveThreadData.keys.indexOf("#{postID}") // Index.threadsNumPerPage + pageNum = Index.liveThreadData.keys.indexOf("#{postID}") // Index.threadsNumPerPage + 1 pageIcon = " Page #{pageNum}" - replyLink = "   [Reply]" + replyLink = "   [Reply]" else pageIcon = '' replyLink = '' @@ -209,12 +214,12 @@ Build = ' ' + "#{date} " + "" + - "No." + + "No." + "#{postID}" + pageIcon + sticky + closed + replyLink + '' + @@ -226,12 +231,11 @@ Build = '' - # Fix pathnames + # Fix quote pathnames in index or cross-{board,thread} posts for quote in $$ '.quotelink', container href = quote.getAttribute 'href' - continue if href[0] is '/' # Cross-board quote, or board link - href = "#{threadID}#{href}" if href[0] is '#' - quote.href = "/#{boardID}/thread/#{href}" # Fix pathnames + continue unless href[0] is '#' + quote.href = Build.path boardID, threadID, href[2..] container @@ -243,7 +247,7 @@ Build = $.el 'a', className: 'summary' textContent: text.join ' ' - href: "/#{boardID}/thread/#{threadID}" + href: Build.path boardID, threadID thread: (board, data, full) -> Build.spoilerRange[board] = data.custom_spoiler @@ -277,7 +281,7 @@ Build = postCount = data.replies + 1 fileCount = data.images + !!data.ext - pageCount = Index.liveThreadData.keys.indexOf("#{thread.ID}") // Index.threadsNumPerPage + pageCount = Index.liveThreadData.keys.indexOf("#{thread.ID}") // Index.threadsNumPerPage + 1 subject = if thread.OP.info.subject "
#{thread.OP.info.subject}
" diff --git a/src/General/Index.coffee b/src/General/Index.coffee index d796ff5e5..a329500be 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -301,8 +301,8 @@ Index = else 'Show' Index.sort() - if Conf['Index Mode'] is 'paged' and Index.getCurrentPage() > 0 - Index.pageNav 0 + if Conf['Index Mode'] is 'paged' and Index.getCurrentPage() > 1 + Index.pageNav 1 else Index.buildIndex() @@ -360,7 +360,7 @@ Index = return e.preventDefault() return if Index.cb.indexNav a, true - Index.userPageNav +a.pathname.split('/')[2] + Index.userPageNav +a.pathname.split('/')[2] or 1 headerNav: (e) -> a = e.target @@ -411,7 +411,7 @@ Index = pageNav: (pageNum) -> return if Index.currentPage is pageNum and not Index.root.parentElement - Navigate.pushState if pageNum is 0 then './' else pageNum + Navigate.pushState if pageNum is 1 then './' else pageNum Index.pageLoad pageNum pageLoad: (pageNum) -> @@ -603,7 +603,7 @@ Index = Index.liveThreadData.forEach (threadData) -> threadRoot = Build.thread g.BOARD, threadData if thread = g.BOARD.threads[threadData.no] - thread.setPage i // Index.threadsNumPerPage + thread.setPage i // Index.threadsNumPerPage + 1 thread.setCount 'post', threadData.replies + 1, threadData.bumplimit thread.setCount 'file', threadData.images + !!threadData.ext, threadData.imagelimit thread.setStatus 'Sticky', !!threadData.sticky @@ -741,7 +741,7 @@ Index = nodes = [] switch Conf['Index Mode'] when 'paged', 'infinite' - pageNum = Index.getCurrentPage() + pageNum = Index.getCurrentPage() - 1 threadsPerPage = Index.getThreadsNumPerPage() threads = [] diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 6fde7e755..acd18d487 100755 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -18,7 +18,8 @@ Main = return Index.catalogSwitch() if g.VIEW is 'thread' g.THREADID = +pathname[3] - if pathname[2] isnt 'thread' or pathname.length > 4 + g.SLUG = pathname[4] if pathname[4]? + if pathname[2] isnt 'thread' pathname[2] = 'thread' history.replaceState null, '', pathname.slice(0,4).join('/') + location.hash diff --git a/src/General/html/Features/Thread-catalog-view.html b/src/General/html/Features/Thread-catalog-view.html index 1df9afccb..2a18fa150 100644 --- a/src/General/html/Features/Thread-catalog-view.html +++ b/src/General/html/Features/Thread-catalog-view.html @@ -1,4 +1,4 @@ - +
#{postCount} / #{fileCount} / #{pageCount} diff --git a/src/General/lib/post.class b/src/General/lib/post.class index a029ae0ed..abe0c47b4 100755 --- a/src/General/lib/post.class +++ b/src/General/lib/post.class @@ -101,8 +101,9 @@ class Post return unless match = quotelink.href.match /// boards\.4chan\.org/ ([^/]+) # boardID - /(?:res|thread)/\d+#p - (\d+) # postID + /(res|thread)/\d+ + (.*)? # thread slug + \#p(\d+) # postID $ /// @@ -138,7 +139,7 @@ class Post @file.isImage = /(jpg|png|gif)$/i.test @file.URL @file.isVideo = /webm$/i.test @file.URL if @file.isImage or @file.isVideo - @file.dimensions = fileText.childNodes[2].textContent.match(/\d+x\d+/)?[0] + @file.dimensions = fileText.childNodes[2].data.match(/\d+x\d+/)[0] @file.name = if !@file.isSpoiler and nameNode = $ 'a', fileText nameNode.title or nameNode.textContent else @@ -155,7 +156,7 @@ class Post cleanup: (root, post) -> for node in $$ '.mobile', root $.rm node - for node in $$ '[id]', post + for node in $$ '[id]:not(.exif)', post node.removeAttribute 'id' for node in $$ '.desktop', root $.rmClass node, 'desktop' diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index 5669e2981..10c00f1ff 100755 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -247,7 +247,7 @@ Keybinds = open: (thread, tab) -> return if g.VIEW isnt 'index' - url = "/#{thread.board}/thread/#{thread}" + url = Build.path thread.board.ID, thread.ID if tab $.open url else diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 12923202a..210071a95 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -228,7 +228,7 @@ QR = $.prepend frag, $.tn '[code]' $.add frag, $.tn '[/code]' for node in $$ 'br', frag - $.replace node, $.tn '\n>' unless node is frag.lastElementChild + $.replace node, $.tn '\n>' unless node is frag.lastChild for node in $$ 's', frag $.replace node, [$.tn('[spoiler]'), node.childNodes..., $.tn '[/spoiler]'] for node in $$ '.prettyprint', frag @@ -871,9 +871,9 @@ QR = QR.cooldown.set {req, post, isReply, threadID} URL = if threadID is postID # new thread - "/#{g.BOARD}/thread/#{threadID}" + Build.path g.BOARD.ID, threadID else if g.VIEW is 'index' and !QR.cooldown.auto and Conf['Open Post in New Tab'] # replying from the index - "/#{g.BOARD}/thread/#{threadID}#p#{postID}" + Build.path g.BOARD.ID, threadID, postID if URL if Conf['Open Post in New Tab'] $.open URL diff --git a/src/Quotelinks/QuoteBacklink.coffee b/src/Quotelinks/QuoteBacklink.coffee index 9e451f1a5..0d5d75b1f 100755 --- a/src/Quotelinks/QuoteBacklink.coffee +++ b/src/Quotelinks/QuoteBacklink.coffee @@ -55,7 +55,7 @@ QuoteBacklink = buildBacklink: (quoted, quoter) -> frag = QuoteBacklink.frag.cloneNode true a = frag.lastElementChild - a.href = "/#{quoter.board}/thread/#{quoter.thread}#p#{quoter}" + a.href = Build.path quoter.board.ID, quoter.thread.ID, quoter.ID a.textContent = text = QuoteBacklink.funk quoter.ID if quoter.isDead $.addClass a, 'deadlink' diff --git a/src/Quotelinks/Quotify.coffee b/src/Quotelinks/Quotify.coffee index 691312044..5186f024c 100755 --- a/src/Quotelinks/Quotify.coffee +++ b/src/Quotelinks/Quotify.coffee @@ -44,7 +44,7 @@ Quotify = # Don't add 'deadlink' when quotifying in an archived post, # and we don't know if the post died yet. a = $.el 'a', - href: "/#{boardID}/thread/#{post.thread}#p#{postID}" + href: Build.path boardID, post.thread.ID, postID className: if post.isDead then 'quotelink deadlink' else 'quotelink' textContent: quote $.extend a.dataset, {boardID, threadID: post.thread.ID, postID}