mirror of
https://github.com/ACSPRI/queXS
synced 2024-04-02 12:12:16 +00:00
408 lines
11 KiB
JavaScript
408 lines
11 KiB
JavaScript
/**
|
|
* Utility methods
|
|
*
|
|
* @category HTML
|
|
* @package Ajax
|
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
*
|
|
* See Main.js for author/license details
|
|
*/
|
|
// {{{ HTML_AJAX_Util
|
|
/**
|
|
* All the utilities we will be using thorough the classes
|
|
*/
|
|
var HTML_AJAX_Util = {
|
|
// Set the element event
|
|
registerEvent: function(element, event, handler)
|
|
{
|
|
element = this.getElement(element);
|
|
if (typeof element.addEventListener != "undefined") { //Dom2
|
|
element.addEventListener(event, handler, false);
|
|
} else if (typeof element.attachEvent != "undefined") { //IE 5+
|
|
element.attachEvent("on" + event, handler);
|
|
} else {
|
|
if (element["on" + event] != null) {
|
|
var oldHandler = element["on" + event];
|
|
element["on" + event] = function(e) {
|
|
oldHander(e);
|
|
handler(e);
|
|
};
|
|
} else {
|
|
element["on" + event] = handler;
|
|
}
|
|
}
|
|
},
|
|
// get the target of an event, automatically checks window.event for ie
|
|
eventTarget: function(event)
|
|
{
|
|
if (!event) var event = window.event;
|
|
if (event.target) return event.target; // w3c
|
|
if (event.srcElement) return event.srcElement; // ie 5
|
|
},
|
|
// gets the type of a variable or its primitive equivalent as a string
|
|
getType: function(inp)
|
|
{
|
|
var type = typeof inp, match;
|
|
if(type == 'object' && !inp)
|
|
{
|
|
return 'null';
|
|
}
|
|
if (type == "object") {
|
|
if(!inp.constructor)
|
|
{
|
|
return 'object';
|
|
}
|
|
var cons = inp.constructor.toString();
|
|
if (match = cons.match(/(\w+)\(/)) {
|
|
cons = match[1].toLowerCase();
|
|
}
|
|
var types = ["boolean", "number", "string", "array"];
|
|
for (key in types) {
|
|
if (cons == types[key]) {
|
|
type = types[key];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return type;
|
|
},
|
|
// repeats the input string the number of times given by multiplier. exactly like PHP's str_repeat()
|
|
strRepeat: function(inp, multiplier) {
|
|
var ret = "";
|
|
while (--multiplier > 0) ret += inp;
|
|
return ret;
|
|
},
|
|
// encode a string allowing it to be used in a query string of a url
|
|
encodeUrl: function(input) {
|
|
return encodeURIComponent(input);
|
|
},
|
|
// decode a url encoded string
|
|
decodeUrl: function(input) {
|
|
return decodeURIComponent(input);
|
|
},
|
|
// recursive variable dumper similar in output to PHP's var_dump(), the differences being: this function displays JS types and type names; JS doesn't provide an object number like PHP does
|
|
varDump: function(inp, printFuncs, _indent, _recursionLevel)
|
|
{
|
|
if (!_recursionLevel) _recursionLevel = 0;
|
|
if (!_indent) _indent = 1;
|
|
var tab = this.strRepeat(" ", ++_indent);
|
|
var type = this.getType(inp), out = type;
|
|
var consrx = /(\w+)\(/;
|
|
consrx.compile();
|
|
if (++_recursionLevel > 6) {
|
|
return tab + inp + "Loop Detected\n";
|
|
}
|
|
switch (type) {
|
|
case "boolean":
|
|
case "number":
|
|
out += "(" + inp.toString() + ")";
|
|
break;
|
|
case "string":
|
|
out += "(" + inp.length + ") \"" + inp + "\"";
|
|
break;
|
|
case "function":
|
|
if (printFuncs) {
|
|
out += inp.toString().replace(/\n/g, "\n" + tab);
|
|
}
|
|
break;
|
|
case "array":
|
|
case "object":
|
|
var atts = "", attc = 0;
|
|
try {
|
|
for (k in inp) {
|
|
atts += tab + "[" + (/\D/.test(k) ? "\"" + k + "\"" : k)
|
|
+ "]=>\n" + tab + this.varDump(inp[k], printFuncs, _indent, _recursionLevel);
|
|
++attc;
|
|
}
|
|
} catch (e) {}
|
|
if (type == "object") {
|
|
var objname, objstr = inp.toString();
|
|
if (objname = objstr.match(/^\[object (\w+)\]$/)) {
|
|
objname = objname[1];
|
|
} else {
|
|
try {
|
|
objname = inp.constructor.toString().match(consrx)[1];
|
|
} catch (e) {
|
|
objname = 'unknown';
|
|
}
|
|
}
|
|
out += "(" + objname + ") ";
|
|
}
|
|
out += "(" + attc + ") {\n" + atts + this.strRepeat(" ", _indent - 1) +"}";
|
|
break;
|
|
}
|
|
return out + "\n";
|
|
},
|
|
// non resursive simple debug printer
|
|
quickPrint: function(input,sep) {
|
|
if (!sep) {
|
|
var sep = "\n";
|
|
}
|
|
var type = HTML_AJAX_Util.getType(input);
|
|
switch (type) {
|
|
case 'string':
|
|
return input;
|
|
case 'array':
|
|
var ret = "";
|
|
for(var i = 0; i < input.length; i++) {
|
|
ret += i+':'+input[i]+sep;
|
|
}
|
|
return ret;
|
|
default:
|
|
var ret = "";
|
|
for(var i in input) {
|
|
ret += i+':'+input[i]+sep;
|
|
}
|
|
return ret;
|
|
}
|
|
},
|
|
//compat function for stupid browsers in which getElementsByTag with a * dunna work
|
|
getAllElements: function(parentElement)
|
|
{
|
|
//check for idiot browsers
|
|
if( document.all)
|
|
{
|
|
if(!parentElement) {
|
|
var allElements = document.all;
|
|
}
|
|
else
|
|
{
|
|
var allElements = [], rightName = new RegExp( parentElement, 'i' ), i;
|
|
for( i=0; i<document.all.length; i++ ) {
|
|
if( rightName.test( document.all[i].parentElement ) )
|
|
allElements.push( document.all[i] );
|
|
}
|
|
}
|
|
return allElements;
|
|
}
|
|
//real browsers just do this
|
|
else
|
|
{
|
|
if (!parentElement) { parentElement = document.body; }
|
|
return parentElement.getElementsByTagName('*');
|
|
}
|
|
},
|
|
getElementsByProperty: function(property, regex, parentElement) {
|
|
var allElements = HTML_AJAX_Util.getAllElements(parentElement);
|
|
var items = [];
|
|
for(var i=0,j=allElements.length; i<j; i++)
|
|
{
|
|
if(regex.test(allElements[i][property]))
|
|
{
|
|
items.push(allElements[i]);
|
|
}
|
|
}
|
|
return items;
|
|
},
|
|
getElementsByClassName: function(className, parentElement) {
|
|
return HTML_AJAX_Util.getElementsByProperty('className',new RegExp('(^| )' + className + '( |$)'),parentElement);
|
|
},
|
|
getElementsById: function(id, parentElement) {
|
|
return HTML_AJAX_Util.getElementsByProperty('id',new RegExp(id),parentElement);
|
|
},
|
|
getElementsByCssSelector: function(selector,parentElement) {
|
|
return cssQuery(selector,parentElement);
|
|
},
|
|
htmlEscape: function(inp) {
|
|
var div = document.createElement('div');
|
|
var text = document.createTextNode(inp);
|
|
div.appendChild(text);
|
|
return div.innerHTML;
|
|
},
|
|
// return the base of the given absolute url, or the filename if the second argument is true
|
|
baseURL: function(absolute, filename) {
|
|
var qPos = absolute.indexOf('?');
|
|
if (qPos >= 0) {
|
|
absolute = absolute.substr(0, qPos);
|
|
}
|
|
var slashPos = Math.max(absolute.lastIndexOf('/'), absolute.lastIndexOf('\\'));
|
|
if (slashPos < 0) {
|
|
return absolute;
|
|
}
|
|
return (filename ? absolute.substr(slashPos + 1) : absolute.substr(0, slashPos + 1));
|
|
},
|
|
// return the query string from a url
|
|
queryString: function(url) {
|
|
var qPos = url.indexOf('?');
|
|
if (qPos >= 0) {
|
|
return url.substr(qPos+1);
|
|
}
|
|
},
|
|
// return the absolute path to the given relative url
|
|
absoluteURL: function(rel, absolute) {
|
|
if (/^https?:\/\//i.test(rel)) {
|
|
return rel;
|
|
}
|
|
if (!absolute) {
|
|
var bases = document.getElementsByTagName('base');
|
|
for (i in bases) {
|
|
if (bases[i].href) {
|
|
absolute = bases[i].href;
|
|
break;
|
|
}
|
|
}
|
|
if (!absolute) {
|
|
absolute = window.location.href;
|
|
}
|
|
}
|
|
if (rel == '') {
|
|
return absolute;
|
|
}
|
|
if (rel.substr(0, 2) == '//') {
|
|
// starts with '//', replace everything but the protocol
|
|
var slashesPos = absolute.indexOf('//');
|
|
if (slashesPos < 0) {
|
|
return 'http:' + rel;
|
|
}
|
|
return absolute.substr(0, slashesPos) + rel;
|
|
}
|
|
var base = this.baseURL(absolute);
|
|
var absParts = base.substr(0, base.length - 1).split('/');
|
|
var absHost = absParts.slice(0, 3).join('/') + '/';
|
|
if (rel.substr(0, 1) == '/') {
|
|
// starts with '/', append it to the host
|
|
return absHost + rel;
|
|
}
|
|
if (rel.substr(0, 1) == '.' && rel.substr(1, 1) != '.') {
|
|
// starts with '.', append it to the base
|
|
return base + rel.substr(1);
|
|
}
|
|
// remove everything upto the path and beyond
|
|
absParts.splice(0, 3);
|
|
var relParts = rel.split('/');
|
|
var loopStart = relParts.length - 1;
|
|
relParts = absParts.concat(relParts);
|
|
for (i = loopStart; i < relParts.length;) {
|
|
if (relParts[i] == '..') {
|
|
if (i == 0) {
|
|
return absolute;
|
|
}
|
|
relParts.splice(i - 1, 2);
|
|
--i;
|
|
continue;
|
|
}
|
|
i++;
|
|
}
|
|
return absHost + relParts.join('/');
|
|
},
|
|
// sets the innerHTML of an element. the third param decides how to write, it replaces by default, others are append|prepend
|
|
setInnerHTML: function(node, innerHTML, type)
|
|
{
|
|
node = this.getElement(node);
|
|
|
|
if (type != 'append') {
|
|
if (type == 'prepend') {
|
|
var oldHtml = node.innerHTML;
|
|
}
|
|
node.innerHTML = '';
|
|
}
|
|
var good_browser = (window.opera || navigator.product == 'Gecko');
|
|
var regex = /^([\s\S]*?)<script([\s\S]*?)>([\s\S]*?)<\/script>([\s\S]*)$/i;
|
|
var regex_src = /src=["'](.*?)["']/i;
|
|
var matches, id, script, output = '', subject = innerHTML;
|
|
var scripts = [];
|
|
|
|
while (true) {
|
|
matches = regex.exec(subject);
|
|
if (matches && matches[0]) {
|
|
subject = matches[4];
|
|
id = 'ih_' + Math.round(Math.random()*9999) + '_' + Math.round(Math.random()*9999);
|
|
|
|
var startLen = matches[3].length;
|
|
script = matches[3].replace(/document\.write\(([\s\S]*?)\)/ig,
|
|
'document.getElementById("' + id + '").innerHTML+=$1');
|
|
|
|
output += matches[1];
|
|
if (startLen != script.length) {
|
|
output += '<span id="' + id + '"></span>';
|
|
}
|
|
|
|
output += '<script' + matches[2] + '>' + script + '</script>';
|
|
if (good_browser) {
|
|
continue;
|
|
}
|
|
if (script) {
|
|
scripts.push(script);
|
|
}
|
|
if (regex_src.test(matches[2])) {
|
|
var script_el = document.createElement("SCRIPT");
|
|
var atts_regex = /(\w+)=["'](.*?)["']([\s\S]*)$/;
|
|
var atts = matches[2];
|
|
for (var i = 0; i < 5; i++) {
|
|
var atts_matches = atts_regex.exec(atts);
|
|
if (atts_matches && atts_matches[0]) {
|
|
script_el.setAttribute(atts_matches[1], atts_matches[2]);
|
|
atts = atts_matches[3];
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
scripts.push(script_el);
|
|
}
|
|
} else {
|
|
output += subject;
|
|
break;
|
|
}
|
|
}
|
|
innerHTML = output;
|
|
|
|
if (good_browser) {
|
|
var el = document.createElement('span');
|
|
el.innerHTML = innerHTML;
|
|
|
|
for(var i = 0; i < el.childNodes.length; i++) {
|
|
node.appendChild(el.childNodes[i].cloneNode(true));
|
|
}
|
|
}
|
|
else {
|
|
node.innerHTML += innerHTML;
|
|
}
|
|
|
|
if (oldHtml) {
|
|
node.innerHTML += oldHtml;
|
|
}
|
|
|
|
if (!good_browser) {
|
|
for(var i = 0; i < scripts.length; i++) {
|
|
if (HTML_AJAX_Util.getType(scripts[i]) == 'string') {
|
|
scripts[i] = scripts[i].replace(/^\s*<!(\[CDATA\[|--)|((\/\/)?--|\]\])>\s*$/g, '');
|
|
window.eval(scripts[i]);
|
|
}
|
|
else {
|
|
node.appendChild(scripts[i]);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
},
|
|
classSep: '(^|$| )',
|
|
hasClass: function(o, className) {
|
|
var o = this.getElement(o);
|
|
var regex = new RegExp(this.classSep + className + this.classSep);
|
|
return regex.test(o.className);
|
|
},
|
|
addClass: function(o, className) {
|
|
var o = this.getElement(o);
|
|
if(!this.hasClass(o, className)) {
|
|
o.className += " " + className;
|
|
}
|
|
},
|
|
removeClass: function(o, className) {
|
|
var o = this.getElement(o);
|
|
var regex = new RegExp(this.classSep + className + this.classSep);
|
|
o.className = o.className.replace(regex, " ");
|
|
},
|
|
replaceClass: function(o, oldClass, newClass) {
|
|
var o = this.getElement(o);
|
|
var regex = new RegExp(this.classSep + oldClass + this.classSep);
|
|
o.className = o.className.replace(regex, newClass);
|
|
},
|
|
getElement: function(el) {
|
|
if (typeof el == 'string') {
|
|
return document.getElementById(el);
|
|
}
|
|
return el;
|
|
}
|
|
}
|
|
// }}}
|