Advertisement
Guest User

SpookyX v24.6

a guest
Apr 8th, 2015
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // Displayable Name of your script
  3. // @name           SpookyX
  4.  
  5. // Brief description
  6. // @description    Enhances functionality of FoolFuuka boards. Devloped further for more comfortable ghost-posting on the moe archives.
  7.  
  8. // Your name, copyright  
  9. // @author          GNH
  10. // @copyright      2014, GNH
  11.  
  12. // Version Number
  13. // @version        24.6
  14.  
  15. // @include          https://*4plebs.org/*
  16. // @include          http://*4plebs.org/*
  17. // @include          https://archive.moe/*
  18. // @include          http://*loveisover.me/*
  19. // @include          https://*loveisover.me/*
  20. // @include          http://*imcute.yt/*
  21. // @include          https://*imcute.yt/*
  22. // @include          http://boards.foolz.us/*
  23. // @include          https://boards.foolz.us/*
  24. // @include          https://*nyafuu.org/*
  25. // @include          http://*nyafuu.org/*
  26. // @include          https://*fgts.jp/*
  27. // @include          http://*fgts.jp/*
  28. // @include          https://*not4plebs.org/*
  29. // @include          http://*not4plebs.org/*
  30.  
  31. // @grant       none
  32.  
  33. // ==/UserScript==
  34.  
  35. /* USER OPTIONS START */
  36. var imgSites = "puu.sh|i.imgur.com|i.4cdn.org|data.archive.moe|i0.kym-cdn.com|[\\S]*.deviantart.net|a.pomf.se|36.media.tumblr.com"; // Sites to embed images from
  37. var imgNumMaster = 1; // Max number of images to embed
  38. var autoplayVids = false; // Make embedded videos play automatically (they start muted, expanding unmutes)
  39. var hideQROptions = true; // Make the reply options hidden by default in the quick reply
  40. var favicon = {
  41.     "unlit": "http://i.imgur.com/xuadeJ2.png", // Choose which favicon is used normally. Default is "http://i.imgur.com/xuadeJ2.png"
  42.     "lit": 2, // Choose which favicon is used to indicate there are unread posts. Preset numbers are 0-4, replace with link to custom image if you desire such as: "http://i.imgur.com/XGsrewo.png"
  43.     "alert":"", // The favicon that indicates unread replies to your posts. Value is ignored if using a preset faviconLit
  44.     "alertOverlay":"http://i.imgur.com/6EfJyYA.png" // The favicon overlay that indicates unread replies. Default is "http://i.imgur.com/6EfJyYA.png"
  45. };
  46. var features = {
  47.     "postCounter":false,   // Add a post counter to the reply box
  48.     "inlineImages":true,   // Load full-size images in the thread, enable click to expand
  49.     "hidePosts":false,     // Allow user to hide posts manually
  50.     "newPosts":true,       // Reflect new posts in the tab name
  51.     "embedImages":true,    // Embed image links in thread
  52.     "embedGalleries":true, // Embed imgur galleries into a single post for ease of image dumps
  53.     "inlineReplies":true,  // Click replies to expand them inline
  54.     "postQuote":true,      // Clicking the post number will insert highlighted text into the reply box
  55.     "filter":false,          // Hide undesirable posts from view
  56.     "labelYourPosts":true, // Add '(You)' to your posts and links that point to them
  57.     "favicon":true,        // Switch to a dynamic favicon that indicates unread posts and unread replies
  58.     "imageHover":true,     // Hovering over images with the mouse brings a full or window scaled version in view
  59.     "videoHover":true      // Hovering over videos with the mouse brings a full or window scaled version in view
  60. };
  61. var filterCharThreshold = 100; // Filter posts with less than this number of characters
  62. var filteredStringsT0 = [    // List of Tier 0 strings to filter for. Capitalisation sensitive
  63.     //"[\\S]*(a{4,}|b{4,}|c{4,}|d{4,}|e{4,}|f{4,}|g{4,}|h{4,}|i{4,}|j{4,}|k{4,}|l{4,}|m{4,}|n{4,}|o{4,}|p{4,}|q{4,}|r{4,}|s{4,}|t{4,}|u{4,}|v{4,}|w{4,}|x{4,}|y{4,}|z{4,})[\\S]*",
  64.     "[\\S]*(e{4,}|E{4,}|i{4,}|I{4,}|o{4,}|O{4,}|u{4,}|U{4,})[\\S]*",
  65.     "E(G|g)(O|o)(-kun|kun)?"
  66. ];
  67. var filteredStringsT1 = [    // List of Tier 1 strings to filter for
  68.     "daki[\\S]*",
  69.     "ded",
  70.     "ayy lmao",
  71.     "incest",
  72.     "imoutos?",
  73.     "moonrunes",
  74.     "tale[\\S]*[^( of witches)]",
  75.     "ree+[\\S]*",
  76.     "boogeyman",
  77.     "normies"
  78. ];
  79. var filteredStringsT2 = [    // List of Tier 2 strings to filter for
  80.     "quest whe?n[?]*",
  81.     "test",
  82.     "tsukaima"
  83. ];
  84. var filteredTrips = [       // List of tripcodes to filter for
  85.     "!!/90sanF9F3Z"
  86. ];
  87. var filteredNames = [       // List of names to filter for
  88.     "久保島のミズゴロウ"
  89. ];
  90. /* USER OPTIONS END */
  91.  
  92. var newPostCount = 0;
  93. var DocumentTitle = document.title;
  94. var ignoreInline = ['v'];
  95. var rulesBox = $(".rules_box").html();
  96. if(autoplayVids){var autoplayVid = "autoplay";}else{var autoplayVid="";}
  97. var queuedYouLabels = [];
  98.  
  99. var pattThreadAndID = new RegExp("thread\/[0-9]+\/");
  100. var pattThreadID = new RegExp("[0-9]+");
  101. var threadID; // Returns undefined if there's no thread
  102. if (pattThreadAndID.exec(document.URL) !== null){
  103.     threadID = pattThreadID.exec(pattThreadAndID.exec(document.URL))[0];
  104. }
  105.  
  106. function ThreadUpdate(features) {
  107.     if (features.postCounter){postCounter();}  
  108.     if (features.inlineImages){inlineImages();}
  109.     if (features.hidePosts){hidePosts();}
  110.     if (features.newPosts){newPosts();}
  111.     if (features.embedImages){embedImages();}
  112.     if (features.inlineReplies){inlineReplies();}
  113.     if (features.postQuote){postQuote();}
  114.     if (features.filter){filter();}
  115. }
  116.  
  117. switch(favicon.lit) {
  118.     case 0: favicon.lit = "http://i.imgur.com/7iTgtjy.png"; favicon.alert = "http://i.imgur.com/QrkQSo0.png"; break;
  119.     case 1: favicon.lit = "http://i.imgur.com/AWVjxfw.png"; favicon.alert = "http://i.imgur.com/KXIPcD9.png"; break;
  120.     case 2: favicon.lit = "http://i.imgur.com/S7uBSPZ.png"; favicon.alert = "http://i.imgur.com/7IxJvBN.png"; break;
  121.     case 3: favicon.lit = "http://i.imgur.com/Rt8dEaq.png"; favicon.alert = "http://i.imgur.com/tvJjpqF.png"; break;
  122.     case 4: favicon.lit = "http://i.imgur.com/3bRaVUl.png"; favicon.alert = "http://i.imgur.com/5Bv27Co.png"; break;
  123.     default: break;
  124. }
  125.  
  126. $.fn.elemText = function() {
  127.     var text = '';
  128.     this.each(function() {
  129.         $(this).contents().each(function() {
  130.             if (this.nodeType == Node.TEXT_NODE)
  131.                 text += this.textContent;
  132.         });
  133.     });
  134.     return text;
  135. };
  136.  
  137. var escapeRegExp;
  138.  
  139. $.fn.isOnScreen = function(){
  140.     var win = $(window);
  141.     var viewport = {
  142.         top : win.scrollTop(),
  143.         left : win.scrollLeft()
  144.     };
  145.     viewport.right = viewport.left + win.width();
  146.     viewport.bottom = viewport.top + win.height() - 200;
  147.  
  148.     var bounds = this.offset();
  149.     bounds.right = bounds.left + this.outerWidth();
  150.     bounds.bottom = bounds.top + this.outerHeight();
  151.  
  152.     return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
  153. };
  154.  
  155. (function () {
  156.     // Referring to the table here:
  157.     // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/regexp
  158.     // these characters should be escaped
  159.     // \ ^ $ * + ? . ( ) | { } [ ]
  160.     // These characters only have special meaning inside of brackets
  161.     // they do not need to be escaped, but they MAY be escaped
  162.     // without any adverse effects (to the best of my knowledge and casual testing)
  163.     // : ! , =
  164.     // my test "~!@#$%^&*(){}[]`/=?+\|-_;:'\",<.>".match(/[\#]/g)
  165.  
  166.     var specials = [
  167.         // order matters for these
  168.         "-"
  169.         , "["
  170.         , "]"
  171.         // order doesn't matter for any of these
  172.         , "/"
  173.         , "{"
  174.         , "}"
  175.         , "("
  176.         , ")"
  177.         , "*"
  178.         , "+"
  179.         , "?"
  180.         , "."
  181.         , "\\"
  182.         , "^"
  183.         , "$"
  184.         , "|"
  185.     ]
  186.  
  187.     // I choose to escape every character with '\'
  188.     // even though only some strictly require it when inside of []
  189.     , regex = RegExp('[' + specials.join('\\') + ']', 'g')
  190.     ;
  191.     escapeRegExp = function (str) {
  192.         return str.replace(regex, "\\$&");
  193.     };
  194.  
  195.     // test escapeRegExp("/path/to/res?search=this.that")
  196. }());
  197.  
  198. shortcut = {
  199.     'all_shortcuts':{},//All the shortcuts are stored in this array
  200.     'add': function(shortcut_combination,callback,opt) {
  201.         //Provide a set of default options
  202.         var default_options = {
  203.             'type':'keydown',
  204.             'propagate':false,
  205.             'disable_in_input':false,
  206.             'target':document,
  207.             'keycode':false
  208.         };
  209.         if(!opt) opt = default_options;
  210.         else {
  211.             for(var dfo in default_options) {
  212.                 if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
  213.             }
  214.         }
  215.  
  216.         var ele = opt.target;
  217.         if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
  218.         var ths = this;
  219.         shortcut_combination = shortcut_combination.toLowerCase();
  220.  
  221.         //The function to be called at keypress
  222.         var func = function(e) {
  223.             e = e || window.event;
  224.  
  225.             if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
  226.                 var element;
  227.                 if(e.target) element=e.target;
  228.                 else if(e.srcElement) element=e.srcElement;
  229.                 if(element.nodeType==3) element=element.parentNode;
  230.  
  231.                 if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
  232.             }
  233.  
  234.             //Find Which key is pressed
  235.             if (e.keyCode) code = e.keyCode;
  236.             else if (e.which) code = e.which;
  237.             var character = String.fromCharCode(code).toLowerCase();
  238.  
  239.             if(code == 188) character=","; //If the user presses , when the type is onkeydown
  240.             if(code == 190) character="."; //If the user presses , when the type is onkeydown
  241.  
  242.             var keys = shortcut_combination.split("+");
  243.             //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
  244.             var kp = 0;
  245.  
  246.             //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
  247.             var shift_nums = {
  248.                 "`":"~",
  249.                 "1":"!",
  250.                 "2":"@",
  251.                 "3":"#",
  252.                 "4":"$",
  253.                 "5":"%",
  254.                 "6":"^",
  255.                 "7":"&",
  256.                 "8":"*",
  257.                 "9":"(",
  258.                 "0":")",
  259.                 "-":"_",
  260.                 "=":"+",
  261.                 ";":":",
  262.                 "'":"\"",
  263.                 ",":"<",
  264.                 ".":">",
  265.                 "/":"?",
  266.                 "\\":"|"
  267.             };
  268.             //Special Keys - and their codes
  269.             var special_keys = {
  270.                 'esc':27,
  271.                 'escape':27,
  272.                 'tab':9,
  273.                 'space':32,
  274.                 'return':13,
  275.                 'enter':13,
  276.                 'backspace':8,
  277.  
  278.                 'scrolllock':145,
  279.                 'scroll_lock':145,
  280.                 'scroll':145,
  281.                 'capslock':20,
  282.                 'caps_lock':20,
  283.                 'caps':20,
  284.                 'numlock':144,
  285.                 'num_lock':144,
  286.                 'num':144,
  287.  
  288.                 'pause':19,
  289.                 'break':19,
  290.  
  291.                 'insert':45,
  292.                 'home':36,
  293.                 'delete':46,
  294.                 'end':35,
  295.  
  296.                 'pageup':33,
  297.                 'page_up':33,
  298.                 'pu':33,
  299.  
  300.                 'pagedown':34,
  301.                 'page_down':34,
  302.                 'pd':34,
  303.  
  304.                 'left':37,
  305.                 'up':38,
  306.                 'right':39,
  307.                 'down':40,
  308.  
  309.                 'f1':112,
  310.                 'f2':113,
  311.                 'f3':114,
  312.                 'f4':115,
  313.                 'f5':116,
  314.                 'f6':117,
  315.                 'f7':118,
  316.                 'f8':119,
  317.                 'f9':120,
  318.                 'f10':121,
  319.                 'f11':122,
  320.                 'f12':123
  321.             };
  322.  
  323.             var modifiers = {
  324.                 shift: { wanted:false, pressed:false},
  325.                 ctrl : { wanted:false, pressed:false},
  326.                 alt  : { wanted:false, pressed:false},
  327.                 meta : { wanted:false, pressed:false} //Meta is Mac specific
  328.             };
  329.  
  330.             if(e.ctrlKey) modifiers.ctrl.pressed = true;
  331.             if(e.shiftKey)  modifiers.shift.pressed = true;
  332.             if(e.altKey)  modifiers.alt.pressed = true;
  333.             if(e.metaKey)   modifiers.meta.pressed = true;
  334.  
  335.             for(var i=0; k=keys[i],i<keys.length; i++) {
  336.                 //Modifiers
  337.                 if(k == 'ctrl' || k == 'control') {
  338.                     kp++;
  339.                     modifiers.ctrl.wanted = true;
  340.  
  341.                 } else if(k == 'shift') {
  342.                     kp++;
  343.                     modifiers.shift.wanted = true;
  344.  
  345.                 } else if(k == 'alt') {
  346.                     kp++;
  347.                     modifiers.alt.wanted = true;
  348.                 } else if(k == 'meta') {
  349.                     kp++;
  350.                     modifiers.meta.wanted = true;
  351.                 } else if(k.length > 1) { //If it is a special key
  352.                     if(special_keys[k] == code) kp++;
  353.  
  354.                 } else if(opt['keycode']) {
  355.                     if(opt['keycode'] == code) kp++;
  356.  
  357.                 } else { //The special keys did not match
  358.                     if(character == k) kp++;
  359.                     else {
  360.                         if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
  361.                             character = shift_nums[character];
  362.                             if(character == k) kp++;
  363.                         }
  364.                     }
  365.                 }
  366.             }
  367.  
  368.             if(kp == keys.length &&
  369.                modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
  370.                modifiers.shift.pressed == modifiers.shift.wanted &&
  371.                modifiers.alt.pressed == modifiers.alt.wanted &&
  372.                modifiers.meta.pressed == modifiers.meta.wanted) {
  373.                 callback(e);
  374.  
  375.                 if(!opt['propagate']) { //Stop the event
  376.                     //e.cancelBubble is supported by IE - this will kill the bubbling process.
  377.                     e.cancelBubble = true;
  378.                     e.returnValue = false;
  379.  
  380.                     //e.stopPropagation works in Firefox.
  381.                     if (e.stopPropagation) {
  382.                         e.stopPropagation();
  383.                         e.preventDefault();
  384.                     }
  385.                     return false;
  386.                 }
  387.             }
  388.         };
  389.         this.all_shortcuts[shortcut_combination] = {
  390.             'callback':func,
  391.             'target':ele,
  392.             'event': opt['type']
  393.         };
  394.         //Attach the function with the event
  395.         if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
  396.         else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
  397.         else ele['on'+opt['type']] = func;
  398.     },
  399.  
  400.     //Remove the shortcut - just specify the shortcut and I will remove the binding
  401.     'remove':function(shortcut_combination) {
  402.         shortcut_combination = shortcut_combination.toLowerCase();
  403.         var binding = this.all_shortcuts[shortcut_combination];
  404.         delete(this.all_shortcuts[shortcut_combination]);
  405.         if(!binding) return;
  406.         var type = binding['event'];
  407.         var ele = binding['target'];
  408.         var callback = binding['callback'];
  409.  
  410.         if(ele.detachEvent) ele.detachEvent('on'+type, callback);
  411.         else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
  412.         else ele['on'+type] = false;
  413.     }
  414. };
  415.  
  416. var getBoard = function() {
  417.     var URL = document.URL;
  418.     return URL.split("/")[3];
  419. };
  420.  
  421. var inlineImages = function()
  422. {
  423.     // I Believe because I'm setting the src of the thumbnail to the full image right away,
  424.     // it also causes the images to be prefetched
  425.     $('.thread_image_box').each(function(index,currentImage) {
  426.         if ($(currentImage).data("inline") != "true"){
  427.             //$(currentImage).find('a').each(function() {
  428.             $(currentImage).find('>a').each(function() {
  429.                 fullImage = $(this).attr('href');
  430.                 //    if (!fullImage.match(/thumb(-[23])?/)){
  431.                 //        if (!fullImage.match(/search(-[23])?/)){
  432.                 //            if (!fullImage.match(/redirect?/)){
  433.                 //                if (!fullImage.match(/download/)){
  434.                 if (fullImage.match(/\.webm$/)){ // Handle post webms
  435.                     $(currentImage).html('<video width="125" style="float:left" name="media" loop muted '+autoplayVid+'><source src="'+fullImage+'" type="video/webm"></video>');
  436.                 }else if (!fullImage.match(/(\.pdf|\.swf)$/)){
  437.                     $(currentImage).find('img').each(function()  {
  438.                         var thumbImage = $(this).attr('src');
  439.                         $(this).attr('src',fullImage);
  440.                         //$(this).error(function(){$(this).attr('src',thumbImage);});
  441.                         $(this).removeAttr('width');
  442.                         $(this).removeAttr('height');
  443.                         if ($(this).data("handled") != "true"){
  444.                             if ($(this).hasClass("thread_image")){ // Handle OP images
  445.                                 $(this).data("handled","true");
  446.                                 $(this).addClass("smallImageOP");
  447.                                 $(this).click(function(e){
  448.                                     if (!e.originalEvent.ctrlKey && e.which == 1){
  449.                                         e.preventDefault();
  450.                                         $($(this)["0"]["previousSibling"]).toggle(); // Toggle the Spoiler text
  451.                                         $(this).toggleClass("smallImageOP");
  452.                                         $(this).toggleClass("bigImage");
  453.                                         $('#hoverUI').html('');
  454.                                         $(this).trigger("mouseenter");
  455.                                     }
  456.                                 });
  457.                             }else{ // Handle post images
  458.                                 $(this).addClass("smallImage");
  459.                                 $(this).click(function(e){
  460.                                     if (!e.originalEvent.ctrlKey && e.which == 1){
  461.                                         e.preventDefault();
  462.                                         $($(this)["0"]["previousSibling"]).toggle(); // Toggle the Spoiler text
  463.                                         $(this).toggleClass("smallImage");
  464.                                         $(this).toggleClass("bigImage");
  465.                                         $('#hoverUI').html('');
  466.                                         $(this).trigger("mouseenter");
  467.                                     }
  468.                                 });
  469.                             }
  470.                         }
  471.                     });
  472.                 }
  473.                 //              }
  474.                 //          }    
  475.                 //      }
  476.                 //  }
  477.             });
  478.             if(features.imageHover){imageHover();}
  479.             $(currentImage).data("inline","true");
  480.         }
  481.     });
  482.  
  483.     $('video').each(function(index,currentVideo) {
  484.         if ($(currentVideo).data("inline") != "true"){
  485.             $(this).click(function(e){
  486.                 //e.preventDefault();
  487.                 if ($(this).hasClass("fullVideo")){
  488.                     this.pause();
  489.                     this.muted=true;
  490.                     $(this).attr('width',"125");
  491.                     $(this).removeAttr('controls');
  492.                     $(this).removeClass("fullVideo");
  493.                 }else{
  494.                     $(this).removeAttr('width');
  495.                     $(this).attr('controls',"");
  496.                     $(this).addClass("fullVideo");
  497.                     this.muted=false;
  498.                     this.play();
  499.                 }
  500.                 $('#hoverUI').html('');
  501.                 $(this).trigger("mouseenter");
  502.             });
  503.             $(currentVideo).data("inline","true");
  504.             if(features.videoHover){videoHover();}
  505.         }
  506.     });
  507. };
  508.  
  509. var inlineReplies = function(){
  510.     $('article.post').each(function(index,currentPost) {
  511.         if ($(currentPost).data("inline") != "true"){
  512.             $(this).addClass("base");
  513.         }
  514.         $(currentPost).data("inline","true");
  515.     });
  516.     $('.post_backlink > .backlink').each(function(index,currentPost) {
  517.         if ($(currentPost).data("inline") != "true"){
  518.             $(this).on("click", function(e){
  519.                 if (!e.originalEvent.ctrlKey && e.which == 1){
  520.                     e.preventDefault();
  521.                     //e.stopPropagation();
  522.                     var postID = $(this).attr("data-post");
  523.                     var rootPostID = $(e["target"].closest('article.base')).attr('id');
  524.                     if ($(e["target"]).hasClass("inlined")){
  525.                         $(e["target"]).removeClass("inlined");
  526.                         $('.sub'+rootPostID).each(function(index,currentPost){
  527.                             $("#"+currentPost.id.substr(1)+".forwarded").removeClass("forwarded");
  528.                         });
  529.                         $('#i'+postID+'.sub'+rootPostID).remove();
  530.                     }else{
  531.                         $(e["target"]).addClass("inlined");
  532.                         $(e["target"]["parentNode"]["parentNode"]).after('<div class="inline sub'+rootPostID+'" id="i'+postID+'"></div>');
  533.                         $("#"+postID).addClass("forwarded").clone().removeClass("forwarded base post").attr("id","r"+postID).appendTo($("#i"+postID+'.sub'+rootPostID));
  534.                         $("#"+rootPostID+'.base .inline').each(function(index,currentPost){
  535.                             if (!$(this).hasClass('sub'+rootPostID)){
  536.                                 $(this).attr("class","inline sub"+rootPostID);
  537.                             }
  538.                         });
  539.                         $("#i"+postID+" .post_wrapper").addClass("post_wrapperInline");
  540.                     }
  541.                 }
  542.             });
  543.             $(currentPost).data("inline","true");
  544.         }
  545.     });
  546.     $('.text .backlink').each(function(index,currentPost) {
  547.         if ($(currentPost).data("inline") != "true"){
  548.             $(this).on("click", function(e){
  549.                 if (!e.originalEvent.ctrlKey && e.which == 1){
  550.                     e.preventDefault();
  551.                     //e.stopPropagation();
  552.                     var postID = $(this).attr("data-post");
  553.                     var rootPostID = $(e["target"].closest('article.base')).attr('id');
  554.                     if ($(e["target"]).hasClass("inlined")){
  555.                         $(e["target"]).removeClass("inlined");
  556.                         $('.sub'+rootPostID).each(function(index,currentPost){
  557.                             $("#"+currentPost.id.substr(1)+".forwarded").removeClass("forwarded");
  558.                         });
  559.                         $('#i'+postID+'.sub'+rootPostID).remove();
  560.                     }else{
  561.                         $(e["target"]).addClass("inlined");
  562.                         $(e["target"]["parentNode"]).after('<div class="inline sub'+rootPostID+'" id="i'+postID+'"></div>');
  563.                         $("#"+postID).addClass("forwarded").clone().removeClass("forwarded base post").attr("id","r"+postID).appendTo($("#i"+postID+'.sub'+rootPostID));
  564.                         $("#"+rootPostID+'.base .inline').each(function(index,currentPost){
  565.                             if (!$(this).hasClass('sub'+rootPostID)){
  566.                                 $(this).attr("class","inline sub"+rootPostID);
  567.                             }
  568.                         });
  569.                         $("#i"+postID+" .post_wrapper").addClass("post_wrapperInline");
  570.                     }
  571.                 }
  572.             });
  573.             $(currentPost).data("inline","true");
  574.         }
  575.     });
  576. };
  577.  
  578. function getSelectionText() {
  579.     var text = "";
  580.     if (window.getSelection) {
  581.         text = window.getSelection().toString();
  582.     } else if (document.selection && document.selection.type != "Control") {
  583.         text = document.selection.createRange().text;
  584.     }
  585.     return text;
  586. }
  587.  
  588. var postQuote = function(){
  589.     $('.post_data > [data-function=quote]').each(function(index,currentPost) {
  590.         if ($(currentPost).data("quotable") != "true"){
  591.             $(this).removeAttr("data-function"); // Disable native quote function
  592.             $(this).on("click", function(e){
  593.                 if (!e.originalEvent.ctrlKey && e.which == 1){
  594.                     e.preventDefault();
  595.                     var postnum = $(this)["0"].innerHTML;
  596.                     var input = document.getElementById('reply_chennodiscursus');
  597.  
  598.                     if (input.selectionStart !== undefined)
  599.                     {
  600.                         var startPos = input.selectionStart;
  601.                         var endPos = input.selectionEnd;
  602.                         var startText = input.value.substring(0, startPos);
  603.                         var endText = input.value.substring(startPos);
  604.  
  605.                         var originalText = input.value;
  606.                         var selectedText = getSelectionText();
  607.                         var newText;
  608.                         if (selectedText === ""){
  609.                             newText = startText +">>"+postnum+"\n"+ endText;
  610.                         }else{
  611.                             newText = startText +">>"+postnum+"\n>"+ selectedText +"\n"+ endText;
  612.                         }
  613.                         document.getElementById('reply_chennodiscursus').value = originalText.replace(originalText,newText);
  614.                     }
  615.                 }
  616.             });
  617.             $(currentPost).data("quotable","true");
  618.         }
  619.     });
  620. };
  621.  
  622. var hidePosts = function(){
  623.     $('.pull-left').each(function(index, currentPost){
  624.         if ($(currentPost).hasClass('stub')) {
  625.             $(currentPost).removeClass('stub');
  626.         }
  627.     });
  628. };
  629.  
  630. var filter = function(){
  631.     var sieveStrT0 = new RegExp("\\b("+filteredStringsT0.join("|")+")\\b"); // \b or (^|\s) works
  632.     var sieveStrT1 = new RegExp("\\b("+filteredStringsT1.join("|")+")\\b","i"); // \b or (^|\s) works
  633.     var sieveStrT2 = new RegExp("(^|\\s)("+filteredStringsT2.join("|")+")($|\\s)","i");
  634.     var sieveTrip = new RegExp("("+filteredTrips.join("|")+")");
  635.     var sieveName = new RegExp("("+filteredNames.join("|")+")");
  636.  
  637.     $('article.post').each(function(index,currentPost){
  638.         if ($(currentPost).data("filtered") != "true"){
  639.             $(currentPost).data("filtered","true");
  640.             var postText = $(this).find('.text').elemText();
  641.             if (sieveTrip.test($(this).find('.post_tripcode').text()) || sieveName.test($(this).find('.post_author').text())){
  642.                 shitpostT2(currentPost, postText);
  643.             }else if(sieveStrT0.test(postText)){
  644.                 //console.log(postText.match(sieveStrT0));
  645.                 shitpostT0(currentPost, postText);
  646.             }else if (postText.length <= filterCharThreshold){
  647.                 if (sieveStrT1.test(postText)){
  648.                     //console.log(postText.match(sieveStrT1));
  649.                     shitpostT1(currentPost, postText);
  650.                 } else if (sieveStrT2.test(postText)){
  651.                     //console.log(postText.match(sieveStrT2));
  652.                     shitpostT2(currentPost, postText);
  653.                 }
  654.             }
  655.         }
  656.     });
  657. };
  658.  
  659. function shitpostT0(post, postText){
  660.     $(post).addClass("shitpost");
  661. }
  662. function shitpostT1(post, postText){
  663.     $(post).addClass("shitpost");
  664. }
  665. function shitpostT2(post, postText){
  666.     $(post).removeClass('stub');
  667.     $(post).find('.pull-left').removeClass('stub');
  668.     var docID = $(post).find('.pull-left > button').attr("data-doc-id");
  669.     $('.doc_id_'+docID).hide();
  670.     $('.stub_doc_id_'+docID).show();
  671. }
  672.  
  673. var embedImages = function() {
  674.     $('.posts article').each(function(index, currentArticle){
  675.         if ($(currentArticle).data('imgEmbed') != 'true'){
  676.             var patt = new RegExp("http[s]?://("+imgSites+")/[^\"]*");
  677.             var pattImgGal = new RegExp("http[s]?://imgur.com/[^\"]*");
  678.             var imgNum = imgNumMaster - $(currentArticle).find('.thread_image_box').length;
  679.             $(currentArticle).find(".text > a, .text > .spoiler, .text > strong").each(function(index, currentLink){
  680.                 if (imgNum === 0) {
  681.                     return false;
  682.                 }
  683.                 var imglink = patt.exec($(this).html());
  684.                 if (imglink !== null){
  685.                     imgNum--;
  686.                     // var patt2 = new RegExp(escapeRegExp(imglink["0"]), 'g'); Can't see what this does, uncomment if things break again
  687.                     imglink["0"] = imglink["0"].replace(/.gifv/g, ".webm"); // Only tested to work with Imgur
  688.                     var filename = '<div class="post_file embedded_post_file"><a href="'+imglink["0"]+'" class="post_file_filename" rel="tooltip" title="'+imglink["0"]+'">'+imglink["0"].match(/[^\/]*/g)[imglink["0"].match(/[^\/]*/g).length -2]+'</a></div>';
  689.                     var filestats = ""; //'<br><span class="post_file_metadata"> 937KiB, '+imglink["0"].naturalWidth+'x'+imglink["0"].naturalHeight+'</span>';
  690.                     if ((/.webm/g).test(imglink["0"])){
  691.                         $(currentArticle).find(".post_wrapper").prepend('<div class="thread_image_box"></div>');
  692.                         $(currentArticle).find(".thread_image_box:first-child").html(filename+'<video width="125" style="float:left" name="media" loop muted '+autoplayVid+'><source src="'+imglink["0"]+'" type="video/webm"></video>'+filestats);
  693.                     }else if ($(this).hasClass("spoiler")){
  694.                         $(currentArticle).find(".post_wrapper").prepend('<div class="thread_image_box">'+filename+'<a href="'+imglink["0"]+'" target="_blank" rel="noreferrer" class="thread_image_link"><div class="spoilerText">Spoiler</div><img src="'+imglink["0"]+'" class="lazyload post_image spoilerImage smallImage"></a>'+filestats+'</div>');
  695.                     }else{
  696.                         $(currentArticle).find(".post_wrapper").prepend('<div class="thread_image_box">'+filename+'<a href="'+imglink["0"]+'" target="_blank" rel="noreferrer" class="thread_image_link"><img src="'+imglink["0"]+'" class="lazyload post_image smallImage"></a>'+filestats+'</div>');
  697.                     }
  698.                     $(this).remove();
  699.                 } else if (features.embedGalleries && pattImgGal.exec($(this).html()) !== null){
  700.                     var link = pattImgGal.exec($(this).html());
  701.                     var individualImages = link[0].match(/[A-z0-9]{7}/g);
  702.                     $.each(individualImages, function(i,imgID){
  703.                         $(currentArticle).find(".post_wrapper").prepend('<div class="thread_image_box"><a href="https://i.imgur.com/'+imgID+'.jpg" target="_blank" rel="noreferrer" class="thread_image_link"><img src="https://i.imgur.com/'+imgID+'.jpg" class="lazyload post_image smallImage"></a></div>');
  704.                     });
  705.                 }
  706.             });
  707.             $(currentArticle).data('imgEmbed', 'true');
  708.         }
  709.     });
  710. };
  711.  
  712. function imageHover(){
  713.     $('img').off("mouseenter");
  714.     $('img').off("mousemove");
  715.     $('img').off("mouseout");
  716.     $('img').on("mouseenter", function(e){
  717.         if(!$(this).hasClass("bigImage")){
  718.             $(this).clone().removeClass("smallImage smallImageOP spoilerImage").addClass("hoverImage").appendTo('#hoverUI');
  719.             $('#hoverUI > img').css({
  720.                 "max-height":window.innerHeight,
  721.                 "max-width":window.innerWidth - e.clientX - 50,
  722.                 "top": function(){
  723.                     return (e.clientY / window.innerHeight)*(window.innerHeight - $('#hoverUI > img')[0].height);
  724.                 },
  725.                 "left":e.clientX + 50
  726.             });
  727.         }
  728.     });
  729.     $('img').on("mousemove", function(e){
  730.         if(!$(this).hasClass("bigImage")){
  731.             $('#hoverUI > img').css({
  732.                 "max-width":window.innerWidth - e.clientX - 50,
  733.                 "top": function(){
  734.                     return (e.clientY / window.innerHeight)*(window.innerHeight - $('#hoverUI > img')[0].height);
  735.                 },
  736.                 "left":e.clientX + 50
  737.             });
  738.         }
  739.     });
  740.     $('img').on("mouseout", function(e){
  741.         $('#hoverUI').html('');
  742.     });
  743. }
  744.  
  745. function videoHover(){
  746.     $('video').off("mouseenter");
  747.     $('video').off("mousemove");
  748.     $('video').off("mouseout");
  749.     $('video').on("mouseenter", function(e){
  750.         if(!$(this).hasClass("fullVideo")){
  751.             $(this).clone().addClass("fullVideo hoverImage").appendTo('#hoverUI');
  752.             $('#hoverUI > video').removeAttr('width');
  753.             $('#hoverUI > video')[0].oncanplay = function(){
  754.                 if ($('#hoverUI > video').length){ // Check if video still exists. This is to prevent the problem where mousing out too soon still triggers the canplay event
  755.                     $('#hoverUI > video')[0].muted=false;
  756.                     $('#hoverUI > video')[0].play();
  757.                     $('#hoverUI > video').css({
  758.                         "max-height":window.innerHeight,
  759.                         "max-width":window.innerWidth - e.clientX - 50,
  760.                         "top": function(){
  761.                             return (e.clientY / window.innerHeight)*(window.innerHeight - $('#hoverUI > video')[0].videoHeight);
  762.                         },
  763.                         "left":e.clientX + 50
  764.                     });
  765.                     $('video').on("mousemove", function(e){
  766.                         $('#hoverUI > video').css({
  767.                             "top": function(){
  768.                                 return (e.clientY / window.innerHeight)*(window.innerHeight - $('#hoverUI > video')[0].videoHeight);
  769.                             },
  770.                             "left":e.clientX + 50
  771.                         });
  772.                     });
  773.                 }
  774.             }
  775.         }
  776.     });
  777.     $('video').on("mouseout", function(e){
  778.         $('#hoverUI').html('');
  779.     });
  780. }
  781.  
  782. var lastSeenPost;
  783. var unseenPosts = [];
  784. var seenPosts = function(){
  785.     $('article.backlink_container').attr('id',"0"); // Prevent error when it's undefined
  786.     $('article').each(function(index, currentArticle){ // Add unseen posts to array
  787.         if (parseInt($(currentArticle).attr('id').replace(/_/g, "")) > lastSeenPost){
  788.             unseenPosts.push($(currentArticle).attr('id'));
  789.         }
  790.     });
  791.     $('article.backlink_container').removeAttr('id'); // Remove id again
  792.     $('#'+unseenPosts[0]).addClass("unseenPost");
  793. };
  794.  
  795. var unseenReplies = [];
  796. var newPosts = function(){
  797.     if (features.favicon){
  798.         //console.log("newPosts called");
  799.         if (windowFocus === true){
  800.             $.each(unseenPosts, function(i,postID){
  801.                 if ($('#'+postID).isOnScreen() === true){
  802.                     lastSeenPost = postID.replace(/_/g, ""); // Update last seen post
  803.                     $.each(unseenReplies, function(i, unseenID){
  804.                         if (unseenID == postID){
  805.                             unseenReplies.splice(i,1); // Remove seen posts from the unseen replies
  806.                             return;
  807.                         }
  808.                     });
  809.                 }
  810.             });
  811.             $.each(unseenPosts.filter(function(el){
  812.                 return el.replace(/_/g, "") <= lastSeenPost;
  813.             }),function(i,postID){
  814.                 $('#'+postID).removeClass("unseenPost"); // Remove unseen class from all posts with lower ID than the last seen one
  815.             });
  816.             unseenPosts = unseenPosts.filter(function(el){
  817.                 return el.replace(/_/g, "") > lastSeenPost; // Remove posts from list of unseen ones if their ID is lower than the last seen one
  818.             });
  819.             $('#'+unseenPosts[0]).addClass("unseenPost"); // Add the unseen class to the first of the unseen posts
  820.         }
  821.         newPostCount = unseenPosts.length;
  822.         if (unseenReplies.length){
  823.             $('#favicon').attr("href", favicon.alert);
  824.         }else if (newPostCount > 0){
  825.             $('#favicon').attr("href", favicon.lit);
  826.         }else{
  827.             $('#favicon').attr("href", favicon.unlit);
  828.         }
  829.     }else{ // Original newpost counter code
  830.         $('article').each(function(index, currentArticle){
  831.             if ($(currentArticle).data('seen') != 'true')
  832.             {
  833.                 $(currentArticle).data('seen', 'true')
  834.                 newPostCount +=1
  835.             }
  836.         });
  837.         if (windowFocus == true){newPostCount = 0;}
  838.     }
  839.     document.title = "(" + newPostCount + ") " + DocumentTitle;
  840. };
  841.  
  842. var postCounter = function() {$(".rules_box").html("<h6>Posts: " + $('.post_wrapper').length + "/400 <br> Images: " + $(".thread_image_box").length + "/250</h6>" + rulesBox);};
  843.  
  844. var bindShortcuts = function()
  845. {
  846.  
  847. };
  848.  
  849. var pokemon = ["bulbasaur","ivysaur","venusaur","charmander","charmeleon","charizard","squirtle","wartortle","blastoise","caterpie","metapod","butterfree","weedle","kakuna","beedrill","pidgey","pidgeotto","pidgeot","rattata","raticate","spearow","fearow","ekans","arbok","pikachu","raichu","sandshrew","sandslash","nidoran♀","nidorina","nidoqueen","nidoran♂","nidorino","nidoking","clefairy","clefable","vulpix","ninetales","jigglypuff","wigglytuff","zubat","golbat","oddish","gloom","vileplume","paras","parasect","venonat","venomoth","diglett","dugtrio","meowth","persian","psyduck","golduck","mankey","primeape","growlithe","arcanine","poliwag","poliwhirl","poliwrath","abra","kadabra","alakazam","machop","machoke","machamp","bellsprout","weepinbell","victreebel","tentacool","tentacruel","geodude","graveler","golem","ponyta","rapidash","slowpoke","slowbro","magnemite","magneton","farfetch'd","doduo","dodrio","seel","dewgong","grimer","muk","shellder","cloyster","gastly","haunter","gengar","onix","drowzee","hypno","krabby","kingler","voltorb","electrode","exeggcute","exeggutor","cubone","marowak","hitmonlee","hitmonchan","lickitung","koffing","weezing","rhyhorn","rhydon","chansey","tangela","kangaskhan","horsea","seadra","goldeen","seaking","staryu","starmie","mr. mime","scyther","jynx","electabuzz","magmar","pinsir","tauros","magikarp","gyarados","lapras","ditto","eevee","vaporeon","jolteon","flareon","porygon","omanyte","omastar","kabuto","kabutops","aerodactyl","snorlax","articuno","zapdos","moltres","dratini","dragonair","dragonite","mewtwo","mew","chikorita","bayleef","meganium","cyndaquil","quilava","typhlosion","totodile","croconaw","feraligatr","sentret","furret","hoothoot","noctowl","ledyba","ledian","spinarak","ariados","crobat","chinchou","lanturn","pichu","cleffa","igglybuff","togepi","togetic","natu","xatu","mareep","flaaffy","ampharos","bellossom","marill","azumarill","sudowoodo","politoed","hoppip","skiploom","jumpluff","aipom","sunkern","sunflora","yanma","wooper","quagsire","espeon","umbreon","murkrow","slowking","misdreavus","unown","wobbuffet","girafarig","pineco","forretress","dunsparce","gligar","steelix","snubbull","granbull","qwilfish","scizor","shuckle","heracross","sneasel","teddiursa","ursaring","slugma","magcargo","swinub","piloswine","corsola","remoraid","octillery","delibird","mantine","skarmory","houndour","houndoom","kingdra","phanpy","donphan","porygon2","stantler","smeargle","tyrogue","hitmontop","smoochum","elekid","magby","miltank","blissey","raikou","entei","suicune","larvitar","pupitar","tyranitar","lugia","ho-oh","celebi","treecko","grovyle","sceptile","torchic","combusken","blaziken","mudkip","marshtomp","swampert","poochyena","mightyena","zigzagoon","linoone","wurmple","silcoon","beautifly","cascoon","dustox","lotad","lombre","ludicolo","seedot","nuzleaf","shiftry","taillow","swellow","wingull","pelipper","ralts","kirlia","gardevoir","surskit","masquerain","shroomish","breloom","slakoth","vigoroth","slaking","nincada","ninjask","shedinja","whismur","loudred","exploud","makuhita","hariyama","azurill","nosepass","skitty","delcatty","sableye","mawile","aron","lairon","aggron","meditite","medicham","electrike","manectric","plusle","minun","volbeat","illumise","roselia","gulpin","swalot","carvanha","sharpedo","wailmer","wailord","numel","camerupt","torkoal","spoink","grumpig","spinda","trapinch","vibrava","flygon","cacnea","cacturne","swablu","altaria","zangoose","seviper","lunatone","solrock","barboach","whiscash","corphish","crawdaunt","baltoy","claydol","lileep","cradily","anorith","armaldo","feebas","milotic","castform","kecleon","shuppet","banette","duskull","dusclops","tropius","chimecho","absol","wynaut","snorunt","glalie","spheal","sealeo","walrein","clamperl","huntail","gorebyss","relicanth","luvdisc","bagon","shelgon","salamence","beldum","metang","metagross","regirock","regice","registeel","latias","latios","kyogre","groudon","rayquaza","jirachi","deoxys","turtwig","grotle","torterra","chimchar","monferno","infernape","piplup","prinplup","empoleon","starly","staravia","staraptor","bidoof","bibarel","kricketot","kricketune","shinx","luxio","luxray","budew","roserade","cranidos","rampardos","shieldon","bastiodon","burmy","wormadam","mothim","combee","vespiquen","pachirisu","buizel","floatzel","cherubi","cherrim","shellos","gastrodon","ambipom","drifloon","drifblim","buneary","lopunny","mismagius","honchkrow","glameow","purugly","chingling","stunky","skuntank","bronzor","bronzong","bonsly","mime jr.","happiny","chatot","spiritomb","gible","gabite","garchomp","munchlax","riolu","lucario","hippopotas","hippowdon","skorupi","drapion","croagunk","toxicroak","carnivine","finneon","lumineon","mantyke","snover","abomasnow","weavile","magnezone","lickilicky","rhyperior","tangrowth","electivire","magmortar","togekiss","yanmega","leafeon","glaceon","gliscor","mamoswine","porygon-z","gallade","probopass","dusknoir","froslass","rotom","uxie","mesprit","azelf","dialga","palkia","heatran","regigigas","giratina","cresselia","phione","manaphy","darkrai","shaymin","arceus","victini","snivy","servine","serperior","tepig","pignite","emboar","oshawott","dewott","samurott","patrat","watchog","lillipup","herdier","stoutland","purrloin","liepard","pansage","simisage","pansear","simisear","panpour","simipour","munna","musharna","pidove","tranquill","unfezant","blitzle","zebstrika","roggenrola","boldore","gigalith","woobat","swoobat","drilbur","excadrill","audino","timburr","gurdurr","conkeldurr","tympole","palpitoad","seismitoad","throh","sawk","sewaddle","swadloon","leavanny","venipede","whirlipede","scolipede","cottonee","whimsicott","petilil","lilligant","basculin","sandile","krokorok","krookodile","darumaka","darmanitan","maractus","dwebble","crustle","scraggy","scrafty","sigilyph","yamask","cofagrigus","tirtouga","carracosta","archen","archeops","trubbish","garbodor","zorua","zoroark","minccino","cinccino","gothita","gothorita","gothitelle","solosis","duosion","reuniclus","ducklett","swanna","vanillite","vanillish","vanilluxe","deerling","sawsbuck","emolga","karrablast","escavalier","foongus","amoonguss","frillish","jellicent","alomomola","joltik","galvantula","ferroseed","ferrothorn","klink","klang","klinklang","tynamo","eelektrik","eelektross","elgyem","beheeyem","litwick","lampent","chandelure","axew","fraxure","haxorus","cubchoo","beartic","cryogonal","shelmet","accelgor","stunfisk","mienfoo","mienshao","druddigon","golett","golurk","pawniard","bisharp","bouffalant","rufflet","braviary","vullaby","mandibuzz","heatmor","durant","deino","zweilous","hydreigon","larvesta","volcarona","cobalion","terrakion","virizion","tornadus","thundurus","reshiram","zekrom","landorus","kyurem","keldeo","meloetta","genesect","chespin","quilladin","chesnaught","fennekin","braixen","delphox","froakie","frogadier","greninja","bunnelby","diggersby","fletchling","fletchinder","talonflame","scatterbug","spewpa","vivillon","litleo","pyroar","flabébé","floette","florges","skiddo","gogoat","pancham","pangoro","furfrou","espurr","meowstic","honedge","doublade","aegislash","spritzee","aromatisse","swirlix","slurpuff","inkay","malamar","binacle","barbaracle","skrelp","dragalge","clauncher","clawitzer","helioptile","heliolisk","tyrunt","tyrantrum","amaura","aurorus","sylveon","hawlucha","dedenne","carbink","goomy","sliggoo","goodra","klefki","phantump","trevenant","pumpkaboo","gourgeist","bergmite","avalugg","noibat","noivern","xerneas","yveltal","zygarde","diancie","hoopa","volcanion"];
  850. function notifyMe(title, image, body){
  851.     //console.log("notifyMe called");
  852.     if (!Notification){
  853.         alert('Please us a modern version of Chrome, Firefox, Opera or Firefox.');
  854.         return;
  855.     }
  856.  
  857.     if (Notification.permission !== "granted")
  858.         Notification.requestPermission();
  859.     var icon = image;
  860.     var timeFade = true;
  861.     if(!Math.floor(Math.random()*8192)){
  862.         var ND = Math.floor(Math.random()*720);
  863.         icon = "http://img.pokemondb.net/sprites/black-white/shiny/"+pokemon[ND]+".png";
  864.         timeFade = false;
  865.     }
  866.  
  867.     var notification = new Notification(title, {
  868.         icon: icon,
  869.         body: body
  870.     });
  871.  
  872.     if (timeFade){
  873.         notification.onshow = function (){
  874.             setTimeout(notification.close.bind(notification), 5000);
  875.         };
  876.     }
  877.     notification.onclick = function (){
  878.         window.focus();
  879.     };
  880. }
  881.  
  882. if (features.labelYourPosts){
  883.     var yourPosts = localStorage.yourPosts;
  884.     if (yourPosts === undefined){
  885.         yourPosts = {};
  886.         console.log("Created post archive for the first time");
  887.     } else {
  888.         yourPosts = JSON.parse(localStorage.yourPosts);
  889.     }
  890. }
  891. if (features.favicon){
  892.     var lastSeenPosts = localStorage.lastSeenPosts;
  893.     if (lastSeenPosts === undefined){
  894.         lastSeenPosts = {};
  895.         console.log("Created unseen replies archive for the first time");
  896.     } else {
  897.         lastSeenPosts = JSON.parse(localStorage.lastSeenPosts);
  898.     }
  899.     lastSeenPost = lastSeenPosts[threadID];
  900. }
  901. window.addEventListener("beforeunload", function (e) { // After user leaves the page
  902.     if (features.labelYourPosts){ // Save the your posts object
  903.         if (localStorage.yourPosts === undefined){
  904.             localStorage.yourPosts = JSON.stringify(yourPosts);
  905.         } else {
  906.             localStorage.yourPosts = JSON.stringify($.extend(true, yourPosts, JSON.parse(localStorage.yourPosts)));
  907.         }
  908.     }
  909.     if (features.favicon){ // Save the last read posts object
  910.         lastSeenPosts[threadID] = lastSeenPost;
  911.         if (localStorage.lastSeenPosts === undefined){
  912.             localStorage.lastSeenPosts = JSON.stringify(lastSeenPosts);
  913.         } else {
  914.             latestLastSeenPosts = JSON.parse(localStorage.lastSeenPosts); // Get the most recent version of the stored object
  915.             if (latestLastSeenPosts[threadID] > lastSeenPosts[threadID]){
  916.                 localStorage.lastSeenPosts = JSON.stringify(latestLastSeenPosts); // Save it again
  917.             }else{
  918.                 localStorage.lastSeenPosts = JSON.stringify(lastSeenPosts); // Save it again
  919.             }
  920.         }
  921.     }
  922.     //var confirmationMessage = "\o/";
  923.  
  924.     //(e || window.event).returnValue = confirmationMessage; //Gecko + IE
  925.     //return confirmationMessage;                            //Webkit, Safari, Chrome
  926. });
  927.  
  928.  
  929. function labelYourPosts(firstcall){
  930.     $.each(queuedYouLabels, function(i, v){ // Parse all names on pageload and with each post submission
  931.         $('#'+v+' .post_author').after('<span> (You)</span>');
  932.     });
  933.     queuedYouLabels = [];
  934.  
  935.     if (firstcall){ // Parse all backlinks present on pageload
  936.         $.each(yourPosts[threadID], function(i,v){
  937.             $('.backlink[data-post='+v+']').each(function(){
  938.                 if ($(this).data('linkedYou') != 'true'){
  939.                     this.textContent += ' (You)';
  940.                     $(this).data('linkedYou','true');
  941.                 }
  942.             });
  943.         });
  944.     }
  945. }
  946.  
  947. function labelNewPosts(response){
  948.     var newPosts = Object.keys(response[threadID]["posts"]);
  949.     $.each(newPosts, function(i,postID){ // For each post returned by update
  950.         var notificationTriggered = false;
  951.         $('#'+postID+' .greentext > a').each(function(i, link){ // For each post content backlink
  952.             var linkID = $(link).attr('data-post');
  953.             if ($.inArray(linkID, yourPosts[threadID])+1){ // If the link points to your post
  954.                 if (!notificationTriggered){
  955.                     notifyMe($('#'+postID+' .post_poster_data').text().trim()+" replied to you","http://i.imgur.com/HTcKk4Y.png",$('#'+postID+' .text').text().trim());
  956.                     unseenReplies.push(postID); // add postID to list of unseen replies
  957.                     notificationTriggered = true;
  958.                 }
  959.                 link.textContent += ' (You)'; // Designate the link as such
  960.             }
  961.             if ($.inArray(postID, yourPosts[threadID])+1){ // If the post is your own
  962.                 var backlink = $('#'+linkID+' .post_backlink [data-post='+postID+']');
  963.                 if (backlink.data('linkedYou') != 'true'){
  964.                     backlink[0].textContent += ' (You)'; // Find your post's new reply backlink and designate it too
  965.                     backlink.data('linkedYou','true');
  966.                 }
  967.             }
  968.         });
  969.         unseenPosts.push(postID); // add postID to list of unseen posts
  970.     });
  971. }
  972.  
  973. var lastSubmittedContent;
  974. function postSubmitEvent(){
  975.     if ($('#reply [type=submit]').length){
  976.         window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  977.         var target =  $('#reply [type=submit]')["0"],
  978.             observer = new MutationObserver(function(mutation) {
  979.                 //console.log("Post Submit Event Triggered");
  980.                 lastSubmittedContent = $('#reply_chennodiscursus')[0].value;
  981.             }),
  982.             config = {
  983.                 attributes: true
  984.             };
  985.         observer.observe(target, config);
  986.     }
  987. }
  988.  
  989. $(document).ready(function(){
  990.     $('head').after('<script src="https://cdn.rawgit.com/madapaja/jquery.selection/master/src/jquery.selection.js"></script>'); // Pull in selection plugin (http://madapaja.github.io/jquery.selection/)
  991.     $('head').after('<style type="text/css" id="FoolX-css">.unseenPost{border-top: red solid 1px;}.hoverImage{position:fixed;float:none!important;}.bigImage{opacity: 1!important; max-width:100%;}.smallImage{max-width:125px; max-height:125px}.smallImageOP{max-width:250px; max-height:250px}.spoilerImage{opacity: 0.1}.spoilerText{position: relative; height: 0px; font-size: 19px; top: 47px;}.forwarded{display:none}.inline{border:1px solid; display: table; margin: 2px 0;}.inlined{opacity:0.5}.post_wrapper{border-right: 1px solid #cccccc;}.post_wrapperInline{border-right:0!important; border-bottom:0!important;}.quickReply{position: fixed; top: 0; right: 0; margin: 3px !important;}.shitpost{opacity: 0.3}.embedded_post_file{margin: 0!important; width: 125px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}</style>');
  992.     if (features.favicon){
  993.         $('head').append('<link id="favicon" rel="shortcut icon" type="image/png" href="'+favicon.unlit+'">');
  994.         $('#reply fieldset .progress').after('<canvas id="myCanvas" width="64" height="64" style="float:left; display:none; position: relative; top: -10px; left: -10px;"></canvas>');
  995.     }
  996.     $('body').append('<div id="hoverUI"></div>');
  997.  
  998.     windowFocus = true;
  999.     $(window).focus(function(){windowFocus = true; ThreadUpdate(features);});
  1000.     $(window).blur(function(){windowFocus = false;});
  1001.     if (hideQROptions){
  1002.         $('#reply').toggleClass("showQROptions"); // Make options hidden in QR by default
  1003.     }
  1004.     if (features.favicon){
  1005.         if (lastSeenPosts[threadID] === undefined){
  1006.             lastSeenPosts[threadID] = threadID;
  1007.         }
  1008.         lastSeenPost = lastSeenPosts[threadID];
  1009.     }
  1010.     if (features.labelYourPosts){
  1011.         if (yourPosts[threadID] === undefined){
  1012.             yourPosts[threadID] = [];
  1013.         } else {
  1014.             queuedYouLabels = yourPosts[threadID].slice(0);
  1015.             //console.log(queuedYouLabels);
  1016.         }
  1017.         //console.log(yourPosts);
  1018.         postSubmitEvent();
  1019.  
  1020.         $(document).ajaxComplete(function(event, request, settings) {
  1021.             //console.log(event);
  1022.             //console.log(request);
  1023.             //console.log(settings);
  1024.             if (request.responseText !== ""){
  1025.                 response = JSON.parse(request.responseText);
  1026.             }else{
  1027.                 response = {"error":"No responseText"};
  1028.             }
  1029.             //console.log(response);
  1030.             if (response.error !== undefined){
  1031.                 //console.log(response.error);
  1032.             }else{
  1033.                 if (settings.type == "POST"){
  1034.                     if (response.error === undefined ){
  1035.                         for (var post in response[threadID]["posts"]) {
  1036.                             //console.log(lastSubmittedContent);                    
  1037.                             if(response[threadID]["posts"][post]["comment"].replace(/[\r\n]/g,'') == lastSubmittedContent.replace(/[\r\n]/g,'')){
  1038.                                 yourPosts[threadID].push(post);
  1039.                                 queuedYouLabels.push(post);
  1040.                                 //console.log(yourPosts);
  1041.                                 //console.log(queuedYouLabels);
  1042.                                 labelYourPosts();
  1043.                                 break;
  1044.                             }
  1045.                         }
  1046.                         labelNewPosts(response);
  1047.                     }else{
  1048.                         console.log(response.error);
  1049.                     }
  1050.                 }else{
  1051.                     if (response[threadID] !== undefined){
  1052.                         labelNewPosts(response);
  1053.                     }else{
  1054.                         //console.log("Not in a thread");
  1055.                     }
  1056.                 }
  1057.             }
  1058.         });
  1059.         labelYourPosts(true); // First call, add (You) to page content
  1060.     }
  1061.     if(features.imageHover){imageHover();}
  1062.     if(features.videoHover){videoHover();}
  1063. });
  1064.  
  1065. var executeShortcut = function(shortcut) {
  1066.     var input = document.getElementById('reply_chennodiscursus');
  1067.  
  1068.     if (input.selectionStart !== undefined){
  1069.         $('#reply_chennodiscursus').selection('insert', {
  1070.             text: "["+shortcut+"]",
  1071.             mode: 'before'
  1072.         });
  1073.         $('#reply_chennodiscursus').selection('insert', {
  1074.             text: "[/"+shortcut+"]",
  1075.             mode: 'after'
  1076.         });
  1077.     }
  1078. };
  1079.  
  1080. function quickReply(){
  1081.     $('#reply').toggleClass("quickReply");
  1082.     $('#reply fieldset > div:nth-child(1)').css("width","");
  1083.     if ($('#reply').hasClass("showQROptions")){
  1084.         $('#reply fieldset > div:nth-child(3)').toggle();
  1085.     }
  1086. }
  1087.  
  1088. function quickReplyOptions(){
  1089.     $('#reply').toggleClass("showQROptions");
  1090.     $('#reply.quickReply fieldset > div:nth-child(3)').toggle();
  1091. }
  1092.  
  1093. var favican = document.createElement("IMG");
  1094. favican.src=favicon.lit;
  1095. var exclam = document.createElement("IMG");
  1096. exclam.src=favicon.alertOverlay;
  1097.  
  1098. function canfav(){
  1099.     $('#myCanvas').toggle();
  1100.     $('#myCanvas')["0"].getContext("2d").drawImage(favican, 0, 0);
  1101.     $('#myCanvas')["0"].getContext("2d").drawImage(exclam, 0, 0);
  1102. }
  1103.  
  1104. $(function(){
  1105.     shortcut.add("ctrl+s", function(){ executeShortcut("spoiler");});
  1106.     shortcut.add("ctrl+i", function(){ executeShortcut("i");});
  1107.     shortcut.add("ctrl+b", function(){ executeShortcut("b");});
  1108.     shortcut.add("ctrl+u", function(){ executeShortcut("u");});
  1109.     shortcut.add("q", function(){quickReply();}, {"disable_in_input":true});
  1110.     shortcut.add("ctrl+q", function(){quickReplyOptions();}, {"disable_in_input":false});
  1111.     if (features.favicon){shortcut.add("f", function(){canfav();}, {"disable_in_input":true});}
  1112.  
  1113.     seenPosts();
  1114.     ThreadUpdate(features);
  1115.     getBoard();
  1116.     bindShortcuts();
  1117.     window.setInterval( function(){ ThreadUpdate(features); }, 500 );
  1118. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement