Khorne in #8chan on irc.rizon.net contributed this thread watcher.

Can't properly attribute the code to him because he doesn't want it
connected to his Github account for some reason.

Conflicts:
	inc/instance-config.php
This commit is contained in:
8chan 2014-10-11 10:21:00 -07:00 committed by czaks
parent f3e2131f06
commit b2cbb70da3
2 changed files with 220 additions and 0 deletions

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

View File

@ -913,3 +913,28 @@ span.pln {
clear: none;
}
}
/* threadwatcher */
#watchlist {
display: none;
max-height: 250px;
overflow: auto;
border: 1px solid;
border-style: none solid solid none;
width: 50%;
margin: 0 auto;
margin-bottom: 10px;
}
.watchlist-inner, .watchlist-controls {
margin: 0 auto;
margin-top: 10px;
margin-bottom: 10px;
text-align: center;
}
#watchlist-toggle, .watchThread, .watchlist-remove, #clearList, #clearGhosts {
cursor: pointer;
}