Advertisement
Guest User

8kun Baker tools v0.2.0

a guest
Dec 24th, 2019
1,203
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  /*
  2.   8Kun Baker Tools
  3.   Version 0.2.0
  4.  
  5.   Features:
  6.   ========
  7.   Notables
  8.     * Highlight posts that are marked notable (I.E. someone has replied and said notable) in Yellow
  9.     * Highlight nominating posts in Pink
  10.     * Higlight nominating posts in posts mentions in Green
  11.     * Filter to only nominating and notable posts
  12.     * Generate notables post
  13.  
  14.   Comfyness
  15.     * Highlight PB links
  16.     * Thread stats overlay with
  17.       * color coded reply count that goes from green to red as bread ages
  18.       * UID Count
  19.       * Jump To Bottom Link
  20.       * Jump To Bottom Top link
  21.  
  22.   Version History:
  23.   https://pastebin.com/eNmTtzdi 0.1.0
  24.   */
  25. (function ($) {
  26.   'use strict';
  27.  
  28.   var BAKER_TOOLS_WINDOW_ID = "baker-tools-window";
  29.  
  30.   /**
  31.    * Wrapper for 8kun active_page variable to determine the type of page the user is on.
  32.    */
  33.   class ActivePage {
  34.     static Index = "index"
  35.     static Catalog = "catalog"
  36.     static Thread = "thread"
  37.  
  38.     static isIndex() {
  39.       return window.active_page == ActivePage.Index;
  40.     }
  41.  
  42.     static isCatalog() {
  43.       return window.active_page == ActivePage.Catalog;
  44.     }
  45.    
  46.     static isThread() {
  47.       console.log(window.active_page == ActivePage.Thread);
  48.       return window.active_page == ActivePage.Thread;
  49.     }
  50.   }
  51.  
  52.   //TODO: Create Dough?
  53.   //TODO: Highlight/filter yous - when they actually work for me again
  54.   //TODO: Nominate notable template
  55.   //
  56.   //TODO: Highlight q posts
  57.   //TODO: Q's Trip-code: Q !!Hs1Jq13jV6 in op
  58.   //    TODO:  highlight q in shortlinks
  59.  
  60.   /******************************
  61.   * Initialization
  62.   ******************************/
  63.  
  64.   /**
  65.   * Sets styles for notable, nominator, nominator in mentions and baker tools window
  66.   */
  67.   function setupStyles() {
  68.     var sheet = window.document.styleSheets[0];
  69.  
  70.     sheet.insertRule(`div.post.${ResearchBread.NOTABLE_CLASS} { background-color: #FFFFCC; }`, sheet.cssRules.length);
  71.     sheet.insertRule(`div.post.${ResearchBread.NOMINATOR_CLASS} { background-color: #FFCCE5;  }`, sheet.cssRules.length);
  72.     sheet.insertRule(`div.post.reply .mentioned .${ResearchBread.NOMINATOR_CLASS} { color: #00CC00; font-weight: bold; font-size: 1.5em}`, sheet.cssRules.length);
  73.     sheet.insertRule(`#${BAKER_TOOLS_WINDOW_ID} { width: 300px; background-color: rgb(214, 218, 240); padding: 5px;
  74.       position: fixed; z-index: 100; float: right; right:28.25px}`, sheet.cssRules.length);
  75.     sheet.insertRule(`#baker-tools-stats { padding: 5px; position: fixed; z-index: 100; float: right; right:28.25px; bottom: 28.25px}`, sheet.cssRules.length);
  76.     sheet.insertRule(`div.post.reply div.body a.previousBread { color: #8B0000; }`, sheet.cssRules.length);
  77.     sheet.insertRule(`a.previousBread::after { content: " (pb)"; }`, sheet.cssRules.length);
  78.   }
  79.  
  80.   /**
  81.    * Listens for "new_post" event and checks for notable nominations
  82.    */
  83.   function setupEventListeners() {
  84.       $(document).on("new_post", function(e, post) {
  85.         var postBody = post.querySelector('.body')
  86.         $(post).removeAttr("style")
  87.          
  88.         if (ResearchBread.isNominatingPost(post)) {
  89.           ResearchBread.markAsNominator(post);
  90.           var [postNumber, notable] = ResearchBread.getNotableFromNominator(post)
  91.           ResearchBread.markAsNotable(notable)
  92.           ResearchBread.markNominatorInMentions(notable, post);
  93.         }
  94.       });
  95.   }
  96.  
  97.  
  98.   /*****************************
  99.    * Research Bread Class
  100.    ****************************/
  101.   class ResearchBread {
  102.     static OP_SUBJECT_SELECTOR = ".post.op > p > label > span.subject";
  103.     static POST_BODY_SELECTOR = ".post > .body";
  104.     static POST_SELECTOR = ".post";
  105.     static NOMINATING_REGEX = /notable/i;
  106.     static REPLY_REGEX = /highlightReply\('(.+?)'/;
  107.     static DOUGH_POSTS_REGEX = /^(Welcome To Q Research General|Global Announcements|War Room|QPosts Archives).*/;
  108.  
  109.     static NOMINATOR_CLASS = "notable-nominator";
  110.     static NOTABLE_CLASS = "notable";
  111.  
  112.     /**
  113.      * Get an array of post bodies with dough posts filtered out
  114.      * @returns NodeList of .post elements
  115.      */
  116.     static getPostsWithoutDough() {
  117.       var posts = Array.from(document.querySelectorAll(ResearchBread.POST_SELECTOR));
  118.       var filteredPosts = posts.filter(function(post){
  119.         return !post.querySelector('.body').innerText.match(ResearchBread.DOUGH_POSTS_REGEX);
  120.       })
  121.       return filteredPosts;
  122.     }
  123.  
  124.     /**
  125.      * Determine what the bread number is
  126.      */
  127.     static getBreadNumber() {
  128.       var breadNumberRegex = /#(.+?) /;
  129.       return document.querySelector(ResearchBread.OP_SUBJECT_SELECTOR)
  130.                       .innerText
  131.                           .match(breadNumberRegex)[1] || "COULD NOT FIND BREAD NUMBER";
  132.     }
  133.  
  134.     /**
  135.      * Is the post nominating a notable
  136.      * @arg Element .post
  137.      */
  138.     static isNominatingPost(post) {
  139.       return post.textContent.search(ResearchBread.NOMINATING_REGEX) != -1 && //User declared something notable
  140.              post.querySelector('.body').innerHTML.match(ResearchBread.REPLY_REGEX); // Link to the notable
  141.     }
  142.  
  143.     /**
  144.      * @arg post .post
  145.      * @return RegexMatch Capture 1 is the number
  146.      */
  147.     static getFirstReplyLink(post) {
  148.         var match = post.querySelector('.body').innerHTML.match(ResearchBread.REPLY_REGEX);
  149.         return match && match[1] || null;
  150.     }
  151.  
  152.     /**
  153.      * Finds posts that are being tagged as notable.    
  154.      *
  155.      * I.E. Finding any post that has been replied to by a post with the string "notable" in it.
  156.      * Maybe at somepoint this can be smarter.  Q give me some dwave snow white tech!
  157.      *
  158.      * Highlights notable posts in yellow
  159.      * Highlights nominating posts in pink <3
  160.      * Highlights nominating posts in mentions
  161.      * Add nominee count to post
  162.      */
  163.     static findNominatedNotables() {
  164.       var postsWithoutDough = ResearchBread.getPostsWithoutDough();
  165.  
  166.       //^s to ignore notables review posts
  167.       var nominatingPosts = postsWithoutDough.filter(post => ResearchBread.isNominatingPost(post));
  168.       var notables = [];
  169.  
  170.       nominatingPosts.forEach(function(nominatingPost) {
  171.         var [postNumber, notable] = ResearchBread.getNotableFromNominator(nominatingPost);
  172.  
  173.         if (postNumber) {
  174.           ResearchBread.markAsNominator(nominatingPost);
  175.  
  176.           if (postNumber in notables) {
  177.             var nominatedPost =  notables[postNumber];
  178.             nominatedPost.nominatingPosts.push(nominatingPost);
  179.           } else {
  180.  
  181.             var description = '[DESCRIPTION]'
  182.             // Post is in this bread.
  183.             // TODO: What to do for lb/pb?
  184.             if (notable)  {
  185.               ResearchBread.markAsNotable(notable);
  186.               description = notable.querySelector('.body').innerText.replace(/\n/g,' ');
  187.             }
  188.  
  189.             notables[postNumber] = {
  190.               nominatingPosts: [nominatingPost],
  191.               shortLink: ">>" + postNumber,
  192.               postNumber: postNumber,
  193.               description: description,
  194.               post: notable,
  195.             };
  196.           }
  197.  
  198.           ResearchBread.markNominatorInMentions(notable, nominatingPost);
  199.         }
  200.       });
  201.       console.log(notables)
  202.       return notables;
  203.     }
  204.  
  205.     static getNotableFromNominator(nominatingPost) {
  206.       var postNumber = ResearchBread.getFirstReplyLink(nominatingPost);
  207.       var nominatedPost = document.querySelector("#reply_" + postNumber);
  208.       return [postNumber, nominatedPost]
  209.     }
  210.  
  211.     /**
  212.      * @arg post .post
  213.      */
  214.     static markAsNotable(post) {
  215.       console.info(`Mark as notable: ${post}`)
  216.       post.classList.add(ResearchBread.NOTABLE_CLASS);
  217.     }
  218.  
  219.     /**
  220.      * @arg post .post
  221.      */
  222.     static markAsNominator(post) {
  223.         console.info(`Mark as nominator: ${post}`)
  224.         post.classList.add(ResearchBread.NOMINATOR_CLASS);
  225.     }
  226.  
  227.     static markNominatorInMentions(notablePost, nominatingPost) {
  228.           console.info(`Mark as nominator in mentions.  Notable: ${notablePost}, Nominating Post: ${nominatingPost}`)
  229.           if (!notablePost) {
  230.             console.info(`Notable post is null - possible pb/lb`)
  231.             return;
  232.           }
  233.           var nominatingPostId = nominatingPost.id.replace("reply_","");
  234.           $(notablePost).find('.mentioned-'+nominatingPostId).addClass(ResearchBread.NOMINATOR_CLASS);
  235.     }
  236.  
  237.     /**
  238.      * Toggle whether only the notable/nominee posts are shown or not
  239.      * @arg onlyShowNotables boolean If true, only show notables/nominators, else show all
  240.      */
  241.     static setOnlyShowNotables(onlyShowNotables) {
  242.       var notableOrNominationPostsSelector = `div.post.${ResearchBread.NOTABLE_CLASS}, div.post.${ResearchBread.NOMINATOR_CLASS}`
  243.       var notableOrNominationPostBreaksSelector = `div.post.${ResearchBread.NOTABLE_CLASS}+br,div.post.${ResearchBread.NOMINATOR_CLASS}+br`;
  244.  
  245.       if (onlyShowNotables){
  246.         $(`<style id='baker-tools-hide-non-notable' type='text/css'>
  247.           div.reply:not(.post-hover), div.post+br {display: none !important; visibility: hidden !important;}
  248.           ${notableOrNominationPostsSelector}, ${notableOrNominationPostBreaksSelector}
  249.           { display: inline-block !important; visibility: visible !important; }
  250.           </style>`).appendTo("head")
  251.       } else {
  252.          $("#baker-tools-hide-non-notable").remove();
  253.         // For whatever reason, when the non notable posts are filtered and new posts come through the auto_update,
  254.         // the posts are created with style="display:block" which messes up display.  Remove style attr
  255.          $(ResearchBread.POST_SELECTOR).removeAttr("style")
  256.       }
  257.     }
  258.  
  259.  
  260.   }
  261.  
  262.  
  263. /*****************************
  264.  * UI
  265.  * ***************************/
  266.  
  267.   /**
  268.    * Creates the Baker Tools link in the top bar (right next to 8kun options)
  269.    */
  270.   function createBakersToolsLink() {
  271.     var bakerToolsLink = document.createElement("a");
  272.     bakerToolsLink.textContent = "[Baker Tools]"
  273.     bakerToolsLink.style.cssText = "float: right;"
  274.     bakerToolsLink.title = "Baker Tools"
  275.     bakerToolsLink.href = "javascript:void(0)"
  276.     document.querySelector('.boardlist').appendChild(bakerToolsLink)
  277.  
  278.     bakerToolsLink.onclick = function() {
  279.       if($(`#${BAKER_TOOLS_WINDOW_ID}`).is(':visible') ) {
  280.         $(`#${BAKER_TOOLS_WINDOW_ID}`).hide();
  281.       } else {
  282.         $(`#${BAKER_TOOLS_WINDOW_ID}`).css({"top": 15});
  283.         $(`#${BAKER_TOOLS_WINDOW_ID}`).show();
  284.       }
  285.     };
  286.   }
  287.  
  288.   function createBakerWindow() {
  289.       var bakerWindow = document.createElement("div");
  290.       bakerWindow.id = BAKER_TOOLS_WINDOW_ID;
  291.  
  292.       bakerWindow.innerHTML = `
  293.       <h2>Baker Tools</h2>
  294.       <label for="baker-show-only-notable">Only Show Notable/Nomination Posts</label>
  295.       <input type="checkbox" id="baker-show-only-notable" />
  296.       <button id="baker-create-notable-post">Create Notable Post</button>
  297.       <textarea id="baker-notable-controls"></textarea>
  298.       `
  299.       document.body.appendChild(bakerWindow);
  300.  
  301.       $('#baker-show-only-notable').change(function(e) {
  302.         ResearchBread.setOnlyShowNotables(e.target.checked)
  303.       });
  304.       $('#baker-create-notable-post').click(function() {
  305.         if($('#baker-notable-controls').val()) {
  306.           if (!confirm("If you continue, any changes you made will be overwritten!")) {
  307.             return;
  308.           }
  309.         }
  310.         $('#baker-notable-controls').val(createNotablesPost());
  311.       })
  312.       $(bakerWindow).draggable();
  313.       $(bakerWindow).hide();
  314.   }
  315.  
  316.      
  317.   /**
  318.    * Create the notables post for review
  319.    */
  320.   function createNotablesPost() {
  321.     var notables = ResearchBread.findNominatedNotables();
  322.     var breadNumber = ResearchBread.getBreadNumber();
  323.     var post = `'''#${breadNumber}'''\n\n`;
  324.  
  325.     notables.forEach(function(notable) {
  326.       post += `${notable.shortLink} ${notable.description}\n\n`;
  327.     });
  328.  
  329.     return post;
  330.   }
  331.  
  332.   function createBreadStatsOverlay() {
  333.       var statsOverlay = document.createElement("div");
  334.       statsOverlay.id = "baker-tools-stats";
  335.  
  336.       statsOverlay.innerHTML = `
  337.       Posts: <span id="baker-tools-stats-post-count" ></span> UIDS: <span id="baker-tools-stats-uid-count"></span>
  338.         <a href="#bottom" alt="to-bottom"></a> <a href="#top" alt="to-top"></a>
  339.       `
  340.  
  341.       var UpdateStats = function() {
  342.         var postCount = $("#thread_stats_posts").text()
  343.         var maxPosts = 750
  344.         var progress = postCount/maxPosts
  345.  
  346.         var postColor = "green";
  347.         if (progress >= .87) {  // ~ 650 posts (100 posts left)
  348.           postColor = "red";
  349.         } else if (progress >= .5) {
  350.           postColor = "goldenrod";
  351.         }
  352.         $("#baker-tools-stats-post-count").text(postCount).css({'color': postColor})
  353.         $("#baker-tools-stats-uid-count").text($("#thread_stats_uids").text())
  354.       }
  355.  
  356.       document.body.appendChild(statsOverlay);
  357.       UpdateStats();
  358.       $(document).on("new_post", function(e, post) { UpdateStats() });
  359.   }
  360.  
  361.   /**
  362.    * Loop through post links and mark those that link to breads other than this one.
  363.    * Setup event listener for new post
  364.    */
  365.   function markPreviousBreadLinksInit() {
  366.     var breadFileName = document.location.pathname.split('/').slice(-1)[0];  
  367.    
  368.     var linkSelector = "div.body > p.body-line.ltr > a"
  369.     var links = $(linkSelector).filter("[onClick]");
  370.  
  371.     var markLinkIfPreviousBread = function(link) {
  372.        var linkFileName = link.href.split('/').slice(-1)[0].split("#")[0];
  373.        if ($(link).attr('onclick').search(ResearchBread.REPLY_REGEX) !=1 &&
  374.              breadFileName != linkFileName) {
  375.            $(link).addClass('previousBread');
  376.        }
  377.     }
  378.  
  379.     links.each((index,link) => markLinkIfPreviousBread(link));
  380.  
  381.     $(document).on("new_post", function(e, post) {
  382.       $(post).find(linkSelector).each((index,link) => markLinkIfPreviousBread(link));
  383.     });
  384.   };
  385.  
  386.  
  387.  
  388.   //Only setup the tools if we are on a thread
  389.   if (ActivePage.isThread()) {
  390.     setupStyles();
  391.  
  392.     $(document).ready(function() {
  393.       createBakerWindow();
  394.       createBakersToolsLink();
  395.       createBreadStatsOverlay();
  396.       ResearchBread.findNominatedNotables();
  397.       markPreviousBreadLinksInit();
  398.       setupEventListeners();
  399.     });
  400.   }
  401.  
  402.  
  403. })(window.jQuery);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement