Jump to content

User:Plastikspork/monobook.js/script.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Plastikspork (talk | contribs) at 21:57, 27 May 2020 (Test). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// ---------------------------------------  --------------------------------------- //
// ----------------------------------- Credits ------------------------------------ //
//
// This script was created by modifying the following scripts:
//      [[User:Lightmouse/monobook.js/script.js]]
//      [[Wikipedia:WikiProject User scripts/Scripts/Formatter]]
//
// This script is intended to be complimentary to these scripts with very little
// to no duplication of function.

// ---------------------------------- Disclaimer ---------------------------------- //
//
// Use at your own risk and make sure you check the edit changes before you save
//
// Let me know [[User_Talk:Plastikspork]] if you find bugs!

// ----------------------------- Installing the Script ---------------------------- //
//
// (1) Open/Create your USERNAME/monobook.js page, where USERNAME is your username.
//     A quick way to get there is to go to your user page, then append
//     '/monobook.js' to the end of the URL.
//
// (2) Put the following command on your monobook.js page:
//          importScript('User:Plastikspork/monobook.js/script.js');
//
// (3) Save the page and reload it by following the instructions at the top of your
//     monobook.js page.  For example, Ctrl+Shift+R in Firefox.

// ------------------------------- Using the Script ------------------------------- //
//
// (1) Open an article which you would like to edit, and you should see a bunch of
//     'Spork' buttons in your 'toolbox' on the left side of your browser.
//
// (2) Click on one of the Spork buttons and the script will run, performing edits
//     by pattern matches.  When it is finished, it will show you the changes and
//     add some comments to the edit summary.  It is up to you to accept these
//     changes as is by clicking 'Save page', modify the changes by further editing
//     the edit form, or reject by leaving the page.
//
//  Note: The script will run very slowly on very large pages, but it does always
//        eventually complete in my experience.

// ----------------------------- Current Functionality ---------------------------- //
//
// [Sprk: WS] Removes excessive non-essential whitespace, non-breaking space, and
//        some minor wikification.
//
// [Sprk: Wki/Lnk Rpair] Wikification, fixes of simple repeated references,
//        conversion of external wikilinks to wikilinks, and simplification of
//        piped wikilinks.
//
// [Sprk: [] to Refs] Replaces [URL] with <ref>URL</ref>
//
// [Sprk: Cite Templte] Adds citation templates to some common
//        untemplated references.
//
// [Sprk: Ref Repeat] Fixes obvious repeated references and marks
//        non-obvious ones for human inspection with REPEAT tags.
//        Once the script runs, you can inspect the tagged refs to
//        see if they are actual repeats, or if they are false
//        positives.
//
// [Sprk: Color] Simplifies some hex color codes to named colors.
//
// [Sprk: Table to Wiki] An attempt to turn HTML tables into
//        wikitables.  Requires some hand tuning after it runs.
//
// ----------------------- Turning off and Renaming Buttons ----------------------- //
//
// The buttons in the script can be selectively disabled and renamed, to rename a
// button, say 'Sprk: WS' to 'Spork: Whitespace', paste the following into your
// monobook.js:
//
//  if( typeof( SporkConfig ) == 'undefined' ) SporkConfig = {};
//  SporkConfig.ws = "Spork: Whitespace";
//
// To rename more buttons, just add an additional line for each button. The initial
// creation of the empty structure only needs to be performed once.
//
// To remove a button, give it a null string for its name. For example,
//
//  if( typeof( SporkConfig ) == 'undefined' ) SporkConfig = {};
//  SporkConfig.ws = "";
//
// will turn off the 'Sprk: WS' button.
//
// The variable names for each button can be found in the code directly below.
// ---------------------------------------  --------------------------------------- //

// Set Default Button Names
if( typeof( SporkConfig ) == 'undefined' ) SporkConfig = {};
if( typeof( SporkConfig.wlr  ) == 'undefined' ) SporkConfig.wlr  = "Sprk: Wki/LinkRepair";
if( typeof( SporkConfig.b2r  ) == 'undefined' ) SporkConfig.b2r  = "Sprk: [] to Refs";
if( typeof( SporkConfig.ct   ) == 'undefined' ) SporkConfig.ct   = "Sprk: CiteTemplate";
if( typeof( SporkConfig.rr   ) == 'undefined' ) SporkConfig.rr   = "Sprk: Ref Repeat";
if( typeof( SporkConfig.ws   ) == 'undefined' ) SporkConfig.ws   = "Sprk: WS";
if( typeof( SporkConfig.c    ) == 'undefined' ) SporkConfig.c    = "Sprk: Color";
if( typeof( SporkConfig.t2w  ) == 'undefined' ) SporkConfig.t2w  = "Sprk: Table to Wiki";
if( typeof( SporkConfig.noa  ) == 'undefined' ) SporkConfig.noa  = ""; // testing 1
if( typeof( SporkConfig.tst  ) == 'undefined' ) SporkConfig.tst  = ""; // testing 2
if( typeof( SporkConfig.fullurl  ) == 'undefined' ) SporkConfig.fullurl  = ""; // testing 3

