`$(document)` fix, Ajax enhancements #113

Merged
2 commits merged into from Mar 2, 2011
View
@@ -14,53 +14,62 @@
$('head').append(script);
};
+ $.ajaxSettings = {
+ type: 'GET',
+ beforeSend: empty, success: empty, error: empty, complete: empty,
+ accepts: {
+ script: 'text/javascript, application/javascript',
+ json: 'application/json',
+ xml: 'application/xml, text/xml',
+ html: 'text/html',
+ text: 'text/plain'
+ }
+ };
+
$.ajax = function(options){
- // { type, url, data, success, dataType, contentType }
options = options || {};
+ var settings = $.extend({}, options);
+ for (key in $.ajaxSettings) if (!settings[key]) settings[key] = $.ajaxSettings[key];
+
+ if (/=\?/.test(settings.url)) return $.ajaxJSONP(settings);
- if (options.url && /=\?/.test(options.url))
- return $.ajaxJSONP(options);
+ if (!settings.url) settings.url = window.location.toString();
+ if (settings.data && !settings.contentType) settings.contentType = "application/x-www-form-urlencoded";
- var data = options.data,
- callback = options.success || empty,
- errback = options.error || empty,
- mime = mimeTypes[options.dataType],
- type = options.type || "GET",
- content = options.contentType || (type === "POST" ? "application/x-www-form-urlencoded" : ""),
+ var mime = settings.accepts[settings.dataType],
xhr = new XMLHttpRequest();
+ settings.headers = $.extend({'X-Requested-With': 'XMLHttpRequest'}, settings.headers || {});
+ if (mime) settings.headers['Accept'] = mime;
+
xhr.onreadystatechange = function(){
if (xhr.readyState == 4) {
+ var result, error = false;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 0) {
if (mime == 'application/json') {
- var result, error = false;
- try {
- result = JSON.parse(xhr.responseText);
- } catch (e) {
- error = e;
- }
- if (error) errback(xhr, 'parsererror', error);
- else callback(result, 'success', xhr);
- } else callback(xhr.responseText, 'success', xhr);
+ try { result = JSON.parse(xhr.responseText); }
+ catch (e) { error = e; }
+ }
+ else result = xhr.responseText;
+ if (error) settings.error(xhr, 'parsererror', error);
+ else settings.success(result, 'success', xhr);
} else {
- errback(xhr, 'error');
+ error = true;
+ settings.error(xhr, 'error');
}
+ settings.complete(xhr, error ? 'error' : 'success');
}
};
- xhr.open(type, options.url || window.location, true);
- if (mime) xhr.setRequestHeader('Accept', mime);
- if (data instanceof Object) data = $.param(data);
- if (content) xhr.setRequestHeader('Content-Type', content);
- xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
- xhr.send(data);
- };
-
- var mimeTypes = $.ajax.mimeTypes = {
- json: 'application/json',
- xml: 'application/xml',
- html: 'text/html',
- text: 'text/plain'
+ xhr.open(settings.type, settings.url, true);
+ if (settings.beforeSend(xhr, settings) === false) {
+ xhr.abort();
+ return false;
+ }
+ if (settings.data instanceof Object) settings.data = $.param(settings.data);
+ if (settings.contentType) settings.headers['Content-Type'] = settings.contentType;
+ for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]);
+ xhr.send(settings.data);
};
$.get = function(url, success){ $.ajax({ url: url, success: success }) };
View
@@ -30,14 +30,15 @@ var Zepto = (function() {
}
function $(selector, context){
- if (selector == document) return Z();
- else if (context !== undefined) return $(context).find(selector);
+ if (!selector) return Z();
+ if (context !== undefined) return $(context).find(selector);
else if (typeof selector === 'function') return $(document).ready(selector);
else if (selector instanceof Z) return selector;
else {
var dom;
if (selector instanceof Array) dom = compact(selector);
- else if (selector instanceof Element || selector === window) dom = [selector];
+ else if (selector instanceof Element || selector === window || selector === document)
+ dom = [selector], selector = null;
else if (fragmentRE.test(selector)) dom = fragment(selector);
else dom = $$(document, selector);
return Z(dom, selector);
@@ -106,7 +107,7 @@ var Zepto = (function() {
var node = this[0], nodes = $$(context !== undefined ? context : document, selector);
if (nodes.length === 0) node = null;
while(node && node !== document && nodes.indexOf(node) < 0) node = node.parentNode;
- return $(node);
+ return $(node !== document && node);
},
parents: function(selector){
var ancestors = [], nodes = this;
View
@@ -121,6 +121,9 @@
send: function(data) {
this.data = data;
},
+ abort: function() {
+ this.aborted = true;
+ },
ready: function(readyState, status, responseText) {
this.readyState = readyState;
this.status = status;
@@ -171,6 +174,20 @@
t.assert(MockXHR.last.headers.some(matchHeader('Content-Type', 'text/html')));
},
+ testContentTypeDefaultsToUrlEncoded: function(t) {
+ $.ajax({ type: 'POST', data: [] });
+ t.assert(MockXHR.last.headers.some(matchHeader('Content-Type', 'application/x-www-form-urlencoded')));
+
+ $.ajax({ type: 'POST', data: [], contentType: 'application/x-foo' });
+ t.assert(MockXHR.last.headers.some(matchHeader('Content-Type', 'application/x-foo')));
+ },
+
+ testCustomHeader: function(t) {
+ $.ajax({ headers: {'X-Awesome': 'true'} });
+ t.assert(MockXHR.last.headers.some(matchHeader('X-Requested-With', 'XMLHttpRequest')));
+ t.assert(MockXHR.last.headers.some(matchHeader('X-Awesome', 'true')));
+ },
+
testJSONResponseBodiesAreParsedWhenDataTypeOptionIsJSON: function(t) {
var result = {};
$.ajax({ dataType: 'json', success: function(json) {result = json } });
@@ -245,6 +262,48 @@
t.assertEqual('Hello', body.message);
t.assertEqual('success', status);
t.assertEqual(MockXHR.last, xhr);
+ },
+
+ testBeforeSendCallback: function(t) {
+ var xhr, beforeFired = false, settings = {};
+ $.ajax({
+ data: "1=2",
+ beforeSend: function(x, s) {
+ beforeFired = true, settings = s, xhr = x;
+ }
+ });
+
+ t.assert(beforeFired);
+ t.assertEqual(MockXHR.last, xhr);
+ t.assertEqual("1=2", settings.data);
+ },
+
+ testBeforeSendAbort: function(t) {
+ var xhr;
+ $.ajax({ beforeSend: function(x) { xhr = x; return false } });
+
+ t.assert(xhr.aborted);
+ },
+
+ testCompleteCallback: function(t) {
+ var status, xhr;
+ $.ajax({ complete: function(x, s) { status = s, xhr = x } });
+
+ MockXHR.last.ready(4, 200, 'OK');
+ t.assertEqual(MockXHR.last, xhr);
+ t.assertEqual('success', status);
+ },
+
+ testCallbackOrder: function(t) {
+ var order = [];
+ $.ajax({
+ beforeSend: function() { order.push('beforeSend') },
+ success: function() { order.push('success') },
+ complete: function() { order.push('complete') }
+ });
+
+ MockXHR.last.ready(4, 200, 'OK');
+ t.assertEqual('beforeSend,success,complete', order.join(','));
}
});
</script>
View
@@ -203,6 +203,13 @@
t.assertLength(1, $('p > span.yay'));
},
+ testDollarWithNil: function(t){
+ t.assertLength(0, $(null));
+ t.assertLength(0, $(undefined));
+ t.assertLength(0, $(false));
+ t.assertLength(0, $(''));
+ },
+
testSize: function(t){
t.assertEqual(4, $('#find1 .findme').size());
},
@@ -244,7 +251,7 @@
testDollarWithDocument: function(t){
var z = $(document);
- t.assertLength(0, z);
+ t.assertLength(1, z);
t.assertEqual('', z.selector);
},