/* Copyright (c) 2008, MyBlock Author: Kristoffer Ahl, Spinit AB */ /* =TODO: Test and document browser compatibility */ /* =TODO: Add comments for variables, functions, methods etc */ /* =TODO: Implement custom events (onAbort, onTimeout etc) */ /* =TODO: Implement status notification events (Processing etc) */ /* =MB.Ajax */ MB.createNamespace("Ajax"); MB.Ajax = function() { /** * @description Turns Ajax off. Used primarily for debug purposes. * @property _ajax_off * @private * @static * @type boolean */ var _ajax_off = MB.Config.Ajax.AjaxOff; // =TODO: Implement or remove /** * @description Turns debug on. Used for debug purposes. * @property _ajax_debug * @private * @static * @type boolean */ var _ajax_debug = MB.Config.Ajax.AjaxDebug; // =TODO: Implement or remove /** * @description Contains version data. * @property _ajax_info * @private * @static * @type string */ var _ajax_info = "MB-Ajax|0.1"; /** * @description Contains valid content-type headers. * @property _content_types * @private * @static * @type object */ var _content_types = { xml : "text/xml", html : "application/x-www-form-urlencoded" // =TODO: Change typename to text!? }; var _timeout_handlers = {}; var _poll_handlers = {}; var _request_id = 0; var createResponseObject = function(xhr,callback) { var response = {}, content_type; /* =TODO: Add response object properties response.type = (abort, timeout, complete) =TODO: Research content types and a better way to handle the response */ if (xhr && xhr.conn && xhr.options) { response.requestId = xhr.rId; content_type = xhr.conn.getResponseHeader("Content-Type"); if (content_type && content_type.indexOf("text/html") >= 0) { response.data = xhr.conn.responseText; } else if (content_type && content_type.indexOf("application/xml")) { response.data = xhr.conn.responseXML; } else { if (xhr.conn.responseXML && xhr.conn.responseXML.nodeType === 9) { response.data = xhr.conn.responseXML; } else { response.data = xhr.conn.responseText; } } response.options = xhr.options; } return response; }; var getXhrObject = function() { var xmlhttp, obj; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); obj = { conn:xmlhttp, rId:_request_id }; } else if(window.ActiveXObject) { try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP.4.0"); obj = { conn:xmlhttp, rId:_request_id }; } catch (e) { try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); obj = { conn:xmlhttp, rId:_request_id }; } catch (e2) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); obj = { conn:xmlhttp, rId:_request_id }; } catch (e3) { xmlhttp = null; } } } } if (obj && typeof obj.rId === "number" && isFinite(obj.rId)) { _request_id++; } else { obj = null; } return obj; }; var handleResponse = function(xhr,callback) { var conn_status, response; try { if (xhr.conn && xhr.conn.status !== undefined && xhr.conn.status !== 0) { conn_status = xhr.conn.status; } else { conn_status = 13030; } } catch(e){ conn_status = 13030; } if (conn_status >= 200 || conn_status < 300 || conn_status === 1223) { response = createResponseObject(xhr,callback); if (xhr.isLoad) { // =TODO: Refactor -> function var options = xhr.options; if (options.target) { var target = options.target; if (typeof target !== "object" || !target.nodeType || target.nodeType !== 1) { target = document.getElementById(options.target); } if (target) { if (options.add) { target.innerHTML += response.data; } else { target.innerHTML = response.data; } } } } else if (callback && callback.success) { callback.success(response); } } else { if (callback && callback.failure) { response = "Failure"; // =TODO: Implement createResponseObject method callback.failure(response); } } MB.Ajax.endRequest(xhr); }; var setRequestHandlers = function(xhr,callback) { var timeout = xhr.options.timeout; var interval = xhr.options.poll; MB.Ajax.getTimoutHandlers[xhr.rId] = window.setTimeout(function() { MB.Ajax.abortRequest(xhr,callback); },timeout); MB.Ajax.getPollHandlers[xhr.rId] = window.setInterval(function() { if(xhr.conn && xhr.conn.readyState === 4){ delete MB.Ajax.getPollHandlers[xhr.rId]; handleResponse(xhr,callback); } },interval); return xhr; }; var setRequestHeader = function(xhr) { if (xhr && xhr.options && xhr.conn) { var contentType = xhr.options.contentType; if (contentType) { xhr.conn.setRequestHeader("Content-Type", contentType); } var headers = xhr.options.requestHeaders; for (var key in headers) { xhr.conn.setRequestHeader(key, headers[key]); } } return xhr; }; return { // =attachLoader, =Deprecated attachLoader : function(target,message,className,imageUrl,clearTarget,beforeTarget) { alert("MB.Ajax.attachLoader() is deprecated!"); MB.UI.attachLoader(target,message,className,imageUrl,clearTarget,beforeTarget); }, // =captureData captureData : function(elem) { var data = "", index, option, selected_values var data_elements = MB.getElementsByTagNames("input,select,textarea",elem); if (!data_elements) return false; for (var i=0; i0) selected_values+= ","; selected_values+= escape(option.value); } } if (selected_values.length>0) { data+= (element.name + "=" + selected_values + "&"); } break; default: break; } if (add) { data+= element.name; data+= "="; data+= encodeURI(element.value); // =TODO: Validate effects of using encodeURI instead of escape data+= "&"; } } if (data.charAt(data.length-1) == "&") { data = data.substr(0,data.length-1); } if (data && data.length > 0) { return data; } else { return null; } }, // =clearLoaders, =Deprecated clearLoaders : function(container) { alert("MB.Ajax.clearLoaders() is deprecated!"); MB.UI.clearLoaders(container); }, // =getContentType getContentType : function(v) { return _content_types[v]; }, // =getTimoutHandlers getTimoutHandlers : function() { return _timeout_handlers; }, // =getPollHandlers getPollHandlers : function() { return _poll_handlers; }, // =abortRequest abortRequest : function(xhr,callback) { if (xhr && xhr.conn) { xhr.conn.abort(); MB.Ajax.endRequest(xhr); } if (callback && callback.failure) { var response = MB.Config.Ajax.Aborted; // =TODO: Implement createResponseObject method callback.failure(response); } return true; }, // =beginRequest beginRequest : function(url,callback,options) { if (!url) return null; var xhr = getXhrObject(); if (xhr) { xhr.options = options; if (!xhr.options) { xhr.options = new MB.Ajax.Options(); } xhr.isLoad = (callback) ? false : true; xhr.conn.onreadystatechange = function () {}; xhr.conn.abort(); // =TODO: Verify the need to abort xhr.conn.open(xhr.options.method.toUpperCase(),url,xhr.options.async); xhr = setRequestHeader(xhr); xhr = setRequestHandlers(xhr,callback); if (callback && callback.beginRequest) { callback.beginRequest(xhr); // =TODO: Implement as custom event } xhr.conn.send(options.postData); return xhr; } else { return null; } }, // =endRequest endRequest : function(xhr) { if (xhr && xhr.conn) { window.clearTimeout(MB.Ajax.getTimoutHandlers[xhr.rId]); delete MB.Ajax.getTimoutHandlers[xhr.rId]; window.clearInterval(MB.Ajax.getPollHandlers[xhr.rId]); delete MB.Ajax.getPollHandlers[xhr.rId]; xhr.conn = null; xhr = null; } }, // =hijax hijax : function(elem,evt,callback,options) { var target = document.getElementById(elem); if (target) { // TODO: Implement "evt" argument target.onsubmit = function() { // =TODO: Important! Research better way to integrate validation var is_valid = (this.validation && this.validation.validate(this)) ? true : false; if (!is_valid) { return false; } else { var url = this.action; if (!options) { options = new MB.Ajax.Options(); } if (this.method) { options.method = this.method.toUpperCase(); } else { options.method = "POST"; } options.postData = MB.Ajax.captureData(target); MB.Ajax.beginRequest(url,callback,options); return false; } } } }, // =load load : function(elem,url,add,options) { if (!options) { options = new MB.Ajax.Options(); } options.target = elem; options.add = (add) ? add : false; MB.Ajax.beginRequest(url,null,options); }, // =Callback Callback : function(successHandler,failureHandler,beginRequestHandler) { return { beginRequest : ((beginRequestHandler) ? beginRequestHandler : null), // =TODO: Implement as custom event failure : ((failureHandler) ? failureHandler : null), success : ((successHandler) ? successHandler : null) }; }, // =Options Options : function() { return { add : false, async : true, contentType : MB.Ajax.getContentType("html"), encoding : "UTF-8", method : "GET", poll : 50, postData : null, requestHeaders : { "X-Request-Type" : "Ajax", "X-Request-Framework" : _ajax_info }, target : null, timeout : 10000 }; } }; }(); // =NOTE: Keep as dev-reference (=TODO:) but remove before release //var successHandler = function(response) { // if (response && response.responseText) { // if (response.options && response.options.target) { // var target = document.getElementById(response.options.target); // if (target) target.innerHTML = response.responseText; // } else { // alert("Success: " + response.responseText); // } // } //} //var failureHandler = function(response) { // alert("Failure: " + response); //} //MB.addEvent(window,"load",function() { // var callback = new MB.Ajax.Callback(successHandler,failureHandler); // var options = new MB.Ajax.Options(); // if (options) { // options.method = "post"; // options.target = "Content-Area-Header"; // options.contentType = MB.Ajax.getContentType("xml"); // options.timeout = 3000; // } // var t = setTimeout(function() { // MB.Ajax.load(document.getElementById("Content-Area"),"http://localhost/MBBeta2/?ajax=1",true); // }, 3000); // MB.Ajax.beginRequest("http://localhost/ajax/resource_2.asp",callback,options); //});