Requests.js: handle errors, various other improvements

This commit is contained in:
rolux 2012-06-17 15:36:55 +02:00
parent ec87a5c51c
commit 77adfbf7b8

View file

@ -2,93 +2,78 @@
/*@ /*@
Ox.get <f> Get a remote file Ox.get <f> Get a remote file
# fixme: remote? same-origin-policy? jsonp?
(url, callback) -> <u> undefined (url, callback) -> <u> undefined
url <s> Remote URL url <s> Remote URL
callback <f> Callback function callback <f> Callback function
data <s> The contents of the remote resource data <s> The contents of the remote resource
error <o|null> Error, or null
code <n> Status code
text <s> Status text
@*/ @*/
Ox.get = function(url, callback) { Ox.get = function(url, callback) {
var req = new XMLHttpRequest(); var request = new XMLHttpRequest();
req.open('GET', url, true); request.open('GET', url, true);
req.onreadystatechange = function() { request.onreadystatechange = function() {
if (req.readyState == 4) { if (request.readyState == 4) {
if (req.status == 200) { if (request.status == 200) {
callback(req.responseText); callback(request.responseText, null);
} else { } else {
throw new Error( callback(null, {
'Cannot get URL "' + url + '" (Status: ' + req.status + ')' code: request.status,
text: request.statusText
});
}
}
};
request.send();
};
/*@
Ox.getAsync <f> Runs an asynchonous loader for an array of URLs
(urls, map, callback) -> <u> undefined
urls <s|a> URL or array of either URLs or arrays of URLs
Multiple URLs in the same array will be processed simultaneously, but
multiple arrays of URLs will be processed in that order.
callback <f> Callback function
results <o> Results
Keys are file names, values are results
errors <o|null> Errors, or null
Keys are file names, values are error objects
@*/
Ox.getAsync = function(urls, map, callback) {
urls = Ox.clone(Ox.makeArray(urls));
var errors = {}, i = 0, n = urls.length, results = {};
function done() {
callback(
n == 1 ? results[urls[0]] : results,
n == 1 ? errors[urls[0]] : Ox.some(errors, function(error) {
return error !== null;
}) ? errors : null
); );
} }
function iterate() {
var url = urls.shift();
Ox.getAsync(url, function(result, error) {
Ox.extend(results, url, result);
Ox.extend(errors, url, error);
urls.length ? iterate() : done();
});
}
if (urls.some(Ox.isArray)) {
iterate();
} else {
urls.forEach(function(url) {
map(url, function(result, error) {
Ox.extend(results, url, result);
Ox.extend(errors, url, error);
++i == n && done();
});
});
} }
};
req.send();
}; };
/*@ /*@
Ox.getJSON <f> Get and parse one or more remote JSON files Ox.getFile <f> Loads a file (image, script or stylesheet)
# fixme: remote? same-origin-policy?
(url, callback) -> <u> undefined
url <s|[s]> One or more remote URLs
callback <f> Callback function
data <o> The parsed contents of the remote resource(s)
For multiple URLs, keys are file names, values are contents
@*/
Ox.getJSON = function(url, callback) {
var urls = Ox.makeArray(url);
Ox.loadAsync(urls, function(url, callback) {
Ox.get(url, function(data) {
var result = {};
result[url] = JSON.parse(data);
callback(result);
});
}, function(results) {
callback(urls.length == 1 ? results[url] : results);
});
}
/*@
Ox.getJSONP <f> Get and parse one or more remote JSONP files
(url, callback) -> <u> undefined
url <s|[s]> One or more remote URLs,
{callback} gets replaced with jsonp callback function name
callback <f> Callback function
data <o> The parsed contents of the remote resource(s)
For multiple URLs, keys are file names, values are contents
@*/
Ox.getJSONP = function(url, callback) {
var urls = Ox.makeArray(url);
Ox.loadAsync(urls, function(url, callback) {
var id = 'callback' + Ox.uid();
Ox.getJSONP[id] = function(data) {
delete Ox.getJSONP[id];
callback(data);
}
Ox.$('body').append(Ox.$('<script>').attr({
'src': url.replace('{callback}', 'Ox.getJSONP.' + id),
'type': 'text/javascript'
}));
}, function(results) {
callback(urls.length == 1 ? results[url] : results);
});
}
/*@
Ox.getJSONC <f> Get and parse a remote JSONC file
JSONC is JSON with JavaScript line or block comments
(url, callback) -> <u> undefined
url <s> Remote URL
callback <f> Callback function
data <s> The parsed contents of the remote resource
@*/
Ox.getJSONC = function(url, callback) {
Ox.get(url, function(data) {
callback(JSON.parse(Ox.minify(data)));
});
};
/*@
Ox.loadFile <f> Loads a file (image, script or stylesheet)
(file="script.js", callback) -> <u> undefined (file="script.js", callback) -> <u> undefined
(file="stylesheet.css", callback) -> <u> undefined (file="stylesheet.css", callback) -> <u> undefined
(file="image.png", callback) -> <u> undefined (file="image.png", callback) -> <u> undefined
@ -96,21 +81,16 @@ Ox.loadFile <f> Loads a file (image, script or stylesheet)
callback <f> Callback function callback <f> Callback function
image <e> DOM element (if the file is an image) image <e> DOM element (if the file is an image)
@*/ @*/
Ox.loadFile = (function() { // FIXME: this doesn't handle errors yet
// fixme: this doesn't handle errors yet Ox.getFile = (function() {
// fixme: rename to getFile?
var cache = {};
return function(files, callback) {
Ox.loadAsync(files, function(file, callback) {
loadFile(file, function(images) {
callback(images ? {file: images} : {});
});
}, callback);
}
function loadFile(file, callback) { var cache = {};
function getFile(file, callback) {
var element, var element,
head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, head = document.head
|| document.getElementsByTagName('head')[0]
|| document.documentElement,
request, request,
type = file.split('.').pop(), type = file.split('.').pop(),
isImage = type != 'css' && type != 'js'; isImage = type != 'css' && type != 'js';
@ -124,13 +104,16 @@ Ox.loadFile = (function() {
element = document.createElement( element = document.createElement(
type == 'css' ? 'link' : 'script' type == 'css' ? 'link' : 'script'
); );
element[type == 'css' ? 'href' : 'src'] = file + '?' + Ox.random(1000000); element[
type == 'css' ? 'href' : 'src'
] = file + '?' + Ox.random(1000000);
element.type = type == 'css' ? 'text/css' : 'text/javascript'; element.type = type == 'css' ? 'text/css' : 'text/javascript';
if (type == 'css') { if (type == 'css') {
element.rel = 'stylesheet'; element.rel = 'stylesheet';
} }
if (/MSIE/.test(navigator.userAgent)) { if (/MSIE/.test(navigator.userAgent)) {
// fixme: find a way to check if css/js have loaded in msie // fixme: find a way to check
// if css/js have loaded in msie
setTimeout(addFileToCache, 2500); setTimeout(addFileToCache, 2500);
} else { } else {
if (type == 'css') { if (type == 'css') {
@ -180,34 +163,78 @@ Ox.loadFile = (function() {
!error && addFileToCache(); !error && addFileToCache();
} }
}; };
return function(files, callback) {
Ox.getAsync(files, function(file, callback) {
getFile(file, function(images) {
callback(images ? {file: images} : {});
});
}, callback);
};
}()); }());
/*@ /*@
Ox.loadAsync <f> Runs an asynchonous function on array elements Ox.getJSON <f> Get and parse one or more remote JSON files
(arr, map, callback) -> <u> undefined (url, callback) -> <u> undefined
arr <s|a> String or array of either strings or arrays of strings url <s|a> One or more remote URLs
Multiple strings in the same array will be processed simultaneously, but
multiple arrays of strings will be processed in that order.
callback <f> Callback function callback <f> Callback function
results <o> Results data <*|o> The parsed content of the remote resource(s)
For multiple URLs, keys are file names, values are parsed contents
error <o|null> Error(s)
For multiple URLs, keys are file names, values are error objects
@*/ @*/
Ox.loadAsync = function(array, map, callback) { Ox.getJSON = function(url, callback, isJSONC) {
array = Ox.makeArray(array); var urls = Ox.makeArray(url);
var i = 0, n = array.length, results = {}; Ox.getAsync(urls, function(url, callback) {
if (array.some(Ox.isArray)) { Ox.get(url, function(data, error) {
iterate(); callback(JSON.parse(
} else { isJSONC ? Ox.minify(data || '') : data
array.forEach(function(value) { ), error);
map(value, function(result) {
Ox.extend(results, result);
++i == n && callback(results);
}); });
}); }, callback);
} };
function iterate() {
Ox.loadAsync(array.shift(), function(result) { /*@
Ox.extend(results, result); Ox.getJSONC <f> Get and parse a remote JSONC file
array.length ? iterate() : callback(results); JSONC is JSON with JavaScript line or block comments
}); (url, callback) -> <u> undefined
} url <s|a> One or more remote URLs
callback <f> Callback function
data <*|o> The parsed content of the remote resource(s)
For multiple URLs, keys are file names, values are parsed contents
error <o|null> Error(s)
For multiple URLs, keys are file names, values are error objects
@*/
Ox.getJSONC = function(url, callback) {
Ox.getJSON(url, function(results, errors) {
callback(results, errors);
}, true);
};
/*@
Ox.getJSONP <f> Get and parse one or more remote JSONP files
(url, callback) -> <u> undefined
url <s|a> One or more remote URLs
{callback} gets replaced with jsonp callback function name
callback <f> Callback function
data <*|o> The parsed content of the remote resource(s)
For multiple URLs, keys are file names, values are parsed contents
error <o|null> Error(s)
For multiple URLs, keys are file names, values are error objects
@*/
Ox.getJSONP = function(url, callback) {
var urls = Ox.makeArray(url);
Ox.getAsync(urls, function(url, callback) {
var id = 'callback' + Ox.uid();
Ox.getJSONP[id] = function(data) {
Ox.print('DATA', data)
delete Ox.getJSONP[id];
callback(data, null);
};
Ox.$('body').append(Ox.$('<script>').attr({
'src': url.replace('{callback}', 'Ox.getJSONP.' + id),
'type': 'text/javascript'
}));
}, callback);
}; };