User:Anomie/ajaxpreview.js
Appearance
From Wikipedia, the free encyclopedia
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump.
This code will be executed when previewing this page.
This code will be executed when previewing this page.
This user script seems to have a documentation page at User:Anomie/ajaxpreview.
/* 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). */ varAJAXPreview={ node:null, txt:null, timer:null, idx:0, spinner:function(){ switch(AJAXPreview.idx++){ case0: AJAXPreview.node.innerHTML='<center style="font-size:50pt">|</center>'; break; case1: AJAXPreview.node.innerHTML='<center style="font-size:50pt">/</center>'; break; case2: AJAXPreview.node.innerHTML='<center style="font-size:50pt">–</center>'; break; case3: 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>'; thrownewError('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(vari=AJAXPreview.$OnLoadHooks.length-1;i>=0;i--) AJAXPreview.$OnLoadHooks[i].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); vard=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'; thrownewError('AJAX error: '+textStatus+' '+errorThrown); }, doPreview:function(ev){ if(!ev)ev=window.event; vartxt=AJAXPreview.getTextContent(); varrefs=AJAXPreview.getRefs(txt); varneed=[]; vargroups={}; for(varginrefs){ groups[g]=''; for(varninrefs[g]){ if(refs[g][n].text===null)need.push([g,n]); } } vardoPreview2=function(wikitext,sts,xhr){ if(wikitext){ refs=AJAXPreview.getRefs(wikitext); for(vari=need.length-1;i>=0;i--){ varx=refs[need[i][0]][need[i][1]]; if(!x)continue; if(x.type=='tag'){ groups[need[i][0]]+='\x7b\x7b#tag:ref|'+x.text+'|name='+need[i][1]+'|group='+need[i][0]+'\x7d\x7d'; }else{ groups[need[i][0]]+='\x3cref name="'+need[i][1]+'" group="'+need[i][0]+'"\x3e'+x.text+'\x3c/ref\x3e'; } } } txt+='\n\n\x7b\x7b-\x7d\x7d\n----\n'; for(vargingroups){ txt+='\n;'+(g?'Group '+g:'References')+'\n\x7b\x7breflist|2|group='+g+'|refs='+groups[g]+'\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); } }); varx=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; } returnfalse; }, getRefs:function(txt){ varg; varrefs={}; // 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?g[1]:''; refs=AJAXPreview.getRefs2(t,g,refs); return''; }); // Next, to reflist and #tag:references txt=AJAXPreview.process_templates(txt,function(n,p,o){ varc=null,g=''; if(n=='Reflist'){ for(varj=0;j<p.length;j++){ varm=p[j].match(/^\s*refs\s*=\s*((?:.|[\r\n])*?)\s*$/); if(m)c=m[1]; varm=p[j].match(/^\s*group\s*=\s*([\x22\x27]?)([^\x22\x27]+?)1円\s*$/); if(m)g=m[2]; } if(c===null)c=''; }elseif(/^#tag:\s*references$/i.test(n)){ c=p.length?p.shift():''; for(varj=0;j<p.length;j++){ varm=p[j].match(/^\s*group\s*=\s*([\x22\x27]?)([^\x22\x27]+?)1円\s*$/); if(m)g=m[2]; } }else{ returnnull; } refs=AJAXPreview.getRefs2(c,g,refs); return''; }); returnAJAXPreview.getRefs2(txt,'',refs); }, getRefs2:function(txt,defgroup,refs){ varg,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?g[1]:defgroup; if(typeof(refs[g])=='undefined')refs[g]={}; n=p.match(/\sname="([^\x22]*)"/i); if(!n)n=p.match(/\sname='([^\x27]*)'/i); if(!n)n=p.match(/\sname=(\S*)/i); if(!n)returnnull; n=n[1]; if(typeof(refs[g][n])=='undefined')refs[g][n]={text:null,type:'?'}; if(refs[g][n].text===null&&typeof(t)!='undefined'&&t!==''&&t!==null){ refs[g][n].text=t; refs[g][n].type='ref' } returnnull; }); // 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))returnnull; g=defgroup;n=null; for(varj=p.length-1;j>=1;j--){ varm=p[j].match(/^\s*group\s*=\s*([\x22\x27]?)([^\x22\x27]+?)1円\s*$/); if(m)g=m[2]; varm=p[j].match(/^\s*name\s*=\s*([\x22\x27]?)([^\x22\x27]+?)1円\s*$/); if(m)n=m[2]; } if(typeof(refs[g])=='undefined')refs[g]={}; if(n!==null){ if(typeof(refs[g][n])=='undefined')refs[g][n]={text:null,type:'?'}; if(refs[g][n].text===null&&p[0]!==''){ refs[g][n].text=p[0]; refs[g][n].type='tag' } } returnnull; }); returnrefs; }, process_templates:function(txt,cb,data){ varstack=[],i=0; while(i<txt.length){ varx=stack.length?stack[stack.length-1]:null; varxb=null; for(varj=0;j<stack.length;j++){ if(stack[j].char=='\x5b')xb=stack[j]; } if(txt.substr(i,2)=='\x7b\x7b'){ varct; for(ct=2;txt.substr(i+ct,1)=='\x7b';ct++); stack.push({char:'\x7b',start:i,count:ct,pstart:i+ct,params:[]}); i+=ct; }elseif(txt.substr(i,2)=='\x5b\x5b'){ varct; for(ct=2;txt.substr(i+ct,1)=='\x5b';ct++); stack.push({char:'\x5b',start:i,count:ct,pstart:i+ct,params:[]}); i+=ct; }elseif(x&&x.char=='\x7b'&&txt.substr(i,2)=='\x7d\x7d'){ varct; 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; vars=x.start-x.count; x.params=[txt.substring(s,i-x.count)]; } // Any left is templates while(ct>=2){ x.count-=2; ct-=2; vars=x.start+x.count; varorig=txt.substring(s,i-ct); varname=x.params.shift(); varoname=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); varret=cb(name,x.params,orig,data,oname); if(ret===null){ x.params=[orig]; }else{ ret=""+ret; vard=(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; } }elseif(xb&&txt.substr(i,2)=='\x5d\x5d'){ // Drop any pending templates, they're not really templates while(stack[stack.length-1]!=xb)stack.pop(); varct; 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; } }elseif(x&&txt.substr(i,1)=='|'){ x.params.push(txt.substring(x.pstart,i)); x.pstart=++i; }else{ i++; } } returntxt; }, onLoad:function(){ varaction=mw.config.get('wgAction'); if(action!='edit'&&action!='submit')return; vareditForm=document.getElementById('editform'); if(!editForm)return; varsectionField=editForm.elements['wpSection']; varisSection=(sectionField&§ionField.value!=""); varp=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(){ varb=newOO.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(){ returnAJAXPreview.txt.value; }, // Add callback functions here. AddOnLoadHook:function(f){ AJAXPreview.$OnLoadHooks.push(f); }, $OnLoadHooks:[] }; $(document).ready(AJAXPreview.onLoad);