User:Zocky/LinkComplete.js

// //  Auto complete for links in the editbox GPL, (c) 2006, en:User:Zocky // type [[foo and press ctrl+space //  should work in most browsers

// hook $(linkCompleteInit);

//init function linkCompleteInit { if ($('wpTextbox1')) {   eventAddListener($('wpTextbox1'),'keydown',linkCompleteKeyHandler); eventAddListener($('wpTextbox1'),'keyup',linkCompleteKeyIgnorer1); eventAddListener($('wpTextbox1'),'keypress',linkCompleteKeyIgnorer2); linkCompleteRegExp = window['linkCompleteTriggers'] || [ /\[\[([^\[\]\|\n]*?)$/ ]; } }

// a bunch of globals [[a var linkCompleteStatus='idle'; var linkCompleteFind=''; var linkCompleteMatches=[]; var linkCompleteNextPage; var linkCompleteNextMatch=0; var linkCompleteStart=0; var linkCompleteTarget=null; var linkCompleteRegExp=[];

// helpers function linkCompleteInsert(s) { var top=linkCompleteTarget.scrollTop; linkCompleteTarget.value = linkCompleteTarget.value.substr(0,linkCompleteStart) + s                          + linkCompleteTarget.value.substr(selectionGetStart(linkCompleteTarget)); linkCompleteTarget.scrollTop=top; selectionSet(linkCompleteTarget, linkCompleteStart+s.length,linkCompleteStart+s.length); }

function linkCompleteInsertMatch { if (linkCompleteNextMatch<linkCompleteMatches.length) {   linkCompleteInsert(linkCompleteMatches[linkCompleteNextMatch]); linkCompleteNextMatch++; return true; } else {   return false; } }

function linkCompleteGetMatches(from) { linkCompleteStatus='waiting'; mwQueryPhp(linkCompleteLoaded,"allpages","apfrom", from, "aplimit","50","apfilterredir","nonredirects","apnamespace",window.linkCompleteNamespace || 0); linkCompleteInsert(linkCompleteFind+'...'); }

function linkCompleteReset { linkCompleteStatus='idle'; linkCompleteInsert(linkCompleteFind); linkCompleteMatches=[]; }

// main function

function linkCompleteKeyIgnorer1(e) { keynum = eventKeyCode(e); if (keynum==9) eventStop(e); }

function linkCompleteKeyIgnorer2(e) { keynum = e.charCode || e.keyCode; if (keynum==9) eventStop(e); }

function linkCompleteKeyHandler(e) { keynum = eventKeyCode(e); target=eventTarget(e);

if ((keynum==9 || e.ctrlKey && keynum==32) && selectionGetStart(target)==selectionGetEnd(target)) {   if (target!=linkCompleteTarget) {       linkCompleteTarget=target; linkCompleteStatus='idle'; }    switch(linkCompleteStatus) {     case 'idle': var find; for (var i in linkCompleteRegExp) {       find = (target.value.substr(0,selectionGetStart(target)).match(linkCompleteRegExp[i]) || [])[1]; if (find) break; }     if (find) {        linkCompleteMatches=[]; linkCompleteNextMatch=0; linkCompleteFind=find; linkCompleteStart=selectionGetStart(target)-find.length; linkCompleteGetMatches(find.capitalize); }      break; case 'waiting': break; case 'loaded': if(linkCompleteNextMatch<linkCompleteMatches.length) {        linkCompleteInsertMatch || linkCompleteReset; }     else {       if (linkCompleteNextPage) {         linkCompleteGetMatches(linkCompleteNextPage); }       else {         linkCompleteNextMatch=0; linkCompleteInsertMatch || linkCompleteReset; }     }    }     eventStop(e); } else {   linkCompleteStatus == 'waiting' && linkCompleteReset; linkCompleteStatus = 'idle'; } }

// JSON callback function linkCompleteLoaded(obj) {  if (obj) {

if (linkCompleteStatus=='waiting') {     for (var i in obj.query.allpages) {        page=obj.query.allpages[i]; if        (           page.title           && (page.ns && page.title.replace(/^.*?:/,'').substr(0,linkCompleteFind.length) == linkCompleteFind.capitalize)          || page.title.substr(0,linkCompleteFind.length) == linkCompleteFind.capitalize        ) {            linkCompleteMatches[linkCompleteMatches.length] = page.ns ? page.title : linkCompleteFind + page.title.substr(linkCompleteFind.length); }     }

linkCompleteNextPage = obj['query-continue'] ? obj['query-continue'].allpages.continue.substr(0,linkCompleteFind.length) == linkCompleteFind.capitalize ? obj['query-continue'].allpages.continue : false : false;

linkCompleteInsertMatch && (linkCompleteStatus='loaded') || linkCompleteReset; } }  else {   linkCompleteReset; } }

// query.php wrapper function mwQueryPhp (cb,what) { var x = window.XMLHttpRequest ? new XMLHttpRequest : window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : false;

if (mwQueryPhp.arguments.length>1 && x)  { var url= mw.config.get('wgScriptPath') +"/api.php?format=json&action=query&list="+what; for (var i=2; i < mwQueryPhp.arguments.length; i+=2 ) {     url=url+"&"+escape(mwQueryPhp.arguments[i]) + "=" + escape(mwQueryPhp.arguments[i+1]); }

x.onreadystatechange=function { if (x.readyState==4) return x.status==200 ? cb(x.responseText.parseJSON) : cb(false); };   x.open("GET",url,true); x.setRequestHeader('Accept','text/*'); x.send(null); return true; } else return false; }

// cross-browser event functions

function eventAddListener (element,event,handler) {  if (element.addEventListener) element.addEventListener(event,handler,false) else element.attachEvent('on'+event,handler); }

function eventRemoveListener (element, event, handler) { if (element.removeEventListener) element.removeEventListener(event,handler,false) else element.detachEvent('on'+event,handler); }

function eventStop(event) { if (event.preventDefault) {    event.preventDefault; event.stopPropagation; } else {  event.returnValue = false; event.cancelBubble = true; } }

function eventTarget(event) { return event.target || event.srcElement; }

function eventKeyCode(event) {  return event.preventDefault ? event.which : event.keyCode ; }

function $(id) { return document.getElementById(id); }

//from http://www.json.org/json.js String.prototype.parseJSON = function { try { return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test( this.replace(/"(\\.|[^"\\])*"/g, ''))) &&           eval('(' + this + ')');    } catch (e) {        return false;    } };

//"foo".capitalize -> "Foo" String.prototype.capitalize = function { return this.substring(0,1).toUpperCase+this.substring(1)};

function selectionSet(input, start, end) { if (input.setSelectionRange) {  input.setSelectionRange(start,end) input.selectionEnd=end; } else {  var range = input.createTextRange; range.collapse(true); range.moveStart("character", start); range.moveEnd("character", end - start); range.select; } };

function selectionGetStart(input) { if (input.setSelectionRange) {  return input.selectionStart; } else {  var range = document.selection.createRange; var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0; if (!isCollapsed)range.collapse(true); var b = range.getBookmark; return b.charCodeAt(2) - 2; } };

function selectionGetEnd(input) { if (input.setSelectionRange) {  return input.selectionEnd; } else {  var range = document.selection.createRange; var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0; if (!isCollapsed)range.collapse(false); var b = range.getBookmark; return b.charCodeAt(2) - 2; } };

//