/**
* @constructor
* @param input Reference to watched input element. Text input expected.
* @param callBack Event handler. Function will be called on input change. Current value of input will be passed as 1st argument.
* @param object Set variable <i>this</i> in called event handler, if event handler is non-static.
* @param interval Set watch interval. Default is 200ms.
* @class Instance of InputWatch watches input element and call event handler on input change.
*/
function InputWatch(input, callBack, object, interval) {
if (interval==undefined)
// 200ms interval by default
interval = 200;
/** @private */ this.input = input;
/** @private */ this.callBack = callBack;
/** @private */ this.object = object;
/** @private */ this.lastVal = this.input.value;
var cbInternal = function() {
var val = this.input.value;
if (val != this.lastVal) {
this.lastVal = val;
this.callBack.call(this.object, val);
}
}
var cbInternalWrapper = function() {
cbInternal.call(arguments.callee.object);
}
cbInternalWrapper.object = this;
window.setInterval(cbInternalWrapper, interval);
}
/**
* @constructor
* @param searchStr Sting to search.
* @class Search text in text.
*/
function SearchEngine(searchStr) {
/**
* Escape regular expressions in text
* @param text Text to escape.
* @return Escaped text.
* @type String
* @private
*/
SearchEngine.prototype.escapeRegExp = function(text) {
text = text.replace(/\\/g, '\\\\');
text = text.replace(/\^/g, '\\^');
text = text.replace(/\$/g, '\\$');
text = text.replace(/\./g, '\\.');
text = text.replace(/\*/g, '\\*');
text = text.replace(/\+/g, '\\+');
text = text.replace(/\?/g, '\\?');
text = text.replace(/\=/g, '\\=');
text = text.replace(/\!/g, '\\!');
text = text.replace(/\:/g, '\\:');
text = text.replace(/\|/g, '\\|');
text = text.replace(/\//g, '\\/');
text = text.replace(/\(/g, '\\(');
text = text.replace(/\)/g, '\\)');
text = text.replace(/\[/g, '\\[');
text = text.replace(/\]/g, '\\]');
text = text.replace(/\{/g, '\\{');
text = text.replace(/\}/g, '\\}');
return text;
}
/**
* @private
*/
SearchEngine.prototype.escapePunctation = function(text) {
text = text.replace(/[aá]/g, '[aá]');
text = text.replace(/[cč]/g, '[cč]');
text = text.replace(/[dď]/g, '[dď]');
text = text.replace(/[eéě]/g, '[eéě]');
text = text.replace(/[ií]/g, '[ií]');
text = text.replace(/[nň]/g, '[nň]');
text = text.replace(/[oó]/g, '[oó]');
text = text.replace(/[rř]/g, '[rř]');
text = text.replace(/[sš]/g, '[sš]');
text = text.replace(/[tť]/g, '[tť]');
text = text.replace(/[uúů]/g, '[uúů]');
text = text.replace(/[yý]/g, '[yý]');
text = text.replace(/[zž]/g, '[zž]');
return text;
}
/** @private */ this.empty = (searchStr==undefined || searchStr.length==0);
if (!this.empty) {
var pattern = searchStr;
pattern = this.escapeRegExp(pattern); // Escape special chars
pattern = this.escapePunctation(pattern); // Escape punctation
pattern = '('+pattern+')'; // Mark re subgroup (for substitutions)
/** @private */ this.re = new RegExp(pattern, 'gi');
}
/**
* Search pattern in given text.
* @param text Text to search in.
* @return Return true if pattern was matched.
* @type bool
*/
SearchEngine.prototype.isMatch = function(text) {
return !this.empty && (-1!= text.search(this.re));
}
}
/**
* @constructor
* @class <b>Experimental!</b> Will be documented later.
*/
function SearchEngineChain(searchStr) {
/** @private */ this.list = new Array();
// Decomposite input to words using white spaces as separator
var decomp = searchStr.split(/ +/);
for (var i=0; i<decomp.length; i++) {
var word = decomp[i];
if (0!=word.length)
// Crate SearchEngine object for current word
this.list.push(new SearchEngine(word));
}
}
SearchEngineChain.prototype.isMatch = function(text) {
if (0==this.list.length)
// empty search
return false;
// Walk trough chain
for (var i=0; i<this.list.length; i++)
if (!this.list[i].isMatch(text))
// particular mismatch
return false;
// 100% match
return true;
}
/**
* @constructor
* @param rootNode Root node for enumeration - his sons are enumerated.
* @param tagName Name of XML elements to enumerate. Other elements (and nodes) are filtered.
* @class Enumeration of son elements of an XML element.
*/
function ChildElementsEnumerator(rootNode, tagName) {
/** @private */ this.nodeList = rootNode.childNodes;
/** @private */ this.tagName = tagName.toLowerCase();
/** @private */ this.nodeCount = this.nodeList.length;
/**
* Reset enumeration to first son element (if exists).
*/
ChildElementsEnumerator.prototype.reset = function() {
this.current = 0;
}
this.reset();
/**
* Return next son element of specified name, if such exists.
* @return Return next son element of specified name, if such exists. Return null in other case.
* @type Element
*/
ChildElementsEnumerator.prototype.next = function() {
for (; this.current < this.nodeCount; this.current++) {
var node = this.nodeList[this.current];
if (
node.nodeType == 1 &&
node.tagName.toLowerCase() == this.tagName)
break;
}
if (this.current < this.nodeCount)
return this.nodeList[this.current++];
else
return null;
}
}
/**
* Create instance of <code>XMLHttp</code> object.
* (browser independency layer)
* @return Return instance of <code>XMLHttp</code> object
*/
function createXmlHttp() {
var xmlHttp = null;
try {
xmlHttp = new XMLHttpRequest();
}
catch(e) {
try {
xmlHttp = new ActiveXObject('Microsoft.XMLHttp');
}
catch(e) { }
}
return xmlHttp;
}
/**
* Define DOM element's <code>innerText</code> property
* if not already defined.
* (browser independency layer)
*/
function patchInnerText() {
if(typeof(HTMLElement) == "undefined" || typeof(document.documentElement.innerText) == "string")
return;
HTMLElement.prototype.__defineSetter__("innerText", function(text) {
while (this.hasChildNodes())
this.removeChild(this.firstChild);
this.appendChild(document.createTextNode(text));
});
HTMLElement.prototype.__defineGetter__("innerText", function() {
return this.textContent;
});
}
/**
* Dump object content to <code>#jsLog</code> block on page.
* (useful for debug purposes)
*/
function dump(object) {
if (null==object)
return;
log = document.getElementById('jsLog');
if (null==log)
return;
var h1 = document.createElement('h1');
h1.innerHTML = 'Dump';
log.appendChild(h1);
var text = new String;
for(tmp in object)
text += '<b>' + tmp + '</b>: ' + object[tmp] + '<br/>\n';
var p = document.createElement('p');
p.innerHTML = text;
log.appendChild(p);
}
/**
* @constructor
* @class <b>Experimental!</b> Will be documented later.
*/
function PropStorage(obj, propList) {
/** @private */ this.map = new Object;
for (var i=0; i<propList.length; i++) {
var property = propList[i];
this.map[property] = obj[property];
}
}
PropStorage.prototype.restore = function(obj) {
for (var prop in this.map)
obj[prop] = this.map[prop];
}