Extension talk:QuickLink/QuickLink.js

From mediawiki.org

modified QuickLink (2010-09-11)[edit]

/*
 QuickLink.js
 Copyright Francisco J. R. Prados 2009, Adam Meyer 2007
 */

var QuickLink = new Object();

QuickLink.searchTimeout = 500;
QuickLink.timer = 0;
QuickLink.counting = false;

QuickLink.searchBuffer = null;

QuickLink.searchBox = null;
QuickLink.textarea = null;
QuickLink.inputField = null;
QuickLink.lastLink = null;

QuickLink.linkStart = -1;
QuickLink.lastSelectedItem = -1;
QuickLink.caret = -1;

QuickLink.lastKey = null;


/*
QuickLink.insertLink function
This function will be triggered when clicking one of the results
returned to the QuickLinkResults div by the wfAjaxQuickLink call
*/
QuickLink.insertLink = function(name) {

	// if QuickLink.linkStart > 0, the search was triggered by the [[ sequence
	// otherwise the search was triggered by the input search box
	
	if( QuickLink.linkStart>0  ) {
		QuickLink.textarea.value = QuickLink.textarea.value.substr(0, QuickLink.linkStart-2) + '[[' + name + ']]' + QuickLink.textarea.value.substr( QuickLink.caret );
		if(QuickLink.textarea.setSelectionRange)
			QuickLink.textarea.setSelectionRange(QuickLink.linkStart + name.length + 2,QuickLink.linkStart + name.length + 2);
		QuickLink.caret = QuickLink.linkStart + name.length + 2;
	}
	else {
		QuickLink.textarea.value = QuickLink.textarea.value.substr( 0, QuickLink.caret ) + '[[' + name + ']]' + QuickLink.textarea.value.substr( QuickLink.caret );
		// problems when using escape!
		//insertTags('[['+name+']]', '', '');
		QuickLink.inputField.value = '';
		QuickLink.caret = QuickLink.caret + name.length + 4;
	}
	QuickLink.lastLink = name;
	QuickLink.setCaret(QuickLink.caret);
	QuickLink.resetSearchBox();
}


QuickLink.textareaOnClick = function(e) {

	QuickLink.resetSearchBox();
		QuickLink.caret = SearchCaret( this );
}


/*
Init function
Creates all the elements neeeded for the search, attachtes
the events and calls QuickLink.resetSearchBox()
*/
QuickLink.load = function() {

	QuickLink.textarea = document.getElementById( 'wpTextbox1');

	// first check if the textbox is readonly
	// (i.e. in protected pages)

	if(!QuickLink.textarea.readOnly) {

		var toolbar = document.getElementById("toolbar");
	
		QuickLink.textarea.onkeyup = QuickLink.textSearch;
		QuickLink.textarea.onkeydown = QuickLink.captureKeys;
		QuickLink.textarea.onclick = QuickLink.textareaOnClick;
		
		// create the input search box in toolbar
		var box = document.createElement("div");
		box.title = "Link an der Cursor-Position einfĂźgen";
		box.id = "QuickLinkBox";
		toolbar.appendChild(box);
	
		var label = document.createElement("span");
		label.innerHTML = "QuickLink";
		label.id = "QuickLinkLabel";
		box.appendChild(label);
		QuickLink.inputFieldLabel = document.createElement("label");
		QuickLink.inputFieldLabel.id = "QuickLinkInputLabel";
		QuickLink.inputFieldLabel.htmlFor = "QuickLinkInput";
		QuickLink.inputFieldLabel.innerHTML = "Link:";
		box.appendChild(QuickLink.inputFieldLabel);
	
		QuickLink.inputField = document.createElement("input");
		QuickLink.inputField.id = "QuickLinkInput";
	 	QuickLink.inputField.onkeyup = QuickLink.delayedSearch;
		box.appendChild(QuickLink.inputField);
	
		var help = document.createElement("a");
		help.innerHTML = "?";
		help.title = "Press Ctrl+Space while writing the article to trigger the search box. Type a string and the matching results will be shown. Press enter to select the first result, or Esc to return to the writing box.";
		//box.appendChild(help);
	
		// create the box for results
		QuickLink.searchBox = document.createElement("div");
		QuickLink.searchBox.id = "QuickLinkResults";
		toolbar.appendChild(QuickLink.searchBox);

		// reset the search box to the initial state
		QuickLink.resetSearchBox();
	}
}


