MediaWiki:Gadget-ReplaceLink.js

Un livre de Wikilivres.

Attention : Depuis MediaWiki 1.18 les pages se terminant avec l'extension .js ou .css sont interprétées comme des pages wiki ! En particulier les modèles (subst ou non) et les liens. Vous devez donc migrer le code source et effectuer vos changements en évitant ces éléments de syntaxe wiki (peu importe leurs emplacements dans le code source : commentaire, chaine) :

  • Double accolades ouvrantes (en particulier avec subst:) : séparer les deux accolades "{"+"{" du reste de la chaine
  • Double crochets ouvrants : même technique de séparation.
  • Signature (tildes ~ multiples) : même technique de séparation.

Note : après avoir enregistré vos préférences, vous devrez attendre que le serveur mette à jour la feuille de style globale avant de forcer le rechargement complet du cache de votre navigateur pour voir les changements.

  • Firefox / Safari : Maintenez la touche Maj (Shift) en cliquant sur le bouton Actualiser ou pressez Ctrl-F5 ou Ctrl-R (⌘-R sur un Mac) ;
  • Google Chrome : Appuyez sur Ctrl-Maj-R (⌘-Shift-R sur un Mac) ;
  • Internet Explorer : Maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5 ;
  • Konqueror : Cliquez sur Actualiser ou pressez F5 ;
  • Opera : Videz le cache dans Outils → Préférences.
// ------------------------------------------------------------------
// Fonctions utiles

function uncodeURIelement(s)
{
s=s.replace(/[\+]/g,' ');
try{return unescape(decodeURI(s)).replace(/[_]/g,' ');}
catch(e){return unescape(s).replace(/[_]/g,' ');}
}

function strangeCharCode(code)
{
    // control code or outside current Unicode limit
    return (code<32)||(code>=127 && code<160)||(code>=0x2FA20);
}

function decodeURIpart(s)
{
    var t = uncodeURIelement(s.replace(/[\+]/g,' ').replace(/\./g,'%'));
    for(var i=0;i<t.length;i++)
        if (strangeCharCode( t.charCodeAt(i) )) return s;
    return t.replace(/[_]/g,' ');
}

function uncodeURI(s)
{
    var i = s.indexOf('#');
    if (i<0) return uncodeURIelement(s);
    return uncodeURIelement(s.substring(0,i+1))+decodeURIpart(s.substring(i+1));
}

function uncodeURIComponent(s)
{
s=s.replace(/[\+]/g,' ');
try{return decodeURIComponent(s).replace(/[_]/g,' ');}
catch(e){return unescape(s).replace(/[_]/g,' ');}
}

// ------------------------------------------------------------------
// Décodage des liens

function UrlLinkDecodeForm(text,args)
{
    var res = "";
    var i = text.indexOf('#');
    if (i<0) res = uncodeURIComponent(text);
    else res = uncodeURIComponent(text.substring(0,i+1))+decodeURIpart(text.substring(i+1));
    return [ res,0,res.length ];
}

function UrlLinkDecodePart(text,args)
{
    var res = decodeURIpart(text);
    return [ res,0,res.length ];
}

// ------------------------------------------------------------------
// Simplification de liens wiki

function getSimplifiedWikiLink(link,text)
{
    link = uncodeURI(link).replace(/_/g, ' ');
    var pagename = mw.config.get('wgPageName').replace(/_/g, ' ');
    if (link==text) text = undefined;
    var k = link.indexOf('#');
    var part = (k<0)?'':decodeURIpart(link.substring(k));
    if (k>=0)
    {
        link = link.substring(0,k);
        if (link==pagename) link='';
    }
    if (link.starts(pagename+'/'))
        link = link.substring(pagename.length);
    else
    {
        m = pagename.lastIndexOf('/');
        if ((m>0) && link.starts(pagename.substring(0,m+1)))
            link = '..'+link.substring(m);
    }
    if (text !== undefined)
    {
        if (link.ends('/')) link = link.substring(0,link.length-1);
        if ((link=='/'+text)||(link=='../'+text)) { link+='/'; text=undefined; }
    }
    return [link+part,text];
}


// ------------------------------------------------------------------
// Wikification des liens

var wm_servers = [ // without language code
  // server domain ,          prefix ,   iswiki
  ["wikimediafoundation.org", "wmf",     true],
  ["www.mediawiki.org",       "mw",      true],
  ["meta.wikimedia.org",      "m",       true],
  ["commons.wikimedia.org",   "commons", true],
  ["species.wikimedia.org",   "species", true],
  ["toolserver.org",          "tools",   false],
];

var wm_servers_lang = [ // with language code
  // server domain ,   prefix
  [".wikibooks.org",   "b"],
  [".wikipedia.org",   "w"],
  [".wikiversity.org", "v"],
  [".wiktionary.org",  "wikt"],
  [".wikiquote.org",   "q"],
  [".wikinews.org",    "n"],
  [".wikisource.org",  "s"],
];

// Find prefix for this project
var wgLinkPrefix = ''; // prefix for this project
for(var i=0;i<wm_servers_lang.length;i++)
  if (wgServerName.ends(wm_servers_lang[i][0]))
  { wgLinkPrefix = wm_servers_lang[i][1]; break; }
if (wgLinkPrefix == '')
for(var i=0;i<wm_servers.length;i++)
  if (wgServerName == wm_servers[i][0])
  { wgLinkPrefix = wm_servers[i][1]; break; }

function wikiLinkStartWithLang(wikilink)
{
    var i = wikilink.indexOf(':');
    return (i>=0)&&(all_langs.indexOf(wikilink.substring(0,i))>=0);
}

function hcode(c)
{ return (c<16?'0':'')+c.toString(16); }
function decodeFormExcept(v, except)
{
    v = v.replace(/[\+]/g,' ');
    try{v = decodeURIComponent(v);}
    catch(e){v = unescape(v);}
    for(var i=0;i<except.length;i++)
        v = v.replace(new RegExp('[\\'+except.charAt(i)+']','g'),'%'+hcode(except.charCodeAt(i)));
    for(var i=0;i<32;i++)
        v = v.replace(new RegExp('[\\x'+hcode(i)+']','g'),'%'+hcode(i));
    return v;
}
function getDecodedValue(form_value)
{
    var j = form_value.indexOf('=');
    if (j<0) return decodeFormExcept(form_value, '% "=#&?|{}<>');
    else return decodeFormExcept(form_value.substring(0,j), '% "=#&?|{}<>')+'='+decodeFormExcept(form_value.substring(j+1), '% "#&?|{}<>');
}
function getJoinedDecodedForm(form)
{
    for(var i=0;i<form.length;i++)
        form[i] = getDecodedValue(form[i]);
    return form.join('&');
}

function getWikiPageLinkFor(server,prefix,langcode,pageurl,iswiki)
{
    if (prefix==wgLinkPrefix) prefix=""; else prefix+=":";
    if (langcode!=mw.config.get('wgContentLanguage') && langcode!="") prefix+=langcode+":";

    var k = pageurl.indexOf('#');
    var part = (k<0)?'':decodeURIpart(pageurl.substring(k));
    if (k>=0) pageurl = pageurl.substring(0,k);

    var k = pageurl.indexOf('?');
    if (k<0)
    {
        // no form
        var pw = iswiki ? mw.config.get('wgArticlePath').replace("$1",'') : '/';
        if (!pageurl.starts(pw)) return undefined;
        return prefix+uncodeURI(pageurl.substring(pw.length)).replace(/_/g,' ')+part;
    }

    var form = pageurl.substring(k+1).split('&');
    pageurl = pageurl.substring(0,k).replace(/_/g, ' ');
    if (iswiki)
    {
        if (pageurl == mw.config.get('wgScript') || pageurl == '/w/wiki.phtml')
        {
            for(var i=0;i<form.length;i++)
                if (form[i].starts('title='))
                {
                    var tit = form.splice(i,1);
                    tit = prefix+uncodeURIComponent(tit[0].substring(6)).replace(/_/g, ' ')+part;
                    return form.length==0?tit:[tit,getJoinedDecodedForm(form)];
                }
        }
        else if ( pageurl.starts(mw.config.get('wgArticlePath').replace("$1",'Special')) ||
                  pageurl.starts(mw.config.get('wgArticlePath').replace("$1",mw.config.get('wgFormattedNamespaces')['-1'])) )
        {
            var pw = mw.config.get('wgArticlePath').replace("$1",'');
            return [prefix+uncodeURI(pageurl.substring(pw.length)).replace(/_/g,' ')+part,getJoinedDecodedForm(form)];
        }
    }
    else return [prefix+uncodeURI(pageurl.substring(1)).replace(/_/g,' ')+part,getJoinedDecodedForm(form)];
    return undefined;
}

function getWikiLinkFor(link)
{
    var i;
    if (link.starts('http://')) i=7;
    else if (link.starts('https://')) i=8;
    else if (link.starts('//')) i=2;
    else return undefined; // may already be a wiki link
    // test if it is a Wikimedia server
    var j = link.indexOf('/',i);
    var serv = (j<0)?link.substring(i):link.substring(i,j);
    for(var a=0;a<wm_servers.length;a++)
        if (serv==wm_servers[a][0])
            return getWikiPageLinkFor(serv,wm_servers[a][1],"",
                (j<0)?"":link.substring(j),wm_servers[a][2]);
    for(var a=0;a<wm_servers_lang.length;a++)
        if (serv.ends(wm_servers_lang[a][0]))
            return getWikiPageLinkFor(serv,wm_servers_lang[a][1],
                serv.substring(0,serv.length-wm_servers_lang[a][0].length),
                (j<0)?"":link.substring(j),true);
    return undefined; // not a Wikimedia server
}

function needEscapeLink(link)
{
    return wikiLinkStartWithLang(link) ||
        link.starts('Category:') ||
        link.starts(mw.config.get('wgFormattedNamespaces')[14]+':');
}

function replaceLinksByWikiLinks(text,args)
{
    var res=new String(text);
    var i,j,k,l,st=0;
    for(;;)
    {
        l=res.indexOf("http",st);
        i=res.indexOf("[",st);
        if (l<0 && i<0) break;
        st++;
        if (( (l>0) && (" ,;\"'\r\f\n\t".indexOf(res.charAt(l-1))<0) )||
            ( (l>=0) && (res.substring(l+4,l+7)!="://") && (res.substring(l+4,l+8)!="s://") )) l=-1;
        if ( (l>=0) && ((i<0) || (l<i)) )
        {
            j = res.indexOf("://",l+4)+3; k = j;
            for(i=j ; i<res.length ; i++)
            {
                if (" \"<>[]\r\f\n\t".indexOf(res.charAt(i)) >= 0) break;
                else if ("!),;\\".indexOf(res.charAt(i)) < 0) j=i+1;
            }
            st = j;
            var wlink = getWikiLinkFor(res.substring(l,j));
            if (typeof(wlink)!='undefined')
            {
                var t;
                if (typeof(wlink)=='object') // form in URL -> fullurl
                {
                    t = "[{{fullurl:"+wlink[0]+"|"+wlink[1]+"}} "+wlink[0]+"]";
                }
                else // no form -> wikilink
                {
                    var ulink = needEscapeLink(wlink)?':'+wlink:wlink;
                    t = "[["+ulink+"]]";
                }
                // now replace characters ( l .. j ) by t
                res = res.substring(0,l)+t+res.substring(j);
                st = l+t.length;
            }
            continue;
        }
        if (i<0) break;
        if (res.charAt(i+1)=='[') { st=i+1;continue; } // support for [[
        var lstart = res.substring(i+1); // must start with http:// https:// or //
        if (!lstart.starts('http://') && !lstart.starts('https://') && !lstart.starts('//'))
            { st=i+1;continue; } // skip the [ which can't be an external link wiki marker
        k=res.indexOf("]",i+1); if (k<0) break;
        st=k+1;
        j=res.indexOf(" ",i+1); if (j>=k) j=-1;
        l=res.indexOf("<",i+1); if (l>=k) l=-1;
        if ((l>=0) && (l<j || j<0)) j=l; else l=j+1;
        var wlink = getWikiLinkFor(res.substring(i+1,j<0?k:j));
        if (typeof(wlink)!='undefined')
        {
            var t;
            if (typeof(wlink)=='object') // form in URL -> fullurl
            {
                t = "[{{fullurl:"+wlink[0]+"|"+wlink[1]+"}}"+((j<0)?"":" "+res.substring(l,k))+"]";
            }
            else // no form -> wikilink
            {
                t = (j<0)?undefined:res.substring(l,k);
                var ulink = needEscapeLink(wlink)?':'+wlink:wlink;
                if ( (typeof(wgPageIsTemplate)!='undefined') && !wgPageIsTemplate)
                {
                    var simple = getSimplifiedWikiLink(ulink,t);
                    ulink = simple[0]; t = simple[1];
                }
                if (t==wlink || t==undefined) t = "[["+ulink+"]]";
                else t = "[["+ulink+"|"+t+"]]";
            }
            // now replace characters ( i .. k+1 ) by t
            res = res.substring(0,i)+t+res.substring(k+1);
            st = i+t.length;
        }
    }
    return [ res,0,res.length ];
}


