function $(elid)
{
return document.getElementById(elid);
}
function bind(toObject, methodName)
{
return function(e){toObject[methodName](e)}
}
function listen(object, hevent, hfunc)
{
if (object.addEventListener)
object.addEventListener(hevent,hfunc,false);
else if (object.attachEvent)
object.attachEvent('on'+hevent,hfunc);
}
function listenex(object, hevent, lobject, lfunc)
{
listen(object, hevent, bind(lobject, lfunc));
}
function AutoTagsField(fieldid)
{
/* Properties */
this.field = $(fieldid);
this.buffer = "";
//Handlers setupment
listenex(this.field, "keyup", this, "key_up_handler");
/* Handlers */
//Handler
this.key_up_handler = function()
{
//Getting values for `default` browsers
var selectionStart = this.field.selectionStart;
var selectionEnd = this.field.selectionEnd;
//Creating selection method for our friend IE
if (document.all)
{
//Creating range
var range = document.selection.createRange();
//Cloning
var crange = range.duplicate();
//Aquiring to the our field
crange.moveToElementText(this.field);
crange.setEndPoint("EndToEnd", range);
//Overwriting values
selectionStart = crange.text.length - range.text.length;
selectionEnd = crange.text.length - selectionStart;
}
//Appending buffer information
this.buffer += this.field.value.substring(selectionStart - 1, selectionStart);
//Receiving matches
var matches = this.filter_tags(this.field.value.match(/<.*?[^\/]>/gm));
//End of tag?
if (this.buffer.match(/<\//g) && matches.length != 0)
{
//Tag name construction
var tagname = "/" + matches.pop().match(/<(.*)>/)[1] + ">";
//Storing position
var safe_position = selectionStart + tagname.length -1;
//Appending to the right place
this.field.value = this.field.value.substring(0, selectionStart-1) + tagname +
this.field.value.substring(selectionStart);
//Setting position
this.field.selectionStart = safe_position;
this.field.selectionEnd = safe_position;
//IE selection
if (document.all)
{
//Collapsing
crange.collapse(true);
//Moving selection start
crange.moveStart("character", safe_position);
//And selectio end
crange.moveEnd("character", selectionEnd);
//Performing
crange.select();
}
//Buffer should be empt now
this.buffer = " ";
//For our friend IE
if (window.event)
window.event.returnValue = false;
//Oops?
return false;
}
}
/* Methods */
//Filtering tags
this.filter_tags = function(tagarray)
{
//Exists?
if (tagarray == null)
return;
//Debug
/*var txt = "<pre>";
for (var l = 0; l < tagarray.length; l++)
{
txt += (l+1).toString() + ". " + tagarray[l].match(/<(.*?)(?:\s+[^>]+|)>/)[1] + "\r\n"
}*/
//Creating arrays
var clean = new Array(), result = new Array();
//Traversing
for (i = 0, ilength = tagarray.length; i < ilength; i++)
{
//Oh, matching
var name = tagarray[i].match(/<(?:\/|)(.*?)(?:\s+[^>]+|)>/)[1];
//Close tag?
var is_close = false;
if (tagarray[i].match(/<\/[^>]+>/))
is_close = true;
//Adding to cleaning array
if (clean[name] == null)
{
clean[name] = { "close" : 0, "open" : 0 };
}
if (is_close)
clean[name].close++;
else
clean[name].open++;
}
//Traversing again
for (elem in clean)
{
//All is ok?
if (clean[elem].open == clean[elem].close)
continue;
result.push("<" + elem + ">");
}
//DEBUG
/*txt += "\r\nCleaned:\r\n";
for (var l = 0; l < result.length; l++)
{
txt += (l+1).toString() + ". " + result[l].match(/<(?:\/|)(.*?)(?:\s+[^>]+|)>/)[1] + "\r\n"
}
txt += "</pre>";
$DEBUG(txt);*/
//To the user
return result;
}
}
var autotags = new AutoTagsField("taglist");