Advertisement
ShaggyZE1

MyAnimeList(MAL) - Preview comments on profile pages

Jan 30th, 2023 (edited)
1,030
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         MyAnimeList(MAL) - Preview comments on profile pages
  3. // @version      1.0.5
  4. // @description  This script will add a preview button next to the submit button so you can preview your bbcode before submitting.
  5. // @author       Cpt_mathix
  6. // @match        *://myanimelist.net/profile*
  7. // @match        *://myanimelist.net/clubs.php*
  8. // @match        *://myanimelist.net/forum*
  9. // @match        *://myanimelist.net/comtocom.php*
  10. // @match        *://myanimelist.net/editprofile.php
  11. // @exclude      *://myanimelist.net/profile/*/reviews
  12. // @exclude      *://myanimelist.net/profile/*/recommendations
  13. // @exclude      *://myanimelist.net/profile/*/clubs
  14. // @exclude      *://myanimelist.net/profile/*/friends
  15. // @grant        none
  16. // @namespace https://greasyfork.org/users/16080
  17. // ==/UserScript==
  18.  
  19. // below a slightly modified version of Patrick Gillespie's BBCode Parser to make it work like the bbcode on myanimelist, thank you for making this available
  20.  
  21. /*
  22. Copyright (C) 2011 Patrick Gillespie, http://patorjk.com/
  23.  
  24. Permission is hereby granted, free of charge, to any person obtaining a copy
  25. of this software and associated documentation files (the "Software"), to deal
  26. in the Software without restriction, including without limitation the rights
  27. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  28. copies of the Software, and to permit persons to whom the Software is
  29. furnished to do so, subject to the following conditions:
  30.  
  31. The above copyright notice and this permission notice shall be included in
  32. all copies or substantial portions of the Software.
  33.  
  34. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  35. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  36. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  37. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  38. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  39. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  40. THE SOFTWARE.
  41. */
  42.  
  43. /*
  44.     Extendible BBCode Parser v1.0.0
  45.     By Patrick Gillespie (patorjk@gmail.com)
  46.     Website: http://patorjk.com/
  47.  
  48.     This module allows you to parse BBCode and to extend to the mark-up language
  49.     to add in your own tags.
  50. */
  51.  
  52. var XBBCODE = (function() {
  53.     "use strict";
  54.  
  55.     // -----------------------------------------------------------------------------
  56.     // Set up private variables
  57.     // -----------------------------------------------------------------------------
  58.  
  59.     var me = {},
  60.         urlPattern = /^(?:https?|file|c):(?:\/{1,3}|\\{1})[-a-zA-Z0-9:;@#%&()~_?\+=\/\\\.]*$/,
  61.         colorNamePattern = /^(?:aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen)$/,
  62.         colorCodePattern = /^#?[a-fA-F0-9]{6}$/,
  63.         emailPattern = /[^\s@]+@[^\s@]+\.[^\s@]+/,
  64.         fontFacePattern = /^([a-z][a-z0-9_]+|"[a-z][a-z0-9_\s]+")$/i,
  65.         tags,
  66.         tagList,
  67.         tagsNoParseList = [],
  68.         bbRegExp,
  69.         pbbRegExp,
  70.         pbbRegExp2,
  71.         openTags,
  72.         closeTags;
  73.  
  74.     /* -----------------------------------------------------------------------------
  75.      * tags
  76.      * This object contains a list of tags that your code will be able to understand.
  77.      * Each tag object has the following properties:
  78.      *
  79.      *   openTag - A function that takes in the tag's parameters (if any) and its
  80.      *             contents, and returns what its HTML open tag should be.
  81.      *             Example: [color=red]test[/color] would take in "=red" as a
  82.      *             parameter input, and "test" as a content input.
  83.      *             It should be noted that any BBCode inside of "content" will have
  84.      *             been processed by the time it enter the openTag function.
  85.      *
  86.      *   closeTag - A function that takes in the tag's parameters (if any) and its
  87.      *              contents, and returns what its HTML close tag should be.
  88.      *
  89.      *   displayContent - Defaults to true. If false, the content for the tag will
  90.      *                    not be displayed. This is useful for tags like IMG where
  91.      *                    its contents are actually a parameter input.
  92.      *
  93.      *   restrictChildrenTo - A list of BBCode tags which are allowed to be nested
  94.      *                        within this BBCode tag. If this property is omitted,
  95.      *                        any BBCode tag may be nested within the tag.
  96.      *
  97.      *   restrictParentsTo - A list of BBCode tags which are allowed to be parents of
  98.      *                       this BBCode tag. If this property is omitted, any BBCode
  99.      *                       tag may be a parent of the tag.
  100.      *
  101.      *   noParse - true or false. If true, none of the content WITHIN this tag will be
  102.      *             parsed by the XBBCode parser.
  103.      *
  104.      *
  105.      *
  106.      * LIMITIONS on adding NEW TAGS:
  107.      *  - Tag names should be alphanumeric (including underscores) and all tags should have an opening tag
  108.      *    and a closing tag.
  109.      *    The [*] tag is an exception because it was already a standard
  110.      *    bbcode tag. Technecially tags don't *have* to be alphanumeric, but since
  111.      *    regular expressions are used to parse the text, if you use a non-alphanumeric
  112.      *    tag names, just make sure the tag name gets escaped properly (if needed).
  113.      * --------------------------------------------------------------------------- */
  114.  
  115.     tags = {
  116.         "b": {
  117.             openTag: function(params,content) {
  118.                 return '<b>';
  119.             },
  120.             closeTag: function(params,content) {
  121.                 return '</b>';
  122.             }
  123.         },
  124.         "br": {
  125.             openTag: function(params,content) {
  126.                 return '<br>';
  127.             },
  128.             closeTag: function(params,content) {
  129.                 return '';
  130.             }
  131.         },
  132.         "center": {
  133.             openTag: function(params,content) {
  134.                 return '<div style="text-align: center;">';
  135.             },
  136.             closeTag: function(params,content) {
  137.                 return '</div>';
  138.             }
  139.         },
  140.         "code": {
  141.             openTag: function(params,content) {
  142.                 return '<div class="codetext"><pre>';
  143.             },
  144.             closeTag: function(params,content) {
  145.                 return '</pre></div>';
  146.             },
  147.             noParse: true
  148.         },
  149.         "color": {
  150.             openTag: function(params,content) {
  151.                 params = params || '';
  152.  
  153.                 var colorCode = (params.substr(1)).toLowerCase() || "black";
  154.                 colorNamePattern.lastIndex = 0;
  155.                 colorCodePattern.lastIndex = 0;
  156.                 if ( !colorNamePattern.test( colorCode ) ) {
  157.                     if ( !colorCodePattern.test( colorCode ) ) {
  158.                         colorCode = "black";
  159.                     } else {
  160.                         if (colorCode.substr(0,1) !== "#") {
  161.                             colorCode = "#" + colorCode;
  162.                         }
  163.                     }
  164.                 }
  165.                 return '<span style="color:' + colorCode + '">';
  166.             },
  167.             closeTag: function(params,content) {
  168.                 return '</span>';
  169.             }
  170.         },
  171.         "font": {
  172.             openTag: function(params,content) {
  173.                 var fonts = "";
  174.                 if (params) {
  175.                     fonts = params.substr(1, params.length - 1);
  176.                     fonts = fonts.replaceAll('\"', '');
  177.                 }
  178.                 return '<span style=\"font-family: ' + fonts + ';\">';
  179.             },
  180.             closeTag: function(params,content) {
  181.                 return '</span>';
  182.             }
  183.         },
  184.         "hr": {
  185.             openTag: function(params,content) {
  186.                 return '<hr>';
  187.             },
  188.             closeTag: function(params,content) {
  189.                 return '';
  190.             },
  191.             displayContent: false
  192.         },
  193.         "i": {
  194.             openTag: function(params,content) {
  195.                 return '<i>';
  196.             },
  197.             closeTag: function(params,content) {
  198.                 return '</i>';
  199.             }
  200.         },
  201.         "img": {
  202.             openTag: function(params,content) {
  203.                 params = params || '';
  204.  
  205.                 var align = (params.substr(1)).toLowerCase() || "";
  206.                 if (align == "align=left") {
  207.                     align = "img-a-l";
  208.                 } else if (align == "align=right") {
  209.                     align = "img-a-r";
  210.                 } else {
  211.                     align = "";
  212.                 }
  213.  
  214.                 var myUrl = content;
  215.  
  216.                 urlPattern.lastIndex = 0;
  217.                 if ( !urlPattern.test( myUrl ) ) {
  218.                     myUrl = "";
  219.                 }
  220.  
  221.                 return '<img style="vertical-align:bottom" class="userimg ' + align + '" src="' + myUrl + '" />';
  222.             },
  223.             closeTag: function(params,content) {
  224.                 return '';
  225.             },
  226.             displayContent: false
  227.         },
  228.         "justify": {
  229.             openTag: function(params,content) {
  230.                 return '<justify>';
  231.             },
  232.             closeTag: function(params,content) {
  233.                 return '</justify>';
  234.             }
  235.         },
  236.         "list": {
  237.             openTag: function(params,content) {
  238.                 params = params || '';
  239.  
  240.                 var type = (params.substr(1)).toLowerCase() || "";
  241.  
  242.                 if (type == 1) {
  243.                     return '<ol>';
  244.                 } else {
  245.                     return '<ul>';
  246.                 }
  247.             },
  248.             closeTag: function(params,content) {
  249.                 params = params || '';
  250.  
  251.                 var type = (params.substr(1)).toLowerCase() || "";
  252.  
  253.                 if (type == 1) {
  254.                     return '</ol>';
  255.                 } else {
  256.                     return '</ul>';
  257.                 }
  258.             },
  259.             restrictChildrenTo: ["*", "li"]
  260.         },
  261.         "pre": {
  262.             openTag: function(params,content) {
  263.                 return '<pre>';
  264.             },
  265.             closeTag: function(params,content) {
  266.                 return '</pre>';
  267.             }
  268.         },
  269.         "quote": {
  270.             openTag: function(params,content) {
  271.                 var user = "";
  272.                 if (!params) {
  273.                     return '<div class="quotetext">';
  274.                 }
  275.                 user = params.substr(1, params.length - 1);
  276.                 user = user.replaceAll('\"', '');
  277.                 return '<div class="quotetext" data-user="' + user + '"><strong><a href="/profile/' + user +'">' + user + ' said:</a></strong><br>';
  278.             },
  279.             closeTag: function(params,content) {
  280.                 return '</div>';
  281.             }
  282.         },
  283.         "right": {
  284.             openTag: function(params,content) {
  285.                 return '<div style="text-align: right;">';
  286.             },
  287.             closeTag: function(params,content) {
  288.                 return '</div>';
  289.             }
  290.         },
  291.         "s": {
  292.             openTag: function(params,content) {
  293.                 return '<span style="text-decoration:line-through;">';
  294.             },
  295.             closeTag: function(params,content) {
  296.                 return '</span>';
  297.             }
  298.         },
  299.         "size": {
  300.             openTag: function(params,content) {
  301.                 params = params || '';
  302.  
  303.                 var mySize = parseInt(params.substr(1),10) || 0;
  304.  
  305.                 return '<span style="font-size:' + mySize +'%;">';
  306.             },
  307.             closeTag: function(params,content) {
  308.                 return '</span>';
  309.             }
  310.         },
  311.         "spoiler": {
  312.             openTag: function(params,content) {
  313.                 var title = "spoiler";
  314.                 if (params) {
  315.                     title = params.substr(1, params.length - 1);
  316.                     title = title.replaceAll('\"', '');
  317.                 }
  318.                 return '<div class="spoiler"><input type="button" class="button show_button" onclick="this.nextSibling.style.display=\'inline-block\';this.style.display=\'none\';" data-showname="Show ' + title + '" data-hidename="Hide ' + title + '" value="Show ' + title + '"><span class="spoiler_content" style="display:none"><input type="button" class="button hide_button" onclick="this.parentNode.style.display=\'none\';this.parentNode.parentNode.childNodes[0].style.display=\'inline-block\';" value="Hide ' + title + '"><br>';
  319.             },
  320.             closeTag: function(params,content) {
  321.                 return '</span></div>';
  322.             }
  323.         },
  324.         "sub": {
  325.             openTag: function(params,content) {
  326.                 return '<sub>';
  327.             },
  328.             closeTag: function(params,content) {
  329.                 return '</sub>';
  330.             }
  331.         },
  332.         "sup": {
  333.             openTag: function(params,content) {
  334.                 return '<sup>';
  335.             },
  336.             closeTag: function(params,content) {
  337.                 return '</sup>';
  338.             }
  339.         },
  340.         "table": {
  341.             openTag: function(params,content) {
  342.                 return '<table>';
  343.             },
  344.             closeTag: function(params,content) {
  345.                 return '</table>';
  346.             }
  347.         },
  348.         "td": {
  349.             openTag: function(params,content) {
  350.                 return '<td>';
  351.             },
  352.             closeTag: function(params,content) {
  353.                 return '</td>';
  354.             }
  355.         },
  356.         "th": {
  357.             openTag: function(params,content) {
  358.                 return '<th>';
  359.             },
  360.             closeTag: function(params,content) {
  361.                 return '</th>';
  362.             }
  363.         },
  364.         "tr": {
  365.             openTag: function(params,content) {
  366.                 return '<tr>';
  367.             },
  368.             closeTag: function(params,content) {
  369.                 return '</tr>';
  370.             }
  371.         },
  372.         "u": {
  373.             openTag: function(params,content) {
  374.                 return '<u>';
  375.             },
  376.             closeTag: function(params,content) {
  377.                 return '</u>';
  378.             }
  379.         },
  380.         "url": {
  381.             openTag: function(params,content) {
  382.  
  383.                 var myUrl;
  384.  
  385.                 if (!params) {
  386.                     myUrl = content.replace(/<.*?>/g,"");
  387.                 } else {
  388.                     myUrl = params.substr(1);
  389.                 }
  390.  
  391.                 urlPattern.lastIndex = 0;
  392.                 if ( !urlPattern.test( myUrl ) ) {
  393.                     myUrl = "#";
  394.                 }
  395.  
  396.                 return '<a href="' + myUrl + '" rel="nofollow">';
  397.             },
  398.             closeTag: function(params,content) {
  399.                 return '</a>';
  400.             }
  401.         },
  402.         "yt": {
  403.             openTag: function(params,content) {
  404.                 return '<iframe width="420" height="345" src="https://www.youtube.com/embed/' + content + '"/>';
  405.             },
  406.             closeTag: function(params,content) {
  407.                 return '</iframe>';
  408.             },
  409.             displayContent: false
  410.         },
  411.         /*
  412.             The [*] tag is special since the user does not define a closing [/*] tag when writing their bbcode.
  413.             Instead this module parses the code and adds the closing [/*] tag in for them. None of the tags you
  414.             add will act like this and this tag is an exception to the others.
  415.         */
  416.         "*": {
  417.             openTag: function(params,content) {
  418.                 return "<li>";
  419.             },
  420.             closeTag: function(params,content) {
  421.                 return "</li>";
  422.             },
  423.             restrictParentsTo: ["list","ul","ol"]
  424.         }
  425.     };
  426.  
  427.     // create tag list and lookup fields
  428.     function initTags() {
  429.         tagList = [];
  430.         var prop,
  431.             ii,
  432.             len;
  433.         for (prop in tags) {
  434.             if (tags.hasOwnProperty(prop)) {
  435.                 if (prop === "*") {
  436.                     tagList.push("\\" + prop);
  437.                 } else {
  438.                     tagList.push(prop);
  439.                     if ( tags[prop].noParse ) {
  440.                         tagsNoParseList.push(prop);
  441.                     }
  442.                 }
  443.  
  444.                 tags[prop].validChildLookup = {};
  445.                 tags[prop].validParentLookup = {};
  446.                 tags[prop].restrictParentsTo = tags[prop].restrictParentsTo || [];
  447.                 tags[prop].restrictChildrenTo = tags[prop].restrictChildrenTo || [];
  448.  
  449.                 len = tags[prop].restrictChildrenTo.length;
  450.                 for (ii = 0; ii < len; ii++) {
  451.                     tags[prop].validChildLookup[ tags[prop].restrictChildrenTo[ii] ] = true;
  452.                 }
  453.                 len = tags[prop].restrictParentsTo.length;
  454.                 for (ii = 0; ii < len; ii++) {
  455.                     tags[prop].validParentLookup[ tags[prop].restrictParentsTo[ii] ] = true;
  456.                 }
  457.             }
  458.         }
  459.  
  460.         bbRegExp = new RegExp("<bbcl=([0-9]+) (" + tagList.join("|") + ")([ =][^>]*?)?>((?:.|[\\r\\n])*?)<bbcl=\\1 /\\2>", "gi");
  461.         pbbRegExp = new RegExp("\\[(" + tagList.join("|") + ")([ =][^\\]]*?)?\\]([^\\[]*?)\\[/\\1\\]", "gi");
  462.         pbbRegExp2 = new RegExp("\\[(" + tagsNoParseList.join("|") + ")([ =][^\\]]*?)?\\]([\\s\\S]*?)\\[/\\1\\]", "gi");
  463.  
  464.         // create the regex for escaping ['s that aren't apart of tags
  465.         (function() {
  466.             var closeTagList = [];
  467.             for (var ii = 0; ii < tagList.length; ii++) {
  468.                 //console.log(tagList[ii]);
  469.                 if ( tagList[ii] !== "\\*" ) { // the * tag doesn't have an offical closing tag
  470.                     closeTagList.push ( "/" + tagList[ii] );
  471.                 }
  472.             }
  473.  
  474.             openTags = new RegExp("(\\[)((?:" + tagList.join("|") + ")(?:[ =][^\\]]*?)?)(\\])", "gi");
  475.             closeTags = new RegExp("(\\[)(" + closeTagList.join("|") + ")(\\])", "gi");
  476.         })();
  477.  
  478.     }
  479.     initTags();
  480.  
  481.     // -----------------------------------------------------------------------------
  482.     // private functions
  483.     // -----------------------------------------------------------------------------
  484.  
  485.     function checkParentChildRestrictions(parentTag, bbcode, bbcodeLevel, tagName, tagParams, tagContents, errQueue) {
  486.  
  487.         errQueue = errQueue || [];
  488.         bbcodeLevel++;
  489.  
  490.         // get a list of all of the child tags to this tag
  491.         var reTagNames = new RegExp("(<bbcl=" + bbcodeLevel + " )(" + tagList.join("|") + ")([ =>])","gi"),
  492.             reTagNamesParts = new RegExp("(<bbcl=" + bbcodeLevel + " )(" + tagList.join("|") + ")([ =>])","i"),
  493.             matchingTags = tagContents.match(reTagNames) || [],
  494.             cInfo,
  495.             errStr,
  496.             ii,
  497.             childTag,
  498.             pInfo = tags[parentTag] || {};
  499.  
  500.         reTagNames.lastIndex = 0;
  501.  
  502.         if (!matchingTags) {
  503.             tagContents = "";
  504.         }
  505.  
  506.         for (ii = 0; ii < matchingTags.length; ii++) {
  507.             reTagNamesParts.lastIndex = 0;
  508.             childTag = (matchingTags[ii].match(reTagNamesParts))[2].toLowerCase();
  509.  
  510.             if ( pInfo && pInfo.restrictChildrenTo && pInfo.restrictChildrenTo.length > 0 ) {
  511.                 if ( !pInfo.validChildLookup[childTag] ) {
  512.                     errStr = "The tag \"" + childTag + "\" is not allowed as a child of the tag \"" + parentTag + "\".";
  513.                     errQueue.push(errStr);
  514.                 }
  515.             }
  516.             cInfo = tags[childTag] || {};
  517.             if ( cInfo.restrictParentsTo.length > 0 ) {
  518.                 if ( !cInfo.validParentLookup[parentTag] ) {
  519.                     errStr = "The tag \"" + parentTag + "\" is not allowed as a parent of the tag \"" + childTag + "\".";
  520.                     errQueue.push(errStr);
  521.                 }
  522.             }
  523.  
  524.         }
  525.  
  526.         tagContents = tagContents.replace(bbRegExp, function(matchStr, bbcodeLevel, tagName, tagParams, tagContents ) {
  527.             errQueue = checkParentChildRestrictions(tagName.toLowerCase(), matchStr, bbcodeLevel, tagName, tagParams, tagContents, errQueue);
  528.             return matchStr;
  529.         });
  530.         return errQueue;
  531.     }
  532.  
  533.     /*
  534.         This function updates or adds a piece of metadata to each tag called "bbcl" which
  535.         indicates how deeply nested a particular tag was in the bbcode. This property is removed
  536.         from the HTML code tags at the end of the processing.
  537.     */
  538.     function updateTagDepths(tagContents) {
  539.         tagContents = tagContents.replace(/\<([^\>][^\>]*?)\>/gi, function(matchStr, subMatchStr) {
  540.             var bbCodeLevel = subMatchStr.match(/^bbcl=([0-9]+) /);
  541.             if (bbCodeLevel === null) {
  542.                 return "<bbcl=0 " + subMatchStr + ">";
  543.             } else {
  544.                 return "<" + subMatchStr.replace(/^(bbcl=)([0-9]+)/, function(matchStr, m1, m2) {
  545.                     return m1 + (parseInt(m2, 10) + 1);
  546.                 }) + ">";
  547.             }
  548.         });
  549.         return tagContents;
  550.     }
  551.  
  552.     /*
  553.         This function removes the metadata added by the updateTagDepths function
  554.     */
  555.     function unprocess(tagContent) {
  556.         return tagContent.replace(/<bbcl=[0-9]+ \/\*>/gi,"").replace(/<bbcl=[0-9]+ /gi,"&#91;").replace(/>/gi,"&#93;");
  557.     }
  558.  
  559.     var replaceFunct = function(matchStr, bbcodeLevel, tagName, tagParams, tagContents) {
  560.  
  561.         tagName = tagName.toLowerCase();
  562.  
  563.         var processedContent = tags[tagName].noParse ? unprocess(tagContents) : tagContents.replace(bbRegExp, replaceFunct),
  564.             openTag = tags[tagName].openTag(tagParams,processedContent),
  565.             closeTag = tags[tagName].closeTag(tagParams,processedContent);
  566.  
  567.         if ( tags[tagName].displayContent === false) {
  568.             processedContent = "";
  569.         }
  570.  
  571.         return openTag + processedContent + closeTag;
  572.     };
  573.  
  574.     function parse(config) {
  575.         var output = config.text;
  576.         output = output.replace(bbRegExp, replaceFunct);
  577.         return output;
  578.     }
  579.  
  580.     /*
  581.         The star tag [*] is special in that it does not use a closing tag. Since this parser requires that tags have a closing
  582.         tag, we must pre-process the input and add in closing tags [/*] for the star tag.
  583.         We have a little levaridge in that we know the text we're processing wont contain the <> characters (they have been
  584.         changed into their HTML entity form to prevent XSS and code injection), so we can use those characters as markers to
  585.         help us define boundaries and figure out where to place the [/*] tags.
  586.     */
  587.     function fixStarTag(text) {
  588.         text = text.replace(/\[(?!\*[ =\]]|list([ =][^\]]*)?\]|\/list[\]])/ig, "<");
  589.         text = text.replace(/\[(?=list([ =][^\]]*)?\]|\/list[\]])/ig, ">");
  590.  
  591.         while (text !== (text = text.replace(/>list([ =][^\]]*)?\]([^>]*?)(>\/list])/gi, function(matchStr,contents,endTag) {
  592.  
  593.             var innerListTxt = matchStr;
  594.             while (innerListTxt !== (innerListTxt = innerListTxt.replace(/\[\*\]([^\[]*?)(\[\*\]|>\/list])/i, function(matchStr,contents,endTag) {
  595.                 if (endTag.toLowerCase() === ">/list]") {
  596.                     endTag = "</*]</list]";
  597.                 } else {
  598.                     endTag = "</*][*]";
  599.                 }
  600.                 return "<*]" + contents + endTag;
  601.             })));
  602.  
  603.             innerListTxt = innerListTxt.replace(/>/g, "<");
  604.             return innerListTxt;
  605.         })));
  606.  
  607.         // add ['s for our tags back in
  608.         text = text.replace(/</g, "[");
  609.         return text;
  610.     }
  611.  
  612.     function addBbcodeLevels(text) {
  613.         while ( text !== (text = text.replace(pbbRegExp, function(matchStr, tagName, tagParams, tagContents) {
  614.             matchStr = matchStr.replace(/\[/g, "<");
  615.             matchStr = matchStr.replace(/\]/g, ">");
  616.             return updateTagDepths(matchStr);
  617.         })) );
  618.         return text;
  619.     }
  620.  
  621.     // -----------------------------------------------------------------------------
  622.     // public functions
  623.     // -----------------------------------------------------------------------------
  624.  
  625.     // API, Expose all available tags
  626.     me.tags = function() {
  627.         return tags;
  628.     };
  629.  
  630.     // API
  631.     me.addTags = function(newtags) {
  632.         var tag;
  633.         for (tag in newtags) {
  634.             tags[tag] = newtags[tag];
  635.         }
  636.         initTags();
  637.     };
  638.  
  639.     me.process = function(config) {
  640.         var ret = {html: "", error: false},
  641.             errQueue = [];
  642.  
  643.         config.text = config.text.replace(/</g, "&lt;"); // escape HTML tag brackets
  644.         config.text = config.text.replace(/>/g, "&gt;"); // escape HTML tag brackets
  645.  
  646.         config.text = config.text.replace(openTags, function(matchStr, openB, contents, closeB) {
  647.             return "<" + contents + ">";
  648.         });
  649.         config.text = config.text.replace(closeTags, function(matchStr, openB, contents, closeB) {
  650.             return "<" + contents + ">";
  651.         });
  652.  
  653.         config.text = config.text.replace(/\[/g, "&#91;"); // escape ['s that aren't apart of tags
  654.         config.text = config.text.replace(/\]/g, "&#93;"); // escape ['s that aren't apart of tags
  655.         config.text = config.text.replace(/</g, "["); // escape ['s that aren't apart of tags
  656.         config.text = config.text.replace(/>/g, "]"); // escape ['s that aren't apart of tags
  657.  
  658.         // process tags that don't have their content parsed
  659.         while ( config.text !== (config.text = config.text.replace(pbbRegExp2, function(matchStr, tagName, tagParams, tagContents) {
  660.             tagContents = tagContents.replace(/\[/g, "&#91;");
  661.             tagContents = tagContents.replace(/\]/g, "&#93;");
  662.             tagParams = tagParams || "";
  663.             tagContents = tagContents || "";
  664.             return "[" + tagName + tagParams + "]" + tagContents + "[/" + tagName + "]";
  665.         })) );
  666.  
  667.         //config.text = fixHrTag(config.text); // add in tags for the [hr] tag
  668.         config.text = fixStarTag(config.text); // add in closing tags for the [*] tag
  669.         config.text = addBbcodeLevels(config.text); // add in level metadata
  670.  
  671.         errQueue = checkParentChildRestrictions("bbcode", config.text, -1, "", "", config.text);
  672.  
  673.         ret.html = parse(config);
  674.  
  675.         if ( ret.html.indexOf("[") !== -1 || ret.html.indexOf("]") !== -1) {
  676.             errQueue.push("Some tags appear to be misaligned.");
  677.         }
  678.  
  679.         if (config.removeMisalignedTags) {
  680.             ret.html = ret.html.replace(/\[.*?\]/g,"");
  681.         }
  682.         if (config.wrapper) {
  683.             ret.html = '<div id="wrapper">' + ret.html + '</div>';
  684.         }
  685.  
  686.         if (!config.escapeHtml) {
  687.             ret.html = ret.html.replace("&#91;", "["); // put ['s back in
  688.             ret.html = ret.html.replace("&#93;", "]"); // put ['s back in
  689.         }
  690.  
  691.         ret.error = errQueue.length !== 0;
  692.         ret.errorQueue = errQueue;
  693.  
  694.         return ret;
  695.     };
  696.  
  697.     return me;
  698. })();
  699.  
  700. /////////////////////////////////////////////////////////////////////
  701. // END OF BBCODE TO HTML PARSER
  702. /////////////////////////////////////////////////////////////////////
  703.  
  704. // starting myanimelist part
  705. init();
  706.  
  707. function init() {
  708.     if (location.href.match('editprofile.php')) {
  709.         addAboutMePreviewButton();
  710.     }
  711.     else if (location.href.match('/profile/')) {
  712.         addMainPreviewButton();
  713.     }
  714.     else if (location.href.match('/clubs.php')) {
  715.         addClubPreviewButton();
  716.     }
  717.     else {
  718.         initializeReplyButtons();
  719.     }
  720. }
  721.  
  722. function initializeReplyButtons() {
  723.     var comments = document.querySelectorAll("div[id^='comBox']");
  724.     for (var i = 0; i < comments.length; i++) {
  725.         var replyButton = comments[i].querySelector('div.postActions > a:nth-child(1)'); // profile pages
  726.  
  727.         if (replyButton === null) {
  728.             replyButton = comments[i].querySelector('small > a:nth-child(1)'); // com to com pages
  729.         }
  730.  
  731.         if (replyButton) {
  732.             replyButton.addEventListener("click", function(){
  733.                 addPreviewButton();
  734.             });
  735.         }
  736.     }
  737. }
  738.  
  739. function addAboutMePreviewButton() {
  740.     var submitButton = document.querySelector("input[name=\"submit\"]");
  741.     var previewHTML = '&nbsp;&nbsp;<input type="button" id="previewButton" class="inputButton" value="Preview About Me">';
  742.     submitButton.insertAdjacentHTML('afterend', previewHTML);
  743.  
  744.     var anchor = document.querySelector("#content form");
  745.     var textarea = anchor.querySelector("textarea[name=\"profile_aboutme\"");
  746.     textarea.insertAdjacentHTML("afterend", "<br><small><b>You can use the \"Preview About Me\" button below to preview your about me or use the following website: <a href='https://cptmathix.github.io/MyAnimeList-BBCODE2HTML/'>https://cptmathix.github.io/MyAnimeList-BBCODE2HTML/</a><b></small>");
  747.  
  748.     document.getElementById("previewButton").addEventListener("click", function() {
  749.         if (document.getElementById("wrapper") !== null) {
  750.             document.getElementById("wrapper").remove();
  751.         }
  752.  
  753.         var result = runParser(textarea.value.replace(/(?:\r\n|\r|\n)/g, ' [br][/br] '));
  754.         anchor.insertAdjacentHTML('afterend', result.html);
  755.     });
  756. }
  757.  
  758. function addClubPreviewButton() {
  759.     var submitButton = document.querySelector("input.inputButton");
  760.     var previewHTML = '&nbsp;&nbsp;<input type="button" id="previewButton" class="inputButton" value="Preview Comment">';
  761.     submitButton.insertAdjacentHTML('afterend', previewHTML);
  762.  
  763.     var anchor = document.querySelector("form.form-club-user-comment");
  764.     var textarea = anchor.querySelector("textarea[name=\"commentText\"");
  765.  
  766.     document.getElementById("previewButton").addEventListener("click", function() {
  767.         if (document.getElementById("wrapper") !== null) {
  768.             document.getElementById("wrapper").remove();
  769.         }
  770.  
  771.         var result = runParser(textarea.value.replace(/(?:\r\n|\r|\n)/g, ' [br][/br] '));
  772.         anchor.insertAdjacentHTML('afterend', result.html);
  773.     });
  774. }
  775.  
  776. function addMainPreviewButton() {
  777.     var html = '<input id="mainPreviewButton" class="inputButton btn-form-submit fs12 pt4 pb4 pl0 pr0" name="commentSubmit" value="Preview Comment">';
  778.     var anchor = document.querySelector("#lastcomment > div.comment-form > form");
  779.     anchor.querySelector("div").insertAdjacentHTML('beforeend', html);
  780.  
  781.     document.getElementById("mainPreviewButton").addEventListener("click", function() {
  782.         if (document.querySelector("#wrapper") !== null) {
  783.             document.querySelector("#wrapper").remove();
  784.         }
  785.  
  786.         var result = runParser(anchor.querySelector("textarea").value.replace(/(?:\r\n|\r|\n)/g, ' [br][/br] '));
  787.         anchor.insertAdjacentHTML('afterend', result.html);
  788.     });
  789. }
  790.  
  791. function addPreviewButton() {
  792.     // Can be removed or Fixed to use textarea mouseover or New reply button onclick to Preview on topic page without going to actual Preview page.
  793.     var html = '<input id="previewButton" type="button" value="Preview Reply" onclick="" class="inputButton btn-form-submit fs11 ml4 pt4 pb4 btn-profile-comment-reply">';
  794.     var anchor;
  795.     if (document.querySelector("div[id^='reply']")) {
  796.     anchor = document.querySelector("div[id^='reply']");
  797.     anchor.querySelector('.spaceit').insertAdjacentHTML('beforeend', html);
  798.     } else {
  799.     anchor = document.querySelector("#quickReply");
  800.     anchor.querySelector('.btn-topic-normal.inverse.noborder').insertAdjacentHTML('beforeend', html);
  801.     }
  802.  
  803.     document.getElementById("previewButton").addEventListener("click", function() {
  804.         if (document.querySelector("#wrapper") !== null) {
  805.             document.querySelector("#wrapper").remove();
  806.         }
  807.         var result = runParser(anchor.querySelector("textarea").value.replace(/(?:\r\n|\r|\n)/g, ' [br][/br] '));
  808.         anchor.insertAdjacentHTML('afterend', result.html);
  809.     });
  810. }
  811.  
  812. function runParser(content) {
  813.     var result = XBBCODE.process(
  814.         {
  815.             text: content,
  816.             removeMisalignedTags: false,
  817.             wrapper: true
  818.         }
  819.     );
  820.  
  821.     return result;
  822. }
  823.  
Advertisement
Comments
  • schmoosey
    1 year
    # text 0.60 KB | 1 0
    1. grammar is very important in comments.
    2.  
    3. One of these would make your point valid, as you have it, "below a..." you're saying there's something below a slightly modified version....
    4.  
    5. "below, a slightly modified version of Patrick Gillespie's BBCode Parser to make it work like the bbcode on myanimelist, thank you for making this available"
    6.  
    7. OR
    8.  
    9. "The below is a slightly modified version of Patrick Gillespie's BBCode Parser to make it work like the bbcode on myanimelist, thank you for making this available"
    10.  
    11.  
    12.  
    13. This is helpful not only for others, but doing this will save you plenty of head aches too.
    • ShaggyZE1
      1 year
      # text 0.48 KB | 0 0
      1. It's actually not as important as one might think, I don't even read the comments, I just look at the code and figure out what it does and what I need to do and hardly comment on my own code, but yea sometimes it helps and it doesn't even need to be in English and any clues can help a programmer, however, I'm only updating it, this is Cpt_mathix's script, pretty sure he's Belgian which would explain the grammar and not sure if he's going to see this comment or has any plans of fixing it.
Add Comment
Please, Sign In to add comment
Advertisement