Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- ==8Kun Baker Tools v0.5.2==
- ==Features:==
- '''Notables'''
- * Highlight posts that are marked notable (I.E. someone has replied and said
- notable) in Yellow
- * Highlight nominating posts in Pink
- * Highlight nominating posts in posts mentions in Green
- * Filter to only nominating and notable posts, Q posts, Q replies
- * Generate notables post
- * Adds "Notable Nomination" button to posts that opens the
- Quick Reply box and prefills it with a BAKER NOTABLE Template
- * Easy access to Breads
- '''Q Posts'''
- * 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
- * Cycle through 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
- * Option to blur images until hover
- * Cycle through (You)'s
- * Cycle through own posts
- ==To Install:==
- 1. Copy this source code
- 2. Go to 8kun
- 3. Click "Options" in the top right
- 4. Choose "User JS" tab
- 5. Paste Baker tools JS
- 6. WWG1WGA
- ==Changelog:==
- '''0.5.0'''
- * Option to show Q/(YOU)/Own Post navigation controls in the boardlist
- * Option to hide Notable nomination button
- * List of research breads
- * BakerTools settings are now saved in local storage
- '''0.4.0'''
- * Option to blur images until hover
- * Adds a "Notable Nomination" button to posts that opens the Quick Reply
- box and prefills it with a BAKER NOTABLE Template
- * Add Q Post navigation links to the Baker Window
- * Add (You) navigation links to the Baker Window
- * Add own post navigation links to the Baker Window
- * Cleaned up baker window design
- * More code cleanup and linting changes
- '''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
- * Refactored code into classes for easier maint.
- '''0.2.0'''
- * 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
- '''0.1.0'''
- Initial release:
- * Highlight notables and nominators
- * Filter to only show notables and nominators
- * Create notables post
- Version History:
- https://pastebin.com/nEhm7yyY 0.5.1
- https://pastebin.com/i9sF0Rd3 0.4.0
- https://pastebin.com/kz9LrcE9 0.3.0
- https://pastebin.com/4aEFsPwK 0.2.0
- https://pastebin.com/eNmTtzdi 0.1.0
- TODO: Nope button
- TODO: false positive notables and nominations
- TODO: Get notable description of pb notables
- TODO: Create Dough?
- TODO: Flood detect
- */
- (function($) {
- "use strict";
- /**
- * Wrapper for 8kun active_page variable to determine the type of
- * page the user is on.
- */
- class ActivePage {
- /**
- * Are we currently on the thread index page?
- * @return {boolean} True if on index
- */
- static isIndex() {
- return window.active_page == ActivePage.Index;
- }
- /**
- * Are we currently on the thread catalog page?
- * @return {boolean} True if on catalog
- */
- static isCatalog() {
- return window.active_page == ActivePage.Catalog;
- }
- /**
- * Are we on a thread page?
- * @return {boolean} True if on thread
- */
- static isThread() {
- console.log(window.active_page == ActivePage.Thread);
- return window.active_page == ActivePage.Thread;
- }
- }
- ActivePage.Index = 'index';
- ActivePage.Catalog = 'catalog';
- ActivePage.Thread = 'thread';
- /* global $ */
- /**
- * Creates first, prev, next, last navigation controls
- */
- class NavigationControl {
- /**
- * Construct navigatio control manager object
- *
- * @param {string} label the label for the control
- * @param {Function} updateFunction Called to get latest data
- * @param {string} updateEventName Called to get latest data
- */
- constructor(label, updateFunction, updateEventName) {
- const strippedName = label.replace(/(\s|\(|\)|'|"|:)/g, '');
- this.label = label;
- this.list = updateFunction();
- $(document).on(updateEventName, () => this.list = updateFunction());
- this.currentIndex = -1;
- this.navigationClass = `bakertools-navcontrol-${strippedName}`;
- this.indexChangeEvent =
- `bakertools-navcontrol-${strippedName}-index-changed`;
- this.currentIndexClass = `${this.navigationClass}-current-index`;
- this.totalClass = `${this.navigationClass}-total`;
- this.goToFirstClass = `${this.navigationClass}-goto-first`;
- this.goToPreviousClass = `${this.navigationClass}-goto-prev`;
- this.goToNextClass = `${this.navigationClass}-goto-next`;
- this.goToLastClass = `${this.navigationClass}-goto-last`;
- this._setupStyles();
- this._createElement();
- this._setupListeners();
- }
- /**
- * setup styles for nav control
- */
- _setupStyles() {
- const sheet = window.document.styleSheets[0];
- sheet.insertRule(`.boardlist
- .${NavigationControl.containerClass}:before {
- content: '[';
- color: #89A;
- }`, sheet.cssRules.length);
- sheet.insertRule(`.boardlist .${NavigationControl.containerClass}:after {
- content: ']';
- color: #89A;
- }`, sheet.cssRules.length);
- sheet.insertRule(`.boardlist .${NavigationControl.containerClass} {
- color: rgb(52, 52, 92);
- }`, sheet.cssRules.length);
- }
- /**
- * Create nav element
- */
- _createElement() {
- this.element = $(`
- <span title="Navigate ${this.label}"
- class="${NavigationControl.containerClass}">
- <label for="${this.navigationClass}">${this.label}:</label>
- <span class="${this.navigationClass}
- ${NavigationControl.navigationControlClass}">
- <i class="fa fa-fast-backward ${this.goToFirstClass}"></i>
- <i class="fa fa-backward ${this.goToPreviousClass}"></i>
- <span class="${this.currentIndexClass}">
- ${this.currentIndex+1}
- </span>
- of
- <span class="${this.totalClass}">${this.list.length}</span>
- <i class="fa fa-forward ${this.goToNextClass}"></i>
- <i class="fa fa-fast-forward ${this.goToLastClass}"></i>
- </span>
- </span>
- `).get(0);
- }
- /**
- * Setup button event listeners
- */
- _setupListeners() {
- $(this.element).find('.'+this.goToFirstClass).click(function(e) {
- this.goToFirstPost();
- }.bind(this));
- $(this.element).find('.'+this.goToPreviousClass).click(function(e) {
- this.goToPreviousPost();
- }.bind(this));
- $(this.element).find('.'+this.goToNextClass).click(function(e) {
- this.goToNextPost();
- }.bind(this));
- $(this.element).find('.'+this.goToLastClass).click(function(e) {
- this.goToLastPost();
- }.bind(this));
- $(document).on(this.indexChangeEvent, function(e, index) {
- if (this.currentIndex == index) return;
- this.currentIndex = index;
- this._setCurrentIndexControlValue(this.currentIndex + 1);
- }.bind(this));
- }
- /**
- * Scroll to first post
- */
- goToFirstPost() {
- console.info(`Go to first ${this.label} post`);
- if (!this.list.length) {
- return;
- }
- this.currentIndex = 0;
- this.scrollToCurrentPost();
- }
- /**
- * Scroll to next navigated post
- */
- goToPreviousPost() {
- console.info(`Go to prev ${this.label} post`);
- if (!this.list.length) {
- return;
- }
- if (this.currentIndex <= 0) {
- this.currentIndex = this.list.length - 1;
- } else {
- this.currentIndex--;
- }
- this.scrollToCurrentPost();
- }
- /**
- * Scroll to next navigated post
- */
- goToNextPost() {
- console.info(`Go to next ${this.label} post`);
- if (!this.list.length) {
- return;
- }
- const lastPostIndex = this.list.length - 1;
- if (this.currentIndex >= lastPostIndex) {
- this.currentIndex = 0;
- } else {
- this.currentIndex++;
- }
- this.scrollToCurrentPost();
- }
- /**
- * Scroll the last post in this bread into view
- */
- goToLastPost() {
- console.info(`Go to last ${this.label} post`);
- if (!this.list.length) {
- return;
- }
- const numPosts = this.list.length;
- this.currentIndex = numPosts - 1;
- this.scrollToCurrentPost();
- }
- /**
- * Scrolls the current selected post into view
- */
- scrollToCurrentPost() {
- const post = this.list[this.currentIndex];
- $(post).get(0).scrollIntoView();
- // Trigger events for other views of this data
- $(document).trigger(this.navigationClass + '-index-updated',
- this.currentIndex);
- // Update our local control
- this._setCurrentIndexControlValue(this.currentIndex + 1);
- window.scrollBy(0, -20);
- }
- /**
- * Sets the value of the current index in the UI
- * @param {number} val
- */
- _setCurrentIndexControlValue(val) {
- $('.'+this.currentIndexClass).text(this.currentIndex+1);
- }
- }
- NavigationControl.containerClass = `bakertools-navcontrol-container`;
- NavigationControl.navigationControlClass = 'bakertools-navigation-control';
- /* global ResearchBread, $, NotableHighlighter */
- /**
- * Wrapper for a post nominated as notable
- */
- class NotablePost {
- /**
- * Construct an empty notable post object
- */
- constructor() {
- this.element = null;
- this.postNumber = null;
- this.description = '[DESCRIPTION]';
- this.nominatingPosts = [];
- }
- /**
- * Create a notable post from a nominating post
- *
- * @param {Element} nominatingPost A post that is nominating a notable
- * @return {NotablePost} a Notable post or NullNotablePost if it fails
- */
- static fromNominatingPost(nominatingPost) {
- const [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;
- }
- let notable = NotablePost.findNotableByPostNumber(postNumber);
- if (!notable) {
- notable = new NotablePost();
- const isPreviousBread = element == null;
- if (!isPreviousBread) {
- notable.setElement(element);
- } else {
- // TODO: set pb description
- // get the json from the post number
- notable.postNumber = postNumber;
- }
- NotablePost._notables.push(notable);
- }
- notable.addNominatingPost(nominatingPost);
- return notable;
- }
- /**
- * Get the post number and the {Element} of a notable post from a
- * nominating post
- *
- * @param {Element} nominatingPost a .div.post that nominates a notable
- * @return {Array} Returns a list with the postNumber and the post element
- */
- static _getNotableFromNominator(nominatingPost) {
- const postNumber = ResearchBread.getFirstReplyLink(nominatingPost);
- const nominatedPost = document.querySelector('#reply_' + postNumber);
- return [postNumber, nominatedPost];
- }
- /**
- * Is this a NullNotablePost
- * @return {boolean} false
- */
- isNull() {
- return false;
- }
- /**
- * @return {Array<NotablePost>} Array of the current notables
- */
- static getNotables() {
- return NotablePost._notables;
- }
- /**
- * @arg {number} postNumber The post number of notable
- * @return {NotablePost}
- */
- static findNotableByPostNumber(postNumber) {
- return NotablePost._notables.find((notable) => notable.postNumber ==
- postNumber);
- }
- /**
- * Set the element of the post
- * @arg {Element} element
- */
- 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()
- .replace('No.', '');
- console.debug(this.postNumber);
- }
- /**
- * Get the reply shortlink for the post
- * @return {string}
- */
- shortLink() {
- return '>>' + this.postNumber;
- }
- /**
- * Add a nominator to the notable
- *
- * @param {Element} nominatingPost A .div.post that nominates this post
- */
- addNominatingPost(nominatingPost) {
- this.nominatingPosts.push(nominatingPost);
- this._markAsNominator(nominatingPost);
- this._markNominatorInMentions(nominatingPost);
- }
- /**
- * @arg {Element} nominatorPost .post
- */
- _markAsNominator(nominatorPost) {
- console.info(`Mark as nominator: ${nominatorPost}`);
- nominatorPost.classList.add(NotableHighlighter.NOMINATOR_CLASS);
- }
- /**
- * @arg {Element} post .post
- */
- _markAsNotable(post) {
- console.info(`Mark as notable: ${post}`);
- post.classList.add(NotableHighlighter.NOTABLE_CLASS);
- }
- /**
- * Gives links to nominators a special style in notable mentions
- *
- * @param {Element} nominatingPost A .div.post that is nominating this
- * notable
- */
- _markNominatorInMentions(nominatingPost) {
- const 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;
- }
- const nominatingPostId = nominatingPost.id.replace('reply_', '');
- $(this.element).find('.mentioned-'+nominatingPostId)
- .addClass(NotableHighlighter.NOMINATOR_CLASS);
- }
- }
- NotablePost._notables = [];
- NotablePost.NULL = null; // NullNotablePost
- /**
- * A null post that is returned when the post cant be found
- */
- class NullNotablePost extends NotablePost {
- /**
- * Returns true because this is a null post
- * @return {boolean} true
- */
- isNull() {
- return true;
- }
- }
- /**
- * Research Bread Class
- */
- class ResearchBread {
- /**
- * Get an array of post bodies with dough posts filtered out
- * @return {NodeList} of .post elements
- */
- static getPostsWithoutDough() {
- const posts = Array.from(document
- .querySelectorAll(ResearchBread.POST_SELECTOR));
- const filteredPosts = posts.filter(function(post) {
- return !post.querySelector('.body')
- .innerText.match(ResearchBread.DOUGH_POSTS_REGEX);
- });
- return filteredPosts;
- }
- /**
- * Determine what the bread number is
- * @return {number} the number of the research bread
- */
- static getBreadNumber() {
- const breadNumberRegex = /#(.+?) /;
- return document.querySelector(ResearchBread.OP_SUBJECT_SELECTOR)
- .innerText
- .match(breadNumberRegex)[1] || 'COULD NOT FIND BREAD NUMBER';
- }
- /**
- * @arg {Element} post .post
- * @return {RegexMatch} Capture 1 is the number
- */
- static getFirstReplyLink(post) {
- const match = post.querySelector('.body')
- .innerHTML
- .match(ResearchBread.REPLY_REGEX);
- return match && match[1] || null;
- }
- }
- ResearchBread.NEW_POST_EVENT = 'new_post';
- ResearchBread.OP_SUBJECT_SELECTOR = '.post.op > p > label > span.subject';
- ResearchBread.POST_BODY_SELECTOR = '.post > .body';
- ResearchBread.POST_SELECTOR = '.post';
- ResearchBread.REPLY_REGEX = /highlightReply\('(.+?)'/;
- ResearchBread.DOUGH_POSTS_REGEX = new RegExp(
- `^(Welcome To Q Research General|` +
- `Global Announcements|` +
- `War Room` +
- `|QPosts Archives).*`);
- /* globals $ */
- /* exported WindowElement */
- /**
- * Class for windows
- */
- class WindowElement {
- /**
- * Construct WindowElement
- * @param {string} windowName
- * @param {string} linkText
- */
- constructor(windowName, linkText) {
- this.styleId = 'bakertools-WindowElement-basestyles';
- this.id = `bakertools-${windowName}-window`;
- this.linkText = linkText;
- this.class = 'bakertools-WindowElement';
- this.headerClass = 'bakertools-WindowElement-header';
- this.windowCloseId = `bakertools-${windowName}-WindowElement-close`;
- this.windowCloseClass = `bakertools-WindowElement-close`;
- this.element = null;
- this._createWindowStyles();
- this._createElement();
- this._setupWindowLink();
- }
- /**
- * Create the window element
- */
- _createElement() {
- this.element = document.createElement('div');
- this.element.id = this.id;
- $(this.element).addClass(this.class);
- this.element.innerHTML = `
- <header class="${this.headerClass}">
- <h3>${this.linkText}</h3>
- <a id="${this.windowCloseId}" class='${this.windowCloseClass}'
- href="javascript:void(0)">
- <i class="fa fa-times"></i>
- </a>
- </header>
- `;
- document.body.appendChild(this.element);
- $(this.element).draggable();
- $(this.element).hide();
- $('#'+this.windowCloseId).click(function(e) {
- this.hide();
- }.bind(this));
- }
- /**
- * Create CSS styles needed by the window
- */
- _createWindowStyles() {
- if ($('#' + this.styleId).length) {
- return;
- }
- $('head').append(`
- <style id='${this.styleId}'>
- .${this.class} {
- width: 300px;
- background-color: rgb(214, 218, 240);
- position: fixed;
- z-index: 100;
- float: right;
- right:28.25px;
- border: 1px solid;
- }
- .${this.class} .${this.headerClass} {
- background: #98E;
- border: solid 1px;
- text-align: center;
- margin: 0px;
- }
- .${this.class} .${this.headerClass} h3 {
- margin: 0;
- }
- .${this.class} .${this.windowCloseClass} {
- top: 0px;
- right: 0px;
- position: absolute;
- margin-right: 3px;
- font-size: 20px;
- }
- .${this.class} details {
- padding: 5px;
- }
- .${this.class} summary {
- margin: 0 0 8px;
- font-weight: bold;
- border-bottom: solid 2px;
- }
- </style>
- `);
- }
- /**
- * Create link for show/hiding window, placed in boardlist bar
- */
- _setupWindowLink() {
- this.link = document.createElement('a');
- this.link.textContent = `[${this.linkText}]`;
- this.link.style.cssText = 'float: right;';
- this.link.title = this.linkText;
- this.link.href = 'javascript:void(0)';
- document.querySelector('.boardlist').appendChild(this.link);
- this.link.onclick = this.toggle.bind(this);
- }
- /**
- * Setup timeout for updating bread list
- */
- _setupListeners() {
- // window.setTimeout(this.updateBreadList, 1000)
- }
- /**
- * Show the window
- */
- show() {
- $(this.element).css({'top': 15});
- $(this.element).show();
- }
- /**
- * Hide the window
- */
- hide() {
- $(this.element).hide();
- }
- /**
- * Is the window visible?
- * @return {boolean} true if window is visible
- */
- isVisible() {
- return $(this.element).is(':visible');
- }
- /**
- * Toggle visibility of window
- */
- toggle() {
- if (this.isVisible()) {
- this.hide();
- } else {
- this.show();
- }
- }
- }
- /* exported BakerWindow */
- /* global NavigationControl, $, WindowElement */
- /**
- * Baker Window
- */
- class BakerWindow extends WindowElement {
- /**
- * Construct Baker window element, register listeners
- */
- constructor() {
- super('baker', 'Baker Tools');
- this.bakerWindowStyleId = 'bakertools-bakerwindow-style';
- this.bakerWindowOptionsId = 'bakertools-window-options';
- this.bakerWindowNavigationId = 'bakertools-window-navigation';
- this.bakerWindowBakerId = 'bakertools-window-baker';
- this.bakerWindowBodyId = 'bakertools-bakerwindow-body';
- this._createStyles();
- this._createBody();
- }
- /**
- * Create CSS styles needed by the window
- */
- _createStyles() {
- if ($('#' + this.bakerWindowStyleId).length) {
- return;
- }
- $('head').append(`
- <style id='${this.bakerWindowStyleId}'>
- #${this.id} #${this.bakerWindowNavigationId}
- .${NavigationControl.containerClass} {
- display: inline-block;
- width: 100%;
- }
- #${this.id} #${this.bakerWindowNavigationId}
- .${NavigationControl.navigationControlClass} {
- float: right;
- }
- </style>
- `);
- }
- /**
- * Create the actual window HTML element
- */
- _createBody() {
- $('#'+this.id).append(`
- <form id="${this.bakerWindowBodyId}">
- <details id='${this.bakerWindowOptionsId}' open>
- <summary>Options</summary>
- </details>
- <details id='${this.bakerWindowNavigationId}' open>
- <summary>Navigation</summary>
- </details>
- <details id='${this.bakerWindowBakerId}' open>
- <summary>Baker Tools</summary>
- </details>
- </form>
- `);
- }
- /**
- * Add form controls to options section of baker window
- * @arg {Element} htmlContentString form controls
- */
- addOption(htmlContentString) {
- $('#'+this.bakerWindowOptionsId).append(htmlContentString);
- }
- /**
- * Add html elements to the navigation section of the baker window
- * @arg {Element} htmlContentString form controls
- */
- addNavigation(htmlContentString) {
- $('#'+this.bakerWindowNavigationId).append(htmlContentString);
- }
- /**
- * Add html elements to the baker section of the baker window
- * @arg {Element} htmlContentString form controls
- */
- addBaker(htmlContentString) {
- $('#'+this.bakerWindowBakerId).append(htmlContentString);
- }
- } // end class BakerWindow
- /* global $ */
- /**
- * Blur images until highlighted
- */
- class BlurImages {
- /**
- * Construct blur images object and setup styles
- */
- constructor() {
- this.blurImages = 'bakertools-blur-images';
- this.blurImagesStyleId = 'bakertools-blur-images-style';
- window.bakerTools.mainWindow.addOption(`
- <label for="${this.blurImages}">Blur Images Until Hover</label>
- <input type="checkbox" id="${this.blurImages}"
- title="Blur images until mouse hover" /></br>
- `);
- $('#'+this.blurImages).change(function(e) {
- this.setBlurImages(e.target.checked);
- }.bind(this));
- this._readSettings();
- }
- /**
- * Read settings from localStorage
- */
- _readSettings() {
- this.setBlurImages(JSON.parse(
- localStorage.getItem(
- BlurImages.BLUR_IMAGES_SETTING),
- ));
- }
- /**
- * Set whether or not images are blurred
- * @param {boolean} blurImages if true, blur images
- */
- setBlurImages(blurImages) {
- $('#'+this.blurImages).prop('checked',
- blurImages);
- localStorage.setItem(BlurImages.BLUR_IMAGES_SETTING,
- blurImages);
- if (blurImages) {
- $(`<style id='${this.blurImagesStyleId}' type='text/css'>
- .post-image {
- filter: blur(5px);
- transition: all 233ms;
- }
- .post-image:hover {
- filter: blur(.5px);
- transition: all 89ms;
- }
- </style>`).appendTo('head');
- } else {
- $(`#${this.blurImagesStyleId}`).remove();
- }
- }
- }
- BlurImages.BLUR_IMAGES_SETTING = 'bakertools-blur-images';
- /* globals $, WindowElement */
- /* exported BreadList */
- /**
- * Creates a list of breads for navigation comfyness
- */
- class BreadList extends WindowElement {
- /**
- * Construct breadlist object
- */
- constructor() {
- super('breadlist', 'Bread List');
- $('#'+this.id).css('height', '400px');
- this.breadListWindowHeaderId = 'bakertools-breadlist-window-header';
- this.breadListWindowCloseId = 'bakertools-breadlist-window-close';
- this.breadListWindowBody = 'bakertools-breadlist-window-body';
- this.breadListTable = 'bakertools-breadlist-table';
- this.lastUpdatedId = 'bakertools-breadlist-lastupdated';
- this._breads = [];
- this.board = 'qresearch';
- this.breadRegex = /(.+)\s+#(\d+):\s+(.+?$)/;
- // /\(.+\) #\(\d+\): \(.+?$\)/;
- this.indexPage = `${window.location.protocol}//${window.location.host}` +
- `/${this.board}/`;
- this._createBody();
- this._setupStyles();
- this.updateBreadList();
- this._setupListeners();
- }
- /**
- * setup table styles
- */
- _setupStyles() {
- // https://stackoverflow.com/questions/21168521/table-fixed-header-and-scrollable-body
- $('head').append(`
- <style id='baketools-breadlist-window-styles'>
- #${this.id} {
- right: 380px;
- }
- #${this.breadListWindowBody} {
- overflow-y: auto;
- height: 365px;
- font-size: .8em;
- }
- #${this.breadListTable} {
- border-collapse: collapse;
- border-spacing: 0px;
- }
- #${this.breadListTable} thead th {
- position: sticky;
- top: 0;
- }
- #${this.breadListTable} th,
- #${this.breadListTable} td {
- border: 1px solid #000;
- border-top: 0;
- }
- #${this.breadListTable} thead th {
- box-shadow: 1px 1px 0 #000;
- }
- </style>
- `);
- }
- /**
- * Create the actual window HTML element
- */
- _createBody() {
- $('#'+this.id).append(`
- <div id='${this.breadListWindowBody}'>
- <table id='${this.breadListTable}'>
- <thead>
- <tr>
- <th>Group</th>
- <th>No.</th>
- <th>Bread</th>
- <th>replies</th>
- </tr>
- </thead>
- <tbody>
- </tbody>
- </table>
- </div>
- <footer>
- Last Updated: <span id="${this.lastUpdatedId}"></span>
- </footer>
- `);
- }
- /**
- * Setup timeout for updating bread list
- */
- _setupListeners() {
- window.setInterval(function(e) {
- this.updateBreadList();
- }.bind(this), 1000 * 60 * 2.5); // 2.5min update
- }
- /**
- * Get the list of breads
- */
- updateBreadList() {
- this.breads = [];
- const promises = [];
- for (let page = 0; page < 3; page++) {
- promises.push(
- $.getJSON(this.indexPage + `${page}.json`,
- this.parseIndex.bind(this)),
- );
- }
- Promise.all(promises).then(function() {
- this.breads.sort(function(a, b) {
- if (a.lastModified < b.lastModified) return -1;
- if (a.lastModified == b.lastModified) return 0;
- if (a.lastModified > b.lastModified) return 1;
- }).reverse();
- console.info(this.breads);
- this.populateBreadTable();
- }.bind(this));
- }
- /**
- * Parse index json for breads
- * @param {Object} index
- */
- parseIndex(index) {
- if (index && index.threads) {
- index.threads.forEach(function(thread) {
- const op = thread.posts[0];
- const match = op.sub.match(this.breadRegex);
- if (match) {
- const researchGroup = match[1];
- const breadNumber = match[2];
- const breadName = match[3];
- this.breads.push(new Bread(
- this.board,
- researchGroup,
- breadNumber,
- breadName,
- op.replies,
- op.no,
- op.last_modified,
- ));
- }
- }.bind(this)); // Index foreach
- } // if index and index.threads
- }
- /**
- * Populate the bread list table
- */
- populateBreadTable() {
- $('#'+this.breadListTable).empty();
- this.breads.forEach(function(bread) {
- this._addBread(bread);
- }.bind(this));
- const lastUpdated = new Date();
- $('#'+this.lastUpdatedId).text(lastUpdated.toLocaleString());
- }
- /**
- * Add bread
- * @param {Bread} bread
- */
- _addBread(bread) {
- $('#'+this.breadListTable).append(`
- <tr>
- <td><a href='${bread.url}'>${bread.researchGroup}</a></td>
- <td><a href='${bread.url}'>${bread.researchNumber}</a></td>
- <td><a href='${bread.url}'>${bread.breadName}</a></td>
- <td><a href='${bread.url}'>${bread.replies}</a></td>
- </tr>
- `);
- }
- }
- /**
- * Represents a research bread
- */
- class Bread {
- /**
- * Construct a bread
- *
- * @param {string} boardName
- * @param {string} researchGroup
- * @param {number} researchNumber
- * @param {string} breadName
- * @param {number} replies
- * @param {number} postId
- * @param {number} lastModified
- */
- constructor(boardName, researchGroup, researchNumber, breadName,
- replies, postId, lastModified) {
- this.boardName = boardName;
- this.researchGroup = researchGroup;
- this.researchNumber = researchNumber;
- this.breadName = breadName;
- this.replies = replies;
- this.postId = postId;
- this.lastModified = lastModified;
- }
- /**
- * Get bread url
- *
- * @return {string} url to bread
- */
- get url() {
- return `${window.location.protocol}//${window.location.host}` +
- `/${this.boardName}/res/${this.postId}.html`;
- }
- }
- /* global $, ResearchBread */
- /**
- * Add notable button to posts that opens quick reply
- * and populates with a template message
- */
- class NominatePostButtons {
- /**
- * Construct NPB object and setup listeners
- */
- constructor() {
- this.nominateButtonClass = 'bakertools-nominate-button';
- this.hidePostNotableButtonCheckboxId = 'bakertools-hide-notables';
- this.bakerNotableHeader = '==BAKER NOTABLE==\n';
- this.notableReasonPlaceholder = '[REASON FOR NOTABLE HERE]';
- $('div.post.reply').each(function(i, post) {
- this._addButtonToPost(post);
- }.bind(this));
- this._setupBakerWindowControls();
- this._setupListeners();
- this._readSettings();
- }
- /**
- * Read settings from localStorage
- */
- _readSettings() {
- this.showNotableNominationButton(JSON.parse(
- localStorage.getItem(
- NominatePostButtons.HIDE_NOMINATE_BUTTON_SETTING),
- ));
- }
- /**
- * Add options to baker window
- */
- _setupBakerWindowControls() {
- window.bakerTools.mainWindow.addOption(`
- <br />
- <label for="${this.hidePostNotableButtonCheckboxId}"
- title="Hide post 'Notable' buttons" >
- Hide "Notable" buttons
- </label>
- <input type="checkbox" id="${this.hidePostNotableButtonCheckboxId}"
- title="Hide post 'Notable' buttons" /><br />
- `);
- }
- /**
- * Setup event listeners
- */
- _setupListeners() {
- $(document).on(ResearchBread.NEW_POST_EVENT, function(e, post) {
- this._addButtonToPost(post);
- }.bind(this));
- $('#'+this.hidePostNotableButtonCheckboxId).change(function(e) {
- this.showNotableNominationButton(e.target.checked);
- }.bind(this));
- }
- /**
- * Show or hide the notable nomination buttons
- *
- * @param {boolean} showNotableNominationButton
- */
- showNotableNominationButton(showNotableNominationButton) {
- $('#'+this.hidePostNotableButtonCheckboxId).prop('checked',
- showNotableNominationButton);
- localStorage.setItem(NominatePostButtons.HIDE_NOMINATE_BUTTON_SETTING,
- showNotableNominationButton);
- const styleId = 'baker-tools-notable-button-style';
- if (showNotableNominationButton) {
- $('head').append(`
- <style id='${styleId}'>
- .${this.nominateButtonClass} {
- display: none;
- }
- `);
- } else {
- $(`#${styleId}`).remove();
- }
- }
- /**
- * Add button to the provided post
- * @param {Element} post
- */
- _addButtonToPost(post) {
- const button = document.createElement('button');
- $(button).addClass(this.nominateButtonClass);
- $(button).append(`
- <i class="fa fa-star" style="color: goldenrod;"></i>
- Notable`);
- $(button).click(function(e) {
- const postNumber = $(post)
- .find('.intro .post_no')
- .text()
- .replace('No.', '');
- const href = $(post)
- .find('.intro .post_no')
- .get(0).href;
- // 8kun core - adds >>postnumber to- and unhides quickreply
- window.citeReply(postNumber, href);
- const quickReplyBody = $('#quick-reply #body');
- const oldText = quickReplyBody.val();
- quickReplyBody.val(oldText + this.bakerNotableHeader +
- this.notableReasonPlaceholder);
- // Don't ask me why i have to do this, ask CodeMonkeyZ
- // Not sure why citeReply which calls cite needs to set a timeout to
- // replace the body of the quickreply with itself. We need to combat
- // that here
- // setTimeout(function() {
- // var tmp = $('#quick-reply textarea[name="body"]').val();
- // $('#quick-reply textarea[name="body"]').val('').focus().val(tmp);
- // }, 1);
- // $(window).on('cite', function(e, id, with_link) {
- // TODO: Figure this out
- const self = this;
- setTimeout(function() {
- quickReplyBody.select();
- quickReplyBody.prop('selectionStart',
- oldText.length + self.bakerNotableHeader.length);
- }, 1.2);
- }.bind(this));
- $(post).find('.post_modified').append(button);
- }
- }
- NominatePostButtons.HIDE_NOMINATE_BUTTON_SETTING =
- 'bakertools-hide-nominate-button';
- /* global $, ResearchBread, NotablePost */
- /**
- * Makes notable posts easier to see by highlighting posts that anons nominate
- * as notable.
- *
- * If someone replies to a post and their post contains the word 'notable',
- * the replied to post will be considered notable.
- *
- * Both the notable post and the nominator posts will be highlighted, as well
- * as the nominator link in the notable's mentions will be highlighted.
- */
- class NotableHighlighter {
- /**
- * Construct notablehighlighter object, find and highlight
- * current notable sand setup listeners
- */
- constructor() {
- this.NOMINATING_REGEX = /notable/i;
- this.showOnlyNotablesCheckboxId = 'bakertools-show-only-notable';
- this.createNotablePostButtonId = 'bakertools-create-notable-post';
- this.notableEditorId = 'bakertools-notable-editor';
- this._createStyles();
- this._setupBakerWindowControls();
- this.findNominatedNotables();
- this._setupListeners();
- this._readSettings();
- }
- /**
- * Read settings from local storage
- */
- _readSettings() {
- this.setOnlyShowNotables(JSON.parse(
- localStorage.getItem(
- NotableHighlighter.ONLY_SHOW_NOTABLES_SETTING),
- ));
- }
- /**
- * Create styles that determine how notables are highlighted
- */
- _createStyles() {
- const 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);
- }
- /**
- * Add controls to the bakerwindow
- */
- _setupBakerWindowControls() {
- const notablePostsTitle = `Only show, notables, nominators, q, q replied
- posts`;
- window.bakerTools.mainWindow.addOption(`
- <label for="${this.showOnlyNotablesCheckboxId}"
- title="${notablePostsTitle}" >
- Only Show Notable/Nomination Posts:
- </label>
- <input type="checkbox" id="${this.showOnlyNotablesCheckboxId}"
- title="${notablePostsTitle}" />
- `);
- window.bakerTools.mainWindow.addBaker(`
- <button type="button" id="${this.createNotablePostButtonId}"
- title="Create notables list post based on current nominated notables" >
- Create Notable Post
- </button>
- <textarea id="${this.notableEditorId}"></textarea>
- `);
- }
- /**
- * Setup listeners for new posts, bakerwindow controls, etc
- */
- _setupListeners() {
- $('#'+this.showOnlyNotablesCheckboxId).change(function(e) {
- this.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));
- $(document).on(ResearchBread.NEW_POST_EVENT, function(e, post) {
- this.checkNewPostsForNotables(post);
- }.bind(this));
- }
- /**
- * Create the notables post for review
- * @return {string} Returns the notable post string
- */
- createNotablesPost() {
- const notables = NotablePost.getNotables();
- const breadNumber = ResearchBread.getBreadNumber();
- let post = `'''#${breadNumber}'''\n\n`;
- notables.forEach(function(notable) {
- post += `${notable.shortLink()} ${notable.description}\n\n`;
- });
- return post;
- }
- /**
- * Checks a post for notable nominations
- * @param {Element} post
- */
- checkNewPostsForNotables(post) {
- $(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
- * @return {Array<NotablePost>}
- */
- findNominatedNotables() {
- const postsWithoutDough = ResearchBread.getPostsWithoutDough();
- // ^s to ignore notables review posts
- const nominatingPosts = postsWithoutDough
- .filter((post) => this.isNominatingPost(post));
- nominatingPosts.forEach(function(nominatingPost) {
- NotablePost.fromNominatingPost(nominatingPost);
- });
- console.log(NotablePost.getNotables());
- return NotablePost.getNotables();
- }
- /**
- * Is the post nominating a notable
- * @arg {Element} post .post
- * @return {boolean} True if post nominates a notable
- */
- isNominatingPost(post) {
- const postContainsNotable = post.textContent
- .search(this.NOMINATING_REGEX) != -1;
- const postIsReplying = post.querySelector('.body')
- .innerHTML
- .match(ResearchBread.REPLY_REGEX);
- return postContainsNotable && postIsReplying;
- }
- /**
- * Toggle whether only the notable/nominee posts are shown or not
- * @arg {boolean} onlyShowNotables boolean If true, only show
- * notables/nominators, else show all
- */
- setOnlyShowNotables(onlyShowNotables) {
- $('#'+this.showOnlyNotablesCheckboxId).prop('checked', onlyShowNotables);
- localStorage.setItem(NotableHighlighter.ONLY_SHOW_NOTABLES_SETTING,
- onlyShowNotables);
- const notableOrNominationPostsSelector =
- `div.post.${NotableHighlighter.NOTABLE_CLASS},
- div.post.${NotableHighlighter.NOMINATOR_CLASS}`;
- const notableOrNominationPostBreaksSelector =
- `div.post.${NotableHighlighter.NOTABLE_CLASS}+br,
- div.post.${NotableHighlighter.NOMINATOR_CLASS}+br`;
- const 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
- // TODO: can we remove this now that we have !important?
- $(ResearchBread.POST_SELECTOR).removeAttr('style');
- }
- }
- /**
- * Retrieves only show notable ssetting from localStorage
- * @return {boolean} true if only show notables is turned on
- */
- getOnlyShowNotables() {
- return localStorage
- .getItem(NotableHighlighter.ONLY_SHOW_NOTABLES_SETTING);
- }
- }
- NotableHighlighter.NOMINATOR_CLASS = 'bakertools-notable-nominator';
- NotableHighlighter.NOTABLE_CLASS = 'bakertools-notable';
- NotableHighlighter.ONLY_SHOW_NOTABLES_SETTING =
- 'bakertools-only-show-notables';
- /* global $ */
- /**
- * Highlights previous bread post links
- */
- class PreviousBreadHighlighter {
- /**
- * Construct pb highlighter object, setup listeners
- */
- constructor() {
- this.previousBreadClass = 'bakertools-PreviousBread';
- this._linkSelector = 'div.body > p.body-line.ltr > a';
- this._setupStyles();
- const links = $(this._linkSelector).filter('[onClick]');
- links.each(function(index, link) {
- this.markLinkIfPreviousBread(link);
- }.bind(this));
- this._setupListeners();
- }
- /**
- * Setup styles for pb links
- */
- _setupStyles() {
- const sheet = window.document.styleSheets[0];
- sheet.insertRule(`div.post.reply div.body
- a.${this.previousBreadClass} {
- color: #8B0000;
- }`, sheet.cssRules.length);
- sheet.insertRule(`a.${this.previousBreadClass}::after {
- content: " (pb)";
- }`, sheet.cssRules.length);
- }
- /**
- * Setup listeners for pb highlighting
- */
- _setupListeners() {
- $(document).on(ResearchBread.NEW_POST_EVENT, function(e, post) {
- $(post).find(this._linkSelector)
- .each((index, link) => this.markLinkIfPreviousBread(link));
- }.bind(this));
- }
- /**
- * Marks the link if it is pb
- *
- * @param {Anchor} link
- */
- markLinkIfPreviousBread(link) {
- const breadFileName = document.location.pathname.split('/').slice(-1)[0];
- const linkFileName = link.href.split('/').slice(-1)[0].split('#')[0];
- if ($(link).attr('onclick').search(ResearchBread.REPLY_REGEX) !=1 &&
- breadFileName != linkFileName) {
- $(link).addClass(this.previousBreadClass);
- }
- }
- }
- /* global $, ResearchBread, NavigationControl */
- /**
- * Highlight Q posts, replies to q, q replies.
- * Adds navigation to baker window
- */
- class QPostHighlighter {
- /**
- * Construct qposthighlighter object and setup listeners
- */
- constructor() {
- this.qPostClass = 'bakertools-q-post';
- this.qReplyClass = 'bakertools-q-reply';
- this.qMentionClass = 'bakertools-q-mention';
- this.qLinkClass = 'bakertools-q-link';
- this._linkSelector = 'div.body > p.body-line.ltr > a';
- this.currentQTripCode = null;
- this.showQNavigationInBoardListId =
- 'bakertools-show-q-nav-in-boardlist';
- this._setupStyles();
- this._getCurrentQTripFromBread();
- this._findQPosts();
- this._setupBakerWindowControls();
- this._setupListeners();
- this._readSettings();
- }
- /**
- * Read settings from localStorage
- */
- _readSettings() {
- this.showQNavigationInBoardList(JSON.parse(
- localStorage
- .getItem(QPostHighlighter.SHOW_Q_NAV_IN_BOARDLIST_SETTING),
- ));
- }
- /**
- * Setup styles for highlighting q posts
- */
- _setupStyles() {
- const sheet = window.document.styleSheets[0];
- // Dark to light
- sheet.insertRule(`div.post.reply.${this.qPostClass} {
- background: #FFFFFF !important;
- 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);
- }
- /**
- * Get Q's current trip code from the bread
- */
- _getCurrentQTripFromBread() {
- const 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];
- }
- /**
- * Find current Q posts in bread
- */
- _findQPosts() {
- const posts = ResearchBread.getPostsWithoutDough();
- $(posts).each(function(i, post) {
- this._doItQ(post);
- }.bind(this));
- }
- /**
- * Check if the post is Q
- * WWG1WGA
- *
- * @param {Element} post a div.post
- */
- _doItQ(post) {
- if (this._markIfQPost(post)) { // Q Post, lets check for q replies
- const qPostNumber = $(post)
- .find('.intro .post_no')
- .text()
- .replace('No.', '');
- const links = $(post)
- .find(this._linkSelector)
- .filter('[onClick]');
- $(links).each(function(i, link) {
- const postNumber = link.href.split('#')[1];
- // Enlightened post
- $(`#reply_${postNumber}`).addClass(this.qReplyClass);
- const metionLinkSelector = `#reply_${postNumber} .intro .mentioned a`;
- $(metionLinkSelector).each(function(i, mentionAnchor) {
- const 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
- const links = $(post).find(this._linkSelector).filter('[onClick]');
- $(links).each(function(i, link) {
- const postNumber = link.href.split('#')[1];
- const replyPost = document.querySelector(`#reply_${postNumber}`);
- if (this._isQ(replyPost)) {
- $(link).addClass(this.qLinkClass);
- }
- }.bind(this));
- }
- }
- /**
- * @arg {Element} post div.post.reply
- * @return {boolean} true if it is a q post
- */
- _markIfQPost(post) {
- let isQ = false;
- if (this._isQ(post)) {
- $(post).addClass(this.qPostClass);
- QPostHighlighter.qPosts.push(post);
- isQ = true;
- $(document).trigger(QPostHighlighter.NEW_Q_POST_EVENT);
- }
- return isQ;
- }
- /**
- * Is the post Q?
- * @param {Element} post a div.post.reply
- * @return {boolean} true if the post is Q
- */
- _isQ(post) {
- return this._getTripCodeOfPost(post) == this.currentQTripCode;
- }
- /**
- * Get the trip code of the provided post
- * @param {Element} post
- * @return {string} tripcode
- */
- _getTripCodeOfPost(post) {
- return $(post).find('.intro span.trip').text();
- }
- /**
- * Add Q post navigation to bakerwindow
- */
- _setupBakerWindowControls() {
- window.bakerTools.mainWindow
- .addOption(`
- <br /><br />
- <label for="${this.showQNavigationInBoardListId}"
- title="Show navigation controls in board list bar" >
- Show Q Nav in Board List:
- </label>
- <input type="checkbox" id="${this.showQNavigationInBoardListId}"
- title="Show navigation controls in board list bar" /><br />
- `);
- this.navigation = new NavigationControl('Q Posts',
- () => QPostHighlighter.qPosts, 'new_q_post');
- window.bakerTools.mainWindow
- .addNavigation(this.navigation.element);
- // Boardlist nav starts out hidden
- // TODO: read from config
- this.boardListNav = new NavigationControl('Q Posts',
- () => QPostHighlighter.qPosts, 'new_q_post');
- $('.boardlist:first').append(this.boardListNav.element);
- $(this.boardListNav.element).hide();
- }
- /**
- * Setup listeners for new posts
- */
- _setupListeners() {
- $(document).on(ResearchBread.NEW_POST_EVENT, function(e, post) {
- this._doItQ(post);
- }.bind(this));
- $('#'+this.showQNavigationInBoardListId).change(function(e) {
- this.showQNavigationInBoardList(e.target.checked);
- }.bind(this));
- }
- /**
- * Show or hide q nav control in the boardlist
- *
- * @param {boolean} showNavInBoardList
- */
- showQNavigationInBoardList(showNavInBoardList) {
- $('#'+this.showQNavigationInBoardListId).prop('checked',
- showNavInBoardList);
- localStorage.setItem(QPostHighlighter.SHOW_Q_NAV_IN_BOARDLIST_SETTING,
- showNavInBoardList);
- if (showNavInBoardList) {
- $(this.boardListNav.element).show();
- } else {
- $(this.boardListNav.element).hide();
- }
- }
- }
- QPostHighlighter.qPosts = [];
- QPostHighlighter.NEW_Q_POST_EVENT = 'bakertools-new-q-post';
- QPostHighlighter.SHOW_Q_NAV_IN_BOARDLIST_SETTING =
- 'bakertools-show-q-nav-in-boardlist';
- /* global $, ResearchBread, QPostHighlighter, NotablePost */
- /**
- * Overlays bread stats (and some other controls) in the bottom right of the
- * screen.
- * TODO: create add method
- */
- class StatsOverlay {
- /**
- * Construct statsoverlay, html element, setup listeners
- */
- constructor() {
- this.id = 'bakertools-stats-overlay';
- this.maxPosts = 750;
- this.postCountId = 'bakertools-stats-post-count';
- this.userCountId = 'bakertools-stats-uid-count';
- this.qCountId = 'bakertools-stats-q-count';
- this.notableCountId = 'bakertools-stats-notable-count';
- this._createStyles();
- this._createElement();
- this._updateStats();
- $(document).on(ResearchBread.NEW_POST_EVENT, function(e, post) {
- this._updateStats();
- }.bind(this));
- }
- /**
- * Create styles for stats overlay
- */
- _createStyles() {
- const sheet = window.document.styleSheets[0];
- sheet.insertRule(`#${this.id} {
- padding: 5px;
- position: fixed;
- z-index: 100;
- float: right;
- right:28.25px;
- bottom: 28.25px;
- }`, sheet.cssRules.length);
- }
- /**
- * Create actual html element for style overlay
- */
- _createElement() {
- this.element = document.createElement('div');
- this.element.id = this.id;
- this.element.innerHTML = `
- Posts: <span id="${this.postCountId}" ></span>
- UIDS: <span id="${this.userCountId}"></span>
- <a href="#bottom" alt="to-bottom">
- <i class="fa fa-angle-double-down"></i>
- </a>
- <a href="#top" alt="to-top"><i class="fa fa-angle-double-up"></i></a><br/>
- Q's: <span id="${this.qCountId}" ></span>
- Notables: <span id="${this.notableCountId}"></span>
- `;
- document.body.appendChild(this.element);
- }
- /**
- * Update the stats fields
- */
- _updateStats() {
- const postCount = $('#thread_stats_posts').text();
- const progress = postCount/this.maxPosts;
- let 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.qCountId).text(QPostHighlighter.qPosts.length);
- $('#'+this.notableCountId).text(NotablePost.getNotables().length);
- }
- } // End StatsOverlay class
- /* global $, NavigationControl, ResearchBread */
- /**
- * Highlight posts that (you)
- * Adds (You) navigation links to baker window
- */
- class YouHighlighter {
- /**
- * Construct YN object
- */
- constructor() {
- this.showYouNavigationInBoardListId =
- 'bakertools-show-you-nav-in-boardlist';
- this.showOwnNavigationInBoardListId =
- 'bakertools-show-own-nav-in-boardlist';
- this._setupBakerWindowControls();
- this._setupListeners();
- this._readSettings();
- }
- /**
- * Read settings from localStorage
- */
- _readSettings() {
- this.showYouNavigationInBoardList(JSON.parse(
- localStorage.getItem(
- YouHighlighter.SHOW_YOU_NAV_IN_BOARDLIST_SETTING),
- ));
- this.showOwnNavigationInBoardList(JSON.parse(
- localStorage.getItem(
- YouHighlighter.SHOW_OWN_NAV_IN_BOARDLIST_SETTING),
- ));
- }
- /**
- * Add (you) navigation to bakerwindow
- */
- _setupBakerWindowControls() {
- const youLabel = `(You)'s`;
- this.youNavigation = new NavigationControl(youLabel,
- this._getYous, ResearchBread.NEW_POST_EVENT);
- // Boardlist nav starts out hidden
- // TODO: read from config
- this.youBoardListNav = new NavigationControl(youLabel,
- this._getYous, ResearchBread.NEW_POST_EVENT);
- $('.boardlist:first').append(this.youBoardListNav.element);
- $(this.youBoardListNav.element).hide();
- window.bakerTools.mainWindow.addOption(`
- <label for="${this.showYouNavigationInBoardListId}"
- title="Show navigation controls in board list bar" >
- Show (You) Nav in Board List:
- </label>
- <input type="checkbox" id="${this.showYouNavigationInBoardListId}"
- title="Show navigation controls in board list bar" /><br />
- `);
- const ownLabel = `Own Posts`;
- this.ownNavigation = new NavigationControl(ownLabel,
- this._getOwnPosts, ResearchBread.NEW_POST_EVENT);
- // Boardlist nav starts out hidden
- // TODO: read from config
- this.ownBoardListNav = new NavigationControl(ownLabel,
- this._getOwnPosts, ResearchBread.NEW_POST_EVENT);
- $('.boardlist:first').append(this.ownBoardListNav.element);
- $(this.ownBoardListNav.element).hide();
- window.bakerTools.mainWindow.addOption(`
- <label for="${this.showOwnNavigationInBoardListId}"
- title="Show navigation controls in board list bar" >
- Show Own Post Nav in Board List:
- </label>
- <input type="checkbox" id="${this.showOwnNavigationInBoardListId}"
- title="Show navigation controls in board list bar" /><br />
- `);
- window.bakerTools.mainWindow.addNavigation(this.youNavigation.element);
- window.bakerTools.mainWindow.addNavigation(this.ownNavigation.element);
- }
- /**
- * Setup listeners for baker window controls
- */
- _setupListeners() {
- $('#'+this.showOwnNavigationInBoardListId).change(function(e) {
- this.showOwnNavigationInBoardList(e.target.checked);
- }.bind(this));
- $('#'+this.showYouNavigationInBoardListId).change(function(e) {
- this.showYouNavigationInBoardList(e.target.checked);
- }.bind(this));
- }
- /**
- * Show/hide you nav in boardlist
- *
- * @param {boolean} showYouNavInBoardList
- */
- showYouNavigationInBoardList(showYouNavInBoardList) {
- $('#'+this.showYouNavigationInBoardListId).prop('checked',
- showYouNavInBoardList);
- localStorage.setItem(YouHighlighter.SHOW_YOU_NAV_IN_BOARDLIST_SETTING,
- showYouNavInBoardList);
- if (showYouNavInBoardList) {
- $(this.youBoardListNav.element).show();
- } else {
- $(this.youBoardListNav.element).hide();
- }
- }
- /**
- * Show/hide own nav in boardlist
- *
- * @param {boolean} showOwnNavInBoardList
- */
- showOwnNavigationInBoardList(showOwnNavInBoardList) {
- $('#'+this.showOwnNavigationInBoardListId).prop('checked',
- showOwnNavInBoardList);
- localStorage.setItem(YouHighlighter.SHOW_OWN_NAV_IN_BOARDLIST_SETTING,
- showOwnNavInBoardList);
- if (showOwnNavInBoardList) {
- $(this.ownBoardListNav.element).show();
- } else {
- $(this.ownBoardListNav.element).hide();
- }
- }
- /**
- * Get (You)'s
- * @return {JQuery}
- */
- _getYous() {
- return $('div.post.reply').filter(function(idx, post) {
- return post.querySelector('.body')
- .innerHTML
- .indexOf('<small>(You)</small>') != -1;
- });
- }
- /**
- * Get own posts
- * @return {JQuery}
- */
- _getOwnPosts() {
- return $('div.post.you');
- }
- }
- YouHighlighter.SHOW_YOU_NAV_IN_BOARDLIST_SETTING =
- 'bakertools-show-you-nav-in-boardlist';
- YouHighlighter.SHOW_OWN_NAV_IN_BOARDLIST_SETTING =
- 'bakertools-show-own-nav-in-boardlist';
- /* global ActivePage, $, QPostHighlighter, YouHighlighter, StatsOverlay,
- NotableHighlighter, BakerWindow, BlurImages, PreviousBreadHighlighter,
- NominatePostButtons, BreadList */
- /**
- * MAIN
- */
- if (ActivePage.isThread()) { // Only setup the tools if we are on a thread
- $(document).ready(function() {
- window.bakerTools = {};
- window.bakerTools.mainWindow = new BakerWindow();
- new BlurImages();
- window.bakerTools.notableHighlighter = new NotableHighlighter();
- window.bakerTools.PreviousBreadHighlighter =
- new PreviousBreadHighlighter();
- window.bakerTools.qPostHighlighter = new QPostHighlighter();
- window.bakerTools.youHighlighter = new YouHighlighter();
- window.bakerTools.statsOverlay = new StatsOverlay();
- new NominatePostButtons();
- new BreadList();
- });
- }
- }(window.jQuery));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement