diff --git a/CHANGELOG.md b/CHANGELOG.md index e4274c0f3..fb8b47c62 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ The attributions below are for work that has been incorporated into the script a The links to individual versions below are to copies of the script with the update URL removed. If you want automatic updates, install the script from the links on the [main page](https://github.com/ccd0/4chan-x). + +### v1.9.13.0 +*2014-11-23* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.13.0/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.13.0/builds/4chan-X-noupdate.crx "Chromium version")] + +**ccd0** +- Improve unread count compatibility with quote threading. +- Add `Fullscreen Gallery` option (off by default). +- Make close, pause, and slideshow keybinds of gallery configurable. + ### v1.9.12.5 *2014-11-22* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.12.5/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.12.5/builds/4chan-X-noupdate.crx "Chromium version")] diff --git a/LICENSE b/LICENSE index 3b441c6ef..a4c2afdab 100755 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.9.12.5 +* 4chan X - Version 1.9.13.0 * * Licensed under the MIT license. * https://github.com/ccd0/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X-beta.crx b/builds/4chan-X-beta.crx index 40b4b31b4..4a05feedc 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 237e3d99a..dd9180555 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.9.12.5 +// @version 1.9.13.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 11136873d..63af86101 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.9.12.5 +// @version 1.9.13.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -24,7 +24,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.9.12.5 +* 4chan X - Version 1.9.13.0 * * Licensed under the MIT license. * https://github.com/ccd0/4chan-x/blob/master/LICENSE @@ -178,6 +178,7 @@ 'Image Hover': [true, 'Show full image / video on mouseover.'], 'Image Hover in Catalog': [false, 'Show full image / video on mouseover in 4chan X catalog.'], 'Gallery': [true, 'Adds a simple and cute image gallery.'], + 'Fullscreen Gallery': [false, 'Open gallery in fullscreen mode.'], 'PDF in Gallery': [false, 'Show PDF files in gallery.'], 'Sauce': [true, 'Add sauce links to images.'], 'Reveal Spoiler Thumbnails': [false, 'Replace spoiler thumbnails with the original image.'], @@ -267,7 +268,7 @@ 'Fit Width': [true], 'Fit Height': [true], 'Scroll to Post': [true], - 'Slide Delay': [5.0] + 'Slide Delay': [6.0] }, threadWatcher: { 'Current Board': [false, 'Only show watched threads from the current board.'], @@ -330,7 +331,7 @@ 'Open empty QR': ['q', 'Open QR without post number inserted.'], 'Open QR': ['Shift+q', 'Open QR with post number inserted.'], 'Open settings': ['Alt+o', 'Open Settings.'], - 'Close': ['Esc', 'Close Settings, Notifications or QR.'], + 'Close': ['Esc', 'Close Settings/Notifications/QR/Gallery.'], 'Spoiler tags': ['Ctrl+s', 'Insert spoiler tags.'], 'Code tags': ['Alt+c', 'Insert code tags.'], 'Eqn tags': ['Alt+e', 'Insert eqn tags.'], @@ -342,6 +343,8 @@ 'Expand image': ['Shift+e', 'Expand selected image.'], 'Expand images': ['e', 'Expand all images.'], 'Open Gallery': ['g', 'Opens the gallery.'], + 'Pause': ['p', 'Pause/play videos in the gallery.'], + 'Slideshow': ['s', 'Toggle the gallery slideshow mode.'], 'fappeTyme': ['f', 'Toggle Fappe Tyme.'], 'werkTyme': ['Shift+w', 'Toggle Werk Tyme.'], 'Front page': ['1', 'Jump to front page.'], @@ -385,7 +388,7 @@ doc = d.documentElement; g = { - VERSION: '1.9.12.5', + VERSION: '1.9.13.0', NAMESPACE: '4chan X.', NAME: '4chan X', FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions', @@ -708,6 +711,15 @@ } }; + $.one = function(el, events, handler) { + var cb; + cb = function(e) { + $.off(el, events, cb); + return handler.call(this, e); + }; + return $.on(el, events, cb); + }; + $.event = function(event, detail, root) { if (root == null) { root = d; @@ -6026,9 +6038,7 @@ el: this.controls, order: 98 }); - if (!Conf['Unread Count']) { - $.on(d, '4chanXInitFinished', this.ready); - } + $.on(d, '4chanXInitFinished', this.ready); return Post.callbacks.push({ name: 'Quote Threading', cb: this.node @@ -6044,10 +6054,8 @@ return post.cb(true); } }); - if (Conf['Unread Count'] && Unread.thread.OP.nodes.root.parentElement.parentElement) { - Unread.read(); - return Unread.update(); - } + Unread.read(); + return Unread.update(); }, node: function() { var keys, len, posts, quote, _i, _len, _ref; @@ -6055,9 +6063,7 @@ if (this.isClone || !QuoteThreading.enabled) { return; } - if (Conf['Unread Count']) { - Unread.addPost(this); - } + Unread.addPost(this); if (this.thread.OP === this || this.isHidden) { return; } @@ -6087,7 +6093,7 @@ if (!force) { height = doc.clientHeight; _ref = root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top; - if (!((Conf['Unread Count'] && posts[post.ID]) || ((bottom < height) && (top > 0)))) { + if (!(posts[post.ID] || ((bottom < height) && (top > 0)))) { return false; } } @@ -6103,9 +6109,6 @@ $.after(root, threadContainer); $.addClass(root, 'threadOP'); } - if (!Conf['Unread Count']) { - return true; - } if (post = posts[post.ID]) { posts.after(post, posts[this.ID]); } else if (posts[this.ID]) { @@ -8298,6 +8301,17 @@ } } } + if (Conf['Fullscreen Gallery']) { + $.one(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', function() { + return $.on(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', cb.close); + }); + if (typeof doc.mozRequestFullScreen === "function") { + doc.mozRequestFullScreen(); + } + if (typeof doc.webkitRequestFullScreen === "function") { + doc.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } + } $.addClass(doc, 'gallery-open'); $.add(d.body, dialog); nodes.thumbs.scrollTop = 0; @@ -8457,7 +8471,7 @@ } cb = (function() { switch (key) { - case 'Esc': + case Conf['Close']: case Conf['Open Gallery']: return Gallery.cb.close; case 'Right': @@ -8467,9 +8481,9 @@ case 'Left': case '': return Gallery.cb.prev; - case 'p': + case Conf['Pause']: return Gallery.cb.pause; - case 's': + case Conf['Slideshow']: return Gallery.cb.toggleSlideshow; } })(); @@ -8553,6 +8567,15 @@ } $.rm(Gallery.nodes.el); $.rmClass(doc, 'gallery-open'); + if (Conf['Fullscreen Gallery']) { + $.off(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', Gallery.cb.close); + if (typeof d.mozCancelFullScreen === "function") { + d.mozCancelFullScreen(); + } + if (typeof d.webkitExitFullscreen === "function") { + d.webkitExitFullscreen(); + } + } delete Gallery.nodes; delete Gallery.fullIDs; doc.style.overflow = ''; @@ -11786,7 +11809,7 @@ Unread = { init: function() { - if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Unread Line'] && !Conf['Desktop Notifications'] && !(Conf['Thread Watcher'] && Conf['Show Unread Count'])) { + if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Unread Line'] && !Conf['Scroll to Last Read Post'] && !Conf['Thread Watcher'] && !Conf['Desktop Notifications'] && !Conf['Quote Threading']) { return; } this.db = new DataBoard('lastReadPosts', this.sync); @@ -11809,7 +11832,7 @@ threadID: this.ID, defaultValue: 0 }); - $.on(d, '4chanXInitFinished', Unread.ready); + $.one(d, '4chanXInitFinished', Unread.ready); $.on(d, 'ThreadUpdate', Unread.onUpdate); $.on(d, 'scroll visibilitychange', Unread.read); if (Conf['Unread Line'] && !Conf['Quote Threading']) { @@ -11818,7 +11841,6 @@ }, ready: function() { var posts; - $.off(d, '4chanXInitFinished', Unread.ready); if (!Conf['Quote Threading']) { posts = []; Unread.thread.posts.forEach(function(post) { @@ -11836,31 +11858,26 @@ } }, scroll: function() { - var down, hash, keys, post, posts, root; + var ID, hash, posts, root, _i, _ref; if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { return; } - if (post = Unread.posts.first) { - while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.data.nodes.root)) { - if (!(post = Get.postFromRoot(root)).isHidden) { - break; - } + posts = Unread.thread.posts; + _ref = posts.keys; + for (_i = _ref.length - 1; _i >= 0; _i += -1) { + ID = _ref[_i]; + if (!(+ID <= Unread.lastReadPost)) { + continue; } - if (!root) { - return; + root = posts[ID].nodes.root; + if (root.getBoundingClientRect().height) { + Header.scrollToIfNeeded(root, true); + break; } - down = true; - } else { - posts = Unread.thread.posts; - keys = posts.keys; - root = posts[keys[keys.length - 1]].nodes.root; - } - if (Header.getBottomOf(root) < 0) { - return Header.scrollTo(root, down); } }, sync: function() { - var ID, lastReadPost, post; + var ID, lastReadPost, _i, _len, _ref; if (Unread.lastReadPost == null) { return; } @@ -11873,13 +11890,12 @@ return; } Unread.lastReadPost = lastReadPost; - post = Unread.posts.first; - while (post) { - if (post.ID > Unread.lastReadPost) { + _ref = Unread.thread.posts.keys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ID = _ref[_i]; + if (+ID > Unread.lastReadPost) { break; } - ID = post.ID; - post = post.next; Unread.posts.rm(ID); delete Unread.postsQuotingYou[ID]; } @@ -11901,13 +11917,14 @@ return Unread.addPostQuotingYou(post); }, addPosts: function(posts) { - var post, _i, _len, _ref, _ref1; + var oldCount, post, _i, _len; + oldCount = Unread.posts.length; for (_i = 0, _len = posts.length; _i < _len; _i++) { post = posts[_i]; Unread.addPost(post); } if (Conf['Unread Line'] && !Conf['Quote Threading']) { - Unread.setLine((_ref = (_ref1 = Unread.posts.first) != null ? _ref1.data : void 0, __indexOf.call(posts, _ref) >= 0)); + Unread.setLine(oldCount === 0 && Unread.posts.length !== 0); } Unread.read(); return Unread.update(); @@ -11971,28 +11988,25 @@ if (!posts[ID]) { return; } - if (post === posts.first && !(Conf['Quote Threading'] && Unread.posts.length)) { - Unread.lastReadPost = ID; - Unread.saveLastReadPost(); - } posts.rm(ID); delete Unread.postsQuotingYou[ID]; + Unread.saveLastReadPost(); return Unread.update(); }, read: $.debounce(100, function(e) { - var ID, data, height, maxID, post, posts, _ref; + var ID, count, data, height, post, posts, _ref; if (d.hidden || !Unread.posts.length) { return; } height = doc.clientHeight; posts = Unread.posts; - maxID = 0; + count = 0; while (post = posts.first) { if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { break; } ID = post.ID, data = post.data; - maxID = Math.max(maxID, ID); + count++; posts.rm(ID); delete Unread.postsQuotingYou[ID]; if (Conf['Mark Quotes of You'] && ((_ref = QR.db) != null ? _ref.get({ @@ -12003,23 +12017,30 @@ QuoteYou.lastRead = data.nodes.root; } } - if (!maxID) { + if (!count) { return; } - if (!(Conf['Quote Threading'] && posts.length)) { - if (Unread.lastReadPost < maxID || !Unread.lastReadPost) { - Unread.lastReadPost = maxID; - } - Unread.saveLastReadPost(); - } + Unread.saveLastReadPost(); if (e) { return Unread.update(); } }), saveLastReadPost: $.debounce(2 * $.SECOND, function() { + var ID, _i, _len, _ref; + _ref = Unread.thread.posts.keys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ID = _ref[_i]; + if (Unread.posts[ID]) { + break; + } + if (+ID > Unread.lastReadPost) { + Unread.lastReadPost = +ID; + } + } if (Unread.thread.isDead && !Unread.thread.isArchived) { return; } + Unread.db.forceSync(); return Unread.db.set({ boardID: Unread.thread.board.ID, threadID: Unread.thread.ID, @@ -12027,15 +12048,20 @@ }); }), setLine: function(force) { - var post; + var ID, posts, _i, _ref; if (!(d.hidden || force === true)) { return; } - if (!(post = Unread.posts.first)) { + if (!Unread.posts.length) { return $.rm(Unread.hr); } - if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.data.nodes.root)) { - return $.before(post.data.nodes.root, Unread.hr); + posts = Unread.thread.posts; + _ref = posts.keys; + for (_i = _ref.length - 1; _i >= 0; _i += -1) { + ID = _ref[_i]; + if (+ID <= Unread.lastReadPost) { + return $.after(posts[ID].nodes.root, Unread.hr); + } } }, update: function() { @@ -13169,7 +13195,7 @@ Gallery.cb.toggle(); break; case Conf['fappeTyme']: - if (g.VIEW === 'catalog') { + if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } FappeTyme.cb.toggle.call({ @@ -13177,7 +13203,7 @@ }); break; case Conf['werkTyme']: - if (g.VIEW === 'catalog') { + if (!Conf['Werk Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } FappeTyme.cb.toggle.call({ @@ -13833,7 +13859,7 @@ className: 'dialog' }); $.extend(dialog, { - innerHTML: "
" + innerHTML: "
" }); $.on($('.export', Settings.dialog), 'click', Settings["export"]); $.on($('.import', Settings.dialog), 'click', Settings["import"]); diff --git a/builds/4chan-X-noupdate.crx b/builds/4chan-X-noupdate.crx index f5ded89a2..042f41322 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 4ee394bae..55e4a1e6d 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.9.12.5 +// @version 1.9.13.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -23,7 +23,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.9.12.5 +* 4chan X - Version 1.9.13.0 * * Licensed under the MIT license. * https://github.com/ccd0/4chan-x/blob/master/LICENSE @@ -177,6 +177,7 @@ 'Image Hover': [true, 'Show full image / video on mouseover.'], 'Image Hover in Catalog': [false, 'Show full image / video on mouseover in 4chan X catalog.'], 'Gallery': [true, 'Adds a simple and cute image gallery.'], + 'Fullscreen Gallery': [false, 'Open gallery in fullscreen mode.'], 'PDF in Gallery': [false, 'Show PDF files in gallery.'], 'Sauce': [true, 'Add sauce links to images.'], 'Reveal Spoiler Thumbnails': [false, 'Replace spoiler thumbnails with the original image.'], @@ -266,7 +267,7 @@ 'Fit Width': [true], 'Fit Height': [true], 'Scroll to Post': [true], - 'Slide Delay': [5.0] + 'Slide Delay': [6.0] }, threadWatcher: { 'Current Board': [false, 'Only show watched threads from the current board.'], @@ -329,7 +330,7 @@ 'Open empty QR': ['q', 'Open QR without post number inserted.'], 'Open QR': ['Shift+q', 'Open QR with post number inserted.'], 'Open settings': ['Alt+o', 'Open Settings.'], - 'Close': ['Esc', 'Close Settings, Notifications or QR.'], + 'Close': ['Esc', 'Close Settings/Notifications/QR/Gallery.'], 'Spoiler tags': ['Ctrl+s', 'Insert spoiler tags.'], 'Code tags': ['Alt+c', 'Insert code tags.'], 'Eqn tags': ['Alt+e', 'Insert eqn tags.'], @@ -341,6 +342,8 @@ 'Expand image': ['Shift+e', 'Expand selected image.'], 'Expand images': ['e', 'Expand all images.'], 'Open Gallery': ['g', 'Opens the gallery.'], + 'Pause': ['p', 'Pause/play videos in the gallery.'], + 'Slideshow': ['s', 'Toggle the gallery slideshow mode.'], 'fappeTyme': ['f', 'Toggle Fappe Tyme.'], 'werkTyme': ['Shift+w', 'Toggle Werk Tyme.'], 'Front page': ['1', 'Jump to front page.'], @@ -384,7 +387,7 @@ doc = d.documentElement; g = { - VERSION: '1.9.12.5', + VERSION: '1.9.13.0', NAMESPACE: '4chan X.', NAME: '4chan X', FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions', @@ -707,6 +710,15 @@ } }; + $.one = function(el, events, handler) { + var cb; + cb = function(e) { + $.off(el, events, cb); + return handler.call(this, e); + }; + return $.on(el, events, cb); + }; + $.event = function(event, detail, root) { if (root == null) { root = d; @@ -6025,9 +6037,7 @@ el: this.controls, order: 98 }); - if (!Conf['Unread Count']) { - $.on(d, '4chanXInitFinished', this.ready); - } + $.on(d, '4chanXInitFinished', this.ready); return Post.callbacks.push({ name: 'Quote Threading', cb: this.node @@ -6043,10 +6053,8 @@ return post.cb(true); } }); - if (Conf['Unread Count'] && Unread.thread.OP.nodes.root.parentElement.parentElement) { - Unread.read(); - return Unread.update(); - } + Unread.read(); + return Unread.update(); }, node: function() { var keys, len, posts, quote, _i, _len, _ref; @@ -6054,9 +6062,7 @@ if (this.isClone || !QuoteThreading.enabled) { return; } - if (Conf['Unread Count']) { - Unread.addPost(this); - } + Unread.addPost(this); if (this.thread.OP === this || this.isHidden) { return; } @@ -6086,7 +6092,7 @@ if (!force) { height = doc.clientHeight; _ref = root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top; - if (!((Conf['Unread Count'] && posts[post.ID]) || ((bottom < height) && (top > 0)))) { + if (!(posts[post.ID] || ((bottom < height) && (top > 0)))) { return false; } } @@ -6102,9 +6108,6 @@ $.after(root, threadContainer); $.addClass(root, 'threadOP'); } - if (!Conf['Unread Count']) { - return true; - } if (post = posts[post.ID]) { posts.after(post, posts[this.ID]); } else if (posts[this.ID]) { @@ -8297,6 +8300,17 @@ } } } + if (Conf['Fullscreen Gallery']) { + $.one(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', function() { + return $.on(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', cb.close); + }); + if (typeof doc.mozRequestFullScreen === "function") { + doc.mozRequestFullScreen(); + } + if (typeof doc.webkitRequestFullScreen === "function") { + doc.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } + } $.addClass(doc, 'gallery-open'); $.add(d.body, dialog); nodes.thumbs.scrollTop = 0; @@ -8456,7 +8470,7 @@ } cb = (function() { switch (key) { - case 'Esc': + case Conf['Close']: case Conf['Open Gallery']: return Gallery.cb.close; case 'Right': @@ -8466,9 +8480,9 @@ case 'Left': case '': return Gallery.cb.prev; - case 'p': + case Conf['Pause']: return Gallery.cb.pause; - case 's': + case Conf['Slideshow']: return Gallery.cb.toggleSlideshow; } })(); @@ -8552,6 +8566,15 @@ } $.rm(Gallery.nodes.el); $.rmClass(doc, 'gallery-open'); + if (Conf['Fullscreen Gallery']) { + $.off(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', Gallery.cb.close); + if (typeof d.mozCancelFullScreen === "function") { + d.mozCancelFullScreen(); + } + if (typeof d.webkitExitFullscreen === "function") { + d.webkitExitFullscreen(); + } + } delete Gallery.nodes; delete Gallery.fullIDs; doc.style.overflow = ''; @@ -11785,7 +11808,7 @@ Unread = { init: function() { - if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Unread Line'] && !Conf['Desktop Notifications'] && !(Conf['Thread Watcher'] && Conf['Show Unread Count'])) { + if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Unread Line'] && !Conf['Scroll to Last Read Post'] && !Conf['Thread Watcher'] && !Conf['Desktop Notifications'] && !Conf['Quote Threading']) { return; } this.db = new DataBoard('lastReadPosts', this.sync); @@ -11808,7 +11831,7 @@ threadID: this.ID, defaultValue: 0 }); - $.on(d, '4chanXInitFinished', Unread.ready); + $.one(d, '4chanXInitFinished', Unread.ready); $.on(d, 'ThreadUpdate', Unread.onUpdate); $.on(d, 'scroll visibilitychange', Unread.read); if (Conf['Unread Line'] && !Conf['Quote Threading']) { @@ -11817,7 +11840,6 @@ }, ready: function() { var posts; - $.off(d, '4chanXInitFinished', Unread.ready); if (!Conf['Quote Threading']) { posts = []; Unread.thread.posts.forEach(function(post) { @@ -11835,31 +11857,26 @@ } }, scroll: function() { - var down, hash, keys, post, posts, root; + var ID, hash, posts, root, _i, _ref; if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { return; } - if (post = Unread.posts.first) { - while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.data.nodes.root)) { - if (!(post = Get.postFromRoot(root)).isHidden) { - break; - } + posts = Unread.thread.posts; + _ref = posts.keys; + for (_i = _ref.length - 1; _i >= 0; _i += -1) { + ID = _ref[_i]; + if (!(+ID <= Unread.lastReadPost)) { + continue; } - if (!root) { - return; + root = posts[ID].nodes.root; + if (root.getBoundingClientRect().height) { + Header.scrollToIfNeeded(root, true); + break; } - down = true; - } else { - posts = Unread.thread.posts; - keys = posts.keys; - root = posts[keys[keys.length - 1]].nodes.root; - } - if (Header.getBottomOf(root) < 0) { - return Header.scrollTo(root, down); } }, sync: function() { - var ID, lastReadPost, post; + var ID, lastReadPost, _i, _len, _ref; if (Unread.lastReadPost == null) { return; } @@ -11872,13 +11889,12 @@ return; } Unread.lastReadPost = lastReadPost; - post = Unread.posts.first; - while (post) { - if (post.ID > Unread.lastReadPost) { + _ref = Unread.thread.posts.keys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ID = _ref[_i]; + if (+ID > Unread.lastReadPost) { break; } - ID = post.ID; - post = post.next; Unread.posts.rm(ID); delete Unread.postsQuotingYou[ID]; } @@ -11900,13 +11916,14 @@ return Unread.addPostQuotingYou(post); }, addPosts: function(posts) { - var post, _i, _len, _ref, _ref1; + var oldCount, post, _i, _len; + oldCount = Unread.posts.length; for (_i = 0, _len = posts.length; _i < _len; _i++) { post = posts[_i]; Unread.addPost(post); } if (Conf['Unread Line'] && !Conf['Quote Threading']) { - Unread.setLine((_ref = (_ref1 = Unread.posts.first) != null ? _ref1.data : void 0, __indexOf.call(posts, _ref) >= 0)); + Unread.setLine(oldCount === 0 && Unread.posts.length !== 0); } Unread.read(); return Unread.update(); @@ -11970,28 +11987,25 @@ if (!posts[ID]) { return; } - if (post === posts.first && !(Conf['Quote Threading'] && Unread.posts.length)) { - Unread.lastReadPost = ID; - Unread.saveLastReadPost(); - } posts.rm(ID); delete Unread.postsQuotingYou[ID]; + Unread.saveLastReadPost(); return Unread.update(); }, read: $.debounce(100, function(e) { - var ID, data, height, maxID, post, posts, _ref; + var ID, count, data, height, post, posts, _ref; if (d.hidden || !Unread.posts.length) { return; } height = doc.clientHeight; posts = Unread.posts; - maxID = 0; + count = 0; while (post = posts.first) { if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { break; } ID = post.ID, data = post.data; - maxID = Math.max(maxID, ID); + count++; posts.rm(ID); delete Unread.postsQuotingYou[ID]; if (Conf['Mark Quotes of You'] && ((_ref = QR.db) != null ? _ref.get({ @@ -12002,23 +12016,30 @@ QuoteYou.lastRead = data.nodes.root; } } - if (!maxID) { + if (!count) { return; } - if (!(Conf['Quote Threading'] && posts.length)) { - if (Unread.lastReadPost < maxID || !Unread.lastReadPost) { - Unread.lastReadPost = maxID; - } - Unread.saveLastReadPost(); - } + Unread.saveLastReadPost(); if (e) { return Unread.update(); } }), saveLastReadPost: $.debounce(2 * $.SECOND, function() { + var ID, _i, _len, _ref; + _ref = Unread.thread.posts.keys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ID = _ref[_i]; + if (Unread.posts[ID]) { + break; + } + if (+ID > Unread.lastReadPost) { + Unread.lastReadPost = +ID; + } + } if (Unread.thread.isDead && !Unread.thread.isArchived) { return; } + Unread.db.forceSync(); return Unread.db.set({ boardID: Unread.thread.board.ID, threadID: Unread.thread.ID, @@ -12026,15 +12047,20 @@ }); }), setLine: function(force) { - var post; + var ID, posts, _i, _ref; if (!(d.hidden || force === true)) { return; } - if (!(post = Unread.posts.first)) { + if (!Unread.posts.length) { return $.rm(Unread.hr); } - if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.data.nodes.root)) { - return $.before(post.data.nodes.root, Unread.hr); + posts = Unread.thread.posts; + _ref = posts.keys; + for (_i = _ref.length - 1; _i >= 0; _i += -1) { + ID = _ref[_i]; + if (+ID <= Unread.lastReadPost) { + return $.after(posts[ID].nodes.root, Unread.hr); + } } }, update: function() { @@ -13168,7 +13194,7 @@ Gallery.cb.toggle(); break; case Conf['fappeTyme']: - if (g.VIEW === 'catalog') { + if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } FappeTyme.cb.toggle.call({ @@ -13176,7 +13202,7 @@ }); break; case Conf['werkTyme']: - if (g.VIEW === 'catalog') { + if (!Conf['Werk Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } FappeTyme.cb.toggle.call({ @@ -13832,7 +13858,7 @@ className: 'dialog' }); $.extend(dialog, { - innerHTML: "
" + innerHTML: "
" }); $.on($('.export', Settings.dialog), 'click', Settings["export"]); $.on($('.import', Settings.dialog), 'click', Settings["import"]); diff --git a/builds/4chan-X.crx b/builds/4chan-X.crx index 8a720b4e4..b31fdd46f 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 f913454fb..5396e7fec 100644 --- a/builds/4chan-X.meta.js +++ b/builds/4chan-X.meta.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X -// @version 1.9.12.5 +// @version 1.9.13.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 6e3c18f94..a237ce893 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.9.12.5 +// @version 1.9.13.0 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -24,7 +24,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.9.12.5 +* 4chan X - Version 1.9.13.0 * * Licensed under the MIT license. * https://github.com/ccd0/4chan-x/blob/master/LICENSE @@ -178,6 +178,7 @@ 'Image Hover': [true, 'Show full image / video on mouseover.'], 'Image Hover in Catalog': [false, 'Show full image / video on mouseover in 4chan X catalog.'], 'Gallery': [true, 'Adds a simple and cute image gallery.'], + 'Fullscreen Gallery': [false, 'Open gallery in fullscreen mode.'], 'PDF in Gallery': [false, 'Show PDF files in gallery.'], 'Sauce': [true, 'Add sauce links to images.'], 'Reveal Spoiler Thumbnails': [false, 'Replace spoiler thumbnails with the original image.'], @@ -267,7 +268,7 @@ 'Fit Width': [true], 'Fit Height': [true], 'Scroll to Post': [true], - 'Slide Delay': [5.0] + 'Slide Delay': [6.0] }, threadWatcher: { 'Current Board': [false, 'Only show watched threads from the current board.'], @@ -330,7 +331,7 @@ 'Open empty QR': ['q', 'Open QR without post number inserted.'], 'Open QR': ['Shift+q', 'Open QR with post number inserted.'], 'Open settings': ['Alt+o', 'Open Settings.'], - 'Close': ['Esc', 'Close Settings, Notifications or QR.'], + 'Close': ['Esc', 'Close Settings/Notifications/QR/Gallery.'], 'Spoiler tags': ['Ctrl+s', 'Insert spoiler tags.'], 'Code tags': ['Alt+c', 'Insert code tags.'], 'Eqn tags': ['Alt+e', 'Insert eqn tags.'], @@ -342,6 +343,8 @@ 'Expand image': ['Shift+e', 'Expand selected image.'], 'Expand images': ['e', 'Expand all images.'], 'Open Gallery': ['g', 'Opens the gallery.'], + 'Pause': ['p', 'Pause/play videos in the gallery.'], + 'Slideshow': ['s', 'Toggle the gallery slideshow mode.'], 'fappeTyme': ['f', 'Toggle Fappe Tyme.'], 'werkTyme': ['Shift+w', 'Toggle Werk Tyme.'], 'Front page': ['1', 'Jump to front page.'], @@ -385,7 +388,7 @@ doc = d.documentElement; g = { - VERSION: '1.9.12.5', + VERSION: '1.9.13.0', NAMESPACE: '4chan X.', NAME: '4chan X', FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions', @@ -708,6 +711,15 @@ } }; + $.one = function(el, events, handler) { + var cb; + cb = function(e) { + $.off(el, events, cb); + return handler.call(this, e); + }; + return $.on(el, events, cb); + }; + $.event = function(event, detail, root) { if (root == null) { root = d; @@ -6026,9 +6038,7 @@ el: this.controls, order: 98 }); - if (!Conf['Unread Count']) { - $.on(d, '4chanXInitFinished', this.ready); - } + $.on(d, '4chanXInitFinished', this.ready); return Post.callbacks.push({ name: 'Quote Threading', cb: this.node @@ -6044,10 +6054,8 @@ return post.cb(true); } }); - if (Conf['Unread Count'] && Unread.thread.OP.nodes.root.parentElement.parentElement) { - Unread.read(); - return Unread.update(); - } + Unread.read(); + return Unread.update(); }, node: function() { var keys, len, posts, quote, _i, _len, _ref; @@ -6055,9 +6063,7 @@ if (this.isClone || !QuoteThreading.enabled) { return; } - if (Conf['Unread Count']) { - Unread.addPost(this); - } + Unread.addPost(this); if (this.thread.OP === this || this.isHidden) { return; } @@ -6087,7 +6093,7 @@ if (!force) { height = doc.clientHeight; _ref = root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top; - if (!((Conf['Unread Count'] && posts[post.ID]) || ((bottom < height) && (top > 0)))) { + if (!(posts[post.ID] || ((bottom < height) && (top > 0)))) { return false; } } @@ -6103,9 +6109,6 @@ $.after(root, threadContainer); $.addClass(root, 'threadOP'); } - if (!Conf['Unread Count']) { - return true; - } if (post = posts[post.ID]) { posts.after(post, posts[this.ID]); } else if (posts[this.ID]) { @@ -8298,6 +8301,17 @@ } } } + if (Conf['Fullscreen Gallery']) { + $.one(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', function() { + return $.on(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', cb.close); + }); + if (typeof doc.mozRequestFullScreen === "function") { + doc.mozRequestFullScreen(); + } + if (typeof doc.webkitRequestFullScreen === "function") { + doc.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } + } $.addClass(doc, 'gallery-open'); $.add(d.body, dialog); nodes.thumbs.scrollTop = 0; @@ -8457,7 +8471,7 @@ } cb = (function() { switch (key) { - case 'Esc': + case Conf['Close']: case Conf['Open Gallery']: return Gallery.cb.close; case 'Right': @@ -8467,9 +8481,9 @@ case 'Left': case '': return Gallery.cb.prev; - case 'p': + case Conf['Pause']: return Gallery.cb.pause; - case 's': + case Conf['Slideshow']: return Gallery.cb.toggleSlideshow; } })(); @@ -8553,6 +8567,15 @@ } $.rm(Gallery.nodes.el); $.rmClass(doc, 'gallery-open'); + if (Conf['Fullscreen Gallery']) { + $.off(d, 'fullscreenchange mozfullscreenchange webkitfullscreenchange', Gallery.cb.close); + if (typeof d.mozCancelFullScreen === "function") { + d.mozCancelFullScreen(); + } + if (typeof d.webkitExitFullscreen === "function") { + d.webkitExitFullscreen(); + } + } delete Gallery.nodes; delete Gallery.fullIDs; doc.style.overflow = ''; @@ -11786,7 +11809,7 @@ Unread = { init: function() { - if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Unread Line'] && !Conf['Desktop Notifications'] && !(Conf['Thread Watcher'] && Conf['Show Unread Count'])) { + if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Unread Line'] && !Conf['Scroll to Last Read Post'] && !Conf['Thread Watcher'] && !Conf['Desktop Notifications'] && !Conf['Quote Threading']) { return; } this.db = new DataBoard('lastReadPosts', this.sync); @@ -11809,7 +11832,7 @@ threadID: this.ID, defaultValue: 0 }); - $.on(d, '4chanXInitFinished', Unread.ready); + $.one(d, '4chanXInitFinished', Unread.ready); $.on(d, 'ThreadUpdate', Unread.onUpdate); $.on(d, 'scroll visibilitychange', Unread.read); if (Conf['Unread Line'] && !Conf['Quote Threading']) { @@ -11818,7 +11841,6 @@ }, ready: function() { var posts; - $.off(d, '4chanXInitFinished', Unread.ready); if (!Conf['Quote Threading']) { posts = []; Unread.thread.posts.forEach(function(post) { @@ -11836,31 +11858,26 @@ } }, scroll: function() { - var down, hash, keys, post, posts, root; + var ID, hash, posts, root, _i, _ref; if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { return; } - if (post = Unread.posts.first) { - while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.data.nodes.root)) { - if (!(post = Get.postFromRoot(root)).isHidden) { - break; - } + posts = Unread.thread.posts; + _ref = posts.keys; + for (_i = _ref.length - 1; _i >= 0; _i += -1) { + ID = _ref[_i]; + if (!(+ID <= Unread.lastReadPost)) { + continue; } - if (!root) { - return; + root = posts[ID].nodes.root; + if (root.getBoundingClientRect().height) { + Header.scrollToIfNeeded(root, true); + break; } - down = true; - } else { - posts = Unread.thread.posts; - keys = posts.keys; - root = posts[keys[keys.length - 1]].nodes.root; - } - if (Header.getBottomOf(root) < 0) { - return Header.scrollTo(root, down); } }, sync: function() { - var ID, lastReadPost, post; + var ID, lastReadPost, _i, _len, _ref; if (Unread.lastReadPost == null) { return; } @@ -11873,13 +11890,12 @@ return; } Unread.lastReadPost = lastReadPost; - post = Unread.posts.first; - while (post) { - if (post.ID > Unread.lastReadPost) { + _ref = Unread.thread.posts.keys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ID = _ref[_i]; + if (+ID > Unread.lastReadPost) { break; } - ID = post.ID; - post = post.next; Unread.posts.rm(ID); delete Unread.postsQuotingYou[ID]; } @@ -11901,13 +11917,14 @@ return Unread.addPostQuotingYou(post); }, addPosts: function(posts) { - var post, _i, _len, _ref, _ref1; + var oldCount, post, _i, _len; + oldCount = Unread.posts.length; for (_i = 0, _len = posts.length; _i < _len; _i++) { post = posts[_i]; Unread.addPost(post); } if (Conf['Unread Line'] && !Conf['Quote Threading']) { - Unread.setLine((_ref = (_ref1 = Unread.posts.first) != null ? _ref1.data : void 0, __indexOf.call(posts, _ref) >= 0)); + Unread.setLine(oldCount === 0 && Unread.posts.length !== 0); } Unread.read(); return Unread.update(); @@ -11971,28 +11988,25 @@ if (!posts[ID]) { return; } - if (post === posts.first && !(Conf['Quote Threading'] && Unread.posts.length)) { - Unread.lastReadPost = ID; - Unread.saveLastReadPost(); - } posts.rm(ID); delete Unread.postsQuotingYou[ID]; + Unread.saveLastReadPost(); return Unread.update(); }, read: $.debounce(100, function(e) { - var ID, data, height, maxID, post, posts, _ref; + var ID, count, data, height, post, posts, _ref; if (d.hidden || !Unread.posts.length) { return; } height = doc.clientHeight; posts = Unread.posts; - maxID = 0; + count = 0; while (post = posts.first) { if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { break; } ID = post.ID, data = post.data; - maxID = Math.max(maxID, ID); + count++; posts.rm(ID); delete Unread.postsQuotingYou[ID]; if (Conf['Mark Quotes of You'] && ((_ref = QR.db) != null ? _ref.get({ @@ -12003,23 +12017,30 @@ QuoteYou.lastRead = data.nodes.root; } } - if (!maxID) { + if (!count) { return; } - if (!(Conf['Quote Threading'] && posts.length)) { - if (Unread.lastReadPost < maxID || !Unread.lastReadPost) { - Unread.lastReadPost = maxID; - } - Unread.saveLastReadPost(); - } + Unread.saveLastReadPost(); if (e) { return Unread.update(); } }), saveLastReadPost: $.debounce(2 * $.SECOND, function() { + var ID, _i, _len, _ref; + _ref = Unread.thread.posts.keys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ID = _ref[_i]; + if (Unread.posts[ID]) { + break; + } + if (+ID > Unread.lastReadPost) { + Unread.lastReadPost = +ID; + } + } if (Unread.thread.isDead && !Unread.thread.isArchived) { return; } + Unread.db.forceSync(); return Unread.db.set({ boardID: Unread.thread.board.ID, threadID: Unread.thread.ID, @@ -12027,15 +12048,20 @@ }); }), setLine: function(force) { - var post; + var ID, posts, _i, _ref; if (!(d.hidden || force === true)) { return; } - if (!(post = Unread.posts.first)) { + if (!Unread.posts.length) { return $.rm(Unread.hr); } - if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.data.nodes.root)) { - return $.before(post.data.nodes.root, Unread.hr); + posts = Unread.thread.posts; + _ref = posts.keys; + for (_i = _ref.length - 1; _i >= 0; _i += -1) { + ID = _ref[_i]; + if (+ID <= Unread.lastReadPost) { + return $.after(posts[ID].nodes.root, Unread.hr); + } } }, update: function() { @@ -13169,7 +13195,7 @@ Gallery.cb.toggle(); break; case Conf['fappeTyme']: - if (g.VIEW === 'catalog') { + if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } FappeTyme.cb.toggle.call({ @@ -13177,7 +13203,7 @@ }); break; case Conf['werkTyme']: - if (g.VIEW === 'catalog') { + if (!Conf['Werk Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') { return; } FappeTyme.cb.toggle.call({ @@ -13833,7 +13859,7 @@ className: 'dialog' }); $.extend(dialog, { - innerHTML: "
" + innerHTML: "
" }); $.on($('.export', Settings.dialog), 'click', Settings["export"]); $.on($('.import', Settings.dialog), 'click', Settings["import"]); diff --git a/builds/4chan-X.zip b/builds/4chan-X.zip index e71b2eda5..7802e3d10 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 09ba804b0..fe28fba2b 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 6a8e5abcd..0f4a55c49 100644 --- a/builds/updates.xml +++ b/builds/updates.xml @@ -1,7 +1,7 @@ - + diff --git a/package.json b/package.json index 3fb63852c..dc3b6bf7d 100755 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Cross-browser userscript for maximum lurking on 4chan.", "meta": { "name": "4chan X", - "version": "1.9.12.5", + "version": "1.9.13.0", "repo": "https://github.com/ccd0/4chan-x/", "page": "https://github.com/ccd0/4chan-x", "downloads": "https://ccd0.github.io/4chan-x/builds/", @@ -67,4 +67,4 @@ "engines": { "node": ">=0.10" } -} +} \ No newline at end of file