/**
* Compat functions
* @category HTML
* @package AJAX
* @author Joshua Eichorn
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
*/
/**
* Functions for compatibility with older browsers
*/
if (!String.fromCharCode && !String.prototype.fromCharCode) {
String.prototype.fromCharCode = function(code)
{
var h = code.toString(16);
if (h.length == 1) {
h = '0' + h;
}
return unescape('%' + h);
}
}
if (!String.charCodeAt && !String.prototype.charCodeAt) {
String.prototype.charCodeAt = function(index)
{
var c = this.charAt(index);
for (i = 1; i < 256; i++) {
if (String.fromCharCode(i) == c) {
return i;
}
}
}
}
// http://www.crockford.com/javascript/remedial.html
if (!Array.splice && !Array.prototype.splice) {
Array.prototype.splice = function(s, d)
{
var max = Math.max,
min = Math.min,
a = [], // The return value array
e, // element
i = max(arguments.length - 2, 0), // insert count
k = 0,
l = this.length,
n, // new length
v, // delta
x; // shift count
s = s || 0;
if (s < 0) {
s += l;
}
s = max(min(s, l), 0); // start point
d = max(min(typeof d == 'number' ? d : l, l - s), 0); // delete count
v = i - d;
n = l + v;
while (k < d) {
e = this[s + k];
if (!e) {
a[k] = e;
}
k += 1;
}
x = l - s - d;
if (v < 0) {
k = s + i;
while (x) {
this[k] = this[k - v];
k += 1;
x -= 1;
}
this.length = n;
} else if (v > 0) {
k = 1;
while (x) {
this[n - k] = this[l - k];
k += 1;
x -= 1;
}
}
for (k = 0; k < i; ++k) {
this[s + k] = arguments[k + 2];
}
return a;
}
}
if (!Array.push && !Array.prototype.push) {
Array.prototype.push = function()
{
for (var i = 0, startLength = this.length; i < arguments.length; i++) {
this[startLength + i] = arguments[i];
}
return this.length;
}
}
if (!Array.pop && !Array.prototype.pop) {
Array.prototype.pop = function()
{
return this.splice(this.length - 1, 1)[0];
}
}
if (window.ActiveXObject && window['DOMParser'] == 'undefined') {
window.DOMParser = new function() {};
DOMParser.prototype = {
parseFromString: function(str, contentType) {
var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
xmlDocument.loadXML(str);
return xmlDocument;
}
};
window.XMLSerializer = new function() {};
XMLSerializer.prototype = {
serializeToString: function(root) {
return root.xml || root.outerHTML;
}
};
}
/**
* JavaScript library for use with HTML_AJAX
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to:
* Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category HTML
* @package Ajax
* @author Joshua Eichorn
* @author Arpad Ray
* @author David Coallier
* @author Elizabeth Smith
* @copyright 2005 Joshua Eichorn, Arpad Ray, David Coallier, Elizabeth Smith
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
*/
/**
* HTML_AJAX static methods, this is the main proxyless api, it also handles global error and event handling
*/
var HTML_AJAX = {
version: '0.5.6',
defaultServerUrl: false,
defaultEncoding: 'JSON',
queues: false,
clientPools: {},
// get an HttpClient, supply a name to use the pool of that name or the default if it isn't found
httpClient: function(name) {
if (name) {
if (this.clientPools[name]) {
return this.clientPools[name].getClient();
}
}
return this.clientPools['default'].getClient();
},
// Pushing the given request to queue specified by it, in default operation this will immediately make a request
// request might be delayed or never happen depending on the queue setup
// making a sync request to a non immediate queue will cause you problems so just don't do it
makeRequest: function(request) {
if (!HTML_AJAX.queues[request.queue]) {
var e = new Error('Unknown Queue: '+request.queue);
if (HTML_AJAX.onError) {
HTML_AJAX.onError(e);
return false;
}
else {
throw(e);
}
}
else {
var qn = request.queue;
var q = HTML_AJAX.queues[qn];
HTML_AJAX.queues[request.queue].addRequest(request);
return HTML_AJAX.queues[request.queue].processRequest();
}
},
// get a serializer object for a specific encoding
serializerForEncoding: function(encoding) {
for(var i in HTML_AJAX.contentTypeMap) {
if (encoding == HTML_AJAX.contentTypeMap[i] || encoding == i) {
return eval("new HTML_AJAX_Serialize_"+i+";");
}
}
return new HTML_AJAX_Serialize_Null();
},
fullcall: function(url,encoding,className,method,callback,args, options) {
var serializer = HTML_AJAX.serializerForEncoding(encoding);
var request = new HTML_AJAX_Request(serializer);
if (callback) {
request.isAsync = true;
}
request.requestUrl = url;
request.className = className;
request.methodName = method;
request.callback = callback;
request.args = args;
if (options) {
for(var i in options) {
request[i] = options[i];
}
if (options.grab) {
if (!request.args || !request.args.length) {
request.requestType = 'GET';
}
}
}
return HTML_AJAX.makeRequest(request);
},
callPhpCallback: function(phpCallback, jsCallback, url) {
var args = new Array();
for (var i = 3; i < arguments.length; i++) {
args.push(arguments[i]);
}
if (HTML_AJAX_Util.getType(phpCallback[0]) == 'object') {
jsCallback(phpCallback[0][phpCallback[1]](args));
return;
}
if (!url) {
url = HTML_AJAX.defaultServerUrl;
}
HTML_AJAX.fullcall(url, HTML_AJAX.defaultEncoding,
false, false, jsCallback, args, {phpCallback: phpCallback});
},
call: function(className,method,callback) {
var args = new Array();
for(var i = 3; i < arguments.length; i++) {
args.push(arguments[i]);
}
return HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,className,method,callback,args);
},
grab: function(url,callback,options) {
if (!options) {
options = {grab:true};
}
else {
options['grab'] = true;
}
return HTML_AJAX.fullcall(url,'Null',false,null,callback, '', options);
},
post: function(url,payload,callback,options) {
var serializer = 'Null';
if (HTML_AJAX_Util.getType(payload) == 'object') {
serializer = 'Urlencoded';
}
return HTML_AJAX.fullcall(url,serializer,false,null,callback, payload, options);
},
replace: function(id) {
var callback = function(result) {
HTML_AJAX_Util.setInnerHTML(HTML_AJAX_Util.getElement(id),result);
}
if (arguments.length == 2) {
// grab replacement
HTML_AJAX.grab(arguments[1],callback);
}
else {
// call replacement
var args = new Array();
for(var i = 3; i < arguments.length; i++) {
args.push(arguments[i]);
}
HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,arguments[1],arguments[2],callback,args, {grab:true});
}
},
append: function(id) {
var callback = function(result) {
HTML_AJAX_Util.setInnerHTML(HTML_AJAX_Util.getElement(id),result,'append');
}
if (arguments.length == 2) {
// grab replacement
HTML_AJAX.grab(arguments[1],callback);
}
else {
// call replacement
var args = new Array();
for(var i = 3; i < arguments.length; i++) {
args.push(arguments[i]);
}
HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,arguments[1],arguments[2],callback,args, {grab:true});
}
},
// override to add top level loading notification (start)
Open: function(request) {
},
// override to add top level loading notification (finish)
Load: function(request) {
},
/*
// A really basic error handler
onError: function(e) {
msg = "";
for(var i in e) {
msg += i+':'+e[i]+"\n";
}
alert(msg);
},
*/
// Class postfix to content-type map
contentTypeMap: {
'JSON': 'application/json',
'Null': 'text/plain',
'Error': 'application/error',
'PHP': 'application/php-serialized',
'HA' : 'application/html_ajax_action',
'Urlencoded': 'application/x-www-form-urlencoded'
},
// used internally to make queues work, override Load or onError to perform custom events when a request is complete
// fires on success and error
requestComplete: function(request,error) {
for(var i in HTML_AJAX.queues) {
if (HTML_AJAX.queues[i].requestComplete) {
HTML_AJAX.queues[i].requestComplete(request,error);
}
}
},
// turns a form into a urlencoded string
formEncode: function(form, array_format) {
form = HTML_AJAX_Util.getElement(form);
var el, inpType, value, name;
var out = (array_format) ? {} : '';
var inputTags = form.getElementsByTagName('INPUT');
var selectTags = form.getElementsByTagName('SELECT');
var buttonTags = form.getElementsByTagName('BUTTON');
var textareaTags = form.getElementsByTagName('TEXTAREA');
var arrayRegex = /(.+)%5B%5D/;
var validElement = function (element) {
if (!element || !element.getAttribute) {
return false;
}
el = element;
name = HTML_AJAX_Util.encodeUrl(el.getAttribute('name'));
if (!name) {
// no element name so skip
return false;
}
if (element.disabled) {
return false;
}
if (!array_format) {
value = HTML_AJAX_Util.encodeUrl(el.value);
} else {
value = el.value;
}
inpType = el.getAttribute('type');
return true;
}
inputLoop:
for (var i=0; i < inputTags.length; i++) {
if (!validElement(inputTags[i])) {
continue;
}
if (inpType == 'checkbox' || inpType == 'radio') {
if (!el.checked) {
// unchecked radios/checkboxes don't get submitted
continue inputLoop;
}
var arr_var = arrayRegex.exec(name);
if (array_format && arr_var) {
if (!out[arr_var[1]]) {
out[arr_var[1]] = new Array();
}
out[arr_var[1]].push(value);
continue inputLoop;
}
}
// add element to output array
if (array_format) {
out[name] = value;
} else {
out += name + '=' + value + '&';
}
} // end inputLoop
selectLoop:
for (var i=0; i 0) {
this.addClient();
}
}
HTML_AJAX_Client_Pool.prototype = {
isEmpty: function()
{
return this._len == 0;
},
addClient: function()
{
if (this.maxClients != 0 && this._len > this.maxClients) {
return false;
}
var key = this._len++;
this._clients[key] = new HTML_AJAX_HttpClient();
return this._clients[key];
},
getClient: function ()
{
for (var i = 0; i < this._len; i++) {
if (!this._clients[i].callInProgress() && this._clients[i].callbackComplete) {
return this._clients[i];
}
}
var client = this.addClient();
if (client) {
return client;
}
return false;
},
removeClient: function (client)
{
for (var i = 0; i < this._len; i++) {
if (!this._clients[i] == client) {
this._clients.splice(i, 1);
return true;
}
}
return false;
},
clear: function ()
{
this._clients = [];
this._len = 0;
}
};
// create a default client pool with unlimited clients
HTML_AJAX.clientPools['default'] = new HTML_AJAX_Client_Pool(0);
/**
* Class that contains everything needed to make a request
* This includes:
* The url were calling
* If were calling a remote method, the class and method name
* The payload, unserialized
* The timeout for async calls
* The callback method
* Optional event handlers: onError, Load, Send
* A serializer instance
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
*
* See Main.js for author/license details
*/
function HTML_AJAX_Request(serializer) {
this.serializer = serializer;
}
HTML_AJAX_Request.prototype = {
// Instance of a serializer
serializer: null,
// Is this an async request
isAsync: false,
// HTTP verb
requestType: 'POST',
// The actual URL the request is sent to
requestUrl: '',
// Remote Class
className: null,
// Remote Method
methodName: null,
// Timeout in milliseconds for requests
timeout: 20000,
// unserialized data, for rpc calls use add args, to send raw data just set this directly
args: null,
// async callback method
callback: null,
// Queue to push this request too
queue: 'default',
// default priority
priority: 0,
// a hash of headers to add to add to this request
customHeaders: {'X-Requested-With': 'XMLHttpRequest', 'X-Ajax-Engine': 'HTML_AJAX/0.5.6'},
// true if this request will be sent using iframes
iframe: false,
// is this a grab request? if so we need to proxy for iframes
grab: false,
// true if this request should expect a multipart response
multipart: false,
// remote callback
phpCallback: false,
/**
* Add an argument for the remote method
* @param string argument name
* @param mixed value
* @return void
* @throws Error code 1004
*/
addArg: function(name, value)
{
if ( !this.args ) {
this.args = [];
}
if (!/[^a-zA-Z_0-9]/.test(name) ) {
this.args[name] = value;
} else {
throw new Error('Invalid parameter name ('+name+')');
}
},
/**
* Get the payload in a serialized manner
*/
getSerializedPayload: function() {
return this.serializer.serialize(this.args);
},
/**
* Get the content type
*/
getContentType: function() {
return this.serializer.contentType;
},
/**
* Get the complete url, adding in any needed get params for rpc
*/
completeUrl: function() {
if (this.className || this.methodName) {
this.addGet('c', this.className);
this.addGet('m', this.methodName);
}
if (this.phpCallback) {
if (HTML_AJAX_Util.getType(this.phpCallback) == 'array') {
this.phpCallback = this.phpCallback.join('.');
}
this.addGet('cb', this.phpCallback);
}
if (this.multipart) {
this.addGet('multipart', '1');
}
return this.requestUrl;
},
/**
* Compare to another request by priority
*/
compareTo: function(other) {
if (this.priority == other.priority) {
return 0;
}
return (this.priority > other.priority ? 1 : -1);
},
/**
* Add a GET argument
*/
addGet: function(name, value) {
var url = new String(this.requestUrl);
url += (url.indexOf('?') < 0 ? '?' : '&') + escape(name) + '=' + escape(value);
this.requestUrl = url;
}
}
/**
* XMLHttpRequest Wrapper
* @category HTML
* @package AJAX
* @author Joshua Eichorn
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
*/
function HTML_AJAX_HttpClient() { }
HTML_AJAX_HttpClient.prototype = {
// request object
request: null,
// timeout id
_timeoutId: null,
callbackComplete: true,
// has this request been aborted
aborted: false,
// method to initialize an xmlhttpclient
init:function()
{
try {
// Mozilla / Safari
//this.xmlhttp = new HTML_AJAX_IframeXHR(); //uncomment these two lines to test iframe
//return;
this.xmlhttp = new XMLHttpRequest();
} catch (e) {
// IE
var XMLHTTP_IDS = new Array(
'MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP' );
var success = false;
for (var i=0;i < XMLHTTP_IDS.length && !success; i++) {
try {
this.xmlhttp = new ActiveXObject(XMLHTTP_IDS[i]);
success = true;
} catch (e) {}
}
if (!success) {
try{
this.xmlhttp = new HTML_AJAX_IframeXHR();
this.request.iframe = true;
} catch(e) {
throw new Error('Unable to create XMLHttpRequest.');
}
}
}
},
// check if there is a call in progress
callInProgress: function()
{
switch ( this.xmlhttp.readyState ) {
case 1:
case 2:
case 3:
return true;
break;
default:
return false;
break;
}
},
// make the request defined in the request object
makeRequest: function()
{
if (!this.xmlhttp) {
this.init();
}
try {
if (this.request.Open) {
this.request.Open();
}
else if (HTML_AJAX.Open) {
HTML_AJAX.Open(this.request);
}
if (this.request.multipart) {
if (document.all) {
this.iframe = true;
} else {
this.xmlhttp.multipart = true;
}
}
// set onreadystatechange here since it will be reset after a completed call in Mozilla
var self = this;
this.xmlhttp.open(this.request.requestType,this.request.completeUrl(),this.request.isAsync);
if (this.request.customHeaders) {
for (var i in this.request.customHeaders) {
this.xmlhttp.setRequestHeader(i, this.request.customHeaders[i]);
}
}
if (this.request.customHeaders && !this.request.customHeaders['Content-Type']) {
var content = this.request.getContentType();
var charsetIndex = content.indexOf('; charset=UTF-8');
if (charsetIndex == -1) {
content += '; charset=UTF-8';
}
this.xmlhttp.setRequestHeader('Content-Type', content);
}
if (this.request.isAsync) {
if (this.request.callback) {
this.callbackComplete = false;
}
this.xmlhttp.onreadystatechange = function() { self._readyStateChangeCallback(); }
} else {
this.xmlhttp.onreadystatechange = function() {}
}
var payload = this.request.getSerializedPayload();
if (payload) {
this.xmlhttp.setRequestHeader('Content-Length', payload.length);
}
this.xmlhttp.send(payload);
if (!this.request.isAsync) {
if ( this.xmlhttp.status == 200 ) {
HTML_AJAX.requestComplete(this.request);
if (this.request.Load) {
this.request.Load();
} else if (HTML_AJAX.Load) {
HTML_AJAX.Load(this.request);
}
return this._decodeResponse();
} else {
var e = new Error('['+this.xmlhttp.status +'] '+this.xmlhttp.statusText);
e.headers = this.xmlhttp.getAllResponseHeaders();
this._handleError(e);
}
}
else {
// setup timeout
var self = this;
this._timeoutId = window.setTimeout(function() { self.abort(true); },this.request.timeout);
}
} catch (e) {
this._handleError(e);
}
},
// abort an inprogress request
abort: function (automatic)
{
if (this.callInProgress()) {
this.aborted = true;
this.xmlhttp.abort();
if (automatic) {
HTML_AJAX.requestComplete(this.request);
this._handleError(new Error('Request Timed Out: time out was '+this.request.timeout+'ms'));
}
}
},
// internal method used to handle ready state changes
_readyStateChangeCallback:function()
{
try {
switch(this.xmlhttp.readyState) {
// XMLHTTPRequest.open() has just been called
case 1:
break;
// XMLHTTPRequest.send() has just been called
case 2:
if (this.request.Send) {
this.request.Send();
} else if (HTML_AJAX.Send) {
HTML_AJAX.Send(this.request);
}
break;
// Fetching response from server in progress
case 3:
if (this.request.Progress) {
this.request.Progress();
} else if (HTML_AJAX.Progress ) {
HTML_AJAX.Progress(this.request);
}
break;
// Download complete
case 4:
window.clearTimeout(this._timeoutId);
if (this.aborted) {
if (this.request.Load) {
this.request.Load();
} else if (HTML_AJAX.Load) {
HTML_AJAX.Load(this.request);
}
}
else if (this.xmlhttp.status == 200) {
if (this.request.Load) {
this.request.Load();
} else if (HTML_AJAX.Load ) {
HTML_AJAX.Load(this.request);
}
var response = this._decodeResponse();
if (this.request.callback) {
this.request.callback(response);
this.callbackComplete = true;
}
}
else {
var e = new Error('HTTP Error Making Request: ['+this.xmlhttp.status+'] '+this.xmlhttp.statusText);
this._handleError(e);
}
HTML_AJAX.requestComplete(this.request);
break;
}
} catch (e) {
this._handleError(e);
}
},
// decode response as needed
_decodeResponse: function() {
//try for x-Content-Type first
var content = null;
try {
content = this.xmlhttp.getResponseHeader('X-Content-Type');
} catch(e) {}
if(!content || content == null)
{
content = this.xmlhttp.getResponseHeader('Content-Type');
}
//strip anything after ;
if(content.indexOf(';') != -1)
{
content = content.substring(0, content.indexOf(';'));
}
// hook for xml, it doesn't need to be unserialized
if(content == 'application/xml' || content == 'text/xml')
{
return this.xmlhttp.responseXML;
}
var unserializer = HTML_AJAX.serializerForEncoding(content);
//alert(this.xmlhttp.getAllResponseHeaders()); // some sort of debug hook is needed here
return unserializer.unserialize(this.xmlhttp.responseText);
},
// handle sending an error where it needs to go
_handleError: function(e)
{
HTML_AJAX.requestComplete(this.request,e);
if (this.request.onError) {
this.request.onError(e);
} else if (HTML_AJAX.onError) {
HTML_AJAX.onError(e,this.request);
}
else {
throw e;
}
}
}
/**
* Class that is used by generated stubs to make actual AJAX calls
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
*/
function HTML_AJAX_Dispatcher(className,mode,callback,serverUrl,serializerType)
{
this.className = className;
this.mode = mode;
this.callback = callback;
this.serializerType = serializerType;
if (serverUrl) {
this.serverUrl = serverUrl
}
else {
this.serverUrl = window.location;
}
}
HTML_AJAX_Dispatcher.prototype = {
/**
* Queue to use when making a request
*/
queue: 'default',
/**
* Timeout for async calls
*/
timeout: 20000,
/**
* Default request priority
*/
priority: 0,
/**
* Request options
*/
options: {},
/**
* Make an ajax call
*
* @param string callName
* @param Array args arguments to the report method
*/
doCall: function(callName,args)
{
var request = new HTML_AJAX_Request();
request.requestUrl = this.serverUrl;
request.className = this.className;
request.methodName = callName;
request.timeout = this.timeout;
request.contentType = this.contentType;
request.serializer = eval('new HTML_AJAX_Serialize_'+this.serializerType);
request.queue = this.queue;
request.priority = this.priority;
for(var i in this.options) {
request[i] = this.options[i];
}
for(var i=0; i < args.length; i++) {
request.addArg(i,args[i]);
};
if ( this.mode == "async" ) {
request.isAsync = true;
if (this.callback[callName]) {
var self = this;
request.callback = function(result) { self.callback[callName](result); }
}
} else {
request.isAsync = false;
}
return HTML_AJAX.makeRequest(request);
},
Sync: function()
{
this.mode = 'sync';
},
Async: function(callback)
{
this.mode = 'async';
if (callback) {
this.callback = callback;
}
}
};
/*
Copyright (c) 2005 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
The global object JSON contains two methods.
JSON.stringify(value) takes a JavaScript value and produces a JSON text.
The value must not be cyclical.
JSON.parse(text) takes a JSON text and produces a JavaScript value. It will
throw a 'JSONError' exception if there is an error.
*/
var HTML_AJAX_JSON = {
copyright: '(c)2005 JSON.org',
license: 'http://www.crockford.com/JSON/license.html',
/*
Stringify a JavaScript value, producing a JSON text.
*/
stringify: function (v) {
var a = [];
/*
Emit a string.
*/
function e(s) {
a[a.length] = s;
}
/*
Convert a value.
*/
function g(x) {
var c, i, l, v;
switch (typeof x) {
case 'object':
if (x) {
if (x instanceof Array) {
e('[');
l = a.length;
for (i = 0; i < x.length; i += 1) {
v = x[i];
if (typeof v != 'undefined' &&
typeof v != 'function') {
if (l < a.length) {
e(',');
}
g(v);
}
}
e(']');
return;
} else if (typeof x.valueOf == 'function') {
e('{');
l = a.length;
for (i in x) {
v = x[i];
if (typeof v != 'undefined' &&
typeof v != 'function' &&
(!v || typeof v != 'object' ||
typeof v.valueOf == 'function')) {
if (l < a.length) {
e(',');
}
g(i);
e(':');
g(v);
}
}
return e('}');
}
}
e('null');
return;
case 'number':
e(isFinite(x) ? +x : 'null');
return;
case 'string':
l = x.length;
e('"');
for (i = 0; i < l; i += 1) {
c = x.charAt(i);
if (c >= ' ') {
if (c == '\\' || c == '"') {
e('\\');
}
e(c);
} else {
switch (c) {
case '\b':
e('\\b');
break;
case '\f':
e('\\f');
break;
case '\n':
e('\\n');
break;
case '\r':
e('\\r');
break;
case '\t':
e('\\t');
break;
default:
c = c.charCodeAt();
e('\\u00' + Math.floor(c / 16).toString(16) +
(c % 16).toString(16));
}
}
}
e('"');
return;
case 'boolean':
e(String(x));
return;
default:
e('null');
return;
}
}
g(v);
return a.join('');
},
/*
Parse a JSON text, producing a JavaScript value.
*/
parse: function (text) {
return
(/^(\s+|[,:{}\[\]]|"(\\["\\\/bfnrtu]|[^\x00-\x1f"\\]+)*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null)+$/.test(text))
&&
eval('(' + text + ')');
}
};/**
* 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= 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 = (navigator.product == 'Gecko');
var regex = /^([\s\S]*?)';
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*\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;
}
}
// }}}