summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/ajax.js17
-rw-r--r--js/auto-reload.js376
-rw-r--r--js/catalog-link.js10
-rw-r--r--js/expand-all-images.js5
-rw-r--r--js/favorites.js1
-rw-r--r--js/file-selector.js191
-rw-r--r--js/forced-anon.js2
-rw-r--r--js/gallery-view.js165
-rw-r--r--js/hide-images.js2
-rw-r--r--js/hide-threads.js2
-rw-r--r--js/id_colors.js71
-rw-r--r--js/id_highlighter.js50
-rw-r--r--js/infinite-scroll.js91
-rw-r--r--js/inline.js154
-rw-r--r--js/live-index.js2
-rw-r--r--js/local-time.js10
-rw-r--r--js/longtable/longtable.js184
-rw-r--r--js/mod/ban-list.js157
-rw-r--r--js/multi-image.js7
-rw-r--r--js/no-animated-gif.js11
-rw-r--r--js/options/user-css.js2
-rw-r--r--js/options/user-js.js2
-rw-r--r--js/own-board.js116
-rw-r--r--js/post-hover.js4
-rw-r--r--js/quick-reply.js11
-rw-r--r--js/settings.js8
-rw-r--r--js/show-own-posts.js86
-rw-r--r--js/thread-stats.js116
-rw-r--r--js/thread-watcher.js195
-rw-r--r--js/threadscroll.js37
-rw-r--r--js/toggle-images.js2
-rw-r--r--js/treeview.js48
-rw-r--r--js/upload-selection.js2
m---------js/wPaint0
-rw-r--r--js/watch.js9
-rw-r--r--js/wpaint.js9
36 files changed, 1890 insertions, 265 deletions
diff --git a/js/ajax.js b/js/ajax.js
index 4501cef2..56f0df5c 100644
--- a/js/ajax.js
+++ b/js/ajax.js
@@ -107,6 +107,7 @@ $(window).ready(function() {
}, 'html');
}
$(form).find('input[type="submit"]').val(_('Posted...'));
+ $(document).trigger("ajax_after_post", post_response);
} else {
alert(_('An unknown error occured when posting!'));
$(form).find('input[type="submit"]').val(submit_txt);
@@ -114,17 +115,10 @@ $(window).ready(function() {
}
},
error: function(xhr, status, er) {
- // An error occured
- do_not_ajax = true;
- $(form).find('input[type="submit"]').each(function() {
- var $replacement = $('<input type="hidden">');
- $replacement.attr('name', $(this).attr('name'));
- $replacement.val(submit_txt);
- $(this)
- .after($replacement)
- .replaceWith($('<input type="button">').val(submit_txt));
- });
- $(form).submit();
+ console.log(xhr);
+ alert(_('The server took too long to submit your post. Your post was probably still submitted. If it wasn\'t, we might be experiencing issues right now -- please try your post again later. Error information: ') + "<div><textarea>" + JSON.stringify(xhr) + "</textarea></div>");
+ $(form).find('input[type="submit"]').val(submit_txt);
+ $(form).find('input[type="submit"]').removeAttr('disabled');
},
data: formData,
cache: false,
@@ -140,6 +134,7 @@ $(window).ready(function() {
};
setup_form($('form[name="post"]'));
$(window).on('quick-reply', function() {
+ $('form#quick-reply').off('submit');
setup_form($('form#quick-reply'));
});
});
diff --git a/js/auto-reload.js b/js/auto-reload.js
index bccc0ec2..d015dfc1 100644
--- a/js/auto-reload.js
+++ b/js/auto-reload.js
@@ -17,227 +17,221 @@
*
*/
-au = false;
-auto_reload_enabled = true; // for watch.js to interop
-function makeIcon(){
- if(au) return;
- au = true;
- $("link[rel='icon']").attr("href", "../static/favicon_au.png");
-}
+auto_reload_enabled = true; // for watch.js to interop
$(document).ready(function(){
- if($('div.banner').length == 0)
- return; // not index
-
- if($(".post.op").size() != 1)
- return; //not thread page
-
- var countdown_interval;
+ if($('div.banner').length == 0)
+ return; // not index
+
+ if($(".post.op").size() != 1)
+ return; //not thread page
+
+ var countdown_interval;
- // Add an update link
- $(".threadlinks span:last-child").after("<span id='updater'><a href='#' id='update_thread' style='padding-left:10px'>"+_("Update")+"</a> ] (<input type='checkbox' id='auto_update_status' checked> "+_("Auto")+") <span id='update_secs'></span></span>");
+ // Add an update link
+ $('.boardlist.bottom').prev().after("<span id='updater'><a href='#' id='update_thread' style='padding-left:10px'>["+_("Update")+"]</a> (<input type='checkbox' id='auto_update_status' checked> "+_("Auto")+") <span id='update_secs'></span></span>");
- // Grab the settings
- var settings = new script_settings('auto-reload');
- var poll_interval_mindelay = settings.get('min_delay_bottom', 5000);
- var poll_interval_maxdelay = settings.get('max_delay', 600000);
- var poll_interval_errordelay = settings.get('error_delay', 30000);
+ // Grab the settings
+ var settings = new script_settings('auto-reload');
+ var poll_interval_mindelay = settings.get('min_delay_bottom', 5000);
+ var poll_interval_maxdelay = settings.get('max_delay', 600000);
+ var poll_interval_errordelay = settings.get('error_delay', 30000);
- // number of ms to wait before reloading
- var poll_interval_delay = poll_interval_mindelay;
- var poll_current_time = poll_interval_delay;
+ // number of ms to wait before reloading
+ var poll_interval_delay = poll_interval_mindelay;
+ var poll_current_time = poll_interval_delay;
- var end_of_page = false;
+ var end_of_page = false;
- var new_posts = 0;
- var first_new_post = null;
+ var new_posts = 0;
+ var first_new_post = null;
+
+ var title = document.title;
- var title = document.title;
-
- if (typeof update_title == "undefined") {
- var update_title = function() {
- if (new_posts) {
- document.title = "("+new_posts+") "+title;
- } else {
- document.title = title;
- }
- };
- }
+ if (typeof update_title == "undefined") {
+ var update_title = function() {
+ if (new_posts) {
+ document.title = "("+new_posts+") "+title;
+ } else {
+ document.title = title;
+ }
+ };
+ }
- if (typeof add_title_collector != "undefined")
+ if (typeof add_title_collector != "undefined")
add_title_collector(function(){
- return new_posts;
+ return new_posts;
});
- var window_active = true;
- $(window).focus(function() {
- window_active = true;
- recheck_activated();
+ var window_active = true;
+ $(window).focus(function() {
+ window_active = true;
+ recheck_activated();
- // Reset the delay if needed
- if(settings.get('reset_focus', true)) {
- poll_interval_delay = poll_interval_mindelay;
- }
- });
- $(window).blur(function() {
- window_active = false;
- });
+ // Reset the delay if needed
+ if(settings.get('reset_focus', true)) {
+ poll_interval_delay = poll_interval_mindelay;
+ }
+ });
+ $(window).blur(function() {
+ window_active = false;
+ });
+
+ $('#auto_update_status').click(function() {
+ if($("#auto_update_status").is(':checked')) {
+ auto_update(poll_interval_mindelay);
+ } else {
+ stop_auto_update();
+ $('#update_secs').text("");
+ }
- $('#auto_update_status').click(function() {
- if($("#auto_update_status").is(':checked')) {
- auto_update(poll_interval_mindelay);
- } else {
- stop_auto_update();
- $('#update_secs').text("");
- }
+ });
+
- });
+ var decrement_timer = function() {
+ poll_current_time = poll_current_time - 1000;
+ $('#update_secs').text(poll_current_time/1000);
+
+ if (poll_current_time <= 0) {
+ poll(manualUpdate = false);
+ }
+ }
+ var recheck_activated = function() {
+ if (new_posts && window_active &&
+ $(window).scrollTop() + $(window).height() >=
+ $('div.boardlist.bottom').position().top) {
- var decrement_timer = function() {
- poll_current_time = poll_current_time - 1000;
- $('#update_secs').text(poll_current_time/1000);
+ new_posts = 0;
+ }
+ update_title();
+ first_new_post = null;
+ };
+
+ // automatically updates the thread after a specified delay
+ var auto_update = function(delay) {
+ clearInterval(countdown_interval);
- if (poll_current_time <= 0) {
- poll(manualUpdate = false);
+ poll_current_time = delay;
+ countdown_interval = setInterval(decrement_timer, 1000);
+ $('#update_secs').text(poll_current_time/1000);
}
- }
-
- var recheck_activated = function() {
- if (new_posts && window_active &&
- $(window).scrollTop() + $(window).height() >=
- $('footer').position().top) {
-
- new_posts = 0;
+
+ var stop_auto_update = function() {
+ clearInterval(countdown_interval);
}
- update_title();
- first_new_post = null;
- };
-
- // automatically updates the thread after a specified delay
- var auto_update = function(delay) {
- clearInterval(countdown_interval);
-
- poll_current_time = delay;
- countdown_interval = setInterval(decrement_timer, 1000);
- $('#update_secs').text(poll_current_time/1000);
- }
-
- var stop_auto_update = function() {
- clearInterval(countdown_interval);
- }
-
- var epoch = (new Date).getTime();
- var epochold = epoch;
-
- var timeDiff = function (delay) {
- if((epoch-epochold) > delay) {
- epochold = epoch = (new Date).getTime();
- return true;
- }else{
- epoch = (new Date).getTime();
- return;
+
+ var epoch = (new Date).getTime();
+ var epochold = epoch;
+
+ var timeDiff = function (delay) {
+ if((epoch-epochold) > delay) {
+ epochold = epoch = (new Date).getTime();
+ return true;
+ }else{
+ epoch = (new Date).getTime();
+ return;
+ }
}
- }
-
- var poll = function(manualUpdate) {
- stop_auto_update();
- $('#update_secs').text(_("Updating..."));
-
- $.ajax({
- url: document.location,
- success: function(data) {
- var loaded_posts = 0; // the number of new posts loaded in this update
- $(data).find('div.postcontainer').each(function() {
- var id = $(this).attr('id').substring(2);
- if($('#' + id).length == 0) {
- if (!new_posts) {
- first_new_post = this;
- makeIcon();
+
+ var poll = function(manualUpdate) {
+ stop_auto_update();
+ $('#update_secs').text(_("Updating..."));
+
+ $.ajax({
+ url: document.location,
+ success: function(data) {
+ var loaded_posts = 0; // the number of new posts loaded in this update
+ $(data).find('div.post.reply').each(function() {
+ var id = $(this).attr('id');
+ if($('#' + id).length == 0) {
+ if (!new_posts) {
+ first_new_post = this;
+ }
+ $(this).insertAfter($('div.post:last').next()).after('<br class="clear">');
+ new_posts++;
+ loaded_posts++;
+ $(document).trigger('new_post', this);
+ recheck_activated();
+ }
+ });
+ time_loaded = Date.now(); // interop with watch.js
+
+
+ if ($('#auto_update_status').is(':checked')) {
+ // If there are no new posts, double the delay. Otherwise set it to the min.
+ if(loaded_posts == 0) {
+ // if the update was manual, don't increase the delay
+ if (manualUpdate == false) {
+ poll_interval_delay *= 2;
+
+ // Don't increase the delay beyond the maximum
+ if(poll_interval_delay > poll_interval_maxdelay) {
+ poll_interval_delay = poll_interval_maxdelay;
+ }
+ }
+ } else {
+ poll_interval_delay = poll_interval_mindelay;
+ }
+
+ auto_update(poll_interval_delay);
+ } else {
+ // Decide the message to show if auto update is disabled
+ if (loaded_posts > 0)
+ $('#update_secs').text(fmt(_("Thread updated with {0} new post(s)"), [loaded_posts]));
+ else
+ $('#update_secs').text(_("No new posts found"));
+ }
+ },
+ error: function(xhr, status_text, error_text) {
+ if (status_text == "error") {
+ if (error_text == "Not Found") {
+ $('#update_secs').text(_("Thread deleted or pruned"));
+ $('#auto_update_status').prop('checked', false);
+ $('#auto_update_status').prop('disabled', true); // disable updates if thread is deleted
+ return;
+ } else {
+ $('#update_secs').text("Error: "+error_text);
+ }
+ } else if (status_text) {
+ $('#update_secs').text(_("Error: ")+status_text);
+ } else {
+ $('#update_secs').text(_("Unknown error"));
+ }
+
+ // Keep trying to update
+ if ($('#auto_update_status').is(':checked')) {
+ poll_interval_delay = poll_interval_errordelay;
+ auto_update(poll_interval_delay);
+ }
}
- $(this).insertAfter($('div.postcontainer:last').next()).after('<br class="clear">');
- new_posts++;
- loaded_posts++;
- $(document).trigger('new_post', this);
- recheck_activated();
- }
});
- time_loaded = Date.now(); // interop with watch.js
-
-
- if ($('#auto_update_status').is(':checked')) {
- // If there are no new posts, double the delay. Otherwise set it to the min.
- if(loaded_posts == 0) {
- // if the update was manual, don't increase the delay
- if (manualUpdate == false) {
- poll_interval_delay *= 2;
-
- // Don't increase the delay beyond the maximum
- if(poll_interval_delay > poll_interval_maxdelay) {
- poll_interval_delay = poll_interval_maxdelay;
- }
- }
- } else {
- poll_interval_delay = poll_interval_mindelay;
- }
-
- auto_update(poll_interval_delay);
- } else {
- // Decide the message to show if auto update is disabled
- if (loaded_posts > 0)
- $('#update_secs').text(fmt(_("Thread updated with {0} new post(s)"), [loaded_posts]));
- else
- $('#update_secs').text(_("No new posts found"));
- }
- },
- error: function(xhr, status_text, error_text) {
- if (status_text == "error") {
- if (error_text == "Not Found") {
- $('#update_secs').text(_("Thread deleted or pruned"));
- $('#auto_update_status').prop('checked', false);
- $('#auto_update_status').prop('disabled', true); // disable updates if thread is deleted
+
+ return false;
+ };
+
+ $(window).scroll(function() {
+ recheck_activated();
+
+ // if the newest post is not visible
+ if($(this).scrollTop() + $(this).height() <
+ $('div.post:last').position().top + $('div.post:last').height()) {
+ end_of_page = false;
return;
- } else {
- $('#update_secs').text("Error: "+error_text);
- }
- } else if (status_text) {
- $('#update_secs').text(_("Error: ")+status_text);
} else {
- $('#update_secs').text(_("Unknown error"));
- }
-
- // Keep trying to update
- if ($('#auto_update_status').is(':checked')) {
- poll_interval_delay = poll_interval_errordelay;
- auto_update(poll_interval_delay);
+ if($("#auto_update_status").is(':checked') && timeDiff(poll_interval_mindelay)) {
+ poll(manualUpdate = true);
+ }
+ end_of_page = true;
}
- }
});
- return false;
- };
-
- $(window).scroll(function() {
- recheck_activated();
+ $('#update_thread').on('click', function() { poll(manualUpdate = true); return false; });
- // if the newest post is not visible
- if($(this).scrollTop() + $(this).height() <
- $('div.post:last').position().top + $('div.post:last').height()) {
- end_of_page = false;
- return;
- } else {
- if($("#auto_update_status").is(':checked') && timeDiff(poll_interval_mindelay)) {
- poll(manualUpdate = true);
- }
- end_of_page = true;
+ if($("#auto_update_status").is(':checked')) {
+ auto_update(poll_interval_delay);
}
- });
-
- $('#update_thread').on('click', function() { poll(manualUpdate = true); return false; });
-
- if($("#auto_update_status").is(':checked')) {
- auto_update(poll_interval_delay);
- }
});
+
diff --git a/js/catalog-link.js b/js/catalog-link.js
index 899e6859..05ee9efb 100644
--- a/js/catalog-link.js
+++ b/js/catalog-link.js
@@ -15,13 +15,8 @@
function catalog() {
var board = $("input[name='board']");
-if (board.length>0) {
-if (window.location.href.indexOf("/res/")==-1){ //if we are inside a thread
-var catalog_url = 'catalog.html';
-}
-else {
-var catalog_url = '../catalog.html';
-}
+var catalog_url = configRoot + board.first().val() + "/catalog.html";
+
var pages = document.getElementsByClassName('pages')[0];
var bottom = document.getElementsByClassName('boardlist bottom')[0]
var subtitle = document.getElementsByClassName('subtitle')[0];
@@ -57,7 +52,6 @@ if (subtitle) {
subtitle.appendChild(link2);
}
}
-}
if (active_page == 'thread' || active_page == 'index') {
$(document).ready(catalog);
diff --git a/js/expand-all-images.js b/js/expand-all-images.js
index fc273e5e..5545045c 100644
--- a/js/expand-all-images.js
+++ b/js/expand-all-images.js
@@ -27,7 +27,10 @@ onready(function(){
$(this).parent().click();
});
- $('hr:first').before('<div id="shrink-all-images" style="text-align:right"><a class="unimportant" href="javascript:void(0)"></a></div>');
+ if (!$('#shrink-all-images').length) {
+ $('hr:first').before('<div id="shrink-all-images" style="text-align:right"><a class="unimportant" href="javascript:void(0)"></a></div>');
+ }
+
$('div#shrink-all-images a')
.text(_('Shrink all images'))
.click(function(){
diff --git a/js/favorites.js b/js/favorites.js
index e325e110..daf7b732 100644
--- a/js/favorites.js
+++ b/js/favorites.js
@@ -54,7 +54,6 @@ if (active_page == 'thread' || active_page == 'index') {
$(document).ready(function(){
var favorites = JSON.parse(localStorage.favorites);
var is_board_favorite = ~$.inArray(board_name, favorites);
- console.log(is_board_favorite);
$('header>h1').append('<a id="favorite-star" href="#" data-active="'+(is_board_favorite ? 'true' : 'false')+'" style="color: '+(is_board_favorite ? 'yellow' : 'grey')+'; text-decoration:none">\u2605</span>');
add_favorites();
diff --git a/js/file-selector.js b/js/file-selector.js
new file mode 100644
index 00000000..207a5ae9
--- /dev/null
+++ b/js/file-selector.js
@@ -0,0 +1,191 @@
+/*
+ * file-selector.js - Add support for drag and drop file selection, and paste from clipbboard on supported browsers.
+ *
+ * Usage:
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/file-selector.js';
+ */
+function init_file_selector(max_images) {
+
+$(document).ready(function () {
+ // add options panel item
+ if (window.Options && Options.get_tab('general')) {
+ Options.extend_tab('general', '<label id="file-drag-drop"><input type="checkbox">' + _('Drag and drop file selection') + '</label>');
+
+ $('#file-drag-drop>input').on('click', function() {
+ if ($('#file-drag-drop>input').is(':checked')) {
+ localStorage.file_dragdrop = 'true';
+ } else {
+ localStorage.file_dragdrop = 'false';
+ }
+ });
+
+ if (typeof localStorage.file_dragdrop === 'undefined') localStorage.file_dragdrop = 'true';
+ if (localStorage.file_dragdrop === 'true') $('#file-drag-drop>input').prop('checked', true);
+ }
+});
+
+// disabled by user, or incompatible browser.
+if (localStorage.file_dragdrop == 'false' || !(window.URL.createObjectURL && window.File))
+ return;
+
+// multipost not enabled
+if (typeof max_images == 'undefined') {
+ var max_images = 1;
+}
+
+$('<div class="dropzone-wrap" style="display: none;">'+
+ '<div class="dropzone" tabindex="0">'+
+ '<div class="file-hint">'+_('Select/drop/paste files here')+'</div>'+
+ '<div class="file-thumbs"></div>'+
+ '</div>'+
+ '</div>'+
+'</div>').prependTo('#upload td');
+
+var files = [];
+$('#upload_file').remove(); // remove the original file selector
+$('.dropzone-wrap').css('user-select', 'none').show(); // let jquery add browser specific prefix
+
+function addFile(file) {
+ if (files.length == max_images)
+ return;
+
+ files.push(file);
+ addThumb(file);
+}
+
+function removeFile(file) {
+ files.splice(files.indexOf(file), 1);
+}
+
+function getThumbElement(file) {
+ return $('.tmb-container').filter(function(){return($(this).data('file-ref')==file);});
+}
+
+function addThumb(file) {
+
+ var fileName = (file.name.length < 24) ? file.name : file.name.substr(0, 22) + '…';
+ var fileType = file.type.split('/')[0];
+ var fileExt = file.type.split('/')[1];
+ var $container = $('<div>')
+ .addClass('tmb-container')
+ .data('file-ref', file)
+ .append(
+ $('<div>').addClass('remove-btn').html('✖'),
+ $('<div>').addClass('file-tmb'),
+ $('<div>').addClass('tmb-filename').html(fileName)
+ )
+ .appendTo('.file-thumbs');
+
+ var $fileThumb = $container.find('.file-tmb');
+ if (fileType == 'image') {
+ // if image file, generate thumbnail
+ var objURL = window.URL.createObjectURL(file);
+ $fileThumb.css('background-image', 'url('+ objURL +')');
+ } else {
+ $fileThumb.html('<span>' + fileExt.toUpperCase() + '</span>');
+ }
+}
+
+$(document).on('ajax_before_post', function (e, formData) {
+ for (var i=0; i<max_images; i++) {
+ var key = 'file';
+ if (i > 0) key += i + 1;
+ if (typeof files[i] === 'undefined') break;
+ formData.append(key, files[i]);
+ }
+});
+
+// clear file queue and UI on success
+$(document).on('ajax_after_post', function () {
+ files = [];
+ $('.file-thumbs').empty();
+});
+
+var dragCounter = 0;
+var dropHandlers = {
+ dragenter: function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ if (dragCounter === 0) $('.dropzone').addClass('dragover');
+ dragCounter++;
+ },
+ dragover: function (e) {
+ // needed for webkit to work
+ e.stopPropagation();
+ e.preventDefault();
+ },
+ dragleave: function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ dragCounter--;
+ if (dragCounter === 0) $('.dropzone').removeClass('dragover');
+ },
+ drop: function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ $('.dropzone').removeClass('dragover');
+ dragCounter = 0;
+
+ var fileList = e.originalEvent.dataTransfer.files;
+ for (var i=0; i<fileList.length; i++) {
+ addFile(fileList[i]);
+ }
+ }
+};
+
+
+// attach handlers
+$(document).on(dropHandlers);
+
+$(document).on('click', '.dropzone .remove-btn', function (e) {
+ e.stopPropagation();
+
+ var file = $(e.target).parent().data('file-ref');
+
+ getThumbElement(file).remove();
+ removeFile(file);
+});
+
+$(document).on('keypress click', '.dropzone', function (e) {
+ e.stopPropagation();
+
+ // accept mouse click or Enter
+ if ((e.which != 1 || e.target.className != 'file-hint') &&
+ e.which != 13)
+ return;
+
+ var $fileSelector = $('<input type="file" multiple>');
+
+ $fileSelector.on('change', function (e) {
+ if (this.files.length > 0) {
+ for (var i=0; i<this.files.length; i++) {
+ addFile(this.files[i]);
+ }
+ }
+ $(this).remove();
+ });
+
+ $fileSelector.click();
+});
+
+$(document).on('paste', function (e) {
+ var clipboard = e.originalEvent.clipboardData;
+ if (typeof clipboard.items != 'undefined' && clipboard.items.length != 0) {
+
+ //Webkit
+ for (var i=0; i<clipboard.items.length; i++) {
+ if (clipboard.items[i].kind != 'file')
+ continue;
+
+ //convert blob to file
+ var file = new File([clipboard.items[i].getAsFile()], 'ClipboardImage.png', {type: 'image/png'});
+ addFile(file);
+ }
+ }
+});
+
+}
diff --git a/js/forced-anon.js b/js/forced-anon.js
index 5ea68199..11327ec9 100644
--- a/js/forced-anon.js
+++ b/js/forced-anon.js
@@ -64,7 +64,7 @@ $(document).ready(function() {
if (window.Options && Options.get_tab('general')) {
selector = '#forced-anon';
event = 'change';
- Options.extend_tab("general", "<label id='forced-anon'><input type='checkbox' /> "+_('Forced anonymity')+"</label>");
+ Options.extend_tab("general", "<label id='forced-anon'><input type='checkbox' />"+_('Forced anonymity')+"</label>");
}
else {
selector = '#forced-anon';
diff --git a/js/gallery-view.js b/js/gallery-view.js
new file mode 100644
index 00000000..2d7d85b4
--- /dev/null
+++ b/js/gallery-view.js
@@ -0,0 +1,165 @@
+if (active_page == 'index' || active_page == 'thread')
+$(function(){
+
+ var gallery_view = false;
+
+ $('hr:first').before('<div id="gallery-view" style="text-align:right"><a class="unimportant" href="javascript:void(0)">-</a></div>');
+ $('#gallery-view a').html(gallery_view ? _("Disable gallery mode") : _("Enable gallery mode")).click(function() {
+ gallery_view = !gallery_view;
+ $(this).html(gallery_view ? _("Disable gallery mode") : _("Enable gallery mode"));
+ toggle_gview(document);
+ });
+
+ var toggle_gview = function(elem) {
+ if (gallery_view) {
+ $(elem).find('img.post-image').parent().each(function() {
+ this.oldonclick = this.onclick;
+ this.onclick = handle_click;
+ $(this).attr('data-galid', Math.random());
+ });
+ }
+ else {
+ $(elem).find('img.post-image').parent().each(function() {
+ if (this.onclick == handle_click) this.onclick = this.oldonclick;
+ });
+ }
+ };
+
+ $(document).on('new_post', toggle_gview);
+
+ var gallery_opened = false;
+
+ var handle_click = function(e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ if (!gallery_opened) open_gallery();
+
+ gallery_setimage($(this).attr('data-galid'));
+ };
+
+ var handler, images, active, toolbar;
+
+ var open_gallery = function() {
+ $('body').css('overflow', 'hidden');
+
+ gallery_opened = true;
+
+ handler = $("<div id='alert_handler'></div>").hide().appendTo('body').css('text-align', 'left');
+
+ $("<div id='alert_background'></div>").click(close_gallery).appendTo(handler);
+
+ images = $("<div id='gallery_images'></div>").appendTo(handler);
+ toolbar = $("<div id='gallery_toolbar'></div>").appendTo(handler);
+ active = $("<div id='gallery_main'></div>").appendTo(handler);
+
+ active.on('click', function() {
+ close_gallery();
+ });
+
+ $('img.post-image').parent().each(function() {
+ var thumb = $(this).find('img').attr('src');
+
+ var i = $('<img>').appendTo(images);
+ i.attr('src', thumb);
+ i.attr('data-galid-th', $(this).attr('data-galid'));
+
+ i.on('click', function(e) {
+ gallery_setimage($(this).attr('data-galid-th'));
+ });
+ });
+
+ $("<a href='javascript:void(0)'><i class='fa fa-times'></i></div>")
+ .click(close_gallery).appendTo(toolbar);
+
+ $('body').on('keydown.gview', function(e) {
+ if (e.which == 39 || e.which == 40) { // right or down arrow
+ gallery_setimage(+1);
+ e.preventDefault();
+ }
+ else if (e.which == 37 || e.which == 38) { // left or up arrow
+ gallery_setimage(-1);
+ e.preventDefault();
+ }
+ });
+
+ handler.fadeIn(400);
+ };
+
+ var gallery_setimage = function(a) {
+ if (a == +1 || a == -1) {
+ var meth = (a == -1) ? 'prev' : 'next';
+ a = $('#gallery_images img.active')[meth]().attr('data-galid-th');
+ if (!a) return;
+ }
+
+ $('#gallery_images img.active').removeClass('active');
+
+ var thumb = $('#gallery_images [data-galid-th="'+a+'"]');
+ var elem = $('a[data-galid="'+a+'"]');
+
+ thumb.addClass('active');
+
+ var topscroll = thumb.position().top + images.scrollTop();
+ topscroll -= images.height() / 2;
+ topscroll += thumb.height() / 2;
+ images.animate({'scrollTop': topscroll}, 300);
+
+ var img = elem.attr('href');
+
+ active.find('img, video').fadeOut(200, function() { $(this).remove(); });
+
+ var i;
+ if (img.match(/player\.php/)) {
+ img = img.replace(/.*player\.php\?v=|&t=.*/g, '');
+ }
+ if (img.match(/\.webm$|\.mp4$|\.ogv$/i)) { // We are handling video nao
+ i = $('<video>');
+ i.attr('src', img);
+ i.attr('autoplay', true);
+ i.attr('controls', true);
+ i.appendTo(active);
+ i.hide();
+ }
+ else { // Just a plain image
+ i = $('<img>');
+ i.attr('src', img);
+ i.appendTo(active);
+ i.hide();
+ }
+
+ // Let's actually preload the next few images
+ var nextimg = $('#gallery_images active');
+ for (var j = 0; j < 3; j++) {
+ nextimg = nextimg.next();
+ var attr;
+ if (attr = nextimg.attr('data-gaild-th')) {
+ var href = $('a[data-galid="'+attr+'"]').attr('href');
+ if (href.match(/\.webm|\.mp4|\.ogv/i)) { j--; continue; }
+ if ($('[data-galid-preload="'+attr+'"]').length) continue;
+ var img = $('<img>').attr('src', href).attr('data-galid-preload', attr).hide().appendTo('body').on('load', function() { $(this).remove(); });
+ }
+ else break;
+ }
+
+ i.one('load canplay', function() {
+ i.css('left', 'calc(50% - '+i.width()+'px / 2)');
+ i.css('top', 'calc(50% - '+i.height()+'px / 2)');
+ i.fadeIn(200);
+ }).on('click', function(e) {
+ e.stopPropagation();
+ gallery_setimage(+1);
+ });
+ };
+
+ var close_gallery = function() {
+ $('body').css('overflow', 'auto');
+
+ gallery_opened = false;
+
+ $('body').off('keydown.gview');
+
+ handler.fadeOut(400, function() { handler.remove(); });
+ };
+
+});
diff --git a/js/hide-images.js b/js/hide-images.js
index ad5f401c..023c166c 100644
--- a/js/hide-images.js
+++ b/js/hide-images.js
@@ -96,6 +96,6 @@ $(document).ready(function(){
$('div.post > a > img.post-image, div > a > img.post-image').each(handle_images);
$(document).on('new_post', function(e, post) {
- $(post).find('> a > img.post-image').each(handle_images);
+ $(post).find('a > img.post-image').each(handle_images);
});
});
diff --git a/js/hide-threads.js b/js/hide-threads.js
index f83b479b..175018ed 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:not(.unanimated),canvas,p.fileinfo,a.hide-thread-link,div.new-posts,br';
+ var fields_to_hide = 'div.post,div.video-container,video,iframe,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/id_colors.js b/js/id_colors.js
new file mode 100644
index 00000000..17f8b4d9
--- /dev/null
+++ b/js/id_colors.js
@@ -0,0 +1,71 @@
+if (active_page == 'thread' || active_page == 'index') {
+ $(document).ready(function(){
+ if (window.Options && Options.get_tab('general')) {
+ selector = '#color-ids>input';
+ event = 'change';
+ Options.extend_tab("general", "<label id='color-ids'><input type='checkbox' /> "+_('Color IDs')+"</label>");
+ }
+
+ else {
+ selector = '#color-ids';
+ event = 'click';
+ $('hr:first').before('<div id="color-ids" style="text-align:right"><a class="unimportant" href="javascript:void(0)">'+_('Color IDs')+'</a></div>')
+ }
+
+ $(selector).on(event, function() {
+ if (localStorage.color_ids === 'true') {
+ localStorage.color_ids = 'false';
+ } else {
+ localStorage.color_ids = 'true';
+ }
+ });
+
+ if (!localStorage.color_ids || localStorage.color_ids === 'false') {
+ return;
+ } else {
+ $('#color-ids>input').attr('checked','checked');
+ }
+
+ function IDToRGB(id_str){
+ var id = id_str.match(/.{1,2}/g);
+ var rgb = new Array();
+
+ for (i = 0; i < id.length; i++) {
+ rgb[i] = parseInt(id[i], 16);
+ }
+
+ return rgb;
+ }
+
+ function colorPostId(el) {
+ var rgb = IDToRGB($(el).text());
+ var ft = "#fff";
+
+ if ((rgb[0]*0.299 + rgb[1]*0.587 + rgb[2]*0.114) > 125)
+ ft = "#000";
+
+ $(el).css({
+ "background-color": "rgb("+rgb[0]+", "+rgb[1]+", "+rgb[2]+")",
+ "padding": "0px 5px",
+ "border-radius": "8px",
+ "color": ft
+ });
+
+ $(el).mouseover(function() {
+ $(this).css('color', '#800000'); // how about a CSS :hover rule instead?
+ }).mouseout(function() {
+ $(this).css('color', ft);
+ });
+ }
+
+ $(".poster_id").each(function(k, v){
+ colorPostId(v);
+ });
+
+ $(document).on('new_post', function(e, post) {
+ $(post).find('.poster_id').each(function(k, v) {
+ colorPostId(v);
+ });
+ });
+ });
+}
diff --git a/js/id_highlighter.js b/js/id_highlighter.js
new file mode 100644
index 00000000..d0a5fabf
--- /dev/null
+++ b/js/id_highlighter.js
@@ -0,0 +1,50 @@
+if (active_page == 'thread' || active_page == 'index') {
+ $(document).ready(function(){
+ function arrayRemove(a, v) { a.splice(a.indexOf(v) == -1 ? a.length : a.indexOf(v), 1); }
+
+ var idshighlighted = [];
+
+ function getPostsById(id){
+ return $(".poster_id").filter(function(i){
+ return $(this).text() == id;
+ });
+ }
+
+ function getMasterPosts(parents){
+ if(!parents.hasClass("post")) return;
+
+ var toRet = [];
+
+ $(parents).each(function(){
+ if($(this).hasClass("post"))
+ toRet.push($(this));
+ });
+
+ return toRet;
+ }
+
+ var id_highlighter = function(){
+ var id = $(this).text();
+
+ if($.inArray(id, idshighlighted) !== -1){
+ arrayRemove(idshighlighted, id);
+
+ $(getMasterPosts(getPostsById(id).parents())).each(function(i){
+ $(this).removeClass("highlighted");
+ });
+ }else{
+ idshighlighted.push(id);
+
+ $(getMasterPosts(getPostsById(id).parents())).each(function(i){
+ $(this).addClass("highlighted");
+ });
+ }
+ }
+
+ $(".poster_id").on('click', id_highlighter);
+
+ $(document).on('new_post', function(e, post) {
+ $(post).find('.poster_id').on('click', id_highlighter);
+ });
+ });
+}
diff --git a/js/infinite-scroll.js b/js/infinite-scroll.js
new file mode 100644
index 00000000..e212f9d6
--- /dev/null
+++ b/js/infinite-scroll.js
@@ -0,0 +1,91 @@
+/*
+ * infinite-scroll.js
+ * https://github.com/vichan-devel/vichan/blob/master/js/infinite-scroll.js
+ *
+ * Released under the MIT license
+ * Copyright (c) 2013-2014 Marcin Łabanowski <marcin@6irc.net>
+ *
+ * Usage:
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/infinite-scroll.js';
+ *
+ */
+
+$(function() {
+if (active_page == 'index') {
+
+
+var loading = false;
+
+var activate = function() {
+ if (document.location.hash != '#all') return false;
+
+ $(window).on("scroll", function() {
+ scrolltest();
+ });
+ scrolltest();
+
+ return true;
+};
+
+var scrolltest = function() {
+ if ($(window).scrollTop() + $(window).height() + 1000 > $(document).height() && !loading) {
+ load_next_page();
+ }
+};
+
+var load_next_page = function() {
+ if (loading) return;
+ loading = true;
+
+ var this_page = $(".pages a.selected:last");
+ var next_page = this_page.next();
+
+ var href = next_page.prop("href");
+ if (!href) return;
+
+ var boardheader = $('<h2>'+_('Page')+' '+next_page.html()+'</h2>');
+ var loading_ind = $('<h2>'+_('Loading...')+'</h2>').insertBefore('form[name="postcontrols"]>.delete:first');
+
+ $.get(href, function(data) {
+ var doc = $(data);
+
+ loading_ind.remove();
+ boardheader.insertBefore('form[name="postcontrols"]>.delete:first');
+
+ var i = 0;
+
+ doc.find('div[id*="thread_"]').each(function() {
+ var checkout = $(this).attr('id').replace('thread_', '');
+ var $this = this;
+
+ if ($('div#thread_' + checkout).length == 0) {
+ // Delay DOM insertion to lessen the lag.
+ setTimeout(function() {
+ $($this).insertBefore('form[name="postcontrols"]>.delete:first');
+ $(document).trigger('new_post', $this);
+ $($this).hide().slideDown();
+ }, 500*i);
+ i++;
+ }
+ });
+ setTimeout(function() {
+ loading = false;
+ scrolltest();
+ }, 500*(i+1));
+
+ next_page.addClass('selected');
+ });
+
+};
+
+var button = $("<a href='#all'>"+_("All")+" </a>").prependTo(".pages");
+
+$(window).on("hashchange", function() {
+ return !activate();
+});
+activate();
+
+
+}
+});
diff --git a/js/inline.js b/js/inline.js
new file mode 100644
index 00000000..4f8c9a72
--- /dev/null
+++ b/js/inline.js
@@ -0,0 +1,154 @@
+$(document).ready(function() {
+ var App = {
+ cache: {},
+ get: function(url, cb) {
+ var $page = App.cache[url]
+ if ($page)
+ return cb($page)
+
+ $.get(url, function(data) {
+ var $page = $(data)
+ App.cache[url] = $page
+ cb($page)
+ })
+ },
+ options: {
+ add: function(key, description, tab) {
+ tab || (tab = 'general')
+
+ var checked = App.options.get(key)
+ var $el = $(
+ '<div>' +
+ '<label>' +
+ '<input type="checkbox">' +
+ description +
+ '</label>' +
+ '</div>')
+
+ $el
+ .find('input')
+ .prop('checked', checked)
+ .on('change', App.options.check(key))
+
+ window.Options.extend_tab(tab, $el)
+ },
+ get: function(key) {
+ if (localStorage[key])
+ return JSON.parse(localStorage[key])
+ },
+ check: function(key) {
+ return function(e) {
+ var val = this.checked
+ localStorage[key] = JSON.stringify(val)
+ }
+ }
+ }
+ }
+
+ var inline = function(e) {
+ e.preventDefault()
+
+ var $root = $(this).closest('.post')
+ var targetNum = this.textContent.slice(2)
+
+ var srcOP = $root.closest('[id^=thread]').attr('id').match(/\d+/)[0]
+
+ var node, targetOP
+ var isBacklink = !!this.className
+ if (isBacklink) {
+ node = $root.find('> .intro')
+ targetOP = srcOP
+ } else {
+ node = $(this)
+
+ var to_search = inMod ? this.search : this.pathname;
+ targetOP = to_search.match(/(\d+).html/)[1]
+ }
+
+ var link = {
+ id: 'inline_' + targetNum,
+ isBacklink: isBacklink,
+ node: node
+ }
+
+ var selector = targetNum === targetOP
+ ? '#op_' + srcOP
+ : '#reply_' + targetNum
+
+ var $clone = $root.find('#inline_' + targetNum)
+ if ($clone.length) {
+ $clone.remove()
+ $(selector)
+ .show()
+ .next()
+ .show()
+ return
+ }
+
+ if (srcOP === targetOP) {
+ if (targetNum === targetOP)
+ link.node = link.node.next()// bypass `(OP)`
+
+ var $target = $(selector)
+ if ($target.length)
+ return add(link, $target)
+ }
+
+ var $loading = $('<div class="inline post">loading...</div>')
+ .attr('id', link.id)
+ .insertAfter(link.node)
+
+ App.get(this.pathname, function($page) {
+ $loading.remove()
+ var $target = $page.find(selector)
+ add(link, $target)
+ })
+ }
+
+ var add = function(link, $target) {
+ var $clone = $target.clone(true)
+
+ if (link.isBacklink && App.options.get('hidePost'))
+ $target
+ .hide()
+ .next()
+ .hide()
+
+ $clone.find('.inline').remove()
+ $clone.attr({
+ "class": 'inline post',
+ id: link.id,
+ style: null// XXX remove post hover styling
+ })
+ $clone.insertAfter(link.node)
+ }
+
+ App.options.add('useInlining', 'Enable inlining')
+ App.options.add('hidePost', 'Hide inlined backlinked posts')
+
+ $('head').append(
+ '<style>' +
+ '.inline {' +
+ 'border: 1px dashed black;' +
+ 'white-space: normal;' +
+ 'overflow: auto;' + // clearfix
+ '}' +
+ '</style>')
+
+ // don't attach to outbound links
+
+ if (App.options.get('useInlining')) {
+ var assign_inline = function() {
+ $('.body a:not([rel]), .mentioned a')
+ .attr('onclick', null)// XXX disable highlightReply
+ .off('click')
+ .click(inline)
+ }
+
+ assign_inline();
+
+ $(document).on('new_post', function(e, post) {
+ assign_inline();
+ });
+ }
+});
diff --git a/js/live-index.js b/js/live-index.js
index 463f7596..017d0c1f 100644
--- a/js/live-index.js
+++ b/js/live-index.js
@@ -58,7 +58,7 @@ if (active_page == 'index' && (""+document.location).match(/\/(index\.html)?(\?|
update_new_threads(new_threads);
});
- }, 1000);
+ }, 20000);
});
$(document).on("new_post", function(e, post) {
diff --git a/js/local-time.js b/js/local-time.js
index e6b3495d..a4e25d6d 100644
--- a/js/local-time.js
+++ b/js/local-time.js
@@ -25,16 +25,6 @@ onready(function(){
return [Math.pow(10, count - num.toString().length), num].join('').substr(1);
};
- var datelocale =
- { days: [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')]
- , shortDays: [_("Sun"), _("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat")]
- , months: [_('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July'), _('August'), _('September'), _('October'), _('November'), _('December')]
- , shortMonths: [_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May'), _('Jun'), _('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec')]
- , AM: _('AM')
- , PM: _('PM')
- , am: _('am')
- , pm: _('pm')
- };
var dateformat = (typeof strftime === 'undefined') ? function(t) {
return zeropad(t.getMonth() + 1, 2) + "/" + zeropad(t.getDate(), 2) + "/" + t.getFullYear().toString().substring(2) +
" (" + [_("Sun"), _("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat"), _("Sun")][t.getDay()] + ") " +
diff --git a/js/longtable/longtable.js b/js/longtable/longtable.js
new file mode 100644
index 00000000..fe3ad1c6
--- /dev/null
+++ b/js/longtable/longtable.js
@@ -0,0 +1,184 @@
+$.fn.longtable = function(fields, options, data) {
+ var elem = $(this).addClass("longtable");
+
+ var orig_data = data;
+
+ options.row_h = options.row_h || 22;
+ options.checkbox = options.checkbox || false;
+
+ var shown_rows = {};
+
+ var sorted_by = undefined;
+ var sorted_reverse = false;
+
+ var filter = function() { return true; };
+
+ var lt = {
+ _gen_field_td: function(field, id) {
+ var el;
+ if (id === undefined) {
+ el = $("<th></th>");
+ el.html(fields[field].name || field);
+
+ if (!fields[field].sort_disable) {
+ el.addClass("sortable").click(function() {
+ lt._sort_by(field);
+ });
+ }
+ }
+ else {
+ el = $("<td></td>");
+ if (fields[field].fmt) { // Special formatting?
+ el.html(fields[field].fmt(data[id]));
+ }
+ else {
+ el.html(data[id][field]);
+ }
+ }
+ el.css("width", fields[field].width);
+ el.css("height", options.row_h);
+ return el;
+ },
+ _gen_tr: function(id) {
+ var el = $("<tr></tr>");
+ $.each(fields, function(field, f) {
+ lt._gen_field_td(field, id).appendTo(el);
+ });
+ if (id !== undefined) {
+ el.addClass("row").addClass("row_"+id);
+ el.css({position: "absolute", top: options.row_h * (id+1)});
+ }
+ return el;
+ },
+ _clean: function() {
+ elem.find('.row').remove();
+ shown_rows = {};
+ },
+ _remove: function(id) {
+ elem.find('.row_'+id).remove();
+ delete shown_rows[id];
+ },
+ _insert: function(id) {
+ var el = lt._gen_tr(id).appendTo(elem);
+ $(elem).trigger("new-row", [data[id], el]);
+ shown_rows[id] = true;
+ },
+
+ _sort_by: function(field) {
+ if (field !== undefined) {
+ if (sorted_by == field) {
+ sorted_reverse = !sorted_reverse;
+ }
+ else {
+ sorted_reverse = !!fields[field].sort_reverse;
+ sorted_by = field;
+ }
+ }
+ lt.sort_by(sorted_by, sorted_reverse);
+ },
+
+ _apply_filter: function() {
+ data = data.filter(filter);
+ },
+ _reset_data: function() {
+ data = orig_data;
+ },
+
+
+ set_filter: function(f) {
+ filter = f;
+ lt._reset_data();
+ lt._apply_filter();
+ lt._sort_by();
+ },
+
+ sort_by: function(field, reverse) {
+ if (field !== undefined) {
+ sorted_by = field;
+ sorted_reverse = reverse;
+
+ var ord = fields[field].sort_fun || function(a,b) { return lt.sort_alphanum(a[field], b[field]); };
+
+ data = data.sort(ord);
+ if (reverse) data = data.reverse();
+ }
+
+ lt.update_data();
+ },
+
+ update_viewport: function() {
+ var first = $(window).scrollTop() - $(elem).offset().top - options.row_h;
+ var last = first + $(window).height();
+
+ first = Math.floor(first / options.row_h);
+ last = Math.ceil (last / options.row_h);
+
+ first = first < 0 ? 0 : first;
+ last = last >= data.length ? data.length - 1 : last;
+
+ $.each(shown_rows, function(id) {
+ if (id < first || id > last) {
+ lt._remove(id);
+ }
+ });
+
+ for (var id = first; id <= last; id++) {
+ if (!shown_rows[id]) lt._insert(id);
+ }
+ },
+
+ update_data: function() {
+ $(elem).height((data.length + 1) * options.row_h);
+
+ lt._clean();
+ lt.update_viewport();
+ },
+
+ get_data: function() {
+ return data;
+ },
+
+ destroy: function() {
+ },
+
+ // http://web.archive.org/web/20130826203933/http://my.opera.com/GreyWyvern/blog/show.dml/1671288
+ sort_alphanum: function(a, b) {
+ function chunkify(t) {
+ var tz = [], x = 0, y = -1, n = 0, i, j;
+
+ while (i = (j = t.charAt(x++)).charCodeAt(0)) {
+ var m = (/* dot: i == 46 || */(i >=48 && i <= 57));
+ if (m !== n) {
+ tz[++y] = "";
+ n = m;
+ }
+ tz[y] += j;
+ }
+ return tz;
+ }
+
+ var aa = chunkify((""+a).toLowerCase());
+ var bb = chunkify((""+b).toLowerCase());
+
+ for (x = 0; aa[x] && bb[x]; x++) {
+ if (aa[x] !== bb[x]) {
+ var c = Number(aa[x]), d = Number(bb[x]);
+ if (c == aa[x] && d == bb[x]) {
+ return c - d;
+ } else return (aa[x] > bb[x]) ? 1 : -1;
+ }
+ }
+ return aa.length - bb.length;
+ }
+ // End of foreign code
+ };
+
+
+
+ lt._gen_tr().appendTo(elem);
+ lt.update_data();
+
+ $(window).on("scroll resize", lt.update_viewport);
+
+ return lt;
+};
diff --git a/js/mod/ban-list.js b/js/mod/ban-list.js
new file mode 100644
index 00000000..7e5fdac0
--- /dev/null
+++ b/js/mod/ban-list.js
@@ -0,0 +1,157 @@
+var banlist_init = function(token, my_boards, inMod) {
+ inMod = !inMod;
+
+ var lt;
+
+ var selected = {};
+
+ var time = function() { return Date.now()/1000|0; }
+
+ $.getJSON(inMod ? ("?/bans.json/"+token) : token, function(t) {
+ $("#banlist").on("new-row", function(e, drow, el) {
+ var sel = selected[drow.id];
+ if (sel) {
+ $(el).find('input.unban').prop("checked", true);
+ }
+ $(el).find('input.unban').on("click", function() {
+ selected[drow.id] = $(this).prop("checked");
+ });
+
+
+ if (drow.expires && drow.expires != 0 && drow.expires < time()) {
+ $(el).find("td").css("text-decoration", "line-through");
+ }
+ });
+
+ var selall = "<input type='checkbox' id='select-all' style='float: left;'>";
+
+ lt = $("#banlist").longtable({
+ mask: {name: selall+_("IP address"), width: "220px", fmt: function(f) {
+ var pre = "";
+ if (inMod && f.access) {
+ pre = "<input type='checkbox' class='unban'>";
+ }
+
+ if (inMod && f.single_addr && !f.masked) {
+ return pre+"<a href='?/IP/"+f.mask+"'>"+f.mask+"</a>";
+ }
+ return pre+f.mask;
+ } },
+ reason: {name: _("Reason"), width: "calc(100% - 715px - 6 * 4px)", fmt: function(f) {
+ var add = "", suf = '';
+ if (f.seen == 1) add += "<i class='fa fa-check' title='"+_("Seen")+"'></i>";
+ if (f.message) {
+ add += "<i class='fa fa-comment' title='"+_("Message for which user was banned is included")+"'></i>";
+ suf = "<br /><br /><strong>"+_("Message:")+"</strong><br />"+f.message;
+ }
+
+ if (add) { add = "<div style='float: right;'>"+add+"</div>"; }
+
+ if (f.reason) return add + f.reason + suf;
+ else return add + "-" + suf;
+ } },
+ board: {name: _("Board"), width: "60px", fmt: function(f) {
+ if (f.board) return "/"+f.board+"/";
+ else return "<em>"+_("all")+"</em>";
+ } },
+ created: {name: _("Set"), width: "100px", fmt: function(f) {
+ return ago(f.created) + _(" ago"); // in AGO form
+ } },
+ // duration?
+ expires: {name: _("Expires"), width: "235px", fmt: function(f) {
+ if (!f.expires || f.expires == 0) return "<em>"+_("never")+"</em>";
+ return strftime(window.post_date, new Date((f.expires|0)*1000), datelocale) +
+ ((f.expires < time()) ? "" : " <small>"+_("in ")+until(f.expires|0)+"</small>");
+ } },
+ username: {name: _("Staff"), width: "100px", fmt: function(f) {
+ var pre='',suf='',un=f.username;
+ if (inMod && f.username && f.username != '?' && !f.vstaff) {
+ pre = "<a href='?/new_PM/"+f.username+"'>";
+ suf = "</a>";
+ }
+ if (!f.username) {
+ un = "<em>"+_("system")+"</em>";
+ }
+ return pre + un + suf;
+ } }
+ }, {}, t);
+
+ $("#select-all").click(function(e) {
+ var $this = $(this);
+ $("input.unban").prop("checked", $this.prop("checked"));
+ lt.get_data().forEach(function(v) { v.access && (selected[v.id] = $this.prop("checked")); });
+ e.stopPropagation();
+ });
+
+ var filter = function(e) {
+ if ($("#only_mine").prop("checked") && ($.inArray(e.board, my_boards) === -1)) return false;
+ if ($("#only_not_expired").prop("checked") && e.expires && e.expires != 0 && e.expires < time()) return false;
+ if ($("#search").val()) {
+ var terms = $("#search").val().split(" ");
+
+ var fields = ["mask", "reason", "board", "staff", "message"];
+
+ var ret_false = false;
+ terms.forEach(function(t) {
+ var fs = fields;
+
+ var re = /^(mask|reason|board|staff|message):/, ma;
+ if (ma = t.match(re)) {
+ fs = [ma[1]];
+ t = t.replace(re, "");
+ }
+
+ var found = false
+ fs.forEach(function(f) {
+ if (e[f] && e[f].indexOf(t) !== -1) {
+ found = true;
+ }
+ });
+ if (!found) ret_false = true;
+ });
+
+ if (ret_false) return false;
+ }
+
+ return true;
+ };
+
+ $("#only_mine, #only_not_expired, #search").on("click input", function() {
+ lt.set_filter(filter);
+ });
+ lt.set_filter(filter);
+
+ $(".banform").on("submit", function() { return false; });
+
+ $("#unban").on("click", function() {
+ $(".banform .hiddens").remove();
+ $("<input type='hidden' name='unban' value='unban' class='hiddens'>").appendTo(".banform");
+
+ $.each(selected, function(e) {
+ $("<input type='hidden' name='ban_"+e+"' value='unban' class='hiddens'>").appendTo(".banform");
+ });
+
+ $(".banform").off("submit").submit();
+ });
+
+ if (device_type == 'desktop') {
+ // Stick topbar
+ var stick_on = $(".banlist-opts").offset().top;
+ var state = true;
+ $(window).on("scroll resize", function() {
+ if ($(window).scrollTop() > stick_on && state == true) {
+ $("body").css("margin-top", $(".banlist-opts").height());
+ $(".banlist-opts").addClass("boardlist top").detach().prependTo("body");
+ $("#banlist tr:not(.row)").addClass("tblhead").detach().appendTo(".banlist-opts");
+ state = !state;
+ }
+ else if ($(window).scrollTop() < stick_on && state == false) {
+ $("body").css("margin-top", "auto");
+ $(".banlist-opts").removeClass("boardlist top").detach().prependTo(".banform");
+ $(".tblhead").detach().prependTo("#banlist");
+ state = !state;
+ }
+ });
+ }
+ });
+}
diff --git a/js/multi-image.js b/js/multi-image.js
index 32d1f256..db4c6bd2 100644
--- a/js/multi-image.js
+++ b/js/multi-image.js
@@ -18,7 +18,12 @@ function multi_image() {
var images_len = $('form:not([id="quick-reply"]) [type=file]').length;
if (!(images_len >= max_images)) {
- $('.add_image').after('<br class="file_separator"/><input type="file" name="file'+(images_len+1)+'" id="upload_file'+(images_len+1)+'">');
+ var new_file = '<br class="file_separator"/><input type="file" name="file'+(images_len+1)+'" id="upload_file'+(images_len+1)+'">';
+
+ $('[type=file]:last').after(new_file);
+ if ($("#quick-reply").length) {
+ $('form:not(#quick-reply) [type=file]:last').after(new_file);
+ }
if (typeof setup_form !== 'undefined') setup_form($('form[name="post"]'));
}
})
diff --git a/js/no-animated-gif.js b/js/no-animated-gif.js
index 7e777d87..a10a6497 100644
--- a/js/no-animated-gif.js
+++ b/js/no-animated-gif.js
@@ -13,7 +13,10 @@
*/
function unanimate_gif(e) {
- var c = $('<canvas class="post-image"></canvas>');
+ if (active_page === "catalog")
+ var c = $('<canvas class="thread-image"></canvas>');
+ else
+ var c = $('<canvas class="post-image"></canvas>');
$(e).parent().prepend(c);
c.attr('width', $(e).width());
c.attr('height',$(e).height());
@@ -32,7 +35,7 @@ function unanimate_gif(e) {
}
function no_animated_gif() {
- var anim_gifs = $('img.post-image[src$=".gif"]');
+ var anim_gifs = $('img.post-image[src$=".gif"], img.thread-image[src$=".gif"]');
localStorage.no_animated_gif = true;
$('#no-animated-gif>a').text(_('Animate GIFs'));
$('#no-animated-gif>input').prop('checked', true);
@@ -48,13 +51,13 @@ function animated_gif() {
$('#no-animated-gif>input').prop('checked', false);
}
-if (active_page == 'thread' || active_page == 'index' || active_page == 'ukko') {
+if (active_page == 'thread' || active_page == 'index' || active_page == 'ukko' || active_page == 'catalog') {
$(function(){
var selector, event;
if (window.Options && Options.get_tab('general')) {
selector = '#no-animated-gif>input';
event = 'change';
- Options.extend_tab("general", "<label id='no-animated-gif'><input type='checkbox' /> "+_('Unanimate GIFs')+"</label>");
+ Options.extend_tab("general", "<label id='no-animated-gif'><input type='checkbox' />"+_('Unanimate GIFs')+"</label>");
}
else {
selector = '#no-animated-gif';
diff --git a/js/options/user-css.js b/js/options/user-css.js
index a6b2d137..840bcd1f 100644
--- a/js/options/user-css.js
+++ b/js/options/user-css.js
@@ -43,7 +43,7 @@ var apply_css = function() {
var update_textarea = function() {
if (!localStorage.user_css) {
textarea.text("/* "+_("Enter here your own CSS rules...")+" */\n" +
- "/* "+_("If you want to make a redistributable style, be sure to\n have a Yotsuba B theme selected.")+" */\n" +
+ "/* "+_("If you want to make a redistributable style, be sure to\nhave a Yotsuba B theme selected.")+" */\n" +
"/* "+_("You can include CSS files from remote servers, for example:")+" */\n" +
'@import "http://example.com/style.css";');
}
diff --git a/js/options/user-js.js b/js/options/user-js.js
index 240e7b95..0b7d140f 100644
--- a/js/options/user-js.js
+++ b/js/options/user-js.js
@@ -52,7 +52,7 @@ var apply_js = function() {
var update_textarea = function() {
if (!localStorage.user_js) {
textarea.text("/* "+_("Enter here your own Javascript code...")+" */\n" +
- "/* "+_("Have a backup of your storage somewhere, as messing here\n may render you this website unusable.")+" */\n" +
+ "/* "+_("Have a backup of your storage somewhere, as messing here\nmay render you this website unusable.")+" */\n" +
"/* "+_("You can include JS files from remote servers, for example:")+" */\n" +
'load_js("http://example.com/script.js");');
}
diff --git a/js/own-board.js b/js/own-board.js
new file mode 100644
index 00000000..497c568c
--- /dev/null
+++ b/js/own-board.js
@@ -0,0 +1,116 @@
+/*****************************************************************
+ * ------- WARNING! --------- *
+ *****************************************************************
+ * This script is at the current time undocumented and *
+ * unsupported. It is still a work in progress and will likely *
+ * change. You are on your own. *
+ *****************************************************************/
+
++function() {
+
+var uniq = function(a) {
+ var b = {};
+ var c = [];
+ a.forEach(function(i) {
+ if (!b[i]) {
+ c.push(i);
+ b[i] = true;
+ }
+ });
+ return c;
+};
+
+
+if (active_page == 'thread' || active_page == 'index') {
+ var board = null;
+
+ $(function() {
+ board = $('input[name="board"]').first().val();
+ });
+
+ $(document).on('ajax_after_post', function(e, r) {
+ var threads = JSON.parse(localStorage.obthreads || '[]');
+
+ var thread = null;
+ if (active_page == 'index') {
+ thread = r.id|0;
+ }
+ else {
+ thread = $('[id^="thread_"]').first().attr('id').replace("thread_", "")|0;
+ }
+
+ threads.push([board, thread]);
+ threads = uniq(threads);
+ localStorage.obthreads = JSON.stringify(threads);
+ });
+}
+
+var loaded = false;
+$(function() {
+ loaded = true;
+});
+
+var activate = function() {
+ if (document.location.hash != '#own') return false;
+
+ if (loaded) late_activate();
+ else $(function() { late_activate(); });
+
+ return true;
+};
+
+var late_activate = function() {
+ $('[id^="thread_"]').remove();
+
+ var threads = JSON.parse(localStorage.obthreads || '[]');
+
+ threads.forEach(function(v) {
+ var board = v[0];
+ var thread = v[1];
+ var url = "/"+board+"/res/"+thread+".html";
+
+ $.get(url, function(html) {
+ var s = $(html).find('[id^="thread_"]');
+
+ s[0].bumptime = (new Date(s.find("time").last().attr("datetime"))).getTime();
+
+ var added = false;
+ $('[id^="thread_"]').each(function() {
+ if (added) return;
+ if (s[0].bumptime > this.bumptime) {
+ added = true;
+ s.insertBefore(this);
+ }
+ });
+ if (!added) {
+ s.appendTo('[name="postcontrols"]');
+ }
+
+ s.find('.post.reply').addClass('hidden').hide().slice(-3).removeClass('hidden').show();
+
+ s.find('.post.reply.hidden').next().addClass('hidden').hide(); // Hide <br> elements
+
+ var posts_omitted = s.find('.post.reply.hidden').length;
+ var images_omitted = s.find('.post.reply.hidden img').length;
+
+ if (posts_omitted > 0) {
+ var omitted = $(fmt('<span class="omitted">'+_('{0} posts and {1} images omitted.')+' '+_('Click reply to view.')+'</span>',
+ [posts_omitted, images_omitted]));
+
+ omitted.appendTo(s.find('.post.op'));
+ }
+
+ var reply = $('<a href="'+url+'">['+_('Reply')+']</a>').appendTo(s.find('.intro').first());
+
+ $(document).trigger('new_post', s[0]);
+ });
+ });
+};
+
+$(window).on("hashchange", function() {
+ return !activate();
+});
+activate();
+
+
+}();
diff --git a/js/post-hover.js b/js/post-hover.js
index e3e4dc62..e30cbf43 100644
--- a/js/post-hover.js
+++ b/js/post-hover.js
@@ -58,8 +58,8 @@ onready(function(){
// link links to itself or to op; ignore
}
else if($post.is(':visible') &&
- $post.offset().top + $post.height() >= $(window).scrollTop() &&
- $post.offset().top <= $(window).scrollTop() + $(window).height()) {
+ $post.offset().top >= $(window).scrollTop() &&
+ $post.offset().top + $post.height() <= $(window).scrollTop() + $(window).height()) {
// post is in view
$post.addClass('highlighted');
} else {
diff --git a/js/quick-reply.js b/js/quick-reply.js
index 07fe4aef..12cca366 100644
--- a/js/quick-reply.js
+++ b/js/quick-reply.js
@@ -83,11 +83,12 @@
}\
#quick-reply textarea {\
width: 100%;\
+ min-width: 100%;\
box-sizing: border-box;\
-webkit-box-sizing:border-box;\
-moz-box-sizing: border-box;\
font-size: 10pt;\
- resize: vertical;\
+ resize: vertical horizontal;\
}\
#quick-reply input, #quick-reply select, #quick-reply textarea {\
margin: 0 0 1px 0;\
@@ -115,7 +116,7 @@
#quick-reply td.recaptcha-response {\
padding: 0 0 1px 0;\
}\
- @media screen and (max-width: 800px) {\
+ @media screen and (max-width: 400px) {\
#quick-reply {\
display: none !important;\
}\
@@ -363,7 +364,7 @@
$(window).ready(function() {
if (settings.get('hide_at_top', true)) {
$(window).scroll(function() {
- if ($(this).width() <= 800)
+ if ($(this).width() <= 400)
return;
if ($(this).scrollTop() < $origPostForm.offset().top + $origPostForm.height() - 100)
$postForm.fadeOut(100);
@@ -384,7 +385,7 @@
};
$(window).on('cite', function(e, id, with_link) {
- if ($(this).width() <= 800)
+ if ($(this).width() <= 400)
return;
show_quick_reply();
if (with_link) {
@@ -439,7 +440,7 @@
$('.quick-reply-btn').hide();
$(window).scroll(function() {
- if ($(this).width() <= 800)
+ if ($(this).width() <= 400)
return;
if ($(this).scrollTop() < $('form[name="post"]:first').offset().top + $('form[name="post"]:first').height() - 100)
$('.quick-reply-btn').fadeOut(100);
diff --git a/js/settings.js b/js/settings.js
index 02d5658d..81e88f7a 100644
--- a/js/settings.js
+++ b/js/settings.js
@@ -55,13 +55,11 @@ tb_settings['wpaint'] = {
// auto-reload.js
tb_settings['auto-reload'] = {
// Minimum delay before reloading the page when at the bottom
- min_delay_bottom: 3000,
- // Minimum delay before reloading the page when not at the bottom
- min_delay_top: 10000,
+ min_delay_bottom: 5000,
// Maximum delay before reloading the page
max_delay: 600000,
- //Delay to wait before reloading when the user scrolls to the bottom
- quick_delay: 100,
+ // Delay if there was an error
+ error_delay: 30000,
// Reset the delay to the minimum upon focussing the window.
reset_focus: true
};
diff --git a/js/show-own-posts.js b/js/show-own-posts.js
new file mode 100644
index 00000000..8b83f4cd
--- /dev/null
+++ b/js/show-own-posts.js
@@ -0,0 +1,86 @@
+/*
+ * show-own-posts.js
+ * https://github.com/savetheinternet/Tinyboard/blob/master/js/show-op.js
+ *
+ * Adds "(You)" to a name field when the post is yours. Update references as well.
+ *
+ * Released under the MIT license
+ * Copyright (c) 2014 Marcin Łabanowski <marcin@6irc.net>
+ *
+ * Usage:
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/ajax.js';
+ * $config['additional_javascript'][] = 'js/show-own-posts.js';
+ *
+ */
+
+
++function(){
+
+
+var update_own = function() {
+ if ($(this).is('.you')) return;
+
+ var thread = $(this).parents('[id^="thread_"]').first();
+ if (!thread.length) {
+ thread = $(this);
+ }
+
+ var board = thread.attr('data-board');
+ var posts = JSON.parse(localStorage.own_posts || '{}');
+
+ var id = $(this).attr('id').split('_')[1];
+
+ if (posts[board] && posts[board].indexOf(id) !== -1) { // Own post!
+ $(this).addClass('you');
+ $(this).find('span.name').first().append(' '+_('(You)'));
+ }
+
+ // Update references
+ $(this).find('div.body:first a:not([rel="nofollow"])').each(function() {
+ var postID;
+
+ if(postID = $(this).text().match(/^>>(\d+)$/))
+ postID = postID[1];
+ else
+ return;
+
+ if (posts[board] && posts[board].indexOf(postID) !== -1) {
+ $(this).after(' <small>'+_('(You)')+'</small>');
+ }
+ });
+};
+
+var update_all = function() {
+ $('div[id^="thread_"], div.post.reply').each(update_own);
+};
+
+var board = null;
+
+$(function() {
+ board = $('input[name="board"]').first().val();
+
+ update_all();
+});
+
+$(document).on('ajax_after_post', function(e, r) {
+ var posts = JSON.parse(localStorage.own_posts || '{}');
+ posts[board] = posts[board] || [];
+ posts[board].push(r.id);
+ localStorage.own_posts = JSON.stringify(posts);
+});
+
+$(document).on('new_post', function(e,post) {
+ var $post = $(post);
+ if ($post.is('div.post.reply')) { // it's a reply
+ $post.each(update_own);
+ }
+ else {
+ $post.each(update_own); // first OP
+ $post.find('div.post.reply').each(update_own); // then replies
+ }
+});
+
+
+
+}();
diff --git a/js/thread-stats.js b/js/thread-stats.js
new file mode 100644
index 00000000..8873dbdb
--- /dev/null
+++ b/js/thread-stats.js
@@ -0,0 +1,116 @@
+/*
+ * thread-stats.js
+ * - Adds statistics of the thread below the posts area
+ * - Shows ID post count beside each postID on hover
+ *
+ * Usage:
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/thread-stats.js';
+ */
+if (active_page == 'thread') {
+$(document).ready(function(){
+ //check if page uses unique ID
+ var IDsupport = ($('.poster_id').length > 0);
+ var thread_id = (document.location.pathname + document.location.search).split('/');
+ thread_id = thread_id[thread_id.length -1].split('+')[0].split('-')[0].split('.')[0];
+
+ $('.boardlist.bottom, footer')
+ .first()
+ .before('<div id="thread_stats"></div>');
+ var el = $('#thread_stats');
+ el.prepend(_('Page')+' <span id="thread_stats_page">?</span>');
+ if (IDsupport){
+ el.prepend('<span id="thread_stats_uids">0</span> UIDs |&nbsp;');
+ }
+ el.prepend('<span id="thread_stats_images">0</span> '+_('images')+' |&nbsp;');
+ el.prepend('<span id="thread_stats_posts">0</span> '+_('replies')+' |&nbsp;');
+ delete el;
+ function update_thread_stats(){
+ var op = $('#thread_'+ thread_id +' > div.post.op:not(.post-hover):not(.inline)').first();
+ var replies = $('#thread_'+ thread_id +' > div.post.reply:not(.post-hover):not(.inline)');
+ // post count
+ $('#thread_stats_posts').text(replies.length);
+ // image count
+ $('#thread_stats_images').text(replies.filter(function(){
+ return $(this).find('> .files').text().trim() != false;
+ }).length);
+ // unique ID count
+ if (IDsupport) {
+ var opID = op.find('> .intro > .poster_id').text();
+ var ids = {};
+ replies.each(function(){
+ var cur = $(this).find('> .intro > .poster_id');
+ var curID = cur.text();
+ if (ids[curID] === undefined) {
+ ids[curID] = 0;
+ }
+ ids[curID]++;
+ });
+ if (ids[opID] === undefined) {
+ ids[opID] = 0;
+ }
+ ids[opID]++;
+ var cur = op.find('>.intro >.poster_id');
+ cur.find('+.posts_by_id').remove();
+ cur.after('<span class="posts_by_id"> ('+ ids[cur.text()] +')</span>');
+ replies.each(function(){
+ cur = $(this).find('>.intro >.poster_id');
+ cur.find('+.posts_by_id').remove();
+ cur.after('<span class="posts_by_id"> ('+ ids[cur.text()] +')</span>');
+ });
+ var size = function(obj) {
+ var size = 0, key;
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) size++;
+ }
+ return size;
+ };
+ $('#thread_stats_uids').text(size(ids));
+ }
+ var board_name = $('input[name="board"]').val();
+ $.getJSON('//'+ document.location.host +'/'+ board_name +'/threads.json').success(function(data){
+ var found, page = '???';
+ for (var i=0;data[i];i++){
+ var threads = data[i].threads;
+ for (var j=0; threads[j]; j++){
+ if (parseInt(threads[j].no) == parseInt(thread_id)) {
+ page = data[i].page +1;
+ found = true;
+ break;
+ }
+ }
+ if (found) break;
+ }
+ $('#thread_stats_page').text(page);
+ if (!found) $('#thread_stats_page').css('color','red');
+ else $('#thread_stats_page').css('color','');
+ });
+ }
+ // load the current page the thread is on.
+ // uses ajax call so it gets loaded on a delay (depending on network resources available)
+ var thread_stats_page_timer = setInterval(function(){
+ var board_name = $('input[name="board"]').val();
+ $.getJSON('//'+ document.location.host +'/'+ board_name +'/threads.json').success(function(data){
+ var found, page = '???';
+ for (var i=0;data[i];i++){
+ var threads = data[i].threads;
+ for (var j=0; threads[j]; j++){
+ if (parseInt(threads[j].no) == parseInt(thread_id)) {
+ page = data[i].page +1;
+ found = true;
+ break;
+ }
+ }
+ if (found) break;
+ }
+ $('#thread_stats_page').text(page);
+ if (!found) $('#thread_stats_page').css('color','red');
+ else $('#thread_stats_page').css('color','');
+ });
+ },30000);
+ $('body').append('<style>.posts_by_id{display:none;}.poster_id:hover+.posts_by_id{display:initial}</style>');
+ update_thread_stats();
+ $('#update_thread').click(update_thread_stats);
+ $(document).on('new_post',update_thread_stats);
+});
+}
diff --git a/js/thread-watcher.js b/js/thread-watcher.js
new file mode 100644
index 00000000..22656e48
--- /dev/null
+++ b/js/thread-watcher.js
@@ -0,0 +1,195 @@
+// Thanks to Khorne on #8chan at irc.rizon.net
+// https://gitlab.com/aymous/8chan-watchlist
+
+'use strict';
+/* jshint globalstrict:true, quotmark:single */
+/* jshint browser:true, jquery:true, devel:true, unused:true, undef:true */
+/* global active_page:false, board_name:false */
+if(!localStorage.watchlist){
+ //If the watchlist is undefined in the localStorage,
+ //initialize it as an empty array.
+ localStorage.watchlist = '[]';
+}
+var watchlist = {};
+
+/**
+ * [render /> Creates a watchlist container and populates it with info
+ * about each thread that's currently being watched. If the watchlist container
+ * already exists, it empties it out and repopulates it.]
+ * @param {[Bool]} reset [If true and the watchlist is rendered, remove it]
+ */
+watchlist.render = function(reset) {
+ /* jshint eqnull:true */
+ if (reset == null) reset = false;
+ /* jshint eqnull:false */
+ if (reset && $('#watchlist').length) $('#watchlist').remove();
+ var threads = [];
+ //Read the watchlist and create a new container for each thread.
+ JSON.parse(localStorage.watchlist).forEach(function(e, i) {
+ //look at line 69, that's what (e) is here.
+ threads.push('<div class="watchlist-inner" id="watchlist-'+i+'">' +
+ '<span>Board: '+e[0]+'</span>&nbsp' +
+ '<span>Thread: '+'<a href="'+e[3]+'">'+e[1]+'</a></span>&nbsp' +
+ '<span>Replies: '+e[2]+'</span>&nbsp' +
+ '<a class="watchlist-remove">[Unwatch]</a>'+
+ '</div>');
+ });
+ if ($('#watchlist').length) {
+ //If the watchlist is already there, empty it and append the threads.
+ $('#watchlist').children('.watchlist-inner').remove();
+ $('#watchlist').append(threads.join(''));
+ } else {
+ //If the watchlist has not yet been rendered, create it.
+ $('form[name="post"]').before(
+ $('<div id="watchlist">'+
+ '<div class="watchlist-controls">'+
+ '<span><a id="clearList">[Clear List]</a></span>&nbsp'+
+ '<span><a id="clearGhosts">[Clear Ghosts]</a></span>'+
+ '</div>'+
+ threads.join('')+
+ '</div>').css({
+ background: $('.reply').css('background'),
+ borderColor : $('.reply').css('border-color')
+ }));
+ }
+ return this;
+};
+
+/**
+ * [add /> adds the given item to the watchlist]
+ * @param {[Obj/Str]} sel [An unwrapped jquery selector.]
+ */
+watchlist.add = function(sel) {
+ var threadName, threadInfo;
+
+ if (active_page === 'thread') {
+ if ($('.subject').length){
+ //If a subject is given, use the first 20 characters as the thread name.
+ threadName = $('.subject').text().substring(0,20);
+ } else { //Otherwise use the thread id.
+ threadName = $('.op').parent().attr('id');
+ }
+ //board name, thread name as defined above, current amount of posts, thread url
+ threadInfo = [board_name, threadName, $('.post').length, location.href];
+
+ } else if (active_page === 'index') {
+
+ var postCount;
+ //Figure out the post count.
+ if ($(sel).parents('.op').children('.omitted').length) {
+ postCount = $(sel).parents('.op').children('.omitted').text().split(' ')[0];
+ } else {
+ postCount = $(sel).parents('.op').siblings('.post').length+1;
+ }
+ //Grab the reply link.
+ var threadLink = $(sel).siblings('a:contains("[Reply]")').attr('href');
+ //Figure out the thread name. If anon, use the thread id.
+ if ($(sel).parent().find('.subject').length) {
+ threadName = $(sel).parent().find('.subject').text().substring(0,20);
+ } else {
+ threadName = $(sel).parents('div').last().attr('id');
+ }
+
+ threadInfo = [board_name, threadName, postCount, threadLink];
+
+ } else {
+ alert('Functionality not yet implemented for this type of page.');
+ return this;
+ }
+
+ //if the thread is already being watched, cancel the function.
+ if (localStorage.watchlist.indexOf(JSON.stringify(threadInfo)) !== -1) {
+ return this;
+ }
+
+ var _watchlist = JSON.parse(localStorage.watchlist); //Read the watchlist
+ _watchlist.push(threadInfo); //Add the new watch item.
+ localStorage.watchlist = JSON.stringify(_watchlist); //Save the watchlist.
+ return this;
+};
+
+/**
+ * [remove /> removes the given item from the watchlist]
+ * @param {[Int]} n [The index at which to remove.]
+ */
+watchlist.remove = function(n) {
+ var _watchlist = JSON.parse(localStorage.watchlist);
+ _watchlist.splice(n, 1);
+ localStorage.watchlist = JSON.stringify(_watchlist);
+ return this;
+};
+
+/**
+ * [clear /> resets the watchlist to the initial empty array]
+ */
+watchlist.clear = function() {
+ localStorage.watchlist = '[]';
+ return this;
+};
+
+/**
+ * [exists /> pings every watched thread to check if it exists and removes it if not]
+ * @param {[Obj/Str]} sel [an unwrapped jq selector]
+ */
+watchlist.exists = function(sel) {
+ $.ajax($(sel).children().children('a').attr('href'), {
+ type :'HEAD',
+ error: function() {
+ watchlist.remove(parseInt($(sel).attr('id').split('-')[1])).render();
+ },
+ success : function(){
+ return;
+ }
+ });
+};
+
+$(document).ready(function(){
+ //Append the watchlist toggle button.
+ $('.boardlist').append('<span>[ <a id="watchlist-toggle">watchlist</a> ]</span>');
+ //Append a watch thread button after every OP.
+ $('.op>.intro').append('<a class="watchThread">[Watch Thread]</a>');
+
+ //Draw the watchlist, hidden.
+ watchlist.render();
+
+ //Show or hide the watchlist.
+ $('#watchlist-toggle').on('click', function(e) {
+ //if ctrl+click, reset the watchlist.
+ if (e.ctrlKey) {
+ watchlist.render(true);
+ }
+ if ($('#watchlist').css('display') !== 'none') {
+ $('#watchlist').css('display', 'none');
+ } else {
+ $('#watchlist').css('display', 'block');
+ } //Shit got really weird with hide/show. Went with css manip. Probably faster anyway.
+ });
+
+ //Trigger the watchlist add function.
+ //The selector is passed as an argument in case the page is not a thread.
+ $('.watchThread').on('click', function() {
+ watchlist.add(this).render();
+ });
+
+ //The index is saved in .watchlist-inner so that it can be passed as the argument here.
+ //$('.watchlist-remove').on('click') won't work in case of re-renders and
+ //the page will need refreshing. This works around that.
+ $(document).on('click', '.watchlist-remove', function() {
+ var item = parseInt($(this).parent().attr('id').split('-')[1]);
+ watchlist.remove(item).render();
+ });
+
+ //Empty the watchlist and redraw it.
+ $('#clearList').on('click', function(){
+ watchlist.clear().render();
+ });
+
+ //Get rid of every watched item that no longer directs to an existing page.
+ $('#clearGhosts').on('click', function() {
+ $('.watchlist-inner').each(function(){
+ watchlist.exists(this);
+ });
+ });
+
+});
+
diff --git a/js/threadscroll.js b/js/threadscroll.js
new file mode 100644
index 00000000..0a233f58
--- /dev/null
+++ b/js/threadscroll.js
@@ -0,0 +1,37 @@
+if(active_page == "index" || active_page == "ukko"){
+ var hoverElem = null;
+
+ $(document).mouseover(function(e){
+ var x = e.clientX, y = e.clientY,
+ elementOnMouseOver = document.elementFromPoint(x, y);
+ hoverElem = $(elementOnMouseOver);
+ });
+
+ $(document).keydown(function(e){
+ //Up arrow
+ if(e.which == 38){
+ var ele = hoverElem;
+ var par = $(ele).parents('div[id^="thread_"]');
+
+ if(par.length == 1){
+ if(par.prev().attr("id") != null){
+ if(par.prev().attr("id").match("^thread")){
+ par.prev()[0].scrollIntoView(true);
+ }
+ }
+ }
+ //Down arrow
+ }else if(e.which == 40){
+ var ele = hoverElem;
+ var par = $(ele).parents('div[id^="thread_"]');
+
+ if(par.length == 1){
+ if(par.next().attr("id") != null){
+ if(par.next().attr("id").match("^thread")){
+ par.next()[0].scrollIntoView(true);
+ }
+ }
+ }
+ }
+ });
+}
diff --git a/js/toggle-images.js b/js/toggle-images.js
index 20940ccf..b8940252 100644
--- a/js/toggle-images.js
+++ b/js/toggle-images.js
@@ -60,7 +60,7 @@ $(document).ready(function(){
if (window.Options && Options.get_tab('general')) {
selector = '#toggle-images>input';
event = 'change';
- Options.extend_tab("general", "<label id='toggle-images'><input type='checkbox' /> "+_('Hide images')+"</label>");
+ Options.extend_tab("general", "<label id='toggle-images'><input type='checkbox' />"+_('Hide images')+"</label>");
}
else {
selector = '#toggle-images a';
diff --git a/js/treeview.js b/js/treeview.js
index 78ad620b..1709debb 100644
--- a/js/treeview.js
+++ b/js/treeview.js
@@ -11,14 +11,28 @@
*
*/
-if (active_page == 'thread')
+if (active_page == 'thread' || active_page == 'ukko' || active_page == 'index')
$(function() {
- $('hr:first').before('<div id="treeview" style="text-align:right"><a class="unimportant" href="javascript:void(0)"></a></div>');
- $('div#treeview a')
- .text(_('Tree view'))
- .click(function(e) {
- e.preventDefault();
+ if (window.Options && Options.get_tab('general')) {
+ var selector = '#treeview-global>input';
+ Options.extend_tab("general", "<label id='treeview-global'><input type='checkbox' /> "+_('Use tree view by default')+"</label>");
+ $(selector).on('change', function() {
+ if (localStorage.treeview === 'true') {
+ localStorage.treeview = 'false';
+ } else {
+ localStorage.treeview = 'true';
+ }
+ });
+ if (localStorage.treeview === 'true') {
+ $(selector).attr('checked', 'checked');
+ }
+ }
+});
+if (active_page == 'thread')
+$(function() {
+ var treeview = function(enable) {
+ if (enable === true) {
$('.post.reply').each(function(){
var references = [];
$(this).find('.body a').each(function(){
@@ -26,7 +40,6 @@ $(function() {
references.push(parseInt($(this).html().replace('&gt;&gt;', '')));
}
});
-
var maxref = references.reduce(function(a,b) { return a > b ? a : b; }, 0);
var parent_post = $("#reply_"+maxref);
@@ -39,7 +52,24 @@ $(function() {
post.detach().css("margin-left", margin).insertAfter(parent_post.next());
br.detach().insertAfter(post);
-
});
- });
+ } else {
+ $('.post.reply').sort(function(a,b) {
+ return parseInt(a.id.replace('reply_', '')) - parseInt(b.id.replace('reply_', ''));
+ }).each(function () {
+ var post = $(this);
+ var br = post.next();
+ post.detach().css('margin-left', '').appendTo('.thread');
+ br.detach().insertAfter(post);
+ });
+ }
+ }
+
+ $('hr:first').before('<div class="unimportant" style="text-align:right"><label for="treeview"><input type="checkbox" id="treeview"> '+_('Tree view')+'</label></div>');
+ $('input#treeview').on('change', function(e) { treeview($(this).is(':checked')); });
+
+ if (localStorage.treeview === 'true') {
+ treeview(true);
+ $('input#treeview').attr('checked', true);
+ }
});
diff --git a/js/upload-selection.js b/js/upload-selection.js
index e2032748..b342a134 100644
--- a/js/upload-selection.js
+++ b/js/upload-selection.js
@@ -25,6 +25,7 @@ $(function(){
$("#upload_url").hide();
$("#upload_embed").hide();
$(".add_image").hide();
+ $(".dropzone-wrap").hide();
$('[id^=upload_file]').each(function(i, v) {
$(v).val('');
@@ -40,6 +41,7 @@ $(function(){
enable_file = function() {
disable_all();
$("#upload").show();
+ $(".dropzone-wrap").show();
$(".file_separator").show();
$("[id^=upload_file]").show();
$(".add_image").show();
diff --git a/js/wPaint b/js/wPaint
-Subproject 2c272dffca0f3d7b7163bd82ba15629f5440927
+Subproject f11220032e7edb8349516d3751d3aaee0fd0de6
diff --git a/js/watch.js b/js/watch.js
index a202130f..07c6942a 100644
--- a/js/watch.js
+++ b/js/watch.js
@@ -98,6 +98,9 @@ $(function(){
else {
bc.threads = bc.threads || {};
bc.threads[thread] = Date.now();
+
+ bc.slugs = bc.slugs || {};
+ bc.slugs[thread] = document.location.pathname + document.location.search;
}
st[board] = bc;
storage_save(st);
@@ -121,7 +124,7 @@ $(function(){
var tag;
if (variant == 'desktop') {
- tag = $("<a href='"+modRoot+board+"/res/"+tid+".html'><span>#"+tid+"</span><span class='cb-uri watch-remove'>"+newposts+"</span>");
+ tag = $("<a href='"+((storage()[board].slugs && storage()[board].slugs[tid]) || (modRoot+board+"/res/"+tid+".html"))+"'><span>#"+tid+"</span><span class='cb-uri watch-remove'>"+newposts+"</span>");
tag.find(".watch-remove").mouseenter(function() {
this.oldval = $(this).html();
$(this).css("min-width", $(this).width());
@@ -132,7 +135,7 @@ $(function(){
})
}
else if (variant == 'mobile') {
- tag = $("<a href='"+modRoot+board+"/res/"+tid+".html'><span>#"+tid+"</span><span class='cb-uri'>"+newposts+"</span>"
+ tag = $("<a href='"+((storage()[board].slugs && storage()[board].slugs[tid]) || (modRoot+board+"/res/"+tid+".html"))+"'><span>#"+tid+"</span><span class='cb-uri'>"+newposts+"</span>"
+"<span class='cb-uri watch-remove'><i class='fa fa-minus'></i></span>");
}
@@ -245,7 +248,7 @@ $(function(){
var st = storage();
var sched = 0;
- var sched_diff = 300;
+ var sched_diff = 2000;
for (var i in st) {
if (st[i].watched) {
diff --git a/js/wpaint.js b/js/wpaint.js
index 9c619070..a245a22b 100644
--- a/js/wpaint.js
+++ b/js/wpaint.js
@@ -13,12 +13,7 @@
* $config['additional_javascript'][] = 'js/jquery.min.js';
* $config['additional_javascript'][] = 'js/jquery-ui.custom.min.js';
* $config['additional_javascript'][] = 'js/ajax.js';
- * $config['additional_javascript'][] = 'js/wPaint/lib/wColorPicker.min.js';
- * $config['additional_javascript'][] = 'js/wPaint/wPaint.min.js';
- * $config['additional_javascript'][] = 'js/wPaint/plugins/main/wPaint.menu.main.min.js';
- * $config['additional_javascript'][] = 'js/wPaint/plugins/text/wPaint.menu.text.min.js';
- * $config['additional_javascript'][] = 'js/wPaint/plugins/shapes/wPaint.menu.main.shapes.min.js';
- * $config['additional_javascript'][] = 'js/wPaint/plugins/file/wPaint.menu.main.file.min.js';
+ * $config['additional_javascript'][] = 'js/wPaint/8ch.js';
* $config['additional_javascript'][] = 'js/wpaint.js';
* $config['additional_javascript'][] = 'js/upload-selection.js';
*
@@ -49,7 +44,7 @@ oekaki.init = function() {
var oekaki_form = '<tr id="oekaki"><th>Oekaki</th><td><div id="wpaintctr"><div id="wpaintdiv"></div></div></td></tr>';
// Add oekaki after the file input
- $('form[name="post"]:not(#quick-reply) input[type="file"]').parent().parent().after(oekaki_form);
+ $('form[name="post"]:not(#quick-reply) [id="upload"]').after(oekaki_form);
$('<link class="wpaintcss" rel="stylesheet" href="'+configRoot+'js/wPaint/wPaint.min.css" />').appendTo($("head"));
$('<link class="wpaintcss" rel="stylesheet" href="'+configRoot+'js/wPaint/lib/wColorPicker.min.css" />').appendTo($("head"));