import { DefaultLoadingManager } from './LoadingManager.js';
/**
* A low level class for loading resources with XMLHttpRequest, used internaly by most loaders.
* It can also be used directly to load any file type that does not have a loader.
* @constructor
* @memberof zen3d
* @param {zen3d.LoadingManager} manager — The loadingManager for the loader to use. Default is zen3d.DefaultLoadingManager.
*/
function FileLoader(manager) {
this.path = undefined;
this.responseType = undefined;
this.withCredentials = undefined;
this.mimeType = undefined;
this.requestHeader = undefined;
this.manager = (manager !== undefined) ? manager : DefaultLoadingManager;
}
Object.assign(FileLoader.prototype, /** @lends zen3d.FileLoader.prototype */{
/**
* Load the URL and pass the response to the onLoad function.
* @param {string} url — the path or URL to the file. This can also be a Data URI.
* @param {Function} [onLoad=] — Will be called when loading completes. The argument will be the loaded response.
* @param {Function} [onProgress=] — Will be called while load progresses. The argument will be the XMLHttpRequest instance, which contains .total and .loaded bytes.
* @param {Function} [onError=] — Will be called if an error occurs.
*/
load: function(url, onLoad, onProgress, onError) {
if (url === undefined) url = '';
if (this.path != undefined) url = this.path + url;
url = this.manager.resolveURL(url);
var scope = this;
// Check for data: URI
var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
var dataUriRegexResult = url.match(dataUriRegex);
var request;
if (dataUriRegexResult) { // Safari can not handle Data URIs through XMLHttpRequest so process manually
var mimeType = dataUriRegexResult[1];
var isBase64 = !!dataUriRegexResult[2];
var data = dataUriRegexResult[3];
data = decodeURIComponent(data);
if (isBase64) data = atob(data); // decode base64
try {
var response;
var responseType = (this.responseType || '').toLowerCase();
switch (responseType) {
case 'arraybuffer':
case 'blob':
response = new ArrayBuffer(data.length);
var view = new Uint8Array(response);
for (var i = 0; i < data.length; i++) {
view[i] = data.charCodeAt(i);
}
if (responseType === 'blob') {
response = new Blob([response], {
type: mimeType
});
}
break;
case 'document':
var parser = new DOMParser();
response = parser.parseFromString(data, mimeType);
break;
case 'json':
response = JSON.parse(data);
break;
default: // 'text' or other
response = data;
break;
}
// Wait for next browser tick
setTimeout(function() {
if (onLoad) onLoad(response);
scope.manager.itemEnd(url);
}, 0);
} catch (error) {
// Wait for next browser tick
setTimeout(function() {
onError && onError(error);
scope.manager.itemError(url);
scope.manager.itemEnd(url);
}, 0);
}
} else {
request = new XMLHttpRequest();
request.open('GET', url, true);
request.addEventListener('load', function(event) {
var response = this.response;
if (this.status === 200) {
if (onLoad) onLoad(response);
scope.manager.itemEnd(url);
} else if (this.status === 0) {
// Some browsers return HTTP Status 0 when using non-http protocol
// e.g. 'file://' or 'data://'. Handle as success.
console.warn('zen3d.FileLoader: HTTP Status 0 received.');
if (onLoad) onLoad(response);
scope.manager.itemEnd(url);
} else {
if (onError) onError(event);
scope.manager.itemError(url);
scope.manager.itemEnd(url);
}
}, false);
if (onProgress !== undefined) {
request.addEventListener('progress', function(event) {
onProgress(event);
}, false);
}
if (onError !== undefined) {
request.addEventListener('error', function(event) {
onError(event);
scope.manager.itemError(url);
scope.manager.itemEnd(url);
}, false);
}
if (this.responseType !== undefined) request.responseType = this.responseType;
if (this.withCredentials !== undefined) request.withCredentials = this.withCredentials;
if (request.overrideMimeType) request.overrideMimeType(this.mimeType !== undefined ? this.mimeType : 'text/plain');
for (var header in this.requestHeader) {
request.setRequestHeader(header, this.requestHeader[header]);
}
request.send(null);
}
scope.manager.itemStart(url);
return request;
},
/**
* Set the base path or URL from which to load files.
* This can be useful if you are loading many models from the same directory.
* @param {string} value
* @return {zen3d.FileLoader}
*/
setPath: function(value) {
this.path = value;
return this;
},
/**
* Change the response type. Valid values are:
* text or empty string (default) - returns the data as string.
* arraybuffer - loads the data into a ArrayBuffer and returns that.
* blob - returns the data as a Blob.
* document - parses the file using the DOMParser.
* json - parses the file using JSON.parse.
* @param {string} value
* @return {zen3d.FileLoader}
*/
setResponseType: function(value) {
this.responseType = value;
return this;
},
/**
* Whether the XMLHttpRequest uses credentials such as cookies, authorization headers or TLS client certificates.
* See {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials XMLHttpRequest.withCredentials}.
* Note that this has no effect if you are loading files locally or from the same domain.
* @param {boolean} value
* @return {zen3d.FileLoader}
*/
setWithCredentials: function(value) {
this.withCredentials = value;
return this;
},
/**
* Set the expected mimeType of the file being loaded.
* Note that in many cases this will be determined automatically, so by default it is undefined.
* @param {string} value
* @return {zen3d.FileLoader}
*/
setMimeType: function(value) {
this.mimeType = value;
return this;
},
/**
* The request header used in HTTP request.
* Default is undefined.
* @param {string} value
* @return {zen3d.FileLoader}
*/
setRequestHeader: function(value) {
this.requestHeader = value;
return this;
}
});
export { FileLoader };