Jump to content

User:Zocky/LinkComplete.js

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.
// <pre><nowiki>
//  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;
 }
}; 

//<nowiki></pre>