ClipFormat! (Derpibooru - comment autoformatter from clipboard)

Save format, images and links when pasting from clipboard into commentbox in derpibooru. (script by VcSaJen, icon by TryHardBrony)

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name        ClipFormat! (Derpibooru - comment autoformatter from clipboard)
// @namespace   https://derpiboo.ru/pasteformatizer
// @description Save format, images and links when pasting from clipboard into commentbox in derpibooru. (script by VcSaJen, icon by TryHardBrony)
// @include     /https?://(www\.)?derpiboo.ru/.*/
// @include     /https?://(www\.)?trixiebooru.org/.*/
// @include     /https?://(www\.)?derpibooru.org/.*/
// @icon        https://dl.dropboxusercontent.com/u/7410519/ScreenS/i_came_to_write_fanfics_by_tryhardbrony-64px-256col.png
// @license     LGPL 3 or later
// @version     0.8
// @grant       GM_addStyle
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/jquery.selection/1.0.1/jquery.selection.min.js
// @require     https://greasyfork.org/scripts/4535-htmlparser/code/htmlparser.js?version=15389
// ==/UserScript==

(function($) //< custom $ compatibility
{ 

  $(function() //ready
  {
    var textasrea_selector = 'textarea#comment_body,textarea#topic_posts_attributes_0_body,textarea#post_body,textarea#image_description';
    var simple_format_tags = /^(em|i|strong|b|ins|u|del|strike|s|pre|sup|sub|cite)$/i;
    var basic_fomat_chars = {"strong":"*",
                             "b":"**",
                             "em":"_",
                             "i":"__",
                             "del":"-",
                             "ins":"+",
                             "sup":"^",
                             "sub":"~",
                             "pre":"@",
                             "cite":"??"
                             };
    //$(textasrea_selector).after('<textarea id="mymymy"></textarea>');
    
    $(textasrea_selector).parent().before($('<div/>',{'class': 'field'}).append($('<label/>',{'for': 'clipformat_check', text: 'Clipformat', 'title': 'Format text from clipboard'}),
                                                                                $('<input/>',{id: 'clipformat_check', 'type': 'checkbox'}),
                                                                                $('<span/>',{id: 'clipformat_error', 'style': 'display:none;', 'class': 'comment_deleted', text: ' Error!'})));
    var mycbChecked;
    
    $('#clipformat_check').change(function (e) {
      mycbChecked = $('#clipformat_check').prop('checked');
      if (mycbChecked)
      {
        $(textasrea_selector).css('outline-color', '#5E95BC');
        $(textasrea_selector).css('outline-width', '1px');
        $(textasrea_selector).css('outline-style', 'solid');
      } else
      {
        $(textasrea_selector).css('outline-style', 'none');
      }
    }).dblclick(function (e) {
      $('#clipformat_check').prop("checked", true);
      $('#clipformat_check').prop("indeterminate", true);
      $('#clipformat_check').trigger("change");
    });
    
    $(textasrea_selector).on('paste', function (e) {
      if (!mycbChecked) return;
      if (e.originalEvent.clipboardData || e.clipboardData)
      {
        //alert('ok!');
        $('#clipformat_error').hide();
        var s = "";
        var clipdata = (e.originalEvent.clipboardData || e.clipboardData);
        
        /*s+="html:"+clipdata.getData('text/html')+"\n";
        s+="plain:"+clipdata.getData('text/plain')+"\n";
        
        var types = clipdata.types;
        var count = types.length;
        s+="types:\n";
        for (var i = 0; i < count; i++) 
        {
            s+="type"+i+": "+types[i]+"\n";
        }
        //$("#output").text(s);
        alert(s);*/
        
        try {
          s="";
          var myhtml = clipdata.getData('text/html');

          if (!myhtml) {
            //alert("NO HTML!"); 
            //flashElement($(textasrea_selector));
            return;
          }
          
          if (/^<html xmlns:v="urn:schemas-microsoft-com:vml"/.test(myhtml))
            myhtml=cleanHTML(myhtml);
            
          myhtml=myhtml.replace(/<!?\[[^>]*?\](?!--)?>/g, "");
          myhtml=myhtml.replace(/<title>([\s\S].*?)<\/title>/gi, " ");
          myhtml=myhtml.replace(/<style[\s\S]*?<\/style>/gi, " ");
          
          if (!$('#clipformat_check').prop('indeterminate'))
          {
            $('#clipformat_check').prop("checked", false);
            $('#clipformat_check').trigger("change");
          }
          
          //alert(myhtml);
          
          function writableTag(tag)
          {
            var result = tag;
            if (result==="strike"||result==="s") result="del";
            if (result==="u") result="ins";
            /*em|i|strong|b|ins|u|del|strike|pre|sup|sub*/
            return result;
          }
          function htmlCharize(s)
          {
            var i, result="";
            for (i=0;i<s.length;i++)
            {
              result+='&#'+s.charCodeAt(i)+';';
            }
            //alert("result="+result);
            return result;
          }
          function escapeFull(s)
          {
            var i, result="";
            for (i=0;i<s.length;i++)
            {
              var tmp="";
              tmp=Number(s.charCodeAt(i)).toString(16);
              if (tmp.length<2) tmp='0'+tmp;
              result+='%'+tmp;
            }
            //alert("result="+result);
            return result;
          }
          function escapeRegexStr(s)
          {
            var i, result="";
            for (i=0;i<s.length;i++)
            {
              var ch = s.charAt(i);
              if (ch==="*"||ch==="+"||ch==="?"||ch==="\\"||ch==="^"||ch==="$"||ch==="."||ch==="|"||ch==="("||ch===")"||ch==="["||ch==="]"||
                  ch==="{"||ch==="}") result+="\\"+ch;
              else result+=ch;
            }
            return result;
          }
          
          var nomoreparseing = false;
          var currentLinkTitle;
          var currentLinkURL;
          var currentLinkContent="";
          var currently_a = false;
          var spoilerLevel = 0;
          var state = {"strong":false,
                       "b":false,
                       "em":false,
                       "i":false,
                       "del":false,
                       "ins":false,
                       "sup":false,
                       "sub":false,
                       "pre":false,
                       "cite":false};
          

          
          HTMLParser(myhtml, {
            start: function( tag, attrs, unary ) {
              tag=tag.toLowerCase();
              if (tag.match(simple_format_tags))
              {
                s += "<" + writableTag(tag) + ">";
                state[writableTag(tag)]=true;
                return;
              }
              var atlist = {"href": "", "src": "http://"};
              /*s += "[" + tag;
           
              for ( var i = 0; i < attrs.length; i++ )
                s += " " + attrs[i].name + '="' + attrs[i].escaped + '"';
          
              s += (unary ? "/" : "") + "]";*/
              
              for ( var i = 0; i < attrs.length; i++ )
                atlist[attrs[i].name.toLowerCase()]=attrs[i].value;
              
              if (unary && tag==="br") s += "\n";
              if (tag==="img")
              {
                var imgstr = "", imgdescr="";
                imgstr += "!"+'<link>'+escapeFull(atlist["src"])+'</link>';
                if (!(currently_a&&currentLinkTitle))
                {
                  if (atlist["title"]!==undefined)
                    imgdescr = atlist["title"];
                  else if (atlist["alt"]!==undefined)
                    imgdescr = atlist["alt"];
                  if (/\)|!/.test(imgdescr))
                    imgdescr = "[=="+imgdescr+"==]";
                }
                if (imgdescr)
                  imgstr += "<bracket>"+imgdescr+"</bracket>";
                imgstr += "!";
                s += imgstr;
                if (currently_a) currentLinkContent+="[img]";
              }
              if (tag==="a")
              {
                if (atlist["href"]==="") 
                {
                  currently_a = false;
                  return;
                }
                
                s += '"';
                currentLinkTitle = decodeSimpleHTMLEntities(atlist["title"]===undefined ? "" : atlist["title"]);
                if (/\)/.test(currentLinkTitle))
                  currentLinkTitle = "[=="+currentLinkTitle+"==]";
                currentLinkURL=atlist["href"];
                currentLinkURL=currentLinkURL.replace(/^.+deviantart\.com\/users\/outgoing\?(.+)$/ig, "$1");
                if (!currentLinkURL.match(/^(?:https?:)/)) currentLinkURL="#nope";
                currentLinkContent="";
                
                currently_a = true;
              }
              if (tag==="blockquote")
              {
                var bqtext = "";
                bqtext+="[bq";
                if (atlist["title"]!==undefined)
                {
                  bqtext+='="'+atlist["title"]+'"';
                }
                bqtext+="]";
                s+=bqtext;
              }
              if (tag==="span")
              {
                //s+="[span]";
                if (spoilerLevel>0) spoilerLevel++;
                if (atlist["class"]==="spoiler" || atlist["class"]==="spoiler-revealed")
                {
                  s+="[spoiler]";
                  spoilerLevel++;
                }
              }
              if (tag==="acronym"||tag==="abbr")
              {
                s+="<acronym";
                if (atlist["title"]!==undefined)
                {
                  s+='='+atlist["title"];
                }
                s+=">";
              }
              if (tag==="hr")
              {
                s+="\n-----------\n";
                return;
              }
            },
            end: function( tag ) {
              tag=tag.toLowerCase();
              if (tag.match(simple_format_tags))
              {
                s += "</" + writableTag(tag) + ">";
                state[writableTag(tag)]=false;
                return;
              }
              if (tag.match(/^(blockquote|dd|dl|fieldset|form|h[1-6]|hr|ol|p|pre|section|table|tfoot|ul|div|li)$/i))
              {
                s += "\n";
              }
              if (tag==="a")
              {
                if (!currently_a) return;
                currently_a = false;
                if (currentLinkContent==="") s+="&nbsp;";
                var linkstr = "";
                if (currentLinkTitle!=="") linkstr+="<bracket>"+currentLinkTitle+"</bracket>";
                currentLinkURL=currentLinkURL.replace(/#$/g,"");
                linkstr+='":<link>'+escapeFull(currentLinkURL)+'</link>'; //I'm a master of kludge!
                s+=linkstr+' ';
                return;
              }
              if (tag==="blockquote")
              {
                s+="[/bq]";
              }
              if (tag==="span")
              {
                //s+="[/span]";
                if (spoilerLevel===1)
                {
                  s+="[/spoiler]";
                  spoilerLevel=0;
                }
                if (spoilerLevel>0) spoilerLevel--;
              }
              if (tag==="acronym"||tag==="abbr")
              {
                s+="</acronym>";
              }
              if (tag==="html")
                nomoreparseing = true;
            },
            chars: function( text ) {
              if (nomoreparseing) return;
              var trimed = text.replace(/\s+/g, " ");
              if (s.length>0 && s.charAt(s.length-1)===" " && (/^\s/.test(trimed)))
                trimed = trimed.replace(/^\s+/g, "");
              
              for(var key in basic_fomat_chars)
              {
                if (state[key])
                {
                  var fmtchr = basic_fomat_chars[key].charAt(0);
                  fmtchr=escapeRegexStr(fmtchr);
                  var myregex = new RegExp("(?:(\\W)"+fmtchr+")|(?:"+fmtchr+"(?=\\W))", 'gm');
                  trimed = trimed.replace(myregex, "$1"+htmlCharize(fmtchr.charAt(fmtchr.length-1)));
                }
              }
              if (currently_a) 
              {
                trimed = trimed.replace(/"/g, "&quot;");
                if (currentLinkTitle==="") 
                {
                  trimed = trimed.replace(/\(/g, "&#40;");
                  trimed = trimed.replace(/\)/g, "&#41;");
                }
                if (currentLinkContent=="")
                {
                  trimed = trimed.replace(/^\s/g, "&#32;");
                }
                currentLinkContent+=trimed;
              }
              //if (state.strong||state.b) text.replace(/(?:(\s)\*)|(?:\*(?=\s))/gm, "&#42;");
              //if (state.em||state.i)     text.replace(/(?:(\s)\*)|(?:\*(?=\s))/gm, "&#95;");
              
              
              s += trimed;
            },
            comment: function( text ) {
              //s += "/*" + text + "*/";
            }
          });
          
          
          
          //var myAntiFormatRegex = /(\W|^)(\*|\*\*|_|__|\?\?|\+|-|\^|~|@)((?:\S)|(?:(?!\2\s)\S.*?\S))\2(?!\2)(?:(?=\W)|$)/g;
          for(var tag in basic_fomat_chars)
          {
            var myAntiFormatRegex = new RegExp("(\\W|^)("+escapeRegexStr(basic_fomat_chars[tag])+")((?:\\S)|(?:(?!\\2\\s)\\S[\\s\\S]*?\\S))\\2(?!\\2)(?:(?=\\W)|$)", 'g');
            s=s.replace(myAntiFormatRegex, function(str, p1, p2, p3, offset, fullstr)
            {
              //alert("replacing!"+p1+","+p2+","+p3);
              if (/^-+$/.test(p3)) return str;
              return p1+htmlCharize(p2)+p3+htmlCharize(p2);
            });
          }
          
          s=s.replace(/\(c\)|\(tm\)|\(r\)|-{5,}|[A-Z]{2,}\([^)]+\)/g, "[==$&==]");
          
          s=s.replace(/([^-])(-{2,4}(?!-))/gi, function(str, p1, p2, offset, fullstr) {return p1+htmlCharize(p2);});
          
          s=s.replace(/\[(<.+?>)\]/g, "&#91;$1&#93;");
          //-----------
          //Escape: end, Format: begin
          //-----------
          s=s.replace(/<acronym=([^>)]+)>([A-Z]{2,})<\/acronym>/g, "$2($1)");
          s=s.replace(/<acronym[^>]*>(.+?)<\/acronym>/g, "$1");
          //var myReplSimpleFormatRegex = new RegExp(, 'g');
          
          for(var tag in basic_fomat_chars)
          {
            var myTagRegEx = new RegExp("(\\w?)<"+tag+">(\\s*)([\\s\\S]*?)(\\s?)</"+tag+">(\\w?)", 'g');
            s=s.replace(myTagRegEx, function(str, p1, p2, p3, p4, p5, offset, fullstr)
            {
              if (p3==="") return p1+p2+p4+p5;
              var b = p1!=="" || p5!=="" || p4!=="";
              if ((tag==="sup"||tag==="sub")&&!b)
              {
                if (offset>0&&!fullstr.charAt(offset-1).match(/[\s\^~]/))
                {
                  b=true;
                }
              }
              //alert(p1+','+p2+','+p3+','+p4+','+p5);

              return p1+(b?"[":"")+basic_fomat_chars[tag]+htmlCharize(p2)+p3+p4+basic_fomat_chars[tag]+(b?"]":"")+p5;
              
              //DONE: Escape brackets in titles and quotes in links!
            });
          }
          
          s=s.replace(/<bracket>/g, "\(");
          s=s.replace(/<\/bracket>/g, "\)");
          
          s=s.replace(/<link>([0-9A-Z%].*?)<\/link>/gi, function(str, p1, offset, fullstr)
          {
            return unescape(p1);
          });
          
          //alert(s);
          //$('#mymymy').val(s);
          //clipdata.setData("Text", s)
          e.preventDefault();
          //this.value = s;
          $(this).selection('replace', {
            text: s,
            caret: 'end'
          });
        } catch(ex) {
          //DONE: add user-friendly error-handling!<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
          $('#clipformat_error').show();
          $('#clipformat_error').attr("title", ex + "\nname: " + ex.name + "\nmessage: " + ex.message + "\nstack: " + ex.stack);
          //alert(s);
          
          //alert(err);
        }
        /*finally {
          
        }*/
        
      }
      else /*alert("Nope.jpg")*/;
    });
  });
  
  // removes MS Office generated guff by Anthony (http://forums.squizsuite.net/index.php?showtopic=11304)
  function cleanHTML(input) {
    // 1. remove line breaks / Mso classes
    var stringStripper = /(\n|\r| class=(")?Mso[a-zA-Z]+(")?)/g; 
    var output = input.replace(stringStripper, ' ');
    // 2. strip Word generated HTML comments
    var commentSripper = new RegExp('<!--(.*?)-->','g');
    var output = output.replace(commentSripper, '');
    var tagStripper = new RegExp('<(/)*(meta|link|span|\\?xml:|st1:|o:|font)(.*?)>','gi');
    // 3. remove tags leave content if any
    output = output.replace(tagStripper, '');
    // 4. Remove everything in between and including tags '<style(.)style(.)>'
    var badTags = ['style', 'script','applet','embed','noframes','noscript'];
    
    for (var i=0; i< badTags.length; i++) {
      tagStripper = new RegExp('<'+badTags[i]+'.*?'+badTags[i]+'(.*?)>', 'gi');
      output = output.replace(tagStripper, '');
    }
    // 5. remove attributes ' style="..."'
    var badAttributes = ['style', 'start'];
    for (var i=0; i< badAttributes.length; i++) {
      var attributeStripper = new RegExp(' ' + badAttributes[i] + '="(.*?)"','gi');
      output = output.replace(attributeStripper, '');
    }
    return output;
  }
  
  function flashElement($el) {
    $el.css({outline:'1px solid yellow'});
    setTimeout(function() {
      $('#clipformat_check').trigger("change");
    }, 500);
  }
  
  function decodeSimpleHTMLEntities(text) { //by William Lahti
    var entities = [
        ['apos', '\''],
        ['amp', '&'],
        ['lt', '<'],
        ['gt', '>']
    ];

    for (var i = 0, max = entities.length; i < max; ++i) 
        text = text.replace(new RegExp('&'+entities[i][0]+';', 'g'), entities[i][1]);

    return text;
  }
  
})( jQuery );

/*
Notes:

regulars:
<b>(?=\S)([^<]*?\S)<\/b> -nope

(\w?)<b>(\s*)(.*?)(\s*)<\/b>(\w?) -yup
*/