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
});
} }
} }
}; };
req.send(); request.send();
}; };
/*@ /*@
Ox.getJSON <f> Get and parse one or more remote JSON files Ox.getAsync <f> Runs an asynchonous loader for an array of URLs
# fixme: remote? same-origin-policy? (urls, map, callback) -> <u> undefined
(url, callback) -> <u> undefined urls <s|a> URL or array of either URLs or arrays of URLs
url <s|[s]> One or more remote 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 callback <f> Callback function
data <o> The parsed contents of the remote resource(s) results <o> Results
For multiple URLs, keys are file names, values are contents Keys are file names, values are results
errors <o|null> Errors, or null
Keys are file names, values are error objects
@*/ @*/
Ox.getJSON = function(url, callback) { Ox.getAsync = function(urls, map, callback) {
var urls = Ox.makeArray(url); urls = Ox.clone(Ox.makeArray(urls));
Ox.loadAsync(urls, function(url, callback) { var errors = {}, i = 0, n = urls.length, results = {};
Ox.get(url, function(data) { function done() {
var result = {}; callback(
result[url] = JSON.parse(data); n == 1 ? results[urls[0]] : results,
callback(result); n == 1 ? errors[urls[0]] : Ox.some(errors, function(error) {
}); return error !== null;
}, function(results) { }) ? errors : null
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({ function iterate() {
'src': url.replace('{callback}', 'Ox.getJSONP.' + id), var url = urls.shift();
'type': 'text/javascript' Ox.getAsync(url, function(result, error) {
})); Ox.extend(results, url, result);
}, function(results) { Ox.extend(errors, url, error);
callback(urls.length == 1 ? results[url] : results); urls.length ? iterate() : done();
}); });
} }
if (urls.some(Ox.isArray)) {
/*@ iterate();
Ox.getJSONC <f> Get and parse a remote JSONC file } else {
JSONC is JSON with JavaScript line or block comments urls.forEach(function(url) {
(url, callback) -> <u> undefined map(url, function(result, error) {
url <s> Remote URL Ox.extend(results, url, result);
callback <f> Callback function Ox.extend(errors, url, error);
data <s> The parsed contents of the remote resource ++i == n && done();
@*/
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) Ox.getFile <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);
}; };