diff --git a/inc/config.php b/inc/config.php
index 802a1471..41cbbd12 100644
--- a/inc/config.php
+++ b/inc/config.php
@@ -1526,6 +1526,11 @@
// Keep the Google Analytics cookies to one domain -- ga._setDomainName()
// $config['google_analytics_domain'] = 'www.example.org';
+ // Link imageboard to your Statcounter.com account to track users and provide traffic insights without the Google botnet.
+ // Extract these values from Statcounter's JS tracking code:
+ // $config['statcounter_project'] = '1234567';
+ // $config['statcounter_security'] = 'acbd1234';
+
// If you use Varnish, Squid, or any similar caching reverse-proxy in front of Tinyboard, you can
// configure Tinyboard to PURGE files when they're written to.
// $config['purge'] = array(
diff --git a/inc/display.php b/inc/display.php
index 9397b4a9..1a78e19b 100644
--- a/inc/display.php
+++ b/inc/display.php
@@ -353,7 +353,7 @@ class Post {
$this->{$key} = $value;
}
- if (isset($this->files))
+ if (isset($this->files) && $this->files)
$this->files = json_decode($this->files);
$this->subject = utf8tohtml($this->subject);
diff --git a/inc/functions.php b/inc/functions.php
index 3a8065c4..33f22942 100644
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -2325,6 +2325,7 @@ function shell_exec_error($command, $suppress_stdout = false) {
* added on. The result is displayed at the top of the post.
*/
function diceRoller($post) {
+ global $config;
if(strpos(strtolower($post->email), 'dice%20') === 0) {
$dicestr = str_split(substr($post->email, strlen('dice%20')));
@@ -2372,7 +2373,7 @@ function diceRoller($post) {
// Prepend the result to the post body
$modifier = ($diceZ != 0) ? ((($diceZ < 0) ? ' - ' : ' + ') . abs($diceZ)) : '';
$dicesum = ($diceX > 1) ? ' = ' . $dicesum : '';
- $post->body = 'Rolled ' . implode(', ', $dicerolls) . $modifier . $dicesum . ' ' . $post->body;
+ $post->body = '
Rolled ' . implode(', ', $dicerolls) . $modifier . $dicesum . '
' . $post->body;
}
}
}
diff --git a/js/expand.js b/js/expand.js
index 0256aebe..0fa8de05 100644
--- a/js/expand.js
+++ b/js/expand.js
@@ -20,8 +20,8 @@ $(document).ready(function(){
var do_expand = function() {
$(this)
.html($(this).text().replace(_("Click reply to view."), ''+_("Click to expand")+' .'))
- .find('a').click(function() {
- var thread = $(this).parent().parent().parent();
+ .find('a').click(window.expand_fun = function() {
+ var thread = $(this).parents('[id^="thread_"]');
var id = thread.attr('id').replace(/^thread_/, '');
$.ajax({
url: thread.find('p.intro a.post_no:first').attr('href'),
@@ -43,12 +43,16 @@ $(document).ready(function(){
last_expanded = post_in_doc;
}
});
- $('' + _('Hide expanded replies') + ' . ')
- .insertAfter(thread.find('span.omitted').css('display', 'none'))
+
+
+ thread.find("span.omitted").css('display', 'none');
+
+ $('' + _('Hide expanded replies') + ' . ')
+ .insertAfter(thread.find('.op div.body, .op span.omitted').last())
.click(function() {
thread.find('.expanded').remove();
- $(this).prev().css('display', '');
- $(this).remove();
+ $(this).parent().find(".omitted:not(.hide-expanded)").css('display', '');
+ $(this).parent().find(".hide-expanded").remove();
});
}
});
diff --git a/js/hide-threads.js b/js/hide-threads.js
index b26feca3..f83b479b 100644
--- a/js/hide-threads.js
+++ b/js/hide-threads.js
@@ -36,7 +36,7 @@ $(document).ready(function(){
}
}
- var fields_to_hide = 'div.post,div.video-container,video,img,p.fileinfo,a.hide-thread-link,br';
+ var fields_to_hide = 'div.post,div.video-container,video,img:not(.unanimated),canvas,p.fileinfo,a.hide-thread-link,div.new-posts,br';
var do_hide_threads = function() {
var id = $(this).children('p.intro').children('a.post_no:eq(1)').text();
diff --git a/js/live-index.js b/js/live-index.js
new file mode 100644
index 00000000..463f7596
--- /dev/null
+++ b/js/live-index.js
@@ -0,0 +1,105 @@
+/*
+ * live-index.js
+ * https://github.com/vichan-devel/Tinyboard/blob/master/js/live-index.js
+ *
+ * Released under the MIT license
+ * Copyright (c) 2014 Marcin Ćabanowski
+ *
+ * Usage:
+ * $config['api']['enabled'] = true;
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/expand.js';
+ * $config['additional_javascript'][] = 'js/live-index.js';
+ *
+ */
+
+if (active_page == 'index' && (""+document.location).match(/\/(index\.html)?(\?|$|#)/))
++function() {
+ // Make jQuery respond to reverse()
+ $.fn.reverse = [].reverse;
+
+ var board_name = (""+document.location).match(/\/([^\/]+)\/[^/]*$/)[1];
+
+ var handle_one_thread = function() {
+ if ($(this).find(".new-posts").length <= 0) {
+ $(this).find("br.clear").before(""+_("No new posts.")+"
");
+ }
+ };
+
+ $(function() {
+ $("hr:first").before(""+_("No new threads.")+"
");
+
+ $('div[id^="thread_"]').each(handle_one_thread);
+
+ setInterval(function() {
+ $.getJSON(configRoot+board_name+"/0.json", function(j) {
+ var new_threads = 0;
+
+ j.threads.forEach(function(t) {
+ var s_thread = $("#thread_"+t.posts[0].no);
+
+ if (s_thread.length) {
+ var my_posts = s_thread.find(".post.reply").length;
+
+ var omitted_posts = s_thread.find(".omitted");
+ if (omitted_posts.length) {
+ omitted_posts = omitted_posts.html().match("^[^0-9]*([0-9]+)")[1]|0;
+ my_posts += omitted_posts;
+ }
+
+ my_posts -= t.posts[0].replies|0;
+ my_posts *= -1;
+ update_new_posts(my_posts, s_thread);
+ }
+ else {
+ new_threads++;
+ }
+ });
+
+ update_new_threads(new_threads);
+ });
+ }, 1000);
+ });
+
+ $(document).on("new_post", function(e, post) {
+ if (!$(post).hasClass("reply")) {
+ handle_one_thread.call(post);
+ }
+ });
+
+ var update_new_threads = function(i) {
+ var msg = i ?
+ (fmt(_("There are {0} new threads."), [i]) + " "+_("Click to expand")+" .") :
+ _("No new threads.");
+
+ if ($(".new-threads").html() != msg) {
+ $(".new-threads").html(msg);
+ $(".new-threads a").click(fetch_new_threads);
+ }
+ };
+
+ var update_new_posts = function(i, th) {
+ var msg = (i>0) ?
+ (fmt(_("There are {0} new posts in this thread."), [i])+" "+_("Click to expand")+" .") :
+ _("No new posts.");
+
+ if ($(th).find(".new-posts").html() != msg) {
+ $(th).find(".new-posts").html(msg);
+ $(th).find(".new-posts a").click(window.expand_fun);
+ }
+ };
+
+ var fetch_new_threads = function() {
+ $.get(""+document.location, function(data) {
+ $(data).find('div[id^="thread_"]').reverse().each(function() {
+ if ($("#"+$(this).attr("id")).length) {
+ // okay, the thread is there
+ }
+ else {
+ var thread = $(this).insertBefore('div[id^="thread_"]:first');
+ $(document).trigger("new_post", this);
+ }
+ });
+ });
+ };
+}();
diff --git a/js/no-animated-gif.js b/js/no-animated-gif.js
index 36d48954..5d21704f 100644
--- a/js/no-animated-gif.js
+++ b/js/no-animated-gif.js
@@ -24,7 +24,7 @@ function unanimate_gif(e) {
draw_image();
}
- $(e).hide();
+ $(e).addClass("unanimated").hide();
}
function no_animated_gif() {
@@ -37,7 +37,7 @@ function no_animated_gif() {
function animated_gif() {
$('canvas.post-image').remove();
- $('img.post-image').show();
+ $('img.post-image').removeClass("unanimated").show();
localStorage.no_animated_gif = false;
$('#no-animated-gif>a').text(_('Unanimate GIFs'));
diff --git a/js/watch.js b/js/watch.js
index 5c111bcd..4c36dbc4 100644
--- a/js/watch.js
+++ b/js/watch.js
@@ -152,12 +152,21 @@ $(function(){
};
var update_pinned = function() {
+ if (updating_suspended) return;
+
if (typeof update_title != "undefined") update_title();
var bl = $('.boardlist').first();
$('#watch-pinned, .watch-menu').remove();
var pinned = $('
').appendTo(bl);
+ if (device_type == "desktop")
+ bl.off().on("mouseenter", function() {
+ updating_suspended = true;
+ }).on("mouseleave", function() {
+ updating_suspended = false;
+ });
+
var st = storage();
for (var i in st) {
if (is_pinned(st[i])) {
@@ -198,7 +207,6 @@ $(function(){
if (device_type == "desktop")
link.off().mouseenter(function() {
- updating_suspended = true;
$('.cb-menu').remove();
var board = $(this).attr("data-board");
@@ -216,7 +224,6 @@ $(function(){
wl.find("a.cb-menuitem").each(init_hover);
}).mouseleave(function() {
- updating_suspended = false;
$('.boardlist .cb-menu').remove();
});
}
@@ -232,30 +239,45 @@ $(function(){
}
};
var fetch_jsons = function() {
- if (updating_suspended) return;
if (window_active) check_scroll();
var st = storage();
+
+ var sched = 0;
+ var sched_diff = 300;
+
for (var i in st) {
if (st[i].watched) {
- var r = $.getJSON(configRoot+i+"/threads.json", function(j, x, r) {
- handle_board_json(r.board, j);
- });
- r.board = i;
+ (function(i) {
+ setTimeout(function() {
+ var r = $.getJSON(configRoot+i+"/threads.json", function(j, x, r) {
+ handle_board_json(r.board, j);
+ });
+ r.board = i;
+ }, sched);
+ sched += sched_diff;
+ })(i);
}
else if (st[i].threads) {
for (var j in st[i].threads) {
- var r = $.getJSON(configRoot+i+"/res/"+j+".json", function(k, x, r) {
- handle_thread_json(r.board, r.thread, k);
- }).error(function(r) {
- if(r.status == 404) handle_thread_404(r.board, r.thread);
- });
-
- r.board = i;
- r.thread = j;
+ (function(i,j) {
+ setTimeout(function() {
+ var r = $.getJSON(configRoot+i+"/res/"+j+".json", function(k, x, r) {
+ handle_thread_json(r.board, r.thread, k);
+ }).error(function(r) {
+ if(r.status == 404) handle_thread_404(r.board, r.thread);
+ });
+
+ r.board = i;
+ r.thread = j;
+ }, sched);
+ })(i,j);
+ sched += sched_diff;
}
}
}
+
+ setTimeout(fetch_jsons, sched + sched_diff);
};
var handle_board_json = function(board, json) {
@@ -293,31 +315,39 @@ $(function(){
status = status || {};
status[board] = status[board] || {};
- status[board].last_thread = last_thread;
- status[board].new_threads = new_threads;
- update_pinned();
+ if (status[board].last_thread != last_thread || status[board].new_threads != new_threads) {
+ status[board].last_thread = last_thread;
+ status[board].new_threads = new_threads;
+ update_pinned();
+ }
};
var handle_thread_json = function(board, threadid, json) {
+ var new_posts = 0;
for (var i in json.posts) {
var post = json.posts[i];
- var new_posts = 0;
if (post.time > storage()[board].threads[threadid] / 1000) {
new_posts++;
}
- status = status || {};
- status[board] = status[board] || {};
- status[board].threads = status[board].threads || {};
+ }
+
+ status = status || {};
+ status[board] = status[board] || {};
+ status[board].threads = status[board].threads || {};
+
+ if (status[board].threads[threadid] != new_posts) {
status[board].threads[threadid] = new_posts;
update_pinned();
- }
+ }
};
var handle_thread_404 = function(board, threadid) {
status = status || {};
status[board] = status[board] || {};
status[board].threads = status[board].threads || {};
- status[board].threads[threadid] = -404; //notify 404
- update_pinned();
+ if (status[board].threads[threadid] != -404) {
+ status[board].threads[threadid] = -404; //notify 404
+ update_pinned();
+ }
};
if (active_page == "thread") {
@@ -386,7 +416,7 @@ $(function(){
$(window).scroll(function() {
var refresh = check_scroll();
if (refresh) {
- fetch_jsons();
+ //fetch_jsons();
refresh = false;
}
});
@@ -417,5 +447,4 @@ $(function(){
update_pinned();
fetch_jsons();
- setInterval(fetch_jsons, 10000);
});
diff --git a/static/d10.svg b/static/d10.svg
new file mode 100644
index 00000000..4d608be7
--- /dev/null
+++ b/static/d10.svg
@@ -0,0 +1,161 @@
+
+
+
+ Ten Side Dice
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+ Openclipart
+
+
+ Ten Sided Dice
+ 2010-11-06T04:13:53
+ A single-colour graphic of a 10-sided die (d10) as used in roleplaying and wargaming.
+ https://openclipart.org/detail/94495/ten-sided-dice-by-wirelizard
+
+
+ wirelizard
+
+
+
+
+ RPG
+ d10
+ dice
+ die
+ game
+ gamer
+ gaming
+ roleplay
+ ten side
+
+
+
+
+
+
+
+
+
+
+
diff --git a/stylesheets/style.css b/stylesheets/style.css
index ff1c4258..4e1c5f86 100644
--- a/stylesheets/style.css
+++ b/stylesheets/style.css
@@ -633,3 +633,12 @@ pre {
padding: 0;
margin: 5px 25px 5px 5px;
}
+
+/* live-index.js */
+.new-posts {
+ opacity: 0.6;
+ margin-top: 1em;
+}
+.new-threads {
+ text-align: center;
+}
diff --git a/templates/main.js b/templates/main.js
index 2da347f0..b0c27f47 100644
--- a/templates/main.js
+++ b/templates/main.js
@@ -305,3 +305,11 @@ var max_images = {{ config.max_images }};
var _gaq = _gaq || [];_gaq.push(['_setAccount', '{% endraw %}{{ config.google_analytics }}{% raw %}']);{% endraw %}{% if config.google_analytics_domain %}{% raw %}_gaq.push(['_setDomainName', '{% endraw %}{{ config.google_analytics_domain }}{% raw %}']){% endraw %}{% endif %}{% if not config.google_analytics_domain %}{% raw %}_gaq.push(['_setDomainName', 'none']){% endraw %}{% endif %}{% raw %};_gaq.push(['_trackPageview']);(function() {var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;ga.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'stats.g.doubleclick.net/dc.js';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);})();{% endraw %}{% endif %}
+{% if config.statcounter_project and config.statcounter_security %}
+var sc = document.createElement('script');
+sc.type = 'text/javascript';
+sc.innerHTML = 'var sc_project={{ config.statcounter_project }};var sc_invisible=1;var sc_security="{{ config.statcounter_security }}";var scJsHost=(("https:" == document.location.protocol) ? "https://secure." : "http://www.");document.write(""+"script>");';
+var s = document.getElementsByTagName('script')[0];
+s.parentNode.insertBefore(sc, s);
+{% endif %}
+