diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e2fb509c..e9c652f2a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,9 @@ -<<<<<<< HEAD -**Zixaphir**: -- Better MediaCru.sh embedding -- Infinite Scrolling - -### v1.2.41 -*2013-10-03* -======= -## 3.14.0 - *2013-11-21* +**MayhemYDG**: +- Tiny posting cooldown adjustment: + - You can post an image reply immediately after a non-image reply. - **New option**: `Auto-hide header on scroll`. - Added support for `4cdn.org`. - -## 3.13.0 - *2013-11-16* - - More index navigation improvements: - Searching in the index is now possible and will show matched OPs by: - The elapsed time since the last index refresh is now indicated at the top of the index. - New setting: `Show replies`, enabled by default. Disable it to only show OPs in the index. - -### 3.12.1 - *2013-11-04* - - The index refreshing notification will now only appear on initial page load with slow connections. -- Minor fixes. - -## 3.12.0 - *2013-11-03* - - Index navigation improvements: - You can now refresh the index page you are on with the refresh shortcut in the header bar or the same keybind for refreshing threads. - You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu:
@@ -53,48 +37,43 @@ - Navigating across index pages is now instantaneous. - Added a keybind to open the catalog search field on index pages. +- Various minor fixes -### 3.11.5 - *2013-10-03* +### v1.2.43 +*2013-11-10* -- Minor Chrome 30 fix. ->>>>>>> ce0c0c1623702e7931908183160fa04a31b26897 +**noface**: +- Strawpoll.me embedding support (as usual, only works on HTTP 4chan due to lack of HTTPS) + +### v1.2.42 +*2013-10-22* + +**Zixaphir**: +- Better MediaCru.sh embedding +- Infinite Scrolling + +### v1.2.41 +*2013-10-03* **MayhemYDG**: - Minor Chrome 30 fix -<<<<<<< HEAD ### v1.2.40 *2013-09-22* -======= -- Tiny posting cooldown adjustment: - - You can post an image reply immediately after a non-image reply. ->>>>>>> ce0c0c1623702e7931908183160fa04a31b26897 **MayhemYDG**: - /pol/ flag selector -<<<<<<< HEAD **seaweedchan**: - Delete cooldown update - Small bug fixes - Don't show warnings AND desktop notifications at the same time, and prefer QR warnings unless the document is hidden -======= -- Update posting cooldown timers to match 4chan settings: - - Cooldown may vary between inter-thread and intra-thread replies. - - Cooldown may vary when posting a file or not. - - Cooldown does not take sageing into account anymore. - - Timers vary across boards. ->>>>>>> ce0c0c1623702e7931908183160fa04a31b26897 ### v1.2.39 *2013-09-19* -<<<<<<< HEAD **seaweedchan**: - Fix thread updater bug introduced in last version -======= -- Updated post and deletion cooldown timers to match 4chan changes: they are now twice as long. ->>>>>>> ce0c0c1623702e7931908183160fa04a31b26897 ### v1.2.38 *2013-09-19* @@ -436,17 +415,8 @@ ### v1.2.3 *2013-05-14* -<<<<<<< HEAD **MayhemYDG**: - Add new archive selection -======= -- **New feature**: `Archive selection` - - Select which archive you want for specific boards and redirection type. - - Access it in the `Archives` tab of the Settings window. -- The list of archived boards will now update automatically, independently from 4chan X updates. - - If you're an archiver and want [data](https://github.com/MayhemYDG/4chan-x/blob/v3/json/archives.json) about your archive to be updated, added or removed: send a PR or open an issue. -- Fix quote previews getting 'stuck' in Opera. ->>>>>>> ce0c0c1623702e7931908183160fa04a31b26897 **seaweedchan**: - Change watcher favicon to a heart. Change class name from `.favicon` to `.watch-thread-link`. Add `.watched` if thread is watched. diff --git a/LICENSE b/LICENSE index fd717aaf9..b14fa2a9d 100755 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.2.41 - 2013-11-22 +* 4chan X - Version 1.2.43 - 2013-11-23 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.meta.js b/builds/4chan-X.meta.js index 0324d73f2..c4efe67c6 100755 --- a/builds/4chan-X.meta.js +++ b/builds/4chan-X.meta.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X -// @version 1.2.41 +// @version 1.2.43 // @minGMVer 1.12 // @minFFVer 22 // @namespace 4chan-X diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index b594b9af4..c46d61b88 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.2.41 +// @version 1.2.43 // @minGMVer 1.12 // @minFFVer 22 // @namespace 4chan-X @@ -22,7 +22,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.2.41 - 2013-11-22 +* 4chan X - Version 1.2.43 - 2013-11-23 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -340,7 +340,7 @@ doc = d.documentElement; g = { - VERSION: '1.2.41', + VERSION: '1.2.43', NAMESPACE: '4chan X.', boards: {}, threads: {}, @@ -5718,6 +5718,15 @@ } } }, + StrawPoll: { + regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+)/, + style: 'border: 0; width: 600px; height: 406px;', + el: function(a) { + return $.el('iframe', { + src: "http://strawpoll.me/embed_1/" + a.dataset.uid + }); + } + }, TwitchTV: { regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/, style: "border: none; width: 640px; height: 360px;", diff --git a/builds/crx/manifest.json b/builds/crx/manifest.json index 52a805af7..e5e00f3a4 100755 --- a/builds/crx/manifest.json +++ b/builds/crx/manifest.json @@ -1,6 +1,6 @@ { "name": "4chan X", - "version": "1.2.41", + "version": "1.2.43", "manifest_version": 2, "description": "Cross-browser userscript for maximum lurking on 4chan.", "icons": { diff --git a/builds/crx/script.js b/builds/crx/script.js index f46f4e729..9850f6274 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.2.41 - 2013-11-22 +* 4chan X - Version 1.2.43 - 2013-11-23 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -82,7 +82,7 @@ 'use strict'; (function() { - var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Gallery, Get, Header, IDColor, ImageExpand, ImageHover, ImageLoader, InfiniScroll, Keybinds, Linkify, Main, Menu, Nav, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g, + var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Gallery, Get, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, InfiniScroll, Keybinds, Linkify, Main, Menu, Nav, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g, __slice = [].slice, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __hasProp = {}.hasOwnProperty, @@ -233,6 +233,11 @@ 'sageEmoji': '4chan SS', 'emojiPos': 'before', 'Custom CSS': false, + Index: { + 'Index Mode': 'paged', + 'Index Sort': 'bump', + 'Show Replies': true + }, Header: { 'Fixed Header': true, 'Header auto-hide': false, @@ -313,7 +318,7 @@ doc = d.documentElement; g = { - VERSION: '1.2.41', + VERSION: '1.2.43', NAMESPACE: '4chan X.', boards: {}, threads: {}, @@ -2054,6 +2059,610 @@ } }; + Index = { + init: function() { + var input, label, modeEntry, repliesEntry, sortEntry, _i, _j, _len, _len1, _ref, _ref1; + + if (g.VIEW !== 'index' || g.BOARD.ID === 'f') { + return; + } + this.button = $.el('a', { + className: 'index-refresh-shortcut fa fa-refresh', + title: 'Refresh Index', + href: 'javascript:;' + }); + $.on(this.button, 'click', this.update); + Header.addShortcut(this.button, 1); + modeEntry = { + el: $.el('span', { + textContent: 'Index mode' + }), + subEntries: [ + { + el: $.el('label', { + innerHTML: ' Paged' + }) + }, { + el: $.el('label', { + innerHTML: ' All threads' + }) + } + ] + }; + _ref = modeEntry.subEntries; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + label = _ref[_i]; + input = label.el.firstChild; + input.checked = Conf['Index Mode'] === input.value; + $.on(input, 'change', $.cb.value); + $.on(input, 'change', this.cb.mode); + } + sortEntry = { + el: $.el('span', { + textContent: 'Sort by' + }), + subEntries: [ + { + el: $.el('label', { + innerHTML: ' Bump order' + }) + }, { + el: $.el('label', { + innerHTML: ' Last reply' + }) + }, { + el: $.el('label', { + innerHTML: ' Creation date' + }) + }, { + el: $.el('label', { + innerHTML: ' Reply count' + }) + }, { + el: $.el('label', { + innerHTML: ' File count' + }) + } + ] + }; + _ref1 = sortEntry.subEntries; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + label = _ref1[_j]; + input = label.el.firstChild; + input.checked = Conf['Index Sort'] === input.value; + $.on(input, 'change', $.cb.value); + $.on(input, 'change', this.cb.sort); + } + repliesEntry = { + el: $.el('label', { + innerHTML: ' Show replies' + }) + }; + input = repliesEntry.el.firstChild; + input.checked = Conf['Show Replies']; + $.on(input, 'change', $.cb.checked); + $.on(input, 'change', this.cb.replies); + $.event('AddMenuEntry', { + type: 'header', + el: $.el('span', { + textContent: 'Index Navigation' + }), + order: 90, + subEntries: [modeEntry, sortEntry, repliesEntry] + }); + $.addClass(doc, 'index-loading'); + this.update(); + this.root = $.el('div', { + className: 'board' + }); + this.pagelist = $.el('div', { + className: 'pagelist', + hidden: true, + innerHTML: "
Catalog
" + }); + this.navLinks = $.el('div', { + className: 'navLinks', + innerHTML: "[Catalog] [" + }); + this.searchInput = $('#index-search', this.navLinks); + this.currentPage = this.getCurrentPage(); + $.on(window, 'popstate', this.cb.popstate); + $.on(this.pagelist, 'click', this.cb.pageNav); + $.on(this.searchInput, 'input', this.onSearchInput); + $.on($('#index-search-clear', this.navLinks), 'click', this.clearSearch); + return $.asap((function() { + return $('.board', doc) || d.readyState !== 'loading'; + }), function() { + var board, navLink, _k, _len2, _ref2; + + board = $('.board'); + $.replace(board, Index.root); + d.implementation.createDocument(null, null, null).appendChild(board); + _ref2 = $$('.navLinks'); + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + navLink = _ref2[_k]; + $.rm(navLink); + } + $.after($.x('child::form/preceding-sibling::hr[1]'), Index.navLinks); + $.rmClass(doc, 'index-loading'); + return $.asap((function() { + return $('.pagelist') || d.readyState !== 'loading'; + }), function() { + return $.replace($('.pagelist'), Index.pagelist); + }); + }); + }, + cb: { + mode: function() { + Index.togglePagelist(); + return Index.buildIndex(); + }, + sort: function() { + Index.sort(); + return Index.buildIndex(); + }, + replies: function() { + Index.buildThreads(); + Index.sort(); + return Index.buildIndex(); + }, + popstate: function(e) { + var pageNum; + + pageNum = Index.getCurrentPage(); + if (Index.currentPage !== pageNum) { + return Index.pageLoad(pageNum); + } + }, + pageNav: function(e) { + var a; + + if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) { + return; + } + switch (e.target.nodeName) { + case 'BUTTON': + a = e.target.parentNode; + break; + case 'A': + a = e.target; + break; + default: + return; + } + if (a.textContent === 'Catalog') { + return; + } + e.preventDefault(); + return Index.pageNav(+a.pathname.split('/')[2]); + } + }, + scrollToIndex: function() { + return Header.scrollToIfNeeded(Index.root); + }, + getCurrentPage: function() { + return +window.location.pathname.split('/')[2]; + }, + pageNav: function(pageNum) { + if (Index.currentPage === pageNum) { + return; + } + history.pushState(null, '', pageNum === 0 ? './' : pageNum); + return Index.pageLoad(pageNum); + }, + pageLoad: function(pageNum) { + Index.currentPage = pageNum; + if (Conf['Index Mode'] !== 'paged') { + return; + } + Index.buildIndex(); + Index.setPage(); + return Index.scrollToIndex(); + }, + getPagesNum: function() { + if (Index.isSearching) { + return Math.ceil((Index.sortedNodes.length / 2) / Index.threadsNumPerPage); + } else { + return Index.pagesNum; + } + }, + getMaxPageNum: function() { + return Math.max(0, Index.getPagesNum() - 1); + }, + togglePagelist: function() { + return Index.pagelist.hidden = Conf['Index Mode'] !== 'paged'; + }, + buildPagelist: function() { + var a, i, maxPageNum, nodes, pagesRoot, _i; + + pagesRoot = $('.pages', Index.pagelist); + maxPageNum = Index.getMaxPageNum(); + if (pagesRoot.childElementCount !== maxPageNum + 1) { + nodes = []; + for (i = _i = 0; _i <= maxPageNum; i = _i += 1) { + a = $.el('a', { + textContent: i, + href: i ? i : './' + }); + nodes.push($.tn('['), a, $.tn('] ')); + } + $.rmAll(pagesRoot); + $.add(pagesRoot, nodes); + } + return Index.togglePagelist(); + }, + setPage: function() { + var a, href, maxPageNum, next, pageNum, pagesRoot, prev, strong; + + pageNum = Index.getCurrentPage(); + maxPageNum = Index.getMaxPageNum(); + pagesRoot = $('.pages', Index.pagelist); + prev = pagesRoot.previousSibling.firstChild; + next = pagesRoot.nextSibling.firstChild; + href = Math.max(pageNum - 1, 0); + prev.href = href === 0 ? './' : href; + prev.firstChild.disabled = href === pageNum; + href = Math.min(pageNum + 1, maxPageNum); + next.href = href === 0 ? './' : href; + next.firstChild.disabled = href === pageNum; + if (strong = $('strong', pagesRoot)) { + if (+strong.textContent === pageNum) { + return; + } + $.replace(strong, strong.firstChild); + } else { + strong = $.el('strong'); + } + a = pagesRoot.children[pageNum]; + $.before(a, strong); + return $.add(strong, a); + }, + update: function() { + var now, _ref, _ref1; + + if (!navigator.onLine) { + return; + } + if ((_ref = Index.req) != null) { + _ref.abort(); + } + if ((_ref1 = Index.notice) != null) { + _ref1.close(); + } + if (d.readyState !== 'loading') { + Index.notice = new Notice('info', 'Refreshing index...'); + } else { + now = Date.now(); + $.ready(function() { + return setTimeout((function() { + if (!(Index.req && !Index.notice)) { + return; + } + return Index.notice = new Notice('info', 'Refreshing index...'); + }), 5 * $.SECOND - (Date.now() - now)); + }); + } + Index.req = $.ajax("//a.4cdn.org/" + g.BOARD + "/catalog.json", { + onabort: Index.load, + onloadend: Index.load + }, { + whenModified: true + }); + return $.addClass(Index.button, 'fa-spin'); + }, + load: function(e) { + var err, notice, req, timeEl; + + $.rmClass(Index.button, 'fa-spin'); + req = Index.req, notice = Index.notice; + delete Index.req; + delete Index.notice; + if (e.type === 'abort') { + req.onloadend = null; + notice.close(); + return; + } + try { + if (req.status === 200) { + Index.parse(JSON.parse(req.response)); + } + } catch (_error) { + err = _error; + c.error('Index failure:', err.stack); + if (notice) { + notice.setType('error'); + notice.el.lastElementChild.textContent = 'Index refresh failed.'; + setTimeout(notice.close, 2 * $.SECOND); + } else { + new Notice('error', 'Index refresh failed.', 2); + } + return; + } + if (notice) { + notice.setType('success'); + notice.el.lastElementChild.textContent = 'Index refreshed!'; + setTimeout(notice.close, $.SECOND); + } + timeEl = $('#index-last-refresh', Index.navLinks); + timeEl.dataset.utc = e.timeStamp; + RelativeDates.update(timeEl); + return Index.scrollToIndex(); + }, + parse: function(pages) { + Index.parseThreadList(pages); + Index.buildThreads(); + Index.sort(); + Index.buildIndex(); + Index.buildPagelist(); + return Index.setPage(); + }, + parseThreadList: function(pages) { + var thread, threadID, _ref, _ref1; + + Index.pagesNum = pages.length; + Index.threadsNumPerPage = pages[0].threads.length; + Index.liveThreadData = pages.reduce((function(arr, next) { + return arr.concat(next.threads); + }), []); + Index.liveThreadIDs = Index.liveThreadData.map(function(data) { + return data.no; + }); + _ref = g.BOARD.threads; + for (threadID in _ref) { + thread = _ref[threadID]; + if (_ref1 = thread.ID, __indexOf.call(Index.liveThreadIDs, _ref1) < 0) { + thread.collect(); + } + } + }, + buildThreads: function() { + var err, errors, i, posts, thread, threadData, threadRoot, threads, _i, _len, _ref; + + Index.nodes = []; + threads = []; + posts = []; + _ref = Index.liveThreadData; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + threadData = _ref[i]; + threadRoot = Build.thread(g.BOARD, threadData); + Index.nodes.push(threadRoot, $.el('hr')); + if (thread = g.BOARD.threads[threadData.no]) { + thread.setPage(Math.floor(i / Index.threadsNumPerPage)); + thread.setStatus('Sticky', !!threadData.sticky); + thread.setStatus('Closed', !!threadData.closed); + } else { + thread = new Thread(threadData.no, g.BOARD); + threads.push(thread); + } + if (thread.ID in thread.posts) { + continue; + } + try { + posts.push(new Post($('.opContainer', threadRoot), thread, g.BOARD)); + } catch (_error) { + err = _error; + if (!errors) { + errors = []; + } + errors.push({ + message: "Parsing of Post No." + thread + " failed. Post will be skipped.", + error: err + }); + } + } + if (errors) { + Main.handleErrors(errors); + } + $.nodes(Index.nodes); + Main.callbackNodes(Thread, threads); + Main.callbackNodes(Post, posts); + return $.event('IndexRefresh'); + }, + buildReplies: function(threadRoots) { + var data, err, errors, i, lastReplies, node, nodes, post, posts, thread, threadRoot, _i, _j, _len, _len1; + + posts = []; + for (_i = 0, _len = threadRoots.length; _i < _len; _i += 2) { + threadRoot = threadRoots[_i]; + thread = Get.threadFromRoot(threadRoot); + i = Index.liveThreadIDs.indexOf(thread.ID); + if (!(lastReplies = Index.liveThreadData[i].last_replies)) { + continue; + } + nodes = []; + for (_j = 0, _len1 = lastReplies.length; _j < _len1; _j++) { + data = lastReplies[_j]; + if (post = thread.posts[data.no]) { + nodes.push(post.nodes.root); + continue; + } + nodes.push(node = Build.postFromObject(data, thread.board.ID)); + try { + posts.push(new Post(node, thread, thread.board)); + } catch (_error) { + err = _error; + if (!errors) { + errors = []; + } + errors.push({ + message: "Parsing of Post No." + data.no + " failed. Post will be skipped.", + error: err + }); + } + } + $.add(threadRoot, nodes); + } + if (errors) { + Main.handleErrors(errors); + } + return Main.callbackNodes(Post, posts); + }, + sort: function() { + var i, offset, sortedThreadIDs, threadID, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; + + switch (Conf['Index Sort']) { + case 'bump': + sortedThreadIDs = Index.liveThreadIDs; + break; + case 'lastreply': + sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { + if ('last_replies' in a) { + a = a.last_replies[a.last_replies.length - 1]; + } + if ('last_replies' in b) { + b = b.last_replies[b.last_replies.length - 1]; + } + return b.no - a.no; + }).map(function(data) { + return data.no; + }); + break; + case 'birth': + sortedThreadIDs = __slice.call(Index.liveThreadIDs).sort(function(a, b) { + return b - a; + }); + break; + case 'replycount': + sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { + return b.replies - a.replies; + }).map(function(data) { + return data.no; + }); + break; + case 'filecount': + sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { + return b.images - a.images; + }).map(function(data) { + return data.no; + }); + } + Index.sortedNodes = []; + for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { + threadID = sortedThreadIDs[_i]; + i = Index.liveThreadIDs.indexOf(threadID) * 2; + Index.sortedNodes.push(Index.nodes[i], Index.nodes[i + 1]); + } + if (Index.isSearching) { + Index.sortedNodes = Index.querySearch(Index.searchInput.value) || Index.sortedNodes; + } + offset = 0; + _ref = Index.sortedNodes; + for (i = _j = 0, _len1 = _ref.length; _j < _len1; i = _j += 2) { + threadRoot = _ref[i]; + if (Get.threadFromRoot(threadRoot).isSticky) { + (_ref1 = Index.sortedNodes).splice.apply(_ref1, [offset++ * 2, 0].concat(__slice.call(Index.sortedNodes.splice(i, 2)))); + } + } + if (!Conf['Filter']) { + return; + } + offset = 0; + _ref2 = Index.sortedNodes; + for (i = _k = 0, _len2 = _ref2.length; _k < _len2; i = _k += 2) { + threadRoot = _ref2[i]; + if (Get.threadFromRoot(threadRoot).isOnTop) { + (_ref3 = Index.sortedNodes).splice.apply(_ref3, [offset++ * 2, 0].concat(__slice.call(Index.sortedNodes.splice(i, 2)))); + } + } + }, + buildIndex: function() { + var nodes, nodesPerPage, pageNum; + + if (Conf['Index Mode'] === 'paged') { + pageNum = Index.getCurrentPage(); + nodesPerPage = Index.threadsNumPerPage * 2; + nodes = Index.sortedNodes.slice(nodesPerPage * pageNum, nodesPerPage * (pageNum + 1)); + } else { + nodes = Index.sortedNodes; + } + $.rmAll(Index.root); + if (Conf['Show Replies']) { + Index.buildReplies(nodes); + } + $.event('IndexBuild', nodes); + return $.add(Index.root, nodes); + }, + isSearching: false, + clearSearch: function() { + Index.searchInput.value = null; + Index.onSearchInput(); + return Index.searchInput.focus(); + }, + onSearchInput: function() { + var pageNum; + + if (Index.isSearching = !!Index.searchInput.value.trim()) { + if (!Index.searchInput.dataset.searching) { + Index.searchInput.dataset.searching = 1; + Index.pageBeforeSearch = Index.getCurrentPage(); + pageNum = 0; + } else { + pageNum = Index.getCurrentPage(); + } + } else { + pageNum = Index.pageBeforeSearch; + delete Index.pageBeforeSearch; + delete Index.searchInput.dataset.searching; + } + Index.sort(); + if (Conf['Index Mode'] === 'paged') { + pageNum = Math.min(pageNum, Index.getMaxPageNum()); + } + Index.buildPagelist(); + if (Index.currentPage === pageNum) { + Index.buildIndex(); + return Index.setPage(); + } else { + return Index.pageNav(pageNum); + } + }, + querySearch: function(query) { + var keywords; + + if (!(keywords = query.toLowerCase().match(/\S+/g))) { + return; + } + return Index.search(keywords); + }, + search: function(keywords) { + var found, i, threadRoot, _i, _len, _ref; + + found = []; + _ref = Index.sortedNodes; + for (i = _i = 0, _len = _ref.length; _i < _len; i = _i += 2) { + threadRoot = _ref[i]; + if (Index.searchMatch(Get.threadFromRoot(threadRoot), keywords)) { + found.push(Index.sortedNodes[i], Index.sortedNodes[i + 1]); + } + } + return found; + }, + searchMatch: function(thread, keywords) { + var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1; + + _ref = thread.OP, info = _ref.info, file = _ref.file; + text = []; + _ref1 = ['comment', 'subject', 'name', 'tripcode', 'email']; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + key = _ref1[_i]; + if (key in info) { + text.push(info[key]); + } + } + if (file) { + text.push(file.name); + } + text = text.join(' ').toLowerCase(); + for (_j = 0, _len1 = keywords.length; _j < _len1; _j++) { + keyword = keywords[_j]; + if (-1 === text.indexOf(keyword)) { + return false; + } + } + return true; + } + }; + Build = { spoilerRange: {}, shortFilename: function(filename, isReply) { @@ -2198,7 +2807,7 @@ container = $.el('div', { id: "pc" + postID, className: "postContainer " + (isOP ? 'op' : 'reply') + "Container", - innerHTML: "" + innerHTML: "" + (isOP ? '' : "
>>
") + "
" + (name || '') + "" + (tripcode + capcodeStart + capcode + userID + flag + sticky + closed) + "
" + subject + "
" + date + "No." + postID + "
" + (isOP ? fileHTML : '') + "
" + subject + "" + emailStart + "" + (name || '') + "" + (tripcode + capcodeStart + emailEnd + capcode + userID + flag) + "" + " " + "" + date + "" + " " + "No." + postID + "" + (pageIcon + sticky + closed + replyLink) + "
" + (isOP ? '' : fileHTML) + "
" + (comment || '') + "
" + " " + "
" }); _ref = $$('.quotelink', container); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -5114,6 +5723,15 @@ } } }, + StrawPoll: { + regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+)/, + style: 'border: 0; width: 600px; height: 406px;', + el: function(a) { + return $.el('iframe', { + src: "http://strawpoll.me/embed_1/" + a.dataset.uid + }); + } + }, TwitchTV: { regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/, style: "border: none; width: 640px; height: 360px;", @@ -11994,8 +12612,7 @@ 'Index Navigation': Nav, 'Keybinds': Keybinds, 'Show Dice Roll': Dice, - 'Banner': Banner, - 'Infinite Scrolling': InfiniScroll + 'Banner': Banner }); $.on(d, 'AddCallback', Main.addCallback); return $.ready(Main.initReady); @@ -12209,7 +12826,7 @@ return Klass.callbacks.push(obj.callback); }, handleErrors: function(errors) { - var div, err, error, logs, _i, _len; + var div, error, logs, _i, _len; if (!(errors instanceof Array)) { error = errors; @@ -12233,12 +12850,7 @@ }); for (_i = 0, _len = errors.length; _i < _len; _i++) { error = errors[_i]; - try { - $.add(logs, Main.parseError(error)); - } catch (_error) { - err = _error; - c.error(error.message, error.stack); - } + $.add(logs, Main.parseError(error)); } return new Notice('error', [div, logs], 30); }, diff --git a/img/changelog/3.9.0/0.png b/img/changelog/3.9.0/0.png deleted file mode 100644 index 36509d96d..000000000 Binary files a/img/changelog/3.9.0/0.png and /dev/null differ diff --git a/latest.js b/latest.js index 2fa58a119..bc17c0c33 100755 --- a/latest.js +++ b/latest.js @@ -1 +1 @@ -postMessage({version:'1.2.41'},'*') +postMessage({version:'1.2.43'},'*') diff --git a/package.json b/package.json index 6f2262747..085fd68ea 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "4chan-X", - "version": "1.2.41", + "version": "1.2.43", "description": "Cross-browser userscript for maximum lurking on 4chan.", "meta": { "name": "4chan X", diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 72ba89654..164756d07 100755 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -346,6 +346,13 @@ Linkify = api: (uid) -> "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/#{uid}" text: (_) -> _.title + StrawPoll: + regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+)/ + style: 'border: 0; width: 600px; height: 406px;' + el: (a) -> + $.el 'iframe', + src: "http://strawpoll.me/embed_1/#{a.dataset.uid}" + TwitchTV: regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/ style: "border: none; width: 640px; height: 360px;"