Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- 8Kun Baker Tools
- Version 0.3.0
- Features:
- ========
- Notables
- * Highlight posts that are marked notable (I.E. someone has replied and said notable) in Yellow
- * Highlight nominating posts in Pink
- * Higlight nominating posts in posts mentions in Green
- * Filter to only nominating and notable posts
- * Generate notables post
- Q Posts :: New In 0.3.0
- * Highlights Q Posts with white BG -> DARK TO LIGHT!
- * Highlights Q posts in mentions (I.E. posts that get (YOU)'ed)
- * Highlights links to Q Posts
- Comfyness
- * Highlight PB links
- * Thread stats overlay with
- * color coded reply count that goes from green to red as bread ages
- * UID Count
- * Jump To Bottom Link
- * Jump To Bottom Top link
- Version History:
- 0.3.0
- https://pastebin.com/4aEFsPwK 0.2.0
- https://pastebin.com/eNmTtzdi 0.1.0
- */
- (function ($) {
- 'use strict';
- /**
- * Wrapper for 8kun active_page variable to determine the type of page the user is on.
- */
- class ActivePage {
- static Index = "index"
- static Catalog = "catalog"
- static Thread = "thread"
- static isIndex() {
- return window.active_page == ActivePage.Index;
- }
- static isCatalog() {
- return window.active_page == ActivePage.Catalog;
- }
- static isThread() {
- console.log(window.active_page == ActivePage.Thread);
- return window.active_page == ActivePage.Thread;
- }
- }
- //TODO: Create Dough?
- //TODO: Highlight/filter yous - when they actually work for me again
- //TODO: Nominate notable template
- //
- //TODO: Bread list
- /*****************************
- * Research Bread Class
- ****************************/
- class ResearchBread {
- static OP_SUBJECT_SELECTOR = ".post.op > p > label > span.subject";
- static POST_BODY_SELECTOR = ".post > .body";
- static POST_SELECTOR = ".post";
- static REPLY_REGEX = /highlightReply\('(.+?)'/;
- static DOUGH_POSTS_REGEX = /^(Welcome To Q Research General|Global Announcements|War Room|QPosts Archives).*/;
- /**
- * Get an array of post bodies with dough posts filtered out
- * @returns NodeList of .post elements
- */
- static getPostsWithoutDough() {
- var posts = Array.from(document.querySelectorAll(ResearchBread.POST_SELECTOR));
- var filteredPosts = posts.filter(function(post){
- return !post.querySelector('.body').innerText.match(ResearchBread.DOUGH_POSTS_REGEX);
- })
- return filteredPosts;
- }
- /**
- * Determine what the bread number is
- */
- static getBreadNumber() {
- var breadNumberRegex = /#(.+?) /;
- return document.querySelector(ResearchBread.OP_SUBJECT_SELECTOR)
- .innerText
- .match(breadNumberRegex)[1] || "COULD NOT FIND BREAD NUMBER";
- }
- /**
- * @arg post .post
- * @return RegexMatch Capture 1 is the number
- */
- static getFirstReplyLink(post) {
- var match = post.querySelector('.body').innerHTML.match(ResearchBread.REPLY_REGEX);
- return match && match[1] || null;
- }
- }
- /*****************************
- * UI
- * ***************************/
- class BakerWindow {
- static ID = "baker-tools-window";
- showOnlyNotablesCheckboxId = "bakertools-show-only-notable"
- createNotablePostButtonId = "bakertools-create-notable-post"
- notableEditorId = "bakertools-notable-editor"
- bakerWindowBodyId = "bakertools-window-body"
- bakerWindowHeaderId = "bakertools-window-header"
- element = null;
- constructor() {
- this._createStyles();
- this._createElement();
- this._setupListeners();
- this._setupBakerWindowLink()
- }
- _createStyles() {
- var sheet = window.document.styleSheets[0];
- sheet.insertRule(`#${BakerWindow.ID} { width: 300px; background-color: rgb(214, 218, 240);
- position: fixed; z-index: 100; float: right; right:28.25px}`, sheet.cssRules.length);
- sheet.insertRule(`#${BakerWindow.ID} #${this.bakerWindowBodyId} { padding: 5px; }`, sheet.cssRules.length);
- sheet.insertRule(`#${BakerWindow.ID} #${this.bakerWindowHeaderId} { background: #98E; border: solid 1px; text-align: center; margin: 0px}`, sheet.cssRules.length);
- sheet.insertRule(`#${BakerWindow.ID} #${this.bakerWindowHeaderId} h3 { margin: 0; }`, sheet.cssRules.length);
- }
- _createElement() {
- this.element = document.createElement("div");
- this.element.id = BakerWindow.ID;
- this.element.innerHTML = `
- <header id="${this.bakerWindowHeaderId}">
- <h3>Baker Tools</h3>
- </header>
- <div id="${this.bakerWindowBodyId}">
- <label for="${this.showOnlyNotablesCheckboxId}">Only Show Notable/Nomination Posts</label>
- <input type="checkbox" id="${this.showOnlyNotablesCheckboxId}" />
- <button id="${this.createNotablePostButtonId}">Create Notable Post</button>
- <textarea id="${this.notableEditorId}"></textarea>
- </div>
- `
- document.body.appendChild(this.element);
- $(this.element).draggable();
- $(this.element).hide();
- }
- _setupListeners() {
- $('#'+this.showOnlyNotablesCheckboxId).change(function(e) {
- bakerTools.notableHighlighter.setOnlyShowNotables(e.target.checked)
- }.bind(this));
- $('#'+this.createNotablePostButtonId).click(function() {
- if($('#'+this.notableEditorId).val()) {
- if (!confirm("If you continue, any changes you made will be overwritten!")) {
- return;
- }
- }
- $('#'+this.notableEditorId).val(this.createNotablesPost());
- }.bind(this));
- }
- _setupBakerWindowLink() {
- this.bakerToolsLink = document.createElement("a");
- this.bakerToolsLink.textContent = "[Baker Tools]"
- this.bakerToolsLink.style.cssText = "float: right;"
- this.bakerToolsLink.title = "Baker Tools"
- this.bakerToolsLink.href = "javascript:void(0)"
- document.querySelector('.boardlist').appendChild(this.bakerToolsLink)
- this.bakerToolsLink.onclick = this.toggle.bind(this);
- }
- show() {
- $(this.element).css({"top": 15});
- $(this.element).show();
- }
- hide() {
- $(this.element).hide();
- }
- isVisible() {
- return $(this.element).is(':visible')
- }
- toggle() {
- if (this.isVisible()) {
- this.hide();
- } else {
- this.show();
- }
- }
- /**
- * Create the notables post for review
- */
- createNotablesPost() {
- var notables = NotablePost.GetNotables();
- var breadNumber = ResearchBread.getBreadNumber();
- var post = `'''#${breadNumber}'''\n\n`;
- notables.forEach(function(notable) {
- post += `${notable.shortLink()} ${notable.description}\n\n`;
- });
- return post;
- }
- } // end class BakerWindow
- class StatsOverlay {
- //TODO: number of notables
- //TODO: number of q posts in bread
- static ID = 'bakertools-stats-overlay'
- static MAX_POSTS = 750
- postCountId = "bakertools-stats-post-count"
- userCountId = "bakertools-stats-uid-count"
- qCountId = "bakertools-stats-q-count"
- notableCountId = "bakertools-stats-notable-count"
- constructor() {
- this._createStyles();
- this._createElement()
- this._UpdateStats();
- $(document).on("new_post", function(e, post) { this._UpdateStats() }.bind(this));
- }
- _createStyles() {
- var sheet = window.document.styleSheets[0];
- sheet.insertRule(`#${StatsOverlay.ID} { padding: 5px; position: fixed; z-index: 100; float: right; right:28.25px; bottom: 28.25px}`, sheet.cssRules.length);
- }
- _createElement() {
- this.element = document.createElement("div");
- this.element.id = StatsOverlay.ID;
- this.element.innerHTML = `
- Posts: <span id="${this.postCountId}" ></span> UIDS: <span id="${this.userCountId}"></span>
- <a href="#bottom" alt="to-bottom">⏬</a> <a href="#top" alt="to-top">⏫</a><br/>
- Q's: <span id="${this.qPostCountId}" ></span> Notables: <span id="${this.notableCountId}"></span>
- `
- document.body.appendChild(this.element);
- }
- _UpdateStats() {
- var postCount = $("#thread_stats_posts").text()
- var progress = postCount/StatsOverlay.MAX_POSTS;
- var postColor = "green";
- if (progress >= .87) { // ~ 650 posts (100 posts left)
- postColor = "red";
- } else if (progress >= .5) {
- postColor = "goldenrod";
- }
- $("#"+this.postCountId).text(postCount).css({'color': postColor})
- $("#"+this.userCountId).text($("#thread_stats_uids").text())
- $("#"+this.qPostCountId).text(QPostHighlighter.qPosts.length)
- $("#"+this.notableCountId).text(NotablePost.GetNotables().length)
- }
- } // End StatsOverlay class
- class NotableHighlighter {
- static NOMINATOR_CLASS = "notable-nominator";
- static NOTABLE_CLASS = "notable";
- static NOMINATING_REGEX = /notable/i;
- constructor() {
- this._createStyles();
- this.findNominatedNotables();
- $(document).on("new_post", function(e, post) { this.checkNewPostsForNotables(post) }.bind(this));
- }
- _createStyles() {
- var sheet = window.document.styleSheets[0];
- sheet.insertRule(`div.post.${NotableHighlighter.NOTABLE_CLASS} { background-color: #FFFFCC; }`, sheet.cssRules.length);
- sheet.insertRule(`div.post.${NotableHighlighter.NOMINATOR_CLASS} { background-color: #FFCCE5; }`, sheet.cssRules.length);
- sheet.insertRule(`div.post.reply .mentioned .${NotableHighlighter.NOMINATOR_CLASS} { color: #00CC00; font-weight: bold; font-size: 1.5em}`, sheet.cssRules.length);
- }
- checkNewPostsForNotables(post) {
- var postBody = post.querySelector('.body')
- $(post).removeAttr("style") //TODO: try removing
- if (this.isNominatingPost(post)) {
- NotablePost.FromNominatingPost(post)
- }
- }
- /**
- * Finds posts that are being tagged as notable.
- *
- * I.E. Finding any post that has been replied to by a post with the string "notable" in it.
- * Maybe at somepoint this can be smarter. Q give me some dwave snow white tech!
- *
- * Highlights notable posts in yellow
- * Highlights nominating posts in pink <3
- * Highlights nominating posts in mentions
- * Add nominee count to post
- */
- findNominatedNotables() {
- var postsWithoutDough = ResearchBread.getPostsWithoutDough();
- //^s to ignore notables review posts
- var nominatingPosts = postsWithoutDough.filter(post => this.isNominatingPost(post));
- nominatingPosts.forEach(function(nominatingPost) {
- var notable = NotablePost.FromNominatingPost(nominatingPost)
- }.bind(this));
- console.log(NotablePost.GetNotables());
- return NotablePost.GetNotables();
- }
- /**
- * Is the post nominating a notable
- * @arg Element .post
- */
- isNominatingPost(post) {
- return post.textContent.search(NotableHighlighter.NOMINATING_REGEX) != -1 && //User declared something notable
- post.querySelector('.body').innerHTML.match(NotableHighlighter.REPLY_REGEX); // Link to the notable
- }
- /**
- * Toggle whether only the notable/nominee posts are shown or not
- * @arg onlyShowNotables boolean If true, only show notables/nominators, else show all
- */
- setOnlyShowNotables(onlyShowNotables) {
- var notableOrNominationPostsSelector = `div.post.${NotableHighlighter.NOTABLE_CLASS}, div.post.${NotableHighlighter.NOMINATOR_CLASS}`
- var notableOrNominationPostBreaksSelector = `div.post.${NotableHighlighter.NOTABLE_CLASS}+br,div.post.${NotableHighlighter.NOMINATOR_CLASS}+br`;
- var onlyShowNotablesStyleId = 'bakertools-only-show-notables';
- if (onlyShowNotables){
- $(`<style id='${onlyShowNotablesStyleId}' type='text/css'>
- div.reply:not(.post-hover), div.post+br {display: none !important; visibility: hidden !important;}
- ${notableOrNominationPostsSelector}, ${notableOrNominationPostBreaksSelector}
- { display: inline-block !important; visibility: visible !important; }
- </style>`).appendTo("head")
- } else {
- $(`#${onlyShowNotablesStyleId}`).remove();
- // For whatever reason, when the non notable posts are filtered and new posts come through the auto_update,
- // the posts are created with style="display:block" which messes up display. Remove style attr
- $(ResearchBread.POST_SELECTOR).removeAttr("style") //TODO: can we remove this now that we have !important?
- }
- }
- }
- class NotablePost {
- static _notables = [];
- element = null;
- postNumber = null;
- description = "[DESCRIPTION]";
- nominatingPosts = [];
- static NULL = null; //NullNotablePost
- constructor() { }
- static FromNominatingPost(nominatingPost) {
- var [postNumber, element] = NotablePost._getNotableFromNominator(nominatingPost);
- if (!postNumber) {
- console.info("Could not find a reply link in nominator post") ;
- console.debug(nominatingPost.querySelector('.body').innerText);
- if (!NotablePost.NULL) {
- NotablePost.NULL = new NullNotablePost();
- }
- return NotablePost.NULL;
- }
- var notable = NotablePost.FindNotableByPostNumber(postNumber)
- if (!notable) {
- var notable = new NotablePost()
- var isPreviousBread = element == null;
- if (!isPreviousBread) {
- notable.setElement(element);
- } else {
- //TODO: set pb description
- notable.postNumber = postNumber;
- }
- NotablePost._notables.push(notable);
- }
- notable.addNominatingPost(nominatingPost);
- return notable;
- }
- isNull() {return false;}
- static GetNotables() {
- return NotablePost._notables;
- }
- static FindNotableByPostNumber(postNumber) {
- return NotablePost._notables.find(notable => notable.postNumber == postNumber);
- }
- setElement(element) {
- this.element = element;
- this._markAsNotable(this.element);
- this.description = element.querySelector('.body').innerText.replace(/\n/g,' ');
- this.postNumber = $(this.element).find('.intro .post_no').text();
- console.debug(this.postNumber);
- }
- shortLink() {
- return ">>" + this.postNumber;
- }
- addNominatingPost(nominatingPost) {
- this.nominatingPosts.push(nominatingPost)
- this._markAsNominator(nominatingPost);
- this._markNominatorInMentions(nominatingPost);
- }
- /**
- * @arg nominatorPost .post
- */
- _markAsNominator(nominatorPost) {
- console.info(`Mark as nominator: ${nominatorPost}`)
- nominatorPost.classList.add(NotableHighlighter.NOMINATOR_CLASS);
- }
- /**
- * @arg post .post
- */
- _markAsNotable(post) {
- console.info(`Mark as notable: ${post}`)
- post.classList.add(NotableHighlighter.NOTABLE_CLASS);
- }
- static _getNotableFromNominator(nominatingPost) {
- var postNumber = ResearchBread.getFirstReplyLink(nominatingPost);
- var nominatedPost = document.querySelector("#reply_" + postNumber);
- return [postNumber, nominatedPost]
- }
- _markNominatorInMentions(nominatingPost) {
- var notableString = this.element && this.element.id || this.postNumber + " (pb)";
- console.info(`Mark as nominator in mentions. Notable: ${notableString}, Nominating Post: ${nominatingPost.id}`)
- if (!this.element) {
- console.info(`Notable post is null - possible pb/lb`)
- return;
- }
- var nominatingPostId = nominatingPost.id.replace("reply_","");
- $(this.element).find('.mentioned-'+nominatingPostId).addClass(NotableHighlighter.NOMINATOR_CLASS);
- }
- }
- class NullNotablePost extends NotablePost {
- isNull() { return true; }
- }
- class PreviousBreadHighlighter {
- static previousBreadClass = "bakertools-PreviousBread"
- _linkSelector = "div.body > p.body-line.ltr > a"
- /**
- * Loop through post links and mark those that link to breads other than this one.
- * Setup event listener for new post
- */
- constructor() {
- this._setupStyles();
- var links = $(this._linkSelector).filter("[onClick]");
- links.each(function (index,link){ this.markLinkIfPreviousBread(link)}.bind(this) );
- this._setupListeners();
- }
- _setupStyles() {
- var sheet = window.document.styleSheets[0];
- sheet.insertRule(`div.post.reply div.body a.${PreviousBreadHighlighter.previousBreadClass} { color: #8B0000; }`, sheet.cssRules.length);
- sheet.insertRule(`a.${PreviousBreadHighlighter.previousBreadClass}::after { content: " (pb)"; }`, sheet.cssRules.length);
- }
- _setupListeners() {
- $(document).on("new_post", function(e, post) {
- $(post).find(this._linkSelector).each((index,link) => this.markLinkIfPreviousBread(link));
- });
- }
- markLinkIfPreviousBread(link) {
- var breadFileName = document.location.pathname.split('/').slice(-1)[0];
- var linkFileName = link.href.split('/').slice(-1)[0].split("#")[0];
- if ($(link).attr('onclick').search(ResearchBread.REPLY_REGEX) !=1 &&
- breadFileName != linkFileName) {
- $(link).addClass(PreviousBreadHighlighter.previousBreadClass);
- }
- }
- }
- class QPostHighlighter {
- qPostClass = "bakertools-q-post"
- qReplyClass = "bakertools-q-reply"
- qMentionClass = "bakertools-q-mention"
- qLinkClass = "bakertools-q-link"
- _linkSelector = "div.body > p.body-line.ltr > a"
- currentQTripCode = null;
- static qPosts = [];
- constructor() {
- this._setupStyles();
- this._getCurrentQTripFromBread();
- this._findQPosts();
- this._setupListeners();
- }
- _setupStyles() {
- var sheet = window.document.styleSheets[0];
- // Dark to light
- sheet.insertRule(`div.post.reply.${this.qPostClass}
- { background: #FFFFFF; display: inline-block !important; visibility: visible !important;}`, sheet.cssRules.length);
- // Enlightened by the Q but still not all the way
- sheet.insertRule(`div.post.reply.${this.qReplyClass}
- { background: #DDDDDD; display: inline-block !important; visibility: visible !important;}`, sheet.cssRules.length);
- //Trippy mentions
- sheet.insertRule(`div.post.reply .intro .${this.qMentionClass}, .${this.qLinkClass}
- {
- padding:1px 3px 1px 3px;
- background-color:black;
- border-radius:8px;
- border:1px solid #bbbbee;
- color:gold;
- background: linear-gradient(300deg, #ff0000, #ff0000, #ff0000, #bbbbbb, #4444ff);
- background-size: 800% 800%;
- -webkit-animation: Patriot 5s ease infinite;
- -moz-animation: Patriot 5s ease infinite;
- -o-animation: Patriot 5s ease infinite;
- animation: Patriot 5s ease infinite;
- -webkit-text-fill-color: transparent;
- background: -o-linear-gradient(transparent, transparent);
- -webkit-background-clip: text;
- }`, sheet.cssRules.length);
- }
- _getCurrentQTripFromBread() {
- var tripCodeMatch = $('div.post.op').text().match(/Q's Trip-code: Q (.+?\s)/)
- if (!tripCodeMatch) {
- console.error("Could not find Q's tripcode");
- return;
- }
- this.currentQTripCode = tripCodeMatch[1].split(' ')[0];
- }
- _findQPosts() {
- var posts = ResearchBread.getPostsWithoutDough();
- $(posts).each(function(i,post){
- this._doItQ(post);
- }.bind(this))
- }
- //WWG1WGA
- _doItQ(post) {
- if (this._markIfQPost(post)) { //Q Post, lets check for q replies
- var qPostNumber = $(post).find('.intro .post_no').text().replace("No.","")
- var links = $(post).find(this._linkSelector).filter('[onClick]')
- $(links).each(function(i,link) {
- var postNumber = link.href.split('#')[1]
- $(`#reply_${postNumber}`).addClass(this.qReplyClass); //Enlightened post
- $(`#reply_${postNumber} .intro .mentioned a`).each(function(i,mentionAnchor) {
- var mentionPostNumber = $(mentionAnchor).text().replace(">>","");
- if (mentionPostNumber == qPostNumber) {
- $(mentionAnchor).addClass(this.qMentionClass);
- }
- }.bind(this));
- }.bind(this));
- } else { // Not Q, but lets check if this post replies to Q
- var links = $(post).find(this._linkSelector).filter('[onClick]')
- $(links).each(function(i,link) {
- var postNumber = link.href.split('#')[1]
- var replyPost = document.querySelector(`#reply_${postNumber}`);
- if (this._isQ(replyPost)) {
- $(link).addClass(this.qLinkClass)
- }
- }.bind(this));
- }
- }
- /**
- * @arg post div.post.reply
- */
- _markIfQPost(post) {
- var isQ = false;
- if (this._isQ(post)) {
- $(post).addClass(this.qPostClass);
- QPostHighlighter.qPosts.push(post)
- isQ = true;
- }
- return isQ;
- }
- _isQ(post) {
- return this._getTripCodeOfPost(post) == this.currentQTripCode;
- }
- _getTripCodeOfPost(post) {
- return $(post).find('.intro span.trip').text()
- }
- _setupListeners() {
- $(document).on("new_post", function(e, post) {
- this._doItQ(post);
- }.bind(this))
- }
- }
- /**************
- * MAIN
- **************/
- //Only setup the tools if we are on a thread
- if (ActivePage.isThread()) {
- $(document).ready(function() {
- window.bakerTools = {};
- bakerTools.mainWindow = new BakerWindow();
- bakerTools.notableHighlighter = new NotableHighlighter();
- bakerTools.PreviousBreadHighlighter = new PreviousBreadHighlighter();
- bakerTools.qPostHighlighter = new QPostHighlighter();
- bakerTools.statsOverlay = new StatsOverlay();
- }.bind(this));
- }
- })(window.jQuery);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement