Merge remote-tracking branch 'upstream/master' into vichan-merge

This commit is contained in:
Simon McFarlane 2015-05-26 23:31:47 -07:00
commit 4b40f69a4e
223 changed files with 65256 additions and 2969 deletions

View file

@ -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'));
});
});

View file

@ -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");
}
$(document).ready(function(){
if($('div.banner').length == 0)
return; // not index
if($('div.banner').length == 0)
return; // not index
if($(".post.op").size() != 1)
return; //not thread page
var countdown_interval;
if($(".post.op").size() != 1)
return; //not thread page
// 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>");
var countdown_interval;
// 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);
// 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>");
// number of ms to wait before reloading
var poll_interval_delay = poll_interval_mindelay;
var poll_current_time = poll_interval_delay;
// 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);
var end_of_page = false;
// number of ms to wait before reloading
var poll_interval_delay = poll_interval_mindelay;
var poll_current_time = poll_interval_delay;
var new_posts = 0;
var first_new_post = null;
var title = document.title;
var end_of_page = false;
if (typeof update_title == "undefined") {
var update_title = function() {
if (new_posts) {
document.title = "("+new_posts+") "+title;
} else {
document.title = title;
}
};
}
var new_posts = 0;
var first_new_post = null;
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 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;
});
$('#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() >=
$('footer').position().top) {
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);
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 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();
}
$(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 {
// Reset the delay if needed
if(settings.get('reset_focus', true)) {
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
});
$(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("");
}
});
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) {
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);
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 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);
}
}
});
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"));
if($("#auto_update_status").is(':checked') && timeDiff(poll_interval_mindelay)) {
poll(manualUpdate = true);
}
end_of_page = true;
}
// Keep trying to update
if ($('#auto_update_status').is(':checked')) {
poll_interval_delay = poll_interval_errordelay;
auto_update(poll_interval_delay);
}
}
});
return false;
};
$('#update_thread').on('click', function() { poll(manualUpdate = true); 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 {
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);
}
});

View file

@ -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);

View file

@ -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(){

View file

@ -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();

191
js/file-selector.js Normal file
View file

@ -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);
}
}
});
}

View file

@ -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';

165
js/gallery-view.js Normal file
View file

@ -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(); });
};
});

View file

@ -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);
});
});

View file

@ -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();

71
js/id_colors.js Normal file
View file

@ -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);
});
});
});
}

50
js/id_highlighter.js Normal file
View file

@ -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);
});
});
}

91
js/infinite-scroll.js Normal file
View file

@ -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();
}
});

154
js/inline.js Normal file
View file

@ -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();
});
}
});

View file

@ -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) {

View file

@ -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()] + ") " +

184
js/longtable/longtable.js Normal file
View file

@ -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;
};

157
js/mod/ban-list.js Normal file
View file

@ -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;
}
});
}
});
}

View file

@ -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"]'));
}
})

View file

@ -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';

View file

@ -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";');
}

View file

@ -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");');
}

116
js/own-board.js Normal file
View file

@ -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();
}();

View file

@ -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 {

View file

@ -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);

View file

@ -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
};

86
js/show-own-posts.js Normal file
View file

@ -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
}
});
}();

116
js/thread-stats.js Normal file
View file

@ -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);
});
}

195
js/thread-watcher.js Normal file
View file

@ -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);
});
});
});

37
js/threadscroll.js Normal file
View file

@ -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);
}
}
}
}
});
}

View file

@ -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';

View file

@ -11,14 +11,28 @@
*
*/
if (active_page == 'thread' || active_page == 'ukko' || active_page == 'index')
$(function() {
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() {
$('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();
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);
}
});

View file

@ -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();

@ -1 +1 @@
Subproject commit 2c272dffca0f3d7b7163bd82ba15629f54409278
Subproject commit f11220032e7edb8349516d3751d3aaee0fd0de68

View file

@ -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) {

View file

@ -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"));