// ------------------------------------------------------------------
// Pour les livres ne respectant pas la convention sur les titres
// Remplacement des liens par des liens vers les sous-pages du livre

function replaceSubpageLink(text,args)
{
    var page=args[0]+"/";
    var res=new String(text);
    var i,j,k,l,st=0;
    for(;;)
    {
        i=res.indexOf("[[",st); if (i<0) break;
        if (res.charAt(i+2)=='[') { st=i+1;continue; } // support for [[[
        k=res.indexOf("]]",i+2); if (k<0) break;
        st=k+2;
        j=res.indexOf("|",i+2); if (j>=k) j=-1;
        l=res.indexOf(":",i+2); if (l>=k) l=-1;

        if ((j>=0)&&(l>j)) l=-1;
        if ((j>=0)&&(j>=( i+2+page.length )))
            if (startsWithAa(res.substring(i+2,j)+"/",page)) continue;

        if (l<=i)
        {
            if (j>=0)
            {
                res=res.substring(0,i+2)+page+res.substring(i+2);
                st=k+2+page.length;
            }
            else
            {
                res=res.substring(0,i+2)+page+res.substring(i+2,k)+"|"+res.substring(i+2);
                //st=k+3+page.length+(k-i-2);
                st=2*k-i+1+page.length;
            }
        }
    }
    return [ res,0,res.length ];
}

function replaceSubpageLinks(page)
{
    replaceSelection(replaceSubpageLink,page);
}


// ------------------------------------------------------------------
// Pour l'importation : remplacement des liens

function replaceExtLink(text,args)
{
    var prefix=args[0]+":";
    var res=new String(text);
    var i,j,k,l,st=0;
    for(;;)
    {
        i=res.indexOf("[[",st); if (i<0) break;
        if (res.charAt(i+2)=='[') { st=i+1;continue; } // support for [[[
        k=res.indexOf("]]",i+2); if (k<0) break;
        j=res.indexOf("|",i+2); if (j>=k) j=-1;
        l=res.indexOf(":",i+2); if (l>=k) l=-1;
        if ((j>=0)&&(l>j)) l=-1;
        if (l>i) st=k+2;
        else
        {
            if (j>=0)
            {
                res=res.substring(0,i+2)+prefix+res.substring(i+2);
                st=k+2+prefix.length;
            }
            else
            {
                res=res.substring(0,i+2)+prefix+res.substring(i+2,k)+"|"+res.substring(k);
                st=k+3+prefix.length;
            }
        }
    }
    return [ res,0,res.length ];
}


