From 803c76a8001024aa1f5993699a75640d5e68b3cc Mon Sep 17 00:00:00 2001 From: 8chan Date: Thu, 9 Oct 2014 16:59:58 -0700 Subject: [PATCH 1/4] .x.x less confusing...will change to less_ip eventually --- inc/bans.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/bans.php b/inc/bans.php index 6ee27dcc..87e06e28 100644 --- a/inc/bans.php +++ b/inc/bans.php @@ -185,7 +185,7 @@ class Bans { $ban['mask'] = preg_split("/[\.:]/", $ban['mask']); $ban['mask'] = array_slice($ban['mask'], 0, 2); $ban['mask'] = implode(".", $ban['mask']); - $ban['mask'] .= ".*"; + $ban['mask'] .= ".x.x"; if (isset ($subnet)) { $ban['mask'] .= "/$subnet"; } From 1506bcc834f2c8f52986fd7e7eabda88dfd46e25 Mon Sep 17 00:00:00 2001 From: 8chan Date: Thu, 9 Oct 2014 17:48:23 -0700 Subject: [PATCH 2/4] Make inline work on new_post event --- js/inline.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/js/inline.js b/js/inline.js index 63b7a8df..57c359b7 100644 --- a/js/inline.js +++ b/js/inline.js @@ -138,8 +138,16 @@ $(document).ready(function() { // don't attach to outbound links if (App.options.get('useInlining')) { - $('.body a:not([rel]), .mentioned a') - .attr('onclick', null)// XXX disable highlightReply - .click(inline) + var assign_inline = function() { + $('.body a:not([rel]), .mentioned a') + .attr('onclick', null)// XXX disable highlightReply + .click(inline) + } + + assign_inline(); + + $(document).on('new_post', function(e, post) { + assign_inline(); + }); } }); From f3e2131f06f6f5b5cccf6d00c79cdd979771c5b0 Mon Sep 17 00:00:00 2001 From: 8chan Date: Fri, 10 Oct 2014 11:13:26 -0700 Subject: [PATCH 3/4] Actually fix new_post event inline.js --- js/inline.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/inline.js b/js/inline.js index 57c359b7..4f8c9a72 100644 --- a/js/inline.js +++ b/js/inline.js @@ -141,6 +141,7 @@ $(document).ready(function() { var assign_inline = function() { $('.body a:not([rel]), .mentioned a') .attr('onclick', null)// XXX disable highlightReply + .off('click') .click(inline) } From b2cbb70da371dad7f9d399067b7e6df17d7a0b68 Mon Sep 17 00:00:00 2001 From: 8chan Date: Sat, 11 Oct 2014 10:21:00 -0700 Subject: [PATCH 4/4] 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 --- js/thread-watcher.js | 195 ++++++++++++++++++++++++++++++++++++++++++ stylesheets/style.css | 25 ++++++ 2 files changed, 220 insertions(+) create mode 100644 js/thread-watcher.js 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('
' + + 'Board: '+e[0]+' ' + + 'Thread: '+''+e[1]+' ' + + 'Replies: '+e[2]+' ' + + '[Unwatch]'+ + '
'); + }); + 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( + $('
'+ + '
'+ + '[Clear List] '+ + '[Clear Ghosts]'+ + '
'+ + threads.join('')+ + '
').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('[ watchlist ]'); + //Append a watch thread button after every OP. + $('.op>.intro').append('[Watch Thread]'); + + //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/stylesheets/style.css b/stylesheets/style.css index 30172427..85909dd0 100644 --- a/stylesheets/style.css +++ b/stylesheets/style.css @@ -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; +} +