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

{

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

{

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;

}

};

//