From Wikipedia, the free encyclopedia
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.

/* If you want to use this script, simply add the following line to your monobook.js:

 

importScript('User:Anomie/ajaxpreview.js'); // Linkback: [[User:Anomie/ajaxpreview.js]]

 

* (Please keep the comment so I can see how many people use this).

*/



var AJAXPreview={

    node:null,

    txt:null,

    timer:null,

    idx:0,



    spinner:function(){

        switch(AJAXPreview.idx++){

          case 0:

            AJAXPreview.node.innerHTML='<center style="font-size:50pt">|</center>';

            break;

          case 1:

            AJAXPreview.node.innerHTML='<center style="font-size:50pt">/</center>';

            break;

          case 2:

            AJAXPreview.node.innerHTML='<center style="font-size:50pt">–</center>';

            break;

          case 3:

            AJAXPreview.node.innerHTML='<center style="font-size:50pt">\\</center>';

            AJAXPreview.idx=0;

            break;

        }

        AJAXPreview.node.style.display='block';

    },



    callback:function(r){

        if(AJAXPreview.timer) window.clearInterval(AJAXPreview.timer);

        AJAXPreview.timer=null;

        if(!r.parse || !r.parse.text || !r.parse.text'*']){

            AJAXPreview.node.innerHTML='<div style="border:1px solid #f00;background-color:#fcc;color:#f00;text-align:center">Bad response</div>';

            throw new Error('Bad response');

        }

        AJAXPreview.node.innerHTML=r.parse.text'*'+'<br />';

        AJAXPreview.node.style.display='block';



        // Set a timeout to allow the browser a chance to parse the innerHTML

        window.setTimeout(function(){

        	mw.hook( 'wikipage.content' ).fire( $( AJAXPreview.node ) );

            for(var i=AJAXPreview.$OnLoadHooks.length-1; i>=0; i--)

                AJAXPreview.$OnLoadHooksi].call(window, AJAXPreview.node);

        }, 250);

    },



    doError:function(xhr,textStatus,errorThrown){

        if(AJAXPreview.timer) window.clearInterval(AJAXPreview.timer);

        AJAXPreview.timer=null;

        while(AJAXPreview.node.firstChild) AJAXPreview.node.removeChild(AJAXPreview.node.firstChild);

        var d=document.createElement('DIV');

        d.style.border='1px solid #f00';

        d.style.backgroundColor='#fcc';

        d.style.color='#f00';

        d.style.textAlign='center';

        d.appendChild(document.createTextNode('AJAX Error: '+textStatus+' '+errorThrown));

        AJAXPreview.node.appendChild(d);

        AJAXPreview.node.style.display='block';

        throw new Error('AJAX error: '+textStatus+' '+errorThrown);

    },



    doPreview:function(ev){

        if(!ev) ev=window.event;

        var txt=AJAXPreview.getTextContent();

        var refs=AJAXPreview.getRefs(txt);

        var need=[];

        var groups={};

        for(var g in refs){

            groupsg='';

            for(var n in refsg]){

                if(refsg][n].text===null) need.push([g,n]);

            }

        }

        var doPreview2=function(wikitext,sts,xhr){

            if(wikitext){

                refs=AJAXPreview.getRefs(wikitext);

                for(var i=need.length-1; i>=0; i--){

                    var x=refsneedi][0]][needi][1]];

                    if(!x) continue;

                    if(x.type=='tag'){

                        groupsneedi][0]]+='\x7b\x7b#tag:ref|'+x.text+'|name='+needi][1+'|group='+needi][0+'\x7d\x7d';

                    } else {

                        groupsneedi][0]]+='\x3cref name="'+needi][1+'" group="'+needi][0+'"\x3e'+x.text+'\x3c/ref\x3e';

                    }

                }

            }

            txt+='\n\n\x7b\x7b-\x7d\x7d\n----\n';

            for(var g in groups){

                txt+='\n;'+(g?'Group '+g:'References')+'\n\x7b\x7breflist|2|group='+g+'|refs='+groupsg+'\x7d\x7d';

            }



            jQuery.ajax({

                url:mw.util.wikiScript('api'),

                dataType:'json',

                type:'POST',

                data:{

                    format:'json',

                    action:'parse',

                    pst:1,

                    text:txt,

                    title:mw.config.get('wgPageName'),

                    prop:'text',

                    disableeditsection:1,

                    preview:1,

                    templatesandboxtitle:mw.config.get('wgPageName'),

                    templatesandboxtext:txt

                },

                success:AJAXPreview.callback,

                error:AJAXPreview.doError

            });

        };

        mw.loader.using('mediawiki.util', function(){

            if(need.length>0){

                jQuery.ajax({

                    url:mw.util.wikiScript('index'),

                    dataType:'text',

                    type:'GET',

                    data:{ action:'raw', title:mw.config.get('wgPageName') },

                    success:doPreview2,

                    error:AJAXPreview.doError

                });

            } else {

                doPreview2(null,null,null);

            }

        });



        var x=document.getElementById('wikiDiff');

        if(x) x.parentNode.removeChild(x);

        if(AJAXPreview.timer) window.clearInterval(AJAXPreview.timer);

        AJAXPreview.timer=window.setInterval(AJAXPreview.spinner, 250);



        this.blur();

        window.scrollTo(0,0);

        if(ev){ // OOUI may not have an event here

            if(ev.preventDefault) ev.preventDefault();

            if(ev.stopPropagation) ev.stopPropagation();

            ev.returnValue=false;

            ev.cancelBubble=true;

        }

        return false;

    },



    getRefs:function(txt){

        var g;



        var refs={};



        // The new "list-defined references" have to be handled specially,

        // which means we have to manage to pull them out of the wikitext. Fun.

        // First, do the XML-style tags.

        txt=txt.replace(/<references((?:\s+[^>]*[^\/>])?)(?:\/>|>((?:.|[\r\n])*?)(<\/references>|$))/ig, function(x,p,t,c){

            p=p.replace(/\s+$/g,'');

            g=p.match(/\sgroup="([^\x22]*)"/i);

            if(!g) g=p.match(/\sgroup='([^\x27]*)'/i);

            if(!g) g=p.match(/\sgroup=(\S*)/i);

            g=g?g1:'';

            refs=AJAXPreview.getRefs2(t,g,refs);

            return '';

        });



        // Next, to reflist and #tag:references

        txt=AJAXPreview.process_templates(txt,function(n,p,o){

            var c=null, g='';

            if(n=='Reflist'){

                for(var j=0; j<p.length; j++){

                    var m=pj].match(/^\s*refs\s*=\s*((?:.|[\r\n])*?)\s*$/);

                    if(m) c=m1];

                    var m=pj].match(/^\s*group\s*=\s*([\x22\x27]?)([^\x22\x27]+?)\1\s*$/);

                    if(m) g=m2];

                }

                if(c===null) c='';

            } else if(/^#tag:\s*references$/i.test(n)){

                c=p.length ? p.shift() : '';

                for(var j=0; j<p.length; j++){

                    var m=pj].match(/^\s*group\s*=\s*([\x22\x27]?)([^\x22\x27]+?)\1\s*$/);

                    if(m) g=m2];

                }

            } else {

                return null;

            }

            refs=AJAXPreview.getRefs2(c,g,refs);

            return '';

        });



        return AJAXPreview.getRefs2(txt,'',refs);

    },

    getRefs2:function(txt,defgroup,refs){

        var g,n;



        // First, pull out regular <refs>. We can do this with a regex.

        txt.replace(/<ref((?:\s+\S+=(?:"[^\x22]*"|'[^\x27]*'|\S*?))*)\s*(?:\/>|>((?:.|[\r\n])*?)<\/ref>)/ig, function(x,p,t){

            g=p.match(/\sgroup="([^\x22]*)"/i);

            if(!g) g=p.match(/\sgroup='([^\x27]*)'/i);

            if(!g) g=p.match(/\sgroup=(\S*)/i);

            g=g?g1:defgroup;

            if(typeof(refsg])=='undefined') refsg={};

            n=p.match(/\sname="([^\x22]*)"/i);

            if(!n) n=p.match(/\sname='([^\x27]*)'/i);

            if(!n) n=p.match(/\sname=(\S*)/i);

            if(!n) return null;

            n=n1];

            if(typeof(refsg][n])=='undefined') refsg][n={text:null,type:'?'};

            if(refsg][n].text===null && typeof(t)!='undefined' && t!=='' && t!==null){

                refsg][n].text=t;

                refsg][n].type='ref'

            }

            return null;

        });



        // Second, if it looks like there are #tag refs, parse them too

        AJAXPreview.process_templates(txt,function(nm,p,o){

            if(!/^#tag:\s*ref$/i.test(nm)) return null;

            g=defgroup; n=null;

            for(var j=p.length-1; j>=1; j--){

                var m=pj].match(/^\s*group\s*=\s*([\x22\x27]?)([^\x22\x27]+?)\1\s*$/);

                if(m) g=m2];

                var m=pj].match(/^\s*name\s*=\s*([\x22\x27]?)([^\x22\x27]+?)\1\s*$/);

                if(m) n=m2];

            }

            if(typeof(refsg])=='undefined') refsg={};

            if(n!==null){

                if(typeof(refsg][n])=='undefined') refsg][n={text:null,type:'?'};

                if(refsg][n].text===null && p0!==''){

                    refsg][n].text=p0];

                    refsg][n].type='tag'

                }

            }

            return null;

        });



        return refs;

    },



    process_templates:function(txt,cb,data){

        var stack=[], i=0;

        while(i<txt.length){

            var x=stack.length?stackstack.length-1:null;

            var xb=null;

            for(var j=0; j<stack.length; j++){

                if(stackj].char=='\x5b') xb=stackj];

            }

            if(txt.substr(i,2)=='\x7b\x7b'){

                var ct;

                for(ct=2; txt.substr(i+ct,1)=='\x7b'; ct++);

                stack.push({char:'\x7b',start:i,count:ct,pstart:i+ct,params:[]});

                i+=ct;

            } else if(txt.substr(i,2)=='\x5b\x5b'){

                var ct;

                for(ct=2; txt.substr(i+ct,1)=='\x5b'; ct++);

                stack.push({char:'\x5b',start:i,count:ct,pstart:i+ct,params:[]});

                i+=ct;

            } else if(x && x.char=='\x7b' && txt.substr(i,2)=='\x7d\x7d'){

                var ct;

                for(ct=2; txt.substr(i+ct,1)=='\x7d'; ct++);

                if(ct>x.count) ct=x.count;

                i+=ct;

                x.params.push(txt.substring(x.pstart,i-ct));

                // First, parse out variables

                while(ct>=3){

                    x.count-=3;

                    ct-=3;

                    var s=x.start-x.count;

                    x.params=txt.substring(s,i-x.count)];

                }

                // Any left is templates

                while(ct>=2){

                    x.count-=2;

                    ct-=2;

                    var s=x.start+x.count;

                    var orig=txt.substring(s,i-ct);

                    var name=x.params.shift();

                    var oname=name;

                    name=name.replace(/_/g,' ');

                    name=name.replace(/^\s+|\s+$/g,'');

                    name=name.replace(/  +/g,' ');

                    name=name.replace(/^Template\s*:\s*/ig,'');

                    name=name.substr(0,1).toUpperCase()+name.substr(1);

                    var ret=cb(name, x.params, orig, data, oname);

                    if(ret===null){

                        x.params=orig];

                    } else {

                        ret=""+ret;

                        var d=(ret=='' && (s==0 || txt.substr(s-1,1)=='\n') && txt.substr(i-ct,1)=='\n')?1:0;

                        txt=txt.substr(0,s)+ret+txt.substr(i-ct+d);

                        i=s+ret.length+ct;

                        x.params=ret];

                    }

                }

                if(x.count<2){

                    stack.pop();

                } else {

                    // The one we just completed might not be the end of the

                    // param, so reset the param array and pstart

                    x.params=[];

                    x.pstart=x.start+x.count;

                }

            } else if(xb && txt.substr(i,2)=='\x5d\x5d'){

                // Drop any pending templates, they're not really templates

                while(stackstack.length-1!=xb) stack.pop();

                var ct;

                for(ct=2; txt.substr(i+ct,1)=='\x5d'; ct++);

                if(ct>xb.count) ct=xb.count;

                i+=ct;

                xb.count-=ct;

                if(xb.count<2){

                    stack.pop();

                } else {

                    // The one we just completed might not be the end of the

                    // param, so reset the param array and pstart

                    xb.params=[];

                    xb.pstart=xb.start+xb.count;

                }

            } else if(x && txt.substr(i,1)=='|'){

                x.params.push(txt.substring(x.pstart,i));

                x.pstart=++i;

            } else {

                i++;

            }

        }

        return txt;

    },

 

    onLoad:function(){

        var action=mw.config.get('wgAction');

        if(action!='edit' && action!='submit') return;



        var editForm=document.getElementById('editform');

        if(!editForm) return;

        var sectionField = editForm.elements'wpSection'];

        var isSection=(sectionField && sectionField.value!="");

        var p=editForm.elements"wpPreview"];

        if(!p) return;



        AJAXPreview.node=document.getElementById('wikiPreview');

        if(!AJAXPreview.node) return;

        AJAXPreview.txt=editForm.elements"wpTextbox1"];

        if(!AJAXPreview.txt) return;



    	mw.loader.using(  'oojs-ui-core'  ).done( function () {

            var b = new OO.ui.ButtonWidget( {

	            label: 'Ajax Preview'+(isSection?' w/Refs':''),

    	        tabIndex: p.tabIndex

        	} );

        	b.on( 'click', AJAXPreview.doPreview );

        	$( p ).before( b.$element, ' ' );

    	} );

        p.value='Preview';



        // Hooks for standard functions

        if(typeof(window.createCollapseButtons) == 'function')

            AJAXPreview.AddOnLoadHook(createCollapseButtons);

        if(typeof(window.createNavigationBarToggleButton) == 'function')

            AJAXPreview.AddOnLoadHook(createNavigationBarToggleButton);

    },



    getTextContent:function(){

        return AJAXPreview.txt.value;

    },



    // Add callback functions here.

    AddOnLoadHook:function(f){

        AJAXPreview.$OnLoadHooks.push(f);

    },

    $OnLoadHooks:[]

};



$(document).ready(AJAXPreview.onLoad);