The version of vichan running on lainchan.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 line
6.7KB

  1. // Thanks to Khorne on #8chan at irc.rizon.net
  2. // https://gitlab.com/aymous/8chan-watchlist
  3. 'use strict';
  4. /* jshint globalstrict:true, quotmark:single */
  5. /* jshint browser:true, jquery:true, devel:true, unused:true, undef:true */
  6. /* global active_page:false, board_name:false */
  7. if(!localStorage.watchlist){
  8. //If the watchlist is undefined in the localStorage,
  9. //initialize it as an empty array.
  10. localStorage.watchlist = '[]';
  11. }
  12. var watchlist = {};
  13. /**
  14. * [render /> Creates a watchlist container and populates it with info
  15. * about each thread that's currently being watched. If the watchlist container
  16. * already exists, it empties it out and repopulates it.]
  17. * @param {[Bool]} reset [If true and the watchlist is rendered, remove it]
  18. */
  19. watchlist.render = function(reset) {
  20. /* jshint eqnull:true */
  21. if (reset == null) reset = false;
  22. /* jshint eqnull:false */
  23. if (reset && $('#watchlist').length) $('#watchlist').remove();
  24. var threads = [];
  25. //Read the watchlist and create a new container for each thread.
  26. JSON.parse(localStorage.watchlist).forEach(function(e, i) {
  27. //look at line 69, that's what (e) is here.
  28. threads.push('<div class="watchlist-inner" id="watchlist-'+i+'">' +
  29. '<span>/'+e[0]+'/ - ' +
  30. '<a href="'+e[3]+'">'+e[1].replace("thread_", _("Thread #"))+'</a>' +
  31. ' ('+e[2]+') </span>' +
  32. '<a class="watchlist-remove">X</a>'+
  33. '</div>');
  34. });
  35. if ($('#watchlist').length) {
  36. //If the watchlist is already there, empty it and append the threads.
  37. $('#watchlist').children('.watchlist-inner').remove();
  38. $('#watchlist').append(threads.join(''));
  39. } else {
  40. //If the watchlist has not yet been rendered, create it.
  41. var menuStyle = getComputedStyle($('.boardlist')[0]);
  42. $((active_page == 'ukko') ? 'hr:first' : (active_page == 'catalog') ? 'body>span:first' : 'form[name="post"]').before(
  43. $('<div id="watchlist">'+
  44. '<div class="watchlist-controls">'+
  45. '<span><a id="clearList">['+_('Clear List')+']</a></span>&nbsp'+
  46. '<span><a id="clearGhosts">['+_('Clear Ghosts')+']</a></span>'+
  47. '</div>'+
  48. threads.join('')+
  49. '</div>').css("background-color", menuStyle.backgroundColor).css("border", menuStyle.borderBottomWidth+" "+menuStyle.borderBottomStyle+" "+menuStyle.borderBottomColor));
  50. }
  51. return this;
  52. };
  53. /**
  54. * [add /> adds the given item to the watchlist]
  55. * @param {[Obj/Str]} sel [An unwrapped jquery selector.]
  56. */
  57. watchlist.add = function(sel) {
  58. var threadName, threadInfo;
  59. var board_name = $(sel).parents('.thread').data('board');
  60. if (active_page === 'thread') {
  61. if ($('.subject').length){
  62. //If a subject is given, use the first 20 characters as the thread name.
  63. threadName = $('.subject').text().substring(0,20);
  64. } else { //Otherwise use the thread id.
  65. threadName = $('.op').parent().attr('id');
  66. }
  67. //board name, thread name as defined above, current amount of posts, thread url
  68. threadInfo = [board_name, threadName, $('.post').length, location.href];
  69. } else if (active_page === 'index' || active_page === 'ukko') {
  70. var postCount;
  71. //Figure out the post count.
  72. if ($(sel).parents('.op').children('.omitted').length) {
  73. postCount = $(sel).parents('.op').children('.omitted').text().split(' ')[0];
  74. } else {
  75. postCount = $(sel).parents('.op').siblings('.post').length+1;
  76. }
  77. //Grab the reply link.;
  78. var threadLink = $(sel).siblings('a:not(.watchThread)').last().attr('href');
  79. //Figure out the thread name. If anon, use the thread id.
  80. if ($(sel).parent().find('.subject').length) {
  81. threadName = $(sel).parent().find('.subject').text().substring(0,20);
  82. } else {
  83. threadName = $(sel).parents('div').last().attr('id');
  84. }
  85. threadInfo = [board_name, threadName, postCount, threadLink];
  86. } else {
  87. alert('Functionality not yet implemented for this type of page.');
  88. return this;
  89. }
  90. //if the thread is already being watched, cancel the function.
  91. if (localStorage.watchlist.indexOf(JSON.stringify(threadInfo)) !== -1) {
  92. return this;
  93. }
  94. var _watchlist = JSON.parse(localStorage.watchlist); //Read the watchlist
  95. _watchlist.push(threadInfo); //Add the new watch item.
  96. localStorage.watchlist = JSON.stringify(_watchlist); //Save the watchlist.
  97. return this;
  98. };
  99. /**
  100. * [remove /> removes the given item from the watchlist]
  101. * @param {[Int]} n [The index at which to remove.]
  102. */
  103. watchlist.remove = function(n) {
  104. var _watchlist = JSON.parse(localStorage.watchlist);
  105. _watchlist.splice(n, 1);
  106. localStorage.watchlist = JSON.stringify(_watchlist);
  107. return this;
  108. };
  109. /**
  110. * [clear /> resets the watchlist to the initial empty array]
  111. */
  112. watchlist.clear = function() {
  113. localStorage.watchlist = '[]';
  114. return this;
  115. };
  116. /**
  117. * [exists /> pings every watched thread to check if it exists and removes it if not]
  118. * @param {[Obj/Str]} sel [an unwrapped jq selector]
  119. */
  120. watchlist.exists = function(sel) {
  121. $.ajax($(sel).children().children('a').attr('href'), {
  122. type :'HEAD',
  123. error: function() {
  124. watchlist.remove(parseInt($(sel).attr('id').split('-')[1])).render();
  125. },
  126. success : function(){
  127. return;
  128. }
  129. });
  130. };
  131. $(document).ready(function(){
  132. if (!(active_page == 'thread' || active_page == 'index' || active_page == 'catalog' || active_page == 'ukko')) {
  133. return;
  134. }
  135. //Append the watchlist toggle button.
  136. $('.boardlist').append('<span>[ <a class="watchlist-toggle" href="#">'+_('watchlist')+'</a> ]</span>');
  137. //Append a watch thread button after every OP.
  138. $('.op>.intro').append('<a class="watchThread" href="#">['+_('Watch Thread')+']</a>');
  139. //Draw the watchlist, hidden.
  140. watchlist.render();
  141. //Show or hide the watchlist.
  142. $('.watchlist-toggle').on('click', function(e) {
  143. e.preventDefault();
  144. //if ctrl+click, reset the watchlist.
  145. if (e.ctrlKey) {
  146. watchlist.render(true);
  147. }
  148. if ($('#watchlist').css('display') !== 'none') {
  149. $('#watchlist').css('display', 'none');
  150. } else {
  151. $('#watchlist').css('display', 'block');
  152. } //Shit got really weird with hide/show. Went with css manip. Probably faster anyway.
  153. });
  154. //Trigger the watchlist add function.
  155. //The selector is passed as an argument in case the page is not a thread.
  156. $('.watchThread').on('click', function(e) {
  157. e.preventDefault();
  158. watchlist.add(this).render();
  159. });
  160. //The index is saved in .watchlist-inner so that it can be passed as the argument here.
  161. //$('.watchlist-remove').on('click') won't work in case of re-renders and
  162. //the page will need refreshing. This works around that.
  163. $(document).on('click', '.watchlist-remove', function() {
  164. var item = parseInt($(this).parent().attr('id').split('-')[1]);
  165. watchlist.remove(item).render();
  166. });
  167. //Empty the watchlist and redraw it.
  168. $('#clearList').on('click', function(){
  169. watchlist.clear().render();
  170. });
  171. //Get rid of every watched item that no longer directs to an existing page.
  172. $('#clearGhosts').on('click', function() {
  173. $('.watchlist-inner').each(function(){
  174. watchlist.exists(this);
  175. });
  176. });
  177. });