QuickLink.searchCall = function(query) {

	if(	QuickLink.lastSelectedItem >= 0) {
	}

	//QuickLink.searchBox.innerHTML = "<p>Retrieving results for '"+query+"' ...</p>";
	sajax_do_call("wfAjaxQuickLink", [query], QuickLink.AJAXStateChange);
}


/*
Callback called when request.readyState = 4
*/
QuickLink.AJAXStateChange = function(request) {

	QuickLink.searchBox.innerHTML = request.responseText;
	QuickLink.selectResult(0);
}


/*
Delayed search method for the QuickLink.inputField.onkeyup event
*/
QuickLink.delayedSearch = function(e) {

	var evt = (e) ? e : window.event;
	var code = evt.keyCode ? evt.keyCode : evt.charCode ? evt.charCode : evt.which ? evt.which : void 0; 
	if(code == 27) {
		QuickLink.resetLinkAndCaret(0);
	}
	else if(code == 13) {
		QuickLink.insertSelectedResult();
	}
	else if(code == 38) {
		QuickLink.selectPreviousResult();
	}
	else if(code == 40) {
		QuickLink.selectNextResult();
	}
	else{

		if(QuickLink.counting)
			clearTimeout(QuickLink.timer);

		QuickLink.timer = setTimeout("QuickLink.inputFieldSearch()",QuickLink.searchTimeout);
		QuickLink.counting = true;
	}
}


/*
Search method for the QuickLink.inputField.onkeyup event
*/
QuickLink.inputFieldSearch = function() {

	// reset delayed search
	QuickLink.counting = false;
	
	var query = document.getElementById('QuickLinkInput').value;

	if (query != QuickLink.searchBuffer) {

		QuickLink.searchBuffer = query;

		if(query.length > 0) {
			QuickLink.initSearchBox();

			if (query.length < 30 && query.length > 0 && query.value != "") {
				QuickLink.searchCall(query);
			}
		}
		else
			QuickLink.resetSearchBox();
	}
}


/*
Search method for IE
*/
SearchCaret = function(textarea) {

	var caret = textarea.selectionEnd;
	if(!caret) {
		if( document.selection ){
			// current selection
			var range = document.selection.createRange();
			var stored_range = range.duplicate();
			// Select all text
			stored_range.moveToElementText( textarea );
			// move 'dummy' end point to end point of original range
			stored_range.setEndPoint( 'EndToEnd', range );
			// calculate caret position
			caret = stored_range.text.length - range.text.length ;
		} else {
			caret = 0;
		}
	}
	return caret;
}

/*
Search method for the QuickLink.textarea.onkeyup event
Search will be triggered when typing the sequence [[, or placing the caret
by an existing sequence
*/
QuickLink.textSearch = function(e) {

	var evt = (e) ? e : window.event;
	if(evt.ctrlKey && evt.keyCode == 32) {
		QuickLink.inputField.focus();
	}
	
	QuickLink.caret = SearchCaret( this );
	
	if(QuickLink.linkStart<0 || QuickLink.caret < QuickLink.linkStart) {
		if ( this.value.charAt(QuickLink.caret-1)=='[' && this.value.charAt(QuickLink.caret-2)=='[') {
			if ( QuickLink.lastKey == 39 && evt.keyCode == 39) {
				// Navigating through the source with cursors- no QuickLink!
				QuickLink.resetSearchBox();
				QuickLink.lastKey = evt.keyCode;
			} else {
				QuickLink.linkStart = QuickLink.caret;
			}
		} else {
			QuickLink.resetSearchBox();
			QuickLink.lastKey = evt.keyCode;
		}
	}
	else {
		QuickLink.initSearchBox();
		var searchString = this.value.substr(QuickLink.linkStart,QuickLink.caret-QuickLink.linkStart);
		//caretxy = vsk_frm_cursor_offset(QuickLink.textarea); 
		//console.log(caretxy);
		//QuickLink.searchBox.style.position = 'absolute';
		//QuickLink.searchBox.style.top = caretxy.y + this.offsetTop + "px";
		//QuickLink.searchBox.style.left = caretxy.x + this.offsetLeft + "px";
		QuickLink.inputField.value = searchString;
		QuickLink.searchCall(searchString);
	}
}


