Skip to content

Commit

Permalink
Khorne in #8chan on irc.rizon.net contributed this thread watcher.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ctrlcctrlv authored and czaks committed Oct 11, 2014
1 parent f3e2131 commit b2cbb70
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 0 deletions.
195 changes: 195 additions & 0 deletions 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);
});
});

});

25 changes: 25 additions & 0 deletions stylesheets/style.css
Expand Up @@ -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;
}

0 comments on commit b2cbb70

Please sign in to comment.