// ---------------------------------------  --------------------------------------- //
// Import Spork-Tools scripts

importScript('User:Plastikspork/tools.js');
importScript('User:Plastikspork/whitespace.js');
importScript('User:Plastikspork/citetools.js');
importScript('User:Plastikspork/reftools.js');
importScript('Wikipedia:AutoEd/htmltowikitext.js');
importScript('Wikipedia:AutoEd/tablestowikitext.js');
importScript('Wikipedia:AutoEd/extrabreaks.js');
importScript('Wikipedia:AutoEd/headlines.js');
importScript('Wikipedia:AutoEd/unicodify.js');
importScript('Wikipedia:AutoEd/unicodehex.js');
importScript('Wikipedia:AutoEd/wikilinks.js');


function autoEdDashes (str)
{
  if (str.search(/nodashes/i) >= 0)
    return str;

  var scpat = /\bscores?\b|\[\[Category:.*\b(sport|athlet|players|teams|games|league|champion|tournament|competit|cup\b|\w+ball\b|hockey|lacrosse|cricket|rugby|tennis|golf|polo|boxing|boxers|martial.art|chess)/i;
  var scoresAreLikely = (str.search(scpat) >= 0);

  // Ensure the replacement isn't a link such as [[FOO - BAR]] before
  // replacing it, so that we don't break the link. But we do want to
  // replace dashes used in the right-side label part of links.  Also,
  // don't break templates, URLs, DOIs, {{#expr:}}, <math> equations,
  // source code, or <ref name="13-70">.
  //
  function ifNotLink (str)
  {
    var pos    = arguments[ arguments.length - 2 ];
    var string = arguments[ arguments.length - 1 ];

    var pat = /\[\[[^|\]]*$|\{\{[^|}]*$|[:\/%][^\s|>]+$|<[^>]*$|#\w*expr:.*$/i;
    if (string.substring(pos-260,pos+1).search(pat) >= 0)
        return str;             // it's a link, so don't change it

    var pat2 = /\{\{(main|see|detail|about|for\b|other|redir|conv|coor|sort|anchor|DNB(?: [Cc]ite|)|[Cc]ite DNB)[^}]*$/i;
    if (string.substring(pos-260,pos+1).search(pat2) >= 0)
        return str;             // likely templates with page-name or neg params
        
    var pat3 = /\|\s*(CAS_number)\s*=\s*/i;
    if (string.substring(pos-260,pos+1).search(pat3) >= 0)
        return str;             // drugbox CAS_number
        
    var pat4 = /\|\s*(doi|isbn)\s*=\s*/i;
    if (string.substring(pos-260,pos+1).search(pat4) >= 0)
        return str;             // doi or isbn

    var m = string.slice(pos).search(/<\/?(math|pre|code|tt|source|syntaxhighlight|gallery)\b/i);
    if (m >= 0 && string.charAt(pos+m+1) == '/')
        return str;             // don't break a <math> equation, or source code

    if (string.slice(pos).search(/^[^|{}[\]<>\n]*\.([a-z]{3,4}\s*[|}]|jpg|png|svg)|^.*hyphen/i) >= 0)
        return str;             // it's a file name parameter, or <!--sic hyphen-->
        
    m = string.slice(pos).search(/\{\{[\s]*[Gg]raph:Chart\b/i);
    if (m >= 0)
        return str;             // don't break a Graph:CHart
    
    if (str.search(/[ |(>][-–]\b/) >= 0)
        return str.replace(/[-–]/, "−");       // minus sign
    else
        return str.replace(/--+\b/g, "—") . replace(/[-–−]+/g, "–");     // dash
  }

  str = str.replace(/\s--?\s/g, ifNotLink);                 // en dash looks better
  str = str.replace(/[a-z\d]---?[a-z\d]/ig, ifNotLink);     // em dash
  str = str.replace(/\d\d\d]*}*[-−](present|current)\b/ig, ifNotLink);       // 1973-present
  str = str.replace(/[^\w−-](18|19|20)\d\d]*}*[-−][^\w−-]/g, ifNotLink);     // (1973-)
  str = str.replace(/\d(s|%|\?|''')[-−]\d/g, ifNotLink);    // 1950s-1960s, 40%-50%
  str = str.replace(/\d[-−](\$|'+)\d/g, ifNotLink);         // $40-$50, 7-'''4''', '49-'53
  str = str.replace(/[½⅓⅔¼¾⅛⅜⅝⅞]%?[-−][\d½⅓⅔¼¾⅛⅜⅝⅞]/g, ifNotLink);           // 3½-6
  str = str.replace(/\d(st|nd|rd|th)?[-−]\d+(st|nd|rd|th)\b/g, ifNotLink);   // 2nd-3rd

  str = str.replace(/([a-z,'"”\]>] +|\(|^\| *|\|\| *)[-–]\d/mig, ifNotLink);   // minus -35
  str = str.replace(/<((sup|sub|td)>\s*)[-–](\d)/ig, "<$1−$3");         // 10<sup>-3</sup>
  str = str.replace(/,*(?=.? ) *[-–—−] *(\d*:\d\d[\s*<])/g, " – $1");   // album track listings

  // November 15, 2005-March 7, 2006; [[March 18]]-[[April 4]]
  str = str.replace(/(\d\]*)[-–—−](\[*(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]* +\d)/g, "$1 – $2");
  // July-August 2007
  str = str.replace(/\b((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*[-−]?\b){2,}/g, ifNotLink);
  // [[266]]-[[283]]
  str = str.replace(/(\d(?: BC)?\]\])[-−]((ca?\.|AD ?)?\[\[\d+[^\d-])/g, "$1–$2");
  // (1984 – 1992)
  str = str.replace(/([(|=] *\[*\d+\]*) +[–—−] +(\[*\d+\]*\s*[)|}])/g, "$1–$2");
  // iv-xii
  str = str.replace(/[ ;(=](?=\w+-)(m*(cm|cd|d?c*)(xc|xl|l?x*)(ix|iv|v?i*)-?\b){2}[^\w-]/g, ifNotLink);

  if (scoresAreLikely)      // W-L-D or 73–70–67–70=280, but not castling
    str = str.replace(/[^\w−–-](?!0-0-0)(\d\d?\d?[-–−]){2,}\d\d?[^\w\/−–-]/g, ifNotLink);

  str = str.replace(/\b(\d+)[–−](year|month|day|hour|minute|mile|yard|foot|inch|bit|door|speed|gun|page|seat|way|point|ton|man)\b/g, "$1-$2");     // hyphen

  // Number ranges and scores should use en dashes, per [[MOS:DASH]].
  // This has been well-tested and false positives (e.g., ID nos.) are rare.
  //
  function range (str, from,to, pos,string)
  {
    var dash   = true;
    var except = /\b(fig(ure)?|table|example|exhibit|circular|section|part|number|no|nr|id|model|pub|std|report|rpt|law|[P.]L|p|page|date|IS\wN\b[ a-z]*|SCOTUS)[^\w(,;]*$/i;
    var rpat   = /^([^A-Za-z]|nbsp)*(AD|BC|B?CE|BP|[kMG]a|km|mi|kg|lb|\w?Hz|vote|decision|record|odds|scor\w*|win|loss|tie|draw|lead|victory|defeat|upset|run|deficit|start|finish|season|game)\b/;
    var lpat   = /\b(pages|pp|rp|nos|\d+\)?'*[:,]|(w[io]n|lost?|tie|dr.w|lea?d|f.ll|vot|rul|decid|pass|fail|defeat|scor|gam|match|trail|finish|end)e?[ds]?|\w\w+ing|ahead|behind|up|down|from|to|is|are|was|were|of|out|by|an?|at|it|went|go|gone|beaten|between)([^a-z]|nbsp)*$/i;
    var inorder   = (to-0 > from.slice(-to.length));     // pp 362-5
    var precision = Math.max( from.search(/0*$/), to.search(/0*$/) );

    if (string.substring(pos-20,pos+1).search(except) >= 0) {
        return str;      // based on preceding word, looks like a ref number
    }
    if (from == 9 && to == 11) {
        dash = false;    // 9-11 is a common special case
    }
    if (from-0 >= to) {
        dash = false;    // values don't look like a range
    }
    if (to-from > 120 && from * (precision > 2 ? 5 : 50) < to && from > 1) {
        dash = false;    // values don't look like a range
    }
    if (scoresAreLikely && from <= 900 && to <= 900) {
        dash = true;     // likely a score or wins-losses
    }
    if (from < 2-to && string.search(/Category:.*\bChess\b/i) >= 0) {
        dash = false;    // chess notations 0-0, 0-1, 1-0
    }
    if (str.charAt(0) == '(' && string.charAt(pos + str.length) == ')') {
        dash = true;     // scores often seen as (8-4)
    }
    if (from.search(/^0./) >= 0 || to.search(/^0./) >= 0) {
        dash = false;    // 3-07 and 0123-4567 look like ref numbers
    }
    if (string.substr(pos-1,15).search(/^\d([:,.])\d+.\d+\1\d/) >= 0) {
        dash = true;     // 10:30-11:30, 35,000-40,000, 2.5-4.0
    }
    if (string.substr(pos,30).search(rpat) >= 0) {
        dash = true;     // 12-5 BC, 5-5000&nbsp;km, 6-4 win, 73-50 vote
    }
    if (string.substring(pos-80,pos).search(lpat) >= 0) {
        dash = true;     // pp.&nbsp;8, 25, 270-74, 313-7; won 6-4, 6-2
    }
    if (from > 1000 && from < 2100 && to.length == 2 && inorder) {
        dash = true;     // 1994-95 year range
    }
    return dash ? ifNotLink(str,pos,string) : str;
  }

  str = str.replace(/[^\w\/+−–-](\d{1,4})[-−](\d{1,4})(?!'*[\w\/+−–-])/g, range);

  return str;
}

// ---------------------------------------  --------------------------------------- //


// Spork: Wiki/LinkRepair
function spork_wiki_link_repair(clk){
  var txt = document.editform.wpTextbox1;
  txt.value = autoEdUnicodify(txt.value);           //See WP:AutoEd/unicodify.js
  txt.value = autoEdHTMLtoWikitext(txt.value);      //See WP:AutoEd/htmltowikitext.js
  txt.value = autoEdHeadlines(txt.value);           //See WP:AutoEd/headlines.js
  txt.value = spork_external_links(txt.value);
  txt.value = spork_extern_wikilinks_to_wikilinks(txt.value); // See User:Plastikspork/tools.js
  txt.value = spork_ref_clean(txt.value);
  txt.value = autoEdUnicodeHex(txt.value);          //See WP:AutoEd/unicodehex.js
  txt.value = spork_special_char(txt.value);
  txt.value = autoEdWikilinks(txt.value);           //See WP:AutoEd/wikilinks.js
  txt.value = spork_convert(txt.value);
  txt.value = spork_lists(txt.value);
  txt.value = txt.value.
        replace(/&mdash;/g, '—').
        replace(/&ndash;/g, '–').     // simplify core regexes
        replace(/&minus;/g, '−');
  txt.value = autoEdDashes(txt.value);

  spork_edit_summary("wikification");
  spork_edit_summary("link repair");

  if(clk) document.editform.wpDiff.click();
}

// Spork: [] to ref
function spork_bracket_to_ref(clk){
  var txt = document.editform.wpTextbox1;

  txt.value = spork_bracket_url_to_ref(txt.value);

  spork_edit_summary("wikification");

  if(clk) document.editform.wpDiff.click();
}

// Spork: CiteTemplate
function spork_citation_template(clk){
  var txt = document.editform.wpTextbox1;

  txt.value = txt.value.replace(/([\[]+http[^\[\]<>]*)(<!-- Bot generated title -->)([\]]+)/gi, '$1$3$2');
  txt.value = txt.value.replace(/(<ref[^<>\/]*>[^<>]*)(<!-- Bot generated title -->)([^<>]*<\/ref>)/gi, '$1$3$2');
  txt.value = spork_cite_web(txt.value);
  txt.value = spork_cite_article(txt.value);
  txt.value = txt.value.replace(/(<ref[^<>\/]*>[^<>]*)(<\/ref>)(<!-- Bot generated title -->)/gi, '$1$3$2');
  txt.value = txt.value.replace(/(\{\{cite[^}]*\|[ ]*title[ ]*=[^\|}]*)([^\|}]*?\}\}[^<>]*)(<!-- Bot generated title -->)/gi, '$1$3$2');
  txt.value = txt.value.replace(/([\[]+http[^\[\]<>]*)([\]]+)(<!-- Bot generated title -->)/gi, '$1$3$2');

  spork_edit_summary("cite template");

  if(clk) document.editform.wpDiff.click();
}

// Spork: Ref Repeat
function spork_ref_repeat(clk){
  var txt = document.editform.wpTextbox1;

  txt.value = spork_ref_clean(txt.value);

  // Mark duplicate ref names with NAME REPEAT1 REPEAT2 (change to name by hand and re-run script)
  txt.value=txt.value.replace(/<ref name[ ]*=[ ]*(["'])([^'"<>]*)\1[ ]*>((?:.|[\r\n])*)<ref name[ ]*=[ ]*\1\2\1[ ]*>/gim, '<ref name=$1$2$1><!-- NAME REPEAT1 -->$3<ref name=$1$2$1><!-- NAME REPEAT2 -->');
  // Mark repeated references with REPEAT (change to name by hand and re-run script)
  txt.value=txt.value.replace(/<ref>([^<>]*)<\/ref>((?:.|[\r\n])*)<ref>\1<\/ref>/gim, '<ref><!--REPEAT-->$1</ref>$2<ref>$1</ref>');
  // Mark possible repeated references with REPEAT1 REPEAT2 (change to name by hand and re-run script)
  txt.value=txt.value.replace(/(<ref[^<>]*>)(|[^<>]*[^<>\/])(https?:[^ <>\[\]\|]*)([ \|}\]][^<>]*)<\/ref>((?:.|[\r\n])*)(<ref[^<>]*>)(|[^<>]*[^<>\/])\3([ \|}\]][^<>]*)<\/ref>/gim, '$1<!--?REPEAT1?-->$2$3$4</ref>$5$6<!--?REPEAT2?-->$7$3$8</ref>');

  spork_edit_summary("ref simplification");

  if(clk) document.editform.wpDiff.click();
}

// Spork: WS
function spork_ws_compress(clk){
  var txt = document.editform.wpTextbox1;

  txt.value = spork_whitespace(txt.value);           //See User:Plastikspork/whitespace.js
  txt.value = spork_ws_refs(txt.value);              //See User:Plastikspork/whitespace.js
  txt.value = spork_ws_nowrap(txt.value);            //See User:Plastikspork/whitespace.js
  txt.value = txt.value.replace(/<[\/\\ ]*br[ ]+clear[ ]*=["' ]*all['" ]*\/?>/gi, '\{\{-\}\}');
  txt.value = autoEdExtraBreaks(txt.value);          //See WP:AutoEd/extrabreaks.js
  txt.value = spork_ws_tables_infoboxes(txt.value);  //See User:Plastikspork/whitespace.js
  txt.value = autoEdUnicodeHex(txt.value);           //See WP:AutoEd/unicodehex.js
  txt.value = spork_special_char(txt.value);
  txt.value = spork_whitespace(txt.value);           //See User:Plastikspork/whitespace.js

  spork_edit_summary("wikification");
  spork_edit_summary("WS removal");

  if(clk) document.editform.wpDiff.click();
}

// Spork: Color
function spork_color(clk){
  var txt = document.editform.wpTextbox1;

  txt.value = spork_color_simple(txt.value);

  spork_edit_summary("color simplification");

  if(clk) document.editform.wpDiff.click();
}

// Spork: Table to Wiki
function spork_wiki_table(clk){
  var txt = document.editform.wpTextbox1;

  txt.value = autoEdTablestoWikitext(txt.value);

  spork_edit_summary("wikification");

  if(clk) document.editform.wpDiff.click();
}

// Spork: No Align
function spork_no_align(clk){
  var txt = document.editform.wpTextbox1;

  txt.value=txt.value.replace(/([\r\n]\||\|\||[\r\n]!|!!|\|-)([ ]*[a-z][^\|!]* |[ ]*)align[ ]*=["' ]*(?:center|left|right)['" ]*/gi, '$1$2 ');
  txt.value=txt.value.replace(/([\r\n]\||\|\||[\r\n]!|!!|\|-)([ ]*[a-z][^\|!]* |[ ]*)(style[ ]*=["' ]*)([ ]*[a-z][^'"\|!]*;|[ ]*)text-align[ ]*:[ ]*(?:center|left|right);?[ ]*/gi, '$1$2$3$4');
  txt.value=txt.value.replace(/([^a-z])style[ ]*=[ ]*["'][ ]*['"]/gi, '$1 ');
  txt.value=txt.value.replace(/([\r\n]\||\|\||[\r\n]!|!!|\|-)[ ]+\|([^\|])/g, '$1 $2');
  txt.value=txt.value.replace(/<[\/]*center[ ]*>/gi, '');
  txt.value=txt.value.replace(/([\r\n]\||\|\||[\r\n]!|!!|\|-)[ ]+([\r\n])/g, '$1$2');
  txt.value=txt.value.replace(/<span [^<>]*>/g, '');
  txt.value=txt.value.replace(/<\/span>/g, '');

  spork_edit_summary("table simplification");
  if(clk) document.editform.wpDiff.click();
}

// Spork: Testing
function spork_testing(clk){
    // Spork: WS
    spork_ws_compress(0);
    // Spork: Wiki/Link/Repair
    spork_wiki_link_repair(0);
    // Spork: [] to Refs
    spork_bracket_to_ref(0);
    // Spork: CiteTemplate
    spork_citation_template(0);
    // Spork: Ref Repeat
    spork_ref_repeat(0);
    // Spork: Color
    spork_color(0);
    // Spork: WS
    spork_ws_compress(0);

    // WP:DATE
    var txt = document.editform.wpTextbox1;
//    txt.value = txt.value.replace(/(\(|years_?active[\s]*=[\s]*)([12][0-9]{3})[\s]*(?:[–—\-–]| to[\s]+present|[–—\-–][\s]*present)([\s]*\)|[\s]*\||[\s]*\}\}|[\s]*$)/gi, '$1since $2$3');

    //txt.value=txt.value.replace(/\[http:\/\/www\.hulu\.com\/watch[^ \[\]]*\]/g, '');
    //txt.value=txt.value.replace(/\[http:\/\/www\.hulu\.com\/watch[^ \[\]]* ([^\[\]]*)\]/g, '$1');

    document.editform.wpSummary.value = "Script assisted wikification";
    if(clk) document.editform.wpDiff.click();
}

// Spork: Fullurl Template
function spork_fullurl(clk){
    // WP:DATE
    var txt = document.editform.wpTextbox1;
    var loopcount = 0;

    txt.value = txt.value.replace(/\{\{SERVER\}\}\/wiki\/([^\?]*)\?([^\[\]{}\|\r\n ]*)([}\]\| \r\n])/gi, '\{\{fullurl:$1|$2\}\}$3');
    txt.value = txt.value.replace(/http:\/\/en\.wikipedia\.org\/wiki\/([^\?]*)\?([^\[\]{}\|\r\n ]*)([}\]\| \r\n])/gi, '\{\{fullurl:$1|$2\}\}$3');
    txt.value = txt.value.replace(/http:\/\/en\.wikipedia\.org\/w\/index\.php\?title=([^&]*)&([^\[\]{}\|\r\n ]*)([}\]\| \r\n])/gi, '\{\{fullurl:$1|$2\}\}$3');
    txt.value = txt.value.replace(/https:\/\/secure\.wikipedia\.org\/wikipedia\/en\/wiki\/([^\?]*)\?([^\[\]{}\|\r\n ]*)([}\]\| \r\n])/gi, '\{\{fullurl:$1|$2\}\}$3');
    loopcount = 0;
    while( txt.value.search( /\{\{fullurl:Special:Search\|[^}]*&search=[^&}]*%20/gi ) >= 0 && loopcount <= 10 ) {
      txt.value = txt.value.replace(/(\{\{fullurl:Special:Search\|[^}]*&search=[^&}]*)%20/gi, '$1+');
      loopcount++;
    }
    loopcount = 0;
    while( txt.value.search( /\{\{fullurl:Special:Search\|[^}]*&search=[^&}]*%27/gi ) >= 0 && loopcount <= 10 ) {
      txt.value = txt.value.replace(/(\{\{fullurl:Special:Search\|[^}]*&search=[^&}]*)%27/gi, "$1'"); // "'"
      loopcount++;
    }

    document.editform.wpSummary.value = "Script assisted wikification";
    if(clk) document.editform.wpDiff.click();
}


// --------------------------------- WS Functions --------------------------------- //

// Called by Spork: WS
function spork_special_char(str) {
  str=str.replace(/([a-z][ ]*) -- ([ ]*[a-z])/gi, '$1 – $2');
  str=str.replace(/&mdash;/gi, '—');
  str=str.replace(/&ndash;/gi, '–');
  // str=str.replace(/[‘’]/g, "'"); //'
  // str=str.replace(/[“”]/g, '"'); //"

  return str;
}

// Called by Spork: Wiki/LinkRepair
function spork_external_links(str) {
  // Common broken links
  str=str.replace(/(\[https?:[^\[\]]+\])([a-z])/gi, '$1 $2');
  str=str.replace(/(\[https?:\/\/[^\]\[\| ]+)[\s]*(?:\||\[)[\s]*([^\]\[\|]*\])/gi, '$1 $2');
  // Convert links to secure wikipedia to standard wikipedia
  str=str.replace(/\https:\/\/secure.wikimedia.org\/wikipedia\/([a-z]+)\//g, 'http://$1.wikipedia.org/');
  // Linking to upload page rather than image page
  str=str.replace(/http:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/[a-z0-9]\/[a-z0-9][a-z0-9]\//gi, 'http://commons.wikimedia.org/wiki/Image:');
  // Punctuation inside external links
  str=str.replace(/(\[https?:[^\[\]\| ]*)[\| ][ ]*([']+|["]+)([^"'\|\[\]]*)\2([:\.,\? ]*\])/g, '$2$1 $3$4$2');
  str=str.replace(/(\[https?:[^\[\]\| ]*)[\| ][ ]*([‘’]|[“])([^“’‘\|\[\]]*)([‘’]|[”])([:\.,\? ]*\])/g, '$2$1 $3$5$4');
  // Extra brackets around references
  str=str.replace(/\[(\[)(http|ftp|https)(:[^\[\]]+\])\]/gi, '$1$2$3');
  // Extra brackets inside references
  str=str.replace(/(<ref[^<>\/]*>)\[([^\[\]<> ]*)\](<\/ref>)/gi, '$1$2$3');

  // Convert "external wikipedia" image references to (PIC) links
  str=str.replace(/(\[)http:\/\/(commons)\.wikimedia\.org\/wiki\/(Image:[^ \[\]\|<>]*)(\])/gi, '($1$1$2:$3|pic$4$4)');
  str=str.replace(/(\[)http:\/\/en\.wikipedia\.org\/wiki\/Image(:[^ \[\]\|<>]*)(\])/gi, '($1$1:File$2|pic$3$3)');

  return str;
}

// Called by Spork: Wiki/LinkRepair
function spork_convert(str) {
  // Template Fun
  str=str.replace(/ ([1-9])[ ]*'[ ]*([1-9]|1[01])[ ]*"[ ]*\([12]\.[0-9][0-9]?[ ]*m\)/g, ' \{\{height|ft=$1|in=$2\}\}'); // " '
  str=str.replace(/ ([0-9][0-9,\.]*)(&nbsp;| )+(\[\[)square mile(\]\])s[ ]+\([0-9][0-9,\.]*(&nbsp;| )+(\[\[)km²(\]\])\)/g, ' \{\{convert|$1|sqmi|km2|lk=on\}\}');
  str=str.replace(/ ([0-9][0-9,\.]*)(&nbsp;| )+(\[\[)square mile(\]\])s[ ]+\([0-9][0-9,\.]*(&nbsp;| )+km²\)/g, ' \{\{convert|$1|sqmi|km2|lk=in\}\}');
  str=str.replace(/ ([0-9][0-9,\.]*)(&nbsp;| )+square miles[ ]+\([0-9][0-9,\.]*(&nbsp;| )+(\[\[)km²(\]\])\)/g, ' \{\{convert|$1|sqmi|km2|lk=out\}\}');
  str=str.replace(/ ([0-9][0-9,\.]*)(&nbsp;| )+square miles[ ]+\([0-9][0-9,\.]*(&nbsp;| )+km²\)/g, ' \{\{convert|$1|sqmi|km2\}\}');
  str=str.replace(/ ([0-9][0-9,\.]*) people per square mile \([0-9][0-9,\.]*\/km²\)/g, ' \{\{convert|$1|PD/sqmi|/km2\}\}');
  str=str.replace(/ ([0-9][0-9,\.]+) people per square mile/g, ' \{\{convert|$1|PD/sqmi|/km2\}\}');
  str=str.replace(/ ([0-9][0-9,\.]*)\/sq&nbsp;mi \([0-9][0-9,\.]*\/km²\)/g, ' \{\{convert|$1|/sqmi|/km2\}\}');
  str=str.replace(/(\{\{convert\|[0-9]+),/g, '$1');

  return str;
}

// Called by Spork: Wiki/LinkRepair
function spork_lists(str) {

  // Wikify bullet lists
  str=str.replace(/([\r\n])•(.*[\r\n])[\r\n]/gim, '$1* $2');
  // Convert all-bold lines to use semicolon markup
  str=str.replace(/([\r\n])'''([^':]*)[']*[ ]*<[\\\/\. ]*BR[^<>]*>([\r\n])/gi, '$1;$2$3');
  str=str.replace(/([\r\n])'''([^':]*)[']*[ ]*([\r\n])/gi, '$1;$2$3');

  return str;
}

// ------------------------------- Color  Functions ------------------------------- //

// Called by Spork: Color
function spork_color_simple(str){

 str=str.replace(/([\r\n]\||[\r\n]!|\|\||!!)([^\|!<>\[\]]*)style[ ]*=[" ]*color[ ]*:[ ]*([a-z0-9\#]*)[; ]*[ "]*([^\|!<>\[\]]*\|)([^\|])/gi, '$1$2 $4<font color="$3">$5');
 str=str.replace(/([\r\n]\||[\r\n]!|\|\||!!)([^\|!<>\[\]]*style[ ]*=[ ]*"[^"<>\|!]*;)[ ]*color[ ]*:[ ]*([a-z0-9\#]*)[ ;]*([^\|!<>\[\]]*\|)([^\|])/gi, '$1$2$4<font color="$3">$5');
 str=str.replace(/<span style=[ "]*(background|background-color):([^ ";]*)[; ]*[" ]*>((&nbsp;){1,4}|\{\{nbsp\|[1-4]\}\})<\/span>/gi, '\{\{colorbox|$2\}\}'); //"
 str=str.replace(/<span style="(background|background-color):([^ ";]*)[; ]*">([^<>]*)<\/span>/gi, '\{\{colorbox|$2|$3\}\}'); //"
 str=str.replace(/(\|\|[^\|\r\n]*)style="(?:background|background-color):([^ ";]*)[; ]*"/gi, '$1bgcolor="$2"'); //"
 str=str.replace(/([\r\n]\|[^\|\r\n]*)style="(?:background|background-color):([^ ";]*)[; ]*"/gi, '$1bgcolor="$2"'); //"
 str=str.replace(/bgcolor="(transparent|none)"/gi, 'style="background: $1"');
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?000000\2/gi,  '$1$2black$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?0000FF\2/gi,   '$1$2blue$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?A52A2A\2/gi,  '$1$2brown$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FF7F50\2/gi,  '$1$2coral$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?00FFFF\2/gi,   '$1$2cyan$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FF00FF\2/gi,'$1$2fuchsia$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FFD700\2/gi,   '$1$2gold$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?808080\2/gi,   '$1$2gray$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?008000\2/gi,  '$1$2green$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?00FF00\2/gi,   '$1$2lime$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FF00FF\2/gi,'$1$2magenta$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?800000\2/gi, '$1$2maroon$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?000080\2/gi,   '$1$2navy$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?808000\2/gi,  '$1$2olive$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FFA500\2/gi, '$1$2orange$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FFC0CB\2/gi,   '$1$2pink$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?800080\2/gi, '$1$2purple$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FF0000\2/gi,    '$1$2red$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?C0C0C0\2/gi, '$1$2silver$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?D2B48C\2/gi,    '$1$2tan$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?008080\2/gi,   '$1$2teal$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?EE82EE\2/gi, '$1$2violet$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FFFFFF\2/gi,  '$1$2white$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FFFF00\2/gi, '$1$2yellow$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?FFF5EE\2/gi,'$1$2seashell$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?F08080\2/gi,'$1$2lightcoral$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\||color[ ]*=|color[ ]*:)[ ]*("?)#?D2691E\2/gi,'$1$2chocolate$2'); // "
 str=str.replace(/(color[ ]?box[ ]*\|)[ ]*"([^\|}{]*)"/gi, '$1$2');

 // Font tag outside of footnote
 str=str.replace(/(<font[^<>]*>[ ]*)(\[\[#fn[^\|\]]*\|)/gi, '$2$1');

 return str;
}

// ------------------------------ testing  Functions ------------------------------ //

function spork_newlines(str) {
  var loopcount = 0;
  // Extra newlines after section headings
  str = str.replace(/([\r\n]=.*=[\r\n])[\t ]*[\r\n][\t ]*([\r\n])/gim, '$1$2');

  // newlines in citation templates (multiple times)
  str = str.replace(/(\{\{(?:cite|citation))[\r\n]/gim, '$1 ');
  loopcount = 0;
  while( str.search( /\{\{(?:cite|citation) [^}]*[\r\n]/gi ) >= 0 && loopcount <= 10 ) {
    str=str.replace(/(\{\{(?:cite|citation) [^}]*)[\r\n]/gim, '$1 ');
    loopcount++;
  }

  // Extra newlines after before bullets
  str=str.replace(/([\r\n]\*.*[\r\n])[\t ]*[\r\n](\*)/gim, '$1$2');
  // Extra newlines before semicolon marked bold lines
  str=str.replace(/([\r\n])([#;:\*].*[\r\n])[ ]*[\r\n]([#;:\*])/gim, '$1$2$3');

  return str;
}

// ----------------------------- interface  Functions ----------------------------- //

function spork_edit_summary(summary){
// Add a tag to the summary box
  var txt = document.editform.wpSummary;
  var fullsummary = "Script assisted " + summary;
  if (txt.value.indexOf(summary) == -1) {
    if (txt.value.match( /Script assisted [A-Za-z]/ )) {
        txt.value = txt.value.replace( /Script assisted /, fullsummary + "/");
    } else if (txt.value.match(/[^\*\/\s][^\/\s]?\s*$/)) {
	txt.value += " | " + fullsummary;
    } else {
        txt.value += fullsummary;
    }
  }
}

addOnloadHook(function () {
  if(document.forms.editform && mw.config.get('wgUserName') == 'Plastikspork') {
    if( SporkConfig.ws != "" )
      addPortletLink('p-tb', 'javascript:spork_ws_compress(1)', SporkConfig.ws);
    if( SporkConfig.wlr != "" )
      addPortletLink('p-tb', 'javascript:spork_wiki_link_repair(1)', SporkConfig.wlr);
    if( SporkConfig.b2r != "" )
      addPortletLink('p-tb', 'javascript:spork_bracket_to_ref(1)', SporkConfig.b2r);
    if( SporkConfig.ct != "" )
      addPortletLink('p-tb', 'javascript:spork_citation_template(1)', SporkConfig.ct);
    if( SporkConfig.rr != "" )
      addPortletLink('p-tb', 'javascript:spork_ref_repeat(1)', SporkConfig.rr);
    if( SporkConfig.c != "" )
      addPortletLink('p-tb', 'javascript:spork_color(1)', SporkConfig.c);
    if( SporkConfig.t2w != "" )
      addPortletLink('p-tb', 'javascript:spork_wiki_table(1)', SporkConfig.t2w);
    if( SporkConfig.noa != "" )
      addPortletLink('p-tb', 'javascript:spork_no_align(1)', SporkConfig.noa);
    if( SporkConfig.tst != "" )
      addPortletLink('p-tb', 'javascript:spork_testing(1)', SporkConfig.tst);
    if( SporkConfig.fullurl != "" )
      addPortletLink('p-tb', 'javascript:spork_fullurl(1)', SporkConfig.fullurl);
  }
});