| /*! |
| * MockJax - jQuery Plugin to Mock Ajax requests |
| * |
| * Version: 1.4.0 |
| * Released: 2011-02-04 |
| * Source: http://github.com/appendto/jquery-mockjax |
| * Docs: http://enterprisejquery.com/2010/07/mock-your-ajax-requests-with-mockjax-for-rapid-development |
| * Plugin: mockjax |
| * Author: Jonathan Sharp (http://jdsharp.com) |
| * License: MIT,GPL |
| * |
| * Copyright (c) 2010 appendTo LLC. |
| * Dual licensed under the MIT or GPL licenses. |
| * http://appendto.com/open-source-licenses |
| */ |
| (function($) { |
| var _ajax = $.ajax, |
| mockHandlers = []; |
| |
| function parseXML(xml) { |
| if ( window['DOMParser'] == undefined && window.ActiveXObject ) { |
| DOMParser = function() { }; |
| DOMParser.prototype.parseFromString = function( xmlString ) { |
| var doc = new ActiveXObject('Microsoft.XMLDOM'); |
| doc.async = 'false'; |
| doc.loadXML( xmlString ); |
| return doc; |
| }; |
| } |
| |
| try { |
| var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' ); |
| if ( $.isXMLDoc( xmlDoc ) ) { |
| var err = $('parsererror', xmlDoc); |
| if ( err.length == 1 ) { |
| throw('Error: ' + $(xmlDoc).text() ); |
| } |
| } else { |
| throw('Unable to parse XML'); |
| } |
| } catch( e ) { |
| var msg = ( e.name == undefined ? e : e.name + ': ' + e.message ); |
| $(document).trigger('xmlParseError', [ msg ]); |
| return undefined; |
| } |
| return xmlDoc; |
| } |
| |
| $.extend({ |
| ajax: function(origSettings) { |
| var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings), |
| mock = false; |
| // Iterate over our mock handlers (in registration order) until we find |
| // one that is willing to intercept the request |
| $.each(mockHandlers, function(k, v) { |
| if ( !mockHandlers[k] ) { |
| return; |
| } |
| var m = null; |
| // If the mock was registered with a function, let the function decide if we |
| // want to mock this request |
| if ( $.isFunction(mockHandlers[k]) ) { |
| m = mockHandlers[k](s); |
| } else { |
| m = mockHandlers[k]; |
| // Inspect the URL of the request and check if the mock handler's url |
| // matches the url for this ajax request |
| if ( $.isFunction(m.url.test) ) { |
| // The user provided a regex for the url, test it |
| if ( !m.url.test( s.url ) ) { |
| m = null; |
| } |
| } else { |
| // Look for a simple wildcard '*' or a direct URL match |
| var star = m.url.indexOf('*'); |
| if ( ( m.url != '*' && m.url != s.url && star == -1 ) || |
| ( star > -1 && m.url.substr(0, star) != s.url.substr(0, star) ) ) { |
| // The url we tested did not match the wildcard * |
| m = null; |
| } |
| } |
| if ( m ) { |
| // Inspect the data submitted in the request (either POST body or GET query string) |
| if ( m.data && s.data ) { |
| var identical = false; |
| // Deep inspect the identity of the objects |
| (function ident(mock, live) { |
| // Test for situations where the data is a querystring (not an object) |
| if (typeof live === 'string') { |
| // Querystring may be a regex |
| identical = $.isFunction( mock.test ) ? mock.test(live) : mock == live; |
| return identical; |
| } |
| $.each(mock, function(k, v) { |
| if ( live[k] === undefined ) { |
| identical = false; |
| return false; |
| } else { |
| identical = true; |
| if ( typeof live[k] == 'object' ) { |
| return ident(mock[k], live[k]); |
| } else { |
| if ( $.isFunction( mock[k].test ) ) { |
| identical = mock[k].test(live[k]); |
| } else { |
| identical = ( mock[k] == live[k] ); |
| } |
| return identical; |
| } |
| } |
| }); |
| })(m.data, s.data); |
| // They're not identical, do not mock this request |
| if ( identical == false ) { |
| m = null; |
| } |
| } |
| // Inspect the request type |
| if ( m && m.type && m.type != s.type ) { |
| // The request type doesn't match (GET vs. POST) |
| m = null; |
| } |
| } |
| } |
| if ( m ) { |
| mock = true; |
| |
| // Handle console logging |
| var c = $.extend({}, $.mockjaxSettings, m); |
| if ( c.log && $.isFunction(c.log) ) { |
| c.log('MOCK ' + s.type.toUpperCase() + ': ' + s.url, $.extend({}, s)); |
| } |
| |
| var jsre = /=\?(&|$)/, jsc = (new Date()).getTime(); |
| |
| // Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here |
| // because there isn't an easy hook for the cross domain script tag of jsonp |
| if ( s.dataType === "jsonp" ) { |
| if ( s.type.toUpperCase() === "GET" ) { |
| if ( !jsre.test( s.url ) ) { |
| s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?"; |
| } |
| } else if ( !s.data || !jsre.test(s.data) ) { |
| s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?"; |
| } |
| s.dataType = "json"; |
| } |
| |
| // Build temporary JSONP function |
| if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) { |
| jsonp = s.jsonpCallback || ("jsonp" + jsc++); |
| |
| // Replace the =? sequence both in the query string and the data |
| if ( s.data ) { |
| s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1"); |
| } |
| |
| s.url = s.url.replace(jsre, "=" + jsonp + "$1"); |
| |
| // We need to make sure |
| // that a JSONP style response is executed properly |
| s.dataType = "script"; |
| |
| // Handle JSONP-style loading |
| window[ jsonp ] = window[ jsonp ] || function( tmp ) { |
| data = tmp; |
| success(); |
| complete(); |
| // Garbage collect |
| window[ jsonp ] = undefined; |
| |
| try { |
| delete window[ jsonp ]; |
| } catch(e) {} |
| |
| if ( head ) { |
| head.removeChild( script ); |
| } |
| }; |
| } |
| |
| var rurl = /^(\w+:)?\/\/([^\/?#]+)/, |
| parts = rurl.exec( s.url ), |
| remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host); |
| |
| // Test if we are going to create a script tag (if so, intercept & mock) |
| if ( s.dataType === "script" && s.type.toUpperCase() === "GET" && remote ) { |
| // Synthesize the mock request for adding a script tag |
| var callbackContext = origSettings && origSettings.context || s; |
| |
| function success() { |
| // If a local callback was specified, fire it and pass it the data |
| if ( s.success ) { |
| s.success.call( callbackContext, ( m.response ? m.response.toString() : m.responseText || ''), status, {} ); |
| } |
| |
| // Fire the global callback |
| if ( s.global ) { |
| trigger( "ajaxSuccess", [{}, s] ); |
| } |
| } |
| |
| function complete() { |
| // Process result |
| if ( s.complete ) { |
| s.complete.call( callbackContext, {} , status ); |
| } |
| |
| // The request was completed |
| if ( s.global ) { |
| trigger( "ajaxComplete", [{}, s] ); |
| } |
| |
| // Handle the global AJAX counter |
| if ( s.global && ! --jQuery.active ) { |
| jQuery.event.trigger( "ajaxStop" ); |
| } |
| } |
| |
| function trigger(type, args) { |
| (s.context ? jQuery(s.context) : jQuery.event).trigger(type, args); |
| } |
| |
| if ( m.response && $.isFunction(m.response) ) { |
| m.response(origSettings); |
| } else { |
| $.globalEval(m.responseText); |
| } |
| success(); |
| complete(); |
| return false; |
| } |
| mock = _ajax.call($, $.extend(true, {}, origSettings, { |
| // Mock the XHR object |
| xhr: function() { |
| // Extend with our default mockjax settings |
| m = $.extend({}, $.mockjaxSettings, m); |
| |
| if ( m.contentType ) { |
| m.headers['content-type'] = m.contentType; |
| } |
| |
| // Return our mock xhr object |
| return { |
| status: m.status, |
| readyState: 1, |
| open: function() { }, |
| send: function() { |
| // This is a substitute for < 1.4 which lacks $.proxy |
| var process = (function(that) { |
| return function() { |
| return (function() { |
| // The request has returned |
| this.status = m.status; |
| this.readyState = 4; |
| |
| // We have an executable function, call it to give |
| // the mock handler a chance to update it's data |
| if ( $.isFunction(m.response) ) { |
| m.response(origSettings); |
| } |
| // Copy over our mock to our xhr object before passing control back to |
| // jQuery's onreadystatechange callback |
| if ( s.dataType == 'json' && ( typeof m.responseText == 'object' ) ) { |
| this.responseText = JSON.stringify(m.responseText); |
| } else if ( s.dataType == 'xml' ) { |
| if ( typeof m.responseXML == 'string' ) { |
| this.responseXML = parseXML(m.responseXML); |
| } else { |
| this.responseXML = m.responseXML; |
| } |
| } else { |
| this.responseText = m.responseText; |
| } |
| // jQuery < 1.4 doesn't have onreadystate change for xhr |
| if ( $.isFunction(this.onreadystatechange) ) { |
| this.onreadystatechange( m.isTimeout ? 'timeout' : undefined ); |
| } |
| }).apply(that); |
| }; |
| })(this); |
| |
| if ( m.proxy ) { |
| // We're proxying this request and loading in an external file instead |
| _ajax({ |
| global: false, |
| url: m.proxy, |
| type: m.proxyType, |
| data: m.data, |
| dataType: s.dataType, |
| complete: function(xhr, txt) { |
| m.responseXML = xhr.responseXML; |
| m.responseText = xhr.responseText; |
| this.responseTimer = setTimeout(process, m.responseTime || 0); |
| } |
| }); |
| } else { |
| // type == 'POST' || 'GET' || 'DELETE' |
| if ( s.async === false ) { |
| // TODO: Blocking delay |
| process(); |
| } else { |
| this.responseTimer = setTimeout(process, m.responseTime || 50); |
| } |
| } |
| }, |
| abort: function() { |
| clearTimeout(this.responseTimer); |
| }, |
| setRequestHeader: function() { }, |
| getResponseHeader: function(header) { |
| // 'Last-modified', 'Etag', 'content-type' are all checked by jQuery |
| if ( m.headers && m.headers[header] ) { |
| // Return arbitrary headers |
| return m.headers[header]; |
| } else if ( header.toLowerCase() == 'last-modified' ) { |
| return m.lastModified || (new Date()).toString(); |
| } else if ( header.toLowerCase() == 'etag' ) { |
| return m.etag || ''; |
| } else if ( header.toLowerCase() == 'content-type' ) { |
| return m.contentType || 'text/plain'; |
| } |
| }, |
| getAllResponseHeaders: function() { |
| var headers = ''; |
| $.each(m.headers, function(k, v) { |
| headers += k + ': ' + v + "\n"; |
| }); |
| return headers; |
| } |
| }; |
| } |
| })); |
| return false; |
| } |
| }); |
| // We don't have a mock request, trigger a normal request |
| if ( !mock ) { |
| return _ajax.apply($, arguments); |
| } else { |
| return mock; |
| } |
| } |
| }); |
| |
| $.mockjaxSettings = { |
| //url: null, |
| //type: 'GET', |
| log: function(msg) { |
| window['console'] && window.console.log && window.console.log(msg); |
| }, |
| status: 200, |
| responseTime: 500, |
| isTimeout: false, |
| contentType: 'text/plain', |
| response: '', |
| responseText: '', |
| responseXML: '', |
| proxy: '', |
| proxyType: 'GET', |
| |
| lastModified: null, |
| etag: '', |
| headers: { |
| etag: 'IJF@H#@923uf8023hFO@I#H#', |
| 'content-type' : 'text/plain' |
| } |
| }; |
| |
| $.mockjax = function(settings) { |
| var i = mockHandlers.length; |
| mockHandlers[i] = settings; |
| return i; |
| }; |
| $.mockjaxClear = function(i) { |
| if ( arguments.length == 1 ) { |
| mockHandlers[i] = null; |
| } else { |
| mockHandlers = []; |
| } |
| }; |
| })(jQuery); |