// ------------------------------------------------------------------
// Pour l'importation : suppression des liens

function removeExtLink(text,args)
{
    var res=new String(text);
    var i,j,k,l,st=0;
    for(;;)
    {
        i=res.indexOf("[[",st); if (i<0) break;
        if (res.charAt(i+2)=='[') { st=i+1;continue; } // support for [[[
        k=res.indexOf("]]",i+2); if (k<0) break;
        j=res.indexOf("|",i+2); if (j>=k) j=-1;
        res=res.substring(0,i)+res.substring((j<0?i+2:j+1),k)+res.substring(k+2);
        st= (j<0) ? k-2 : k+i-j ;
    }
    return [ res,0,res.length ];
}


// ------------------------------------------------------------------
// Simplification des liens

var long_def_lang="en:";
var wm_projects_lang = [ // with language code, long prefixes
  // long-prefix , short-prefix
//  ["wikibooks:","b:"], // doesn't work on wikibooks
  ["wikipedia:","w:"],
  ["wikiversity:","v:"],
  ["wiktionary:","wikt:"],
  ["wikiquote:","q:"],
  ["wikinews:","n:"],
  ["wikisource:","s:"],
];

function replaceLinksBySimpleLinks(text,args)
{
    var res=new String(text);
    var i,j,k,l,st=0;
    l_simple_links:
    for(;;)
    {
        i=res.indexOf("[[",st); if (i<0) break;
        if (res.charAt(i+2)=='[') { st=i+1;continue; } // support for [[[
        k=res.indexOf("]]",i+2); if (k<0) break;
        j=res.indexOf("|",i+2); if (j>=k) j=-1;
        l=res.indexOf(":",i+2); if (l>=k) l=-1;
        m=(l<0)?-1:res.indexOf(":",l+1); if ((m>=k)||(m>l+4)) m=-1;
        if ((j>=0)&&(l>j)) l=-1;
        if ((j>=0)&&(m>j)) m=-1;
        if (m<0)
        {
            // Original values
            var olink = res.substring(i+2,(j<0)?k:j);
            var otext = (j<0)?undefined:res.substring(j+1,k);
            var simple = getSimplifiedWikiLink(olink,otext);
            var link = simple[0], text = simple[1];
            if ((olink!=link) || (otext!=text))
            {
                var t = (text===undefined)?link:link+'|'+text;
                res = res.substring(0,i+2)+t+res.substring(k);
                st=i+4+t.length;
            }
            else st=k+2;
        }
        else
        {
            var link = res.substring(i+2,(j<0)?k:j);
            for(var a=0;a<wm_projects_lang.length;a++)
                if (link.startsAa(wm_projects_lang[a][0]))
                {
                    if (res.substring(l+1,m)==mw.config.get('wgContentLanguage')) l=m;
                    res = res.substring(0,i+2)+wm_projects_lang[a][1]+res.substring(l+1);
                    st = i+4+wm_projects_lang[a][1].length; // after ]]
                    continue l_simple_links;
                }
            st=k+2;
        }
    }
    return [ res,0,res.length ];
}


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

/*
    prefix: préfixe du projet wiki pour les liens (w pour wikipédia, ...)
            ou option
               -        supprimer les liens
               -wiki    wikifier les liens
               -simple  simplifier les liens
*/
function replaceExtLinks(prefix)
{
    if (typeof(prefix)=='undefined' || prefix=='-') replaceSelection(removeExtLink);
    else if (prefix=='-wiki') replaceSelection(replaceLinksByWikiLinks);
    else if (prefix=='-simple') replaceSelection(replaceLinksBySimpleLinks);
    else replaceSelection(replaceExtLink,prefix);
}

function UrlLinkDecode(level)
{
    replaceSelection(level==0?UrlLinkDecodeForm:UrlLinkDecodePart);
}

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