/*
Key capture method for the textarea
*/
QuickLink.captureKeys = function(e) {

	var evt = (e) ? e : window.event;
	var code = evt.keyCode ? evt.keyCode : evt.charCode ? evt.charCode : evt.which ? evt.which : void 0;
	if(QuickLink.linkStart>0) {
		switch(code) {
			// space
			case 32:
			break;
			// left
			case 37:
			break;
			// up
			case 38:
			break;
			// right
			case 39:
			break;
			// down
			case 40:
			break;
			// enter
			case 13:
			QuickLink.insertSelectedResult();
			break;
			// escape
			case 27:
			QuickLink.resetLinkAndCaret(2);
			break;
		}	
		//e.cancelBubble=true;
		//e.stopPropagation()
	}
}

QuickLink.initSearchBox = function() {

	QuickLink.searchBox.style.visibility = 'visible';
	QuickLink.lastSelectedItem = -1;
}

/*
OnKeyDown: escape
IE: escape sets the caret to the end of the textarea
*/
QuickLink.resetLinkAndCaret = function(offSet) {

	// remove link
	var LinkStart = null;
	if (offSet == 0) {
		//nothing written to the textarea!
		LinkStart = QuickLink.caret;
	} else {
		LinkStart = QuickLink.caret - QuickLink.inputField.value.length - offSet;
		QuickLink.textarea.value = QuickLink.textarea.value.substr (0, LinkStart ) + QuickLink.textarea.value.substr( LinkStart + offSet + QuickLink.inputField.value.length );
	}
	// set caret back to the beginning position
	QuickLink.setCaret(LinkStart);
	QuickLink.resetSearchBox();
}


QuickLink.setCaret = function(caretPos) {

	QuickLink.textarea.focus();
	if(QuickLink.textarea.setSelectionRange) {
		// FF
		QuickLink.textarea.setSelectionRange(caretPos,caretPos);
	} else if (QuickLink.textarea.createTextRange) {
		// IE - counts line wraps
		if( QuickLink.linkStart>0 ) {
			// triggered by '[['
			var dummy_textarea = QuickLink.textarea.value.substr( 0, QuickLink.linkStart - 2 );
			if ( QuickLink.lastLink != null ) {
				dummy_textarea = dummy_textarea + '[[' + QuickLink.lastLink + ']]';
			}
		} else {
			var dummy_textarea = QuickLink.textarea.value.substr( 0, QuickLink.caret );
		}
		caretPos = dummy_textarea.replace(/\r\n/g,' ').length;
		window.setTimeout( 'QuickLink.setCaretIE(' + caretPos + ');', 10);
	}
}

QuickLink.setCaretIE = function(caretPos) {

	var range = document.selection.createRange();
	var stored_range = range.duplicate();
	stored_range.moveToElementText( QuickLink.textarea );
	stored_range.collapse(true);
	stored_range.moveStart( 'character', caretPos );
	stored_range.moveEnd( 'character', 0 );
	stored_range.select();
}

QuickLink.resetSearchBox = function() {

	QuickLink.inputField.value = '';
	QuickLink.searchBox.style.visibility = 'hidden';
	QuickLink.linkStart = -1;
	QuickLink.lastSelectedItem = -1;
	QuickLink.lastLink = null;
}

QuickLink.selectResult = function(item) {

	// if QuickLink.lastSelectedItem < 0 then notihng was selected

	if(QuickLink.lastSelectedItem >= 0)
		if(QuickLink.searchBox.getElementsByTagName('a').item(QuickLink.lastSelectedItem))
			QuickLink.searchBox.getElementsByTagName('a')[QuickLink.lastSelectedItem].className = 'unselected';

	// select an item only if item > -1
	// if item is out of range, QuickLink.lastSelectedItem = -1
	if(item >= 0)
		if(QuickLink.searchBox.getElementsByTagName('a').item(item)) {
			QuickLink.searchBox.getElementsByTagName('a')[item].className = 'selected';
			QuickLink.lastSelectedItem = item;
		}
		else {
			QuickLink.lastSelectedItem = -1;
		}
}


QuickLink.insertSelectedResult = function() {

	var selectedResult = QuickLink.searchBox.getElementsByTagName('a').item(QuickLink.lastSelectedItem);
	
	if(selectedResult)
		selectedResult.onclick();
}


QuickLink.selectNextResult = function() {

	var max = QuickLink.searchBox.getElementsByTagName('a').length;
	
	if(QuickLink.lastSelectedItem < max-1) {
		QuickLink.selectResult(QuickLink.lastSelectedItem+1);
	}
}


QuickLink.selectPreviousResult = function() {

	if(QuickLink.lastSelectedItem > 0) {
		QuickLink.selectResult(QuickLink.lastSelectedItem-1);
	}
}