diff --git a/CHANGELOG.md b/CHANGELOG.md
index 772fa3131..8c3537620 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,15 @@
**MayhemYDG**:
- Tiny fixes
+- Add page count to thread stats
+- Better performance for Fit Height by using vh
**seaweedchan**:
+- Added OpenSettings event on 4chan X settings/sections open for userscripts like OneeChan and 4chan Style Script
+- Changed defaults that use the arrow keys to shift+arrow key to not conflict with scrolling
+- Made Mayhem's page count in thread stats optional
+- Small bug fixes
+- Fix YouTube videos in Firefox taking z-index priority
+- Fix Persistent QR not working for /f/
- New image expansion option: `Advance on contract`. Advances to next post unless Fappe Tyme is enabled (temporary)
- Change `.qr-link` to `.qr-link-container` and `.qr-link>a` to `.qr-link`
- Update /q/'s posting cooldown
@@ -16,6 +24,10 @@
**Wohlfe**:
- Add /pol/ archiving for FoolzaShit
+**zixaphir**:
+- New option: `Image Prefetching`. Adds a toggle to the header menu for per-thread prefetching.
+- Make Advance on contract work with Fappe Tyme
+
### v2.0.4
*2013-05-15*
**MayhemYDG**:
diff --git a/LICENSE b/LICENSE
index 2a1ed0010..1e7622f68 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
/*
-* appchan x - Version 2.0.4 - 2013-05-23
+* appchan x - Version 2.0.4 - 2013-05-27
*
* Licensed under the MIT license.
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
diff --git a/builds/appchan-x.js b/builds/appchan-x.js
index bdb77753d..93ac23922 100644
--- a/builds/appchan-x.js
+++ b/builds/appchan-x.js
@@ -20,7 +20,7 @@
// ==/UserScript==
/*
-* appchan x - Version 2.0.4 - 2013-05-23
+* appchan x - Version 2.0.4 - 2013-05-27
*
* Licensed under the MIT license.
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
@@ -186,6 +186,7 @@
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.'],
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title.'],
'Thread Stats': [true, 'Display reply and image count.'],
+ 'Page Count in Stats': [false, 'Display the page count in the thread stats as well.'],
'Updater and Stats in Header': [true, 'Places the thread updater and thread stats in the header instead of floating them.'],
'Thread Watcher': [true, 'Bookmark threads.'],
'Toggleable Thread Watcher': [false, 'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.'],
@@ -350,7 +351,7 @@
},
time: '%m/%d/%y(%a)%H:%M:%S',
backlink: '>>%id',
- fileInfo: '%l (%p%s, %r)',
+ fileInfo: '%L (%p%s, %r)',
favicon: 'ferongr',
usercss: "/* Tripcode Italics: */\n/*\nspan.postertrip {\nfont-style: italic;\n}\n*/\n\n/* Add a rounded border to thumbnails (but not expanded images): */\n/*\n.fileThumb > img:first-child {\nborder: solid 2px rgba(0,0,100,0.5);\nborder-radius: 10px;\n}\n*/\n\n/* Make highlighted posts look inset on the page: */\n/*\ndiv.post:target,\ndiv.post.highlight {\nbox-shadow: inset 2px 2px 2px rgba(0,0,0,0.2);\n}\n*/",
hotkeys: {
@@ -373,11 +374,11 @@
'fappeTyme': ['f', 'Fappe Tyme.'],
'Front page': ['0', 'Jump to page 0.'],
'Open front page': ['Shift+0', 'Open page 0 in a new tab.'],
- 'Next page': ['Right', 'Jump to the next page.'],
- 'Previous page': ['Left', 'Jump to the previous page.'],
+ 'Next page': ['Shift+Right', 'Jump to the next page.'],
+ 'Previous page': ['Shift+Left', 'Jump to the previous page.'],
'Open catalog': ['Shift+c', 'Open the catalog of the current board'],
- 'Next thread': ['Down', 'See next thread.'],
- 'Previous thread': ['Up', 'See previous thread.'],
+ 'Next thread': ['Shift+Down', 'See next thread.'],
+ 'Previous thread': ['Shift+Up', 'See previous thread.'],
'Expand thread': ['Ctrl+e', 'Expand thread.'],
'Open thread': ['o', 'Open thread in current tab.'],
'Open thread tab': ['Shift+o', 'Open thread in new tab.'],
@@ -4164,7 +4165,7 @@
}
flag = flagCode ? (" ") : '';
if (file != null ? file.isDeleted : void 0) {
- fileHtml = isOP ? ("
") + (" ") + " " : ("") + (" ") + " ";
+ fileHtml = isOP ? ("
") + (" ") + " " : ("") + (" ") + " ";
} else if (file) {
ext = file.name.slice(-3);
if (!file.twidth && !file.theight && ext === 'gif') {
@@ -6671,7 +6672,7 @@
regExp: /.*(?:youtu.be\/|youtube.*v=|youtube.*\/embed\/|youtube.*\/v\/|youtube.*videos\/)([^#\&\?]*)\??(t\=.*)?/,
el: function() {
return $.el('iframe', {
- src: "//www.youtube.com/embed/" + this.name + (this.option ? '#' + this.option : '')
+ src: "//www.youtube.com/embed/" + this.name + (this.option ? '#' + this.option : '') + "?wmode=opaque"
});
},
title: {
@@ -6688,7 +6689,7 @@
style: 'border: 0; width: 150px; height: 45px;',
el: function() {
return $.el('object', {
- innerHTML: " "
+ innerHTML: " "
});
}
},
@@ -6696,7 +6697,7 @@
regExp: /.*(?:vimeo.com\/)([^#\&\?]*).*/,
el: function() {
return $.el('iframe', {
- src: "//player.vimeo.com/video/" + this.name
+ src: "//player.vimeo.com/video/" + this.name + "?wmode=opaque"
});
},
title: {
@@ -6711,8 +6712,8 @@
LiveLeak: {
regExp: /.*(?:liveleak.com\/view.+i=)([0-9a-z_]+)/,
el: function() {
- return $.el('iframe', {
- src: "http://www.liveleak.com/e/" + this.name + "?autostart=true"
+ return $.el('object', {
+ innerHTML: " "
});
}
},
@@ -6885,7 +6886,11 @@
this.db = new DataBoard('yourPosts');
$.ready(this.initReady);
if (Conf['Persistent QR']) {
- $.on(d, '4chanXInitFinished', this.persist);
+ if (g.BOARD.ID !== 'f') {
+ $.on(d, '4chanXInitFinished', this.persist);
+ } else {
+ $.ready(this.persist);
+ }
}
Post.prototype.callbacks.push({
name: 'Quick Reply',
@@ -7150,6 +7155,9 @@
list = $("#list-" + type, QR.nodes.el);
for (_i = 0, _len = arr.length; _i < _len; _i++) {
val = arr[_i];
+ if (!val) {
+ continue;
+ }
$.add(list, $.el('option', {
textContent: val
}));
@@ -8456,14 +8464,11 @@
}
},
setFitness: function() {
- var checked;
-
- checked = this.checked;
- (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
+ (this.checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
if (this.name !== 'Fit height') {
return;
}
- if (checked) {
+ if (this.checked) {
$.on(window, 'resize', ImageExpand.resize);
if (!ImageExpand.style) {
ImageExpand.style = $.addStyle(null);
@@ -8474,6 +8479,9 @@
}
}
},
+ resize: function() {
+ return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
+ },
toggle: function(post) {
var headRect, node, rect, root, thumb, top;
@@ -8669,9 +8677,6 @@
};
}
},
- resize: function() {
- return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
- },
menuToggle: function(e) {
return ImageExpand.opmenu.toggle(e, this, g);
}
@@ -8792,7 +8797,7 @@
return $.event('AddMenuEntry', {
type: 'header',
el: prefetch,
- order: 120
+ order: 104
});
},
node: function() {
@@ -9278,20 +9283,23 @@
}
if (Conf['Updater and Stats in Header']) {
this.dialog = sc = $.el('span', {
- innerHTML: "0 / 0 ",
- id: 'thread-stats'
+ innerHTML: "0 / 0 " + (Conf["Page Count in Stats"] ? " / 0 " : ""),
+ id: 'thread-stats',
+ title: 'Post Count / File Count' + (Conf["Page Count in Stats"] ? " / Page Count" : "")
});
$.ready(function() {
return Header.addShortcut(sc);
});
} else {
- this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "0 / 0
");
+ this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "0 / 0 " + (Conf["Page Count in Stats"] ? " / 0 " : "") + "
");
$.ready(function() {
return $.add(d.body, sc);
});
}
this.postCountEl = $('#post-count', sc);
this.fileCountEl = $('#file-count', sc);
+ this.pageCountEl = $('#page-count', sc);
+ this.lastModified = '0';
return Thread.prototype.callbacks.push({
name: 'Thread Stats',
cb: this.node
@@ -9311,6 +9319,7 @@
}
}
ThreadStats.thread = this;
+ ThreadStats.fetchPage();
ThreadStats.update(postCount, fileCount);
return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
@@ -9331,6 +9340,43 @@
fileCountEl.textContent = fileCount;
(thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
+ },
+ fetchPage: function() {
+ if (ThreadStats.thread.isDead || !Conf["Page Count in Stats"]) {
+ return;
+ }
+ setTimeout(ThreadStats.fetchPage, 2 * $.MINUTE);
+ return $.ajax("//api.4chan.org/" + ThreadStats.thread.board + "/threads.json", {
+ onload: ThreadStats.onThreadsLoad
+ }, {
+ headers: {
+ 'If-Modified-Since': ThreadStats.lastModified
+ }
+ });
+ },
+ onThreadsLoad: function() {
+ var page, pages, thread, _i, _j, _len, _len1, _ref;
+
+ if (!Conf["Page Count in Stats"]) {
+ return;
+ }
+ ThreadStats.lastModified = this.getResponseHeader('Last-Modified');
+ if (this.status !== 200) {
+ return;
+ }
+ pages = JSON.parse(this.response);
+ for (_i = 0, _len = pages.length; _i < _len; _i++) {
+ page = pages[_i];
+ _ref = page.threads;
+ for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
+ thread = _ref[_j];
+ if (thread.no === ThreadStats.thread.ID) {
+ ThreadStats.pageCountEl.textContent = page.page;
+ (page.page === pages.length - 1 ? $.addClass : $.rmClass)(ThreadStats.pageCountEl, 'warning');
+ return;
+ }
+ }
+ }
}
};
@@ -12766,11 +12812,17 @@
$.open("/" + g.BOARD + "/#delform");
break;
case Conf['Next page']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
if (form = $('.next form')) {
window.location = form.action;
}
break;
case Conf['Previous page']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
if (form = $('.prev form')) {
window.location = form.action;
}
@@ -13485,7 +13537,8 @@
(sectionToOpen ? sectionToOpen : links[0]).click();
$.on($('.close', dialog), 'click', Settings.close);
$.on(overlay, 'click', Settings.close);
- return $.add(d.body, [overlay, dialog]);
+ $.add(d.body, [overlay, dialog]);
+ return $.event('OpenSettings', null, dialog);
},
close: function() {
if (!Settings.dialog) {
@@ -13521,7 +13574,8 @@
$.rmAll(section);
section.className = "section-" + this.hyphenatedTitle;
this.open(section, mode);
- return section.scrollTop = 0;
+ section.scrollTop = 0;
+ return $.event('OpenSettings', null, section);
},
main: function(section) {
var arr, button, description, div, fs, hiddenNum, input, inputs, items, key, obj, _ref;
diff --git a/builds/appchan-x.user.js b/builds/appchan-x.user.js
index d93ff8d7c..7d9c615c4 100644
--- a/builds/appchan-x.user.js
+++ b/builds/appchan-x.user.js
@@ -20,7 +20,7 @@
// ==/UserScript==
/*
-* appchan x - Version 2.0.4 - 2013-05-23
+* appchan x - Version 2.0.4 - 2013-05-27
*
* Licensed under the MIT license.
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
@@ -186,6 +186,7 @@
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.'],
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title.'],
'Thread Stats': [true, 'Display reply and image count.'],
+ 'Page Count in Stats': [false, 'Display the page count in the thread stats as well.'],
'Updater and Stats in Header': [true, 'Places the thread updater and thread stats in the header instead of floating them.'],
'Thread Watcher': [true, 'Bookmark threads.'],
'Toggleable Thread Watcher': [false, 'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.'],
@@ -351,7 +352,7 @@
},
time: '%m/%d/%y(%a)%H:%M:%S',
backlink: '>>%id',
- fileInfo: '%l (%p%s, %r)',
+ fileInfo: '%L (%p%s, %r)',
favicon: 'ferongr',
usercss: "/* Tripcode Italics: */\n/*\nspan.postertrip {\nfont-style: italic;\n}\n*/\n\n/* Add a rounded border to thumbnails (but not expanded images): */\n/*\n.fileThumb > img:first-child {\nborder: solid 2px rgba(0,0,100,0.5);\nborder-radius: 10px;\n}\n*/\n\n/* Make highlighted posts look inset on the page: */\n/*\ndiv.post:target,\ndiv.post.highlight {\nbox-shadow: inset 2px 2px 2px rgba(0,0,0,0.2);\n}\n*/",
hotkeys: {
@@ -374,11 +375,11 @@
'fappeTyme': ['f', 'Fappe Tyme.'],
'Front page': ['0', 'Jump to page 0.'],
'Open front page': ['Shift+0', 'Open page 0 in a new tab.'],
- 'Next page': ['Right', 'Jump to the next page.'],
- 'Previous page': ['Left', 'Jump to the previous page.'],
+ 'Next page': ['Shift+Right', 'Jump to the next page.'],
+ 'Previous page': ['Shift+Left', 'Jump to the previous page.'],
'Open catalog': ['Shift+c', 'Open the catalog of the current board'],
- 'Next thread': ['Down', 'See next thread.'],
- 'Previous thread': ['Up', 'See previous thread.'],
+ 'Next thread': ['Shift+Down', 'See next thread.'],
+ 'Previous thread': ['Shift+Up', 'See previous thread.'],
'Expand thread': ['Ctrl+e', 'Expand thread.'],
'Open thread': ['o', 'Open thread in current tab.'],
'Open thread tab': ['Shift+o', 'Open thread in new tab.'],
@@ -4160,7 +4161,7 @@
}
flag = flagCode ? (" ") : '';
if (file != null ? file.isDeleted : void 0) {
- fileHtml = isOP ? ("
") + (" ") + " " : ("") + (" ") + " ";
+ fileHtml = isOP ? ("
") + (" ") + " " : ("") + (" ") + " ";
} else if (file) {
ext = file.name.slice(-3);
if (!file.twidth && !file.theight && ext === 'gif') {
@@ -6655,7 +6656,7 @@
regExp: /.*(?:youtu.be\/|youtube.*v=|youtube.*\/embed\/|youtube.*\/v\/|youtube.*videos\/)([^#\&\?]*)\??(t\=.*)?/,
el: function() {
return $.el('iframe', {
- src: "//www.youtube.com/embed/" + this.name + (this.option ? '#' + this.option : '')
+ src: "//www.youtube.com/embed/" + this.name + (this.option ? '#' + this.option : '') + "?wmode=opaque"
});
},
title: {
@@ -6672,7 +6673,7 @@
style: 'border: 0; width: 150px; height: 45px;',
el: function() {
return $.el('object', {
- innerHTML: " "
+ innerHTML: " "
});
}
},
@@ -6680,7 +6681,7 @@
regExp: /.*(?:vimeo.com\/)([^#\&\?]*).*/,
el: function() {
return $.el('iframe', {
- src: "//player.vimeo.com/video/" + this.name
+ src: "//player.vimeo.com/video/" + this.name + "?wmode=opaque"
});
},
title: {
@@ -6695,8 +6696,8 @@
LiveLeak: {
regExp: /.*(?:liveleak.com\/view.+i=)([0-9a-z_]+)/,
el: function() {
- return $.el('iframe', {
- src: "http://www.liveleak.com/e/" + this.name + "?autostart=true"
+ return $.el('object', {
+ innerHTML: " "
});
}
},
@@ -6869,7 +6870,11 @@
this.db = new DataBoard('yourPosts');
$.ready(this.initReady);
if (Conf['Persistent QR']) {
- $.on(d, '4chanXInitFinished', this.persist);
+ if (g.BOARD.ID !== 'f') {
+ $.on(d, '4chanXInitFinished', this.persist);
+ } else {
+ $.ready(this.persist);
+ }
}
Post.prototype.callbacks.push({
name: 'Quick Reply',
@@ -7134,6 +7139,9 @@
list = $("#list-" + type, QR.nodes.el);
for (_i = 0, _len = arr.length; _i < _len; _i++) {
val = arr[_i];
+ if (!val) {
+ continue;
+ }
$.add(list, $.el('option', {
textContent: val
}));
@@ -8465,22 +8473,7 @@
}
},
setFitness: function() {
- var checked;
-
- checked = this.checked;
- (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
- if (this.name !== 'Fit height') {
- return;
- }
- if (checked) {
- $.on(window, 'resize', ImageExpand.resize);
- if (!ImageExpand.style) {
- ImageExpand.style = $.addStyle(null);
- }
- return ImageExpand.resize();
- } else {
- return $.off(window, 'resize', ImageExpand.resize);
- }
+ return (this.checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
}
},
toggle: function(post) {
@@ -8678,9 +8671,6 @@
};
}
},
- resize: function() {
- return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
- },
menuToggle: function(e) {
return ImageExpand.opmenu.toggle(e, this, g);
}
@@ -8801,7 +8791,7 @@
return $.event('AddMenuEntry', {
type: 'header',
el: prefetch,
- order: 120
+ order: 104
});
},
node: function() {
@@ -9287,20 +9277,23 @@
}
if (Conf['Updater and Stats in Header']) {
this.dialog = sc = $.el('span', {
- innerHTML: "0 / 0 ",
- id: 'thread-stats'
+ innerHTML: "0 / 0 " + (Conf["Page Count in Stats"] ? " / 0 " : ""),
+ id: 'thread-stats',
+ title: 'Post Count / File Count' + (Conf["Page Count in Stats"] ? " / Page Count" : "")
});
$.ready(function() {
return Header.addShortcut(sc);
});
} else {
- this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "0 / 0
");
+ this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "0 / 0 " + (Conf["Page Count in Stats"] ? " / 0 " : "") + "
");
$.ready(function() {
return $.add(d.body, sc);
});
}
this.postCountEl = $('#post-count', sc);
this.fileCountEl = $('#file-count', sc);
+ this.pageCountEl = $('#page-count', sc);
+ this.lastModified = '0';
return Thread.prototype.callbacks.push({
name: 'Thread Stats',
cb: this.node
@@ -9320,6 +9313,7 @@
}
}
ThreadStats.thread = this;
+ ThreadStats.fetchPage();
ThreadStats.update(postCount, fileCount);
return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
@@ -9340,6 +9334,43 @@
fileCountEl.textContent = fileCount;
(thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
+ },
+ fetchPage: function() {
+ if (ThreadStats.thread.isDead || !Conf["Page Count in Stats"]) {
+ return;
+ }
+ setTimeout(ThreadStats.fetchPage, 2 * $.MINUTE);
+ return $.ajax("//api.4chan.org/" + ThreadStats.thread.board + "/threads.json", {
+ onload: ThreadStats.onThreadsLoad
+ }, {
+ headers: {
+ 'If-Modified-Since': ThreadStats.lastModified
+ }
+ });
+ },
+ onThreadsLoad: function() {
+ var page, pages, thread, _i, _j, _len, _len1, _ref;
+
+ if (!Conf["Page Count in Stats"]) {
+ return;
+ }
+ ThreadStats.lastModified = this.getResponseHeader('Last-Modified');
+ if (this.status !== 200) {
+ return;
+ }
+ pages = JSON.parse(this.response);
+ for (_i = 0, _len = pages.length; _i < _len; _i++) {
+ page = pages[_i];
+ _ref = page.threads;
+ for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
+ thread = _ref[_j];
+ if (thread.no === ThreadStats.thread.ID) {
+ ThreadStats.pageCountEl.textContent = page.page;
+ (page.page === pages.length - 1 ? $.addClass : $.rmClass)(ThreadStats.pageCountEl, 'warning');
+ return;
+ }
+ }
+ }
}
};
@@ -12775,11 +12806,17 @@
$.open("/" + g.BOARD + "/#delform");
break;
case Conf['Next page']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
if (form = $('.next form')) {
window.location = form.action;
}
break;
case Conf['Previous page']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
if (form = $('.prev form')) {
window.location = form.action;
}
@@ -13494,7 +13531,8 @@
(sectionToOpen ? sectionToOpen : links[0]).click();
$.on($('.close', dialog), 'click', Settings.close);
$.on(overlay, 'click', Settings.close);
- return $.add(d.body, [overlay, dialog]);
+ $.add(d.body, [overlay, dialog]);
+ return $.event('OpenSettings', null, dialog);
},
close: function() {
if (!Settings.dialog) {
@@ -13530,7 +13568,8 @@
$.rmAll(section);
section.className = "section-" + this.hyphenatedTitle;
this.open(section, mode);
- return section.scrollTop = 0;
+ section.scrollTop = 0;
+ return $.event('OpenSettings', null, section);
},
main: function(section) {
var arr, button, description, div, fs, hiddenNum, input, inputs, items, key, obj, _ref;
diff --git a/builds/crx/script.js b/builds/crx/script.js
index 75776790f..9dc79b956 100644
--- a/builds/crx/script.js
+++ b/builds/crx/script.js
@@ -1,6 +1,6 @@
// Generated by CoffeeScript
/*
-* appchan x - Version 2.0.4 - 2013-05-23
+* appchan x - Version 2.0.4 - 2013-05-27
*
* Licensed under the MIT license.
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
@@ -167,6 +167,7 @@
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.'],
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title.'],
'Thread Stats': [true, 'Display reply and image count.'],
+ 'Page Count in Stats': [false, 'Display the page count in the thread stats as well.'],
'Updater and Stats in Header': [true, 'Places the thread updater and thread stats in the header instead of floating them.'],
'Thread Watcher': [true, 'Bookmark threads.'],
'Toggleable Thread Watcher': [false, 'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.'],
@@ -331,7 +332,7 @@
},
time: '%m/%d/%y(%a)%H:%M:%S',
backlink: '>>%id',
- fileInfo: '%l (%p%s, %r)',
+ fileInfo: '%L (%p%s, %r)',
favicon: 'ferongr',
usercss: "/* Tripcode Italics: */\n/*\nspan.postertrip {\nfont-style: italic;\n}\n*/\n\n/* Add a rounded border to thumbnails (but not expanded images): */\n/*\n.fileThumb > img:first-child {\nborder: solid 2px rgba(0,0,100,0.5);\nborder-radius: 10px;\n}\n*/\n\n/* Make highlighted posts look inset on the page: */\n/*\ndiv.post:target,\ndiv.post.highlight {\nbox-shadow: inset 2px 2px 2px rgba(0,0,0,0.2);\n}\n*/",
hotkeys: {
@@ -354,11 +355,11 @@
'fappeTyme': ['f', 'Fappe Tyme.'],
'Front page': ['0', 'Jump to page 0.'],
'Open front page': ['Shift+0', 'Open page 0 in a new tab.'],
- 'Next page': ['Right', 'Jump to the next page.'],
- 'Previous page': ['Left', 'Jump to the previous page.'],
+ 'Next page': ['Shift+Right', 'Jump to the next page.'],
+ 'Previous page': ['Shift+Left', 'Jump to the previous page.'],
'Open catalog': ['Shift+c', 'Open the catalog of the current board'],
- 'Next thread': ['Down', 'See next thread.'],
- 'Previous thread': ['Up', 'See previous thread.'],
+ 'Next thread': ['Shift+Down', 'See next thread.'],
+ 'Previous thread': ['Shift+Up', 'See previous thread.'],
'Expand thread': ['Ctrl+e', 'Expand thread.'],
'Open thread': ['o', 'Open thread in current tab.'],
'Open thread tab': ['Shift+o', 'Open thread in new tab.'],
@@ -4161,7 +4162,7 @@
}
flag = flagCode ? (" ") : '';
if (file != null ? file.isDeleted : void 0) {
- fileHtml = isOP ? ("
") + (" ") + " " : ("") + (" ") + " ";
+ fileHtml = isOP ? ("
") + (" ") + " " : ("") + (" ") + " ";
} else if (file) {
ext = file.name.slice(-3);
if (!file.twidth && !file.theight && ext === 'gif') {
@@ -6656,7 +6657,7 @@
regExp: /.*(?:youtu.be\/|youtube.*v=|youtube.*\/embed\/|youtube.*\/v\/|youtube.*videos\/)([^#\&\?]*)\??(t\=.*)?/,
el: function() {
return $.el('iframe', {
- src: "//www.youtube.com/embed/" + this.name + (this.option ? '#' + this.option : '')
+ src: "//www.youtube.com/embed/" + this.name + (this.option ? '#' + this.option : '') + "?wmode=opaque"
});
},
title: {
@@ -6673,7 +6674,7 @@
style: 'border: 0; width: 150px; height: 45px;',
el: function() {
return $.el('object', {
- innerHTML: " "
+ innerHTML: " "
});
}
},
@@ -6681,7 +6682,7 @@
regExp: /.*(?:vimeo.com\/)([^#\&\?]*).*/,
el: function() {
return $.el('iframe', {
- src: "//player.vimeo.com/video/" + this.name
+ src: "//player.vimeo.com/video/" + this.name + "?wmode=opaque"
});
},
title: {
@@ -6696,8 +6697,8 @@
LiveLeak: {
regExp: /.*(?:liveleak.com\/view.+i=)([0-9a-z_]+)/,
el: function() {
- return $.el('iframe', {
- src: "http://www.liveleak.com/e/" + this.name + "?autostart=true"
+ return $.el('object', {
+ innerHTML: " "
});
}
},
@@ -6870,7 +6871,11 @@
this.db = new DataBoard('yourPosts');
$.ready(this.initReady);
if (Conf['Persistent QR']) {
- $.on(d, '4chanXInitFinished', this.persist);
+ if (g.BOARD.ID !== 'f') {
+ $.on(d, '4chanXInitFinished', this.persist);
+ } else {
+ $.ready(this.persist);
+ }
}
Post.prototype.callbacks.push({
name: 'Quick Reply',
@@ -7136,6 +7141,9 @@
list = $("#list-" + type, QR.nodes.el);
for (_i = 0, _len = arr.length; _i < _len; _i++) {
val = arr[_i];
+ if (!val) {
+ continue;
+ }
$.add(list, $.el('option', {
textContent: val
}));
@@ -8442,22 +8450,7 @@
}
},
setFitness: function() {
- var checked;
-
- checked = this.checked;
- (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
- if (this.name !== 'Fit height') {
- return;
- }
- if (checked) {
- $.on(window, 'resize', ImageExpand.resize);
- if (!ImageExpand.style) {
- ImageExpand.style = $.addStyle(null);
- }
- return ImageExpand.resize();
- } else {
- return $.off(window, 'resize', ImageExpand.resize);
- }
+ return (this.checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
}
},
toggle: function(post) {
@@ -8655,9 +8648,6 @@
};
}
},
- resize: function() {
- return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
- },
menuToggle: function(e) {
return ImageExpand.opmenu.toggle(e, this, g);
}
@@ -8778,7 +8768,7 @@
return $.event('AddMenuEntry', {
type: 'header',
el: prefetch,
- order: 120
+ order: 104
});
},
node: function() {
@@ -9264,20 +9254,23 @@
}
if (Conf['Updater and Stats in Header']) {
this.dialog = sc = $.el('span', {
- innerHTML: "0 / 0 ",
- id: 'thread-stats'
+ innerHTML: "0 / 0 " + (Conf["Page Count in Stats"] ? " / 0 " : ""),
+ id: 'thread-stats',
+ title: 'Post Count / File Count' + (Conf["Page Count in Stats"] ? " / Page Count" : "")
});
$.ready(function() {
return Header.addShortcut(sc);
});
} else {
- this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "0 / 0
");
+ this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "0 / 0 " + (Conf["Page Count in Stats"] ? " / 0 " : "") + "
");
$.ready(function() {
return $.add(d.body, sc);
});
}
this.postCountEl = $('#post-count', sc);
this.fileCountEl = $('#file-count', sc);
+ this.pageCountEl = $('#page-count', sc);
+ this.lastModified = '0';
return Thread.prototype.callbacks.push({
name: 'Thread Stats',
cb: this.node
@@ -9297,6 +9290,7 @@
}
}
ThreadStats.thread = this;
+ ThreadStats.fetchPage();
ThreadStats.update(postCount, fileCount);
return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
@@ -9317,6 +9311,43 @@
fileCountEl.textContent = fileCount;
(thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
+ },
+ fetchPage: function() {
+ if (ThreadStats.thread.isDead || !Conf["Page Count in Stats"]) {
+ return;
+ }
+ setTimeout(ThreadStats.fetchPage, 2 * $.MINUTE);
+ return $.ajax("//api.4chan.org/" + ThreadStats.thread.board + "/threads.json", {
+ onload: ThreadStats.onThreadsLoad
+ }, {
+ headers: {
+ 'If-Modified-Since': ThreadStats.lastModified
+ }
+ });
+ },
+ onThreadsLoad: function() {
+ var page, pages, thread, _i, _j, _len, _len1, _ref;
+
+ if (!Conf["Page Count in Stats"]) {
+ return;
+ }
+ ThreadStats.lastModified = this.getResponseHeader('Last-Modified');
+ if (this.status !== 200) {
+ return;
+ }
+ pages = JSON.parse(this.response);
+ for (_i = 0, _len = pages.length; _i < _len; _i++) {
+ page = pages[_i];
+ _ref = page.threads;
+ for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
+ thread = _ref[_j];
+ if (thread.no === ThreadStats.thread.ID) {
+ ThreadStats.pageCountEl.textContent = page.page;
+ (page.page === pages.length - 1 ? $.addClass : $.rmClass)(ThreadStats.pageCountEl, 'warning');
+ return;
+ }
+ }
+ }
}
};
@@ -12757,11 +12788,17 @@
$.open("/" + g.BOARD + "/#delform");
break;
case Conf['Next page']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
if (form = $('.next form')) {
window.location = form.action;
}
break;
case Conf['Previous page']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
if (form = $('.prev form')) {
window.location = form.action;
}
@@ -13476,7 +13513,8 @@
(sectionToOpen ? sectionToOpen : links[0]).click();
$.on($('.close', dialog), 'click', Settings.close);
$.on(overlay, 'click', Settings.close);
- return $.add(d.body, [overlay, dialog]);
+ $.add(d.body, [overlay, dialog]);
+ return $.event('OpenSettings', null, dialog);
},
close: function() {
if (!Settings.dialog) {
@@ -13512,7 +13550,8 @@
$.rmAll(section);
section.className = "section-" + this.hyphenatedTitle;
this.open(section, mode);
- return section.scrollTop = 0;
+ section.scrollTop = 0;
+ return $.event('OpenSettings', null, section);
},
main: function(section) {
var arr, button, description, div, fs, hiddenNum, input, inputs, items, key, obj, _ref;
diff --git a/src/General/Build.coffee b/src/General/Build.coffee
index 1f14e7107..67f6793e5 100644
--- a/src/General/Build.coffee
+++ b/src/General/Build.coffee
@@ -117,11 +117,11 @@ Build =
if file?.isDeleted
fileHtml = if isOP
- "
" +
+ "
" +
" " +
" "
else
- "" +
+ "" +
" " +
" "
else if file
diff --git a/src/General/Config.coffee b/src/General/Config.coffee
index 028099a70..2ba5b277a 100644
--- a/src/General/Config.coffee
+++ b/src/General/Config.coffee
@@ -221,6 +221,10 @@ Config =
true
'Display reply and image count.'
]
+ 'Page Count in Stats': [
+ false
+ 'Display the page count in the thread stats as well.'
+ ]
'Updater and Stats in Header': [
true,
'Places the thread updater and thread stats in the header instead of floating them.'
@@ -813,7 +817,7 @@ http://iqdb.org/?url=%TURL
backlink: '>>%id'
- fileInfo: '%l (%p%s, %r)'
+ fileInfo: '%L (%p%s, %r)'
favicon: 'ferongr'
@@ -924,11 +928,11 @@ box-shadow: inset 2px 2px 2px rgba(0,0,0,0.2);
'Open page 0 in a new tab.'
]
'Next page': [
- 'Right'
+ 'Shift+Right'
'Jump to the next page.'
]
'Previous page': [
- 'Left'
+ 'Shift+Left'
'Jump to the previous page.'
]
'Open catalog': [
@@ -937,11 +941,11 @@ box-shadow: inset 2px 2px 2px rgba(0,0,0,0.2);
]
# Thread Navigation
'Next thread': [
- 'Down'
+ 'Shift+Down'
'See next thread.'
]
'Previous thread': [
- 'Up'
+ 'Shift+Up'
'See previous thread.'
]
'Expand thread': [
diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee
index 032f65953..7ea9d7031 100644
--- a/src/General/Settings.coffee
+++ b/src/General/Settings.coffee
@@ -93,6 +93,8 @@ Settings =
$.add d.body, [overlay, dialog]
+ $.event 'OpenSettings', null, dialog
+
close: ->
return unless Settings.dialog
$.rm Settings.overlay
@@ -117,6 +119,7 @@ Settings =
section.className = "section-#{@hyphenatedTitle}"
@open section, mode
section.scrollTop = 0
+ $.event 'OpenSettings', null, section
main: (section) ->
items = {}
diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee
index e6f33bbd8..b74eadd85 100644
--- a/src/Images/ImageExpand.coffee
+++ b/src/Images/ImageExpand.coffee
@@ -55,16 +55,20 @@ ImageExpand =
$.queueTask func, post
return
setFitness: ->
- {checked} = @
- (if checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-'
+ (if @checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-'
+<% if (type === 'userjs') { %>
+# XXX Opera doesn't support CSS vh.
return unless @name is 'Fit height'
- if checked
+ if @checked
$.on window, 'resize', ImageExpand.resize
unless ImageExpand.style
ImageExpand.style = $.addStyle null
ImageExpand.resize()
else
$.off window, 'resize', ImageExpand.resize
+ resize: ->
+ ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:#{doc.clientHeight}px}"
+<% } %>
toggle: (post) ->
{thumb} = post.file
@@ -204,8 +208,5 @@ ImageExpand =
$.on input, 'change', $.cb.checked
el: label
- resize: ->
- ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:#{doc.clientHeight}px}"
-
menuToggle: (e) ->
- ImageExpand.opmenu.toggle e, @, g
\ No newline at end of file
+ ImageExpand.opmenu.toggle e, @, g
diff --git a/src/Images/ImageLoader.coffee b/src/Images/ImageLoader.coffee
index 4146116b5..b4df767d2 100644
--- a/src/Images/ImageLoader.coffee
+++ b/src/Images/ImageLoader.coffee
@@ -18,7 +18,7 @@ ImageLoader =
$.event 'AddMenuEntry',
type: 'header'
el: prefetch
- order: 120
+ order: 104
node: ->
return if @isClone or @isHidden or @thread.isHidden or !@file?.isImage
diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee
index 8862fd11d..776cb059e 100644
--- a/src/Linkification/Linkify.coffee
+++ b/src/Linkification/Linkify.coffee
@@ -151,7 +151,7 @@ Linkify =
regExp: /.*(?:youtu.be\/|youtube.*v=|youtube.*\/embed\/|youtube.*\/v\/|youtube.*videos\/)([^#\&\?]*)\??(t\=.*)?/
el: ->
$.el 'iframe',
- src: "//www.youtube.com/embed/#{@name}#{if @option then '#' + @option else ''}"
+ src: "//www.youtube.com/embed/#{@name}#{if @option then '#' + @option else ''}?wmode=opaque"
title:
api: -> "https://gdata.youtube.com/feeds/api/videos/#{@name}?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode"
text: -> JSON.parse(@responseText).entry.title.$t
@@ -161,13 +161,13 @@ Linkify =
style: 'border: 0; width: 150px; height: 45px;'
el: ->
$.el 'object',
- innerHTML: " "
+ innerHTML: " "
Vimeo:
regExp: /.*(?:vimeo.com\/)([^#\&\?]*).*/
el: ->
$.el 'iframe',
- src: "//player.vimeo.com/video/#{@name}"
+ src: "//player.vimeo.com/video/#{@name}?wmode=opaque"
title:
api: -> "https://vimeo.com/api/oembed.json?url=http://vimeo.com/#{@name}"
text: -> JSON.parse(@responseText).title
@@ -175,8 +175,8 @@ Linkify =
LiveLeak:
regExp: /.*(?:liveleak.com\/view.+i=)([0-9a-z_]+)/
el: ->
- $.el 'iframe',
- src: "http://www.liveleak.com/e/#{@name}?autostart=true"
+ $.el 'object',
+ innerHTML: " "
audio:
regExp: /(.*\.(mp3|ogg|wav))$/
diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee
index b2b023f4a..f7045e8cf 100644
--- a/src/Miscellaneous/Keybinds.coffee
+++ b/src/Miscellaneous/Keybinds.coffee
@@ -79,9 +79,11 @@ Keybinds =
when Conf['Open front page']
$.open "/#{g.BOARD}/#delform"
when Conf['Next page']
+ return if g.VIEW is 'thread'
if form = $ '.next form'
window.location = form.action
when Conf['Previous page']
+ return if g.VIEW is 'thread'
if form = $ '.prev form'
window.location = form.action
when Conf['Open catalog']
diff --git a/src/Monitoring/ThreadStats.coffee b/src/Monitoring/ThreadStats.coffee
index 7cb857ca5..8cfae31c5 100644
--- a/src/Monitoring/ThreadStats.coffee
+++ b/src/Monitoring/ThreadStats.coffee
@@ -4,18 +4,21 @@ ThreadStats =
if Conf['Updater and Stats in Header']
@dialog = sc = $.el 'span',
- innerHTML: "0 / 0 "
+ innerHTML: "0 / 0 #{if Conf["Page Count in Stats"] then " / 0 " else ""}"
id: 'thread-stats'
+ title: 'Post Count / File Count' + (if Conf["Page Count in Stats"] then " / Page Count" else "")
$.ready ->
Header.addShortcut sc
else
@dialog = sc = UI.dialog 'thread-stats', 'bottom: 0px; right: 0px;',
- "0 / 0
"
+ "0 / 0 #{if Conf["Page Count in Stats"] then " / 0 " else ""}
"
$.ready =>
$.add d.body, sc
@postCountEl = $ '#post-count', sc
@fileCountEl = $ '#file-count', sc
+ @pageCountEl = $ '#page-count', sc
+ @lastModified = '0'
Thread::callbacks.push
name: 'Thread Stats'
@@ -28,6 +31,7 @@ ThreadStats =
postCount++
fileCount++ if post.file
ThreadStats.thread = @
+ ThreadStats.fetchPage()
ThreadStats.update postCount, fileCount
$.on d, 'ThreadUpdate', ThreadStats.onUpdate
@@ -41,4 +45,22 @@ ThreadStats =
postCountEl.textContent = postCount
fileCountEl.textContent = fileCount
(if thread.postLimit and !thread.isSticky then $.addClass else $.rmClass) postCountEl, 'warning'
- (if thread.fileLimit and !thread.isSticky then $.addClass else $.rmClass) fileCountEl, 'warning'
\ No newline at end of file
+ (if thread.fileLimit and !thread.isSticky then $.addClass else $.rmClass) fileCountEl, 'warning'
+
+ fetchPage: ->
+ return if ThreadStats.thread.isDead or !Conf["Page Count in Stats"]
+ setTimeout ThreadStats.fetchPage, 2 * $.MINUTE
+ $.ajax "//api.4chan.org/#{ThreadStats.thread.board}/threads.json", onload: ThreadStats.onThreadsLoad,
+ headers: 'If-Modified-Since': ThreadStats.lastModified
+
+ onThreadsLoad: ->
+ return if !Conf["Page Count in Stats"]
+ ThreadStats.lastModified = @getResponseHeader 'Last-Modified'
+ return if @status isnt 200
+ pages = JSON.parse @response
+ for page in pages
+ for thread in page.threads
+ if thread.no is ThreadStats.thread.ID
+ ThreadStats.pageCountEl.textContent = page.page
+ (if page.page is pages.length - 1 then $.addClass else $.rmClass) ThreadStats.pageCountEl, 'warning'
+ return
diff --git a/src/Posting/QuickReply.coffee b/src/Posting/QuickReply.coffee
index 79909909e..011242f38 100644
--- a/src/Posting/QuickReply.coffee
+++ b/src/Posting/QuickReply.coffee
@@ -3,7 +3,12 @@ QR =
@db = new DataBoard 'yourPosts'
$.ready @initReady
- $.on d, '4chanXInitFinished', @persist if Conf['Persistent QR']
+
+ if Conf['Persistent QR']
+ unless g.BOARD.ID is 'f'
+ $.on d, '4chanXInitFinished', @persist
+ else
+ $.ready @persist
Post::callbacks.push
name: 'Quick Reply'
@@ -209,6 +214,8 @@ QR =
loadPersonas: (type, arr) ->
list = $ "#list-#{type}", QR.nodes.el
for val in arr
+ # XXX Firefox displays empty s in the completion list.
+ continue unless val
$.add list, $.el 'option',
textContent: val
return