UNPKG

5.78 kBJavaScriptView Raw
1import { Cache } from './Cache.js';
2import { Loader } from './Loader.js';
3
4const loading = {};
5
6function FileLoader( manager ) {
7
8 Loader.call( this, manager );
9
10}
11
12FileLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
13
14 constructor: FileLoader,
15
16 load: function ( url, onLoad, onProgress, onError ) {
17
18 if ( url === undefined ) url = '';
19
20 if ( this.path !== undefined ) url = this.path + url;
21
22 url = this.manager.resolveURL( url );
23
24 const scope = this;
25
26 const cached = Cache.get( url );
27
28 if ( cached !== undefined ) {
29
30 scope.manager.itemStart( url );
31
32 setTimeout( function () {
33
34 if ( onLoad ) onLoad( cached );
35
36 scope.manager.itemEnd( url );
37
38 }, 0 );
39
40 return cached;
41
42 }
43
44 // Check if request is duplicate
45
46 if ( loading[ url ] !== undefined ) {
47
48 loading[ url ].push( {
49
50 onLoad: onLoad,
51 onProgress: onProgress,
52 onError: onError
53
54 } );
55
56 return;
57
58 }
59
60 // Check for data: URI
61 const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
62 const dataUriRegexResult = url.match( dataUriRegex );
63 let request;
64
65 // Safari can not handle Data URIs through XMLHttpRequest so process manually
66 if ( dataUriRegexResult ) {
67
68 const mimeType = dataUriRegexResult[ 1 ];
69 const isBase64 = !! dataUriRegexResult[ 2 ];
70
71 let data = dataUriRegexResult[ 3 ];
72 data = decodeURIComponent( data );
73
74 if ( isBase64 ) data = atob( data );
75
76 try {
77
78 let response;
79 const responseType = ( this.responseType || '' ).toLowerCase();
80
81 switch ( responseType ) {
82
83 case 'arraybuffer':
84 case 'blob':
85
86 const view = new Uint8Array( data.length );
87
88 for ( let i = 0; i < data.length; i ++ ) {
89
90 view[ i ] = data.charCodeAt( i );
91
92 }
93
94 if ( responseType === 'blob' ) {
95
96 response = new Blob( [ view.buffer ], { type: mimeType } );
97
98 } else {
99
100 response = view.buffer;
101
102 }
103
104 break;
105
106 case 'document':
107
108 const parser = new DOMParser();
109 response = parser.parseFromString( data, mimeType );
110
111 break;
112
113 case 'json':
114
115 response = JSON.parse( data );
116
117 break;
118
119 default: // 'text' or other
120
121 response = data;
122
123 break;
124
125 }
126
127 // Wait for next browser tick like standard XMLHttpRequest event dispatching does
128 setTimeout( function () {
129
130 if ( onLoad ) onLoad( response );
131
132 scope.manager.itemEnd( url );
133
134 }, 0 );
135
136 } catch ( error ) {
137
138 // Wait for next browser tick like standard XMLHttpRequest event dispatching does
139 setTimeout( function () {
140
141 if ( onError ) onError( error );
142
143 scope.manager.itemError( url );
144 scope.manager.itemEnd( url );
145
146 }, 0 );
147
148 }
149
150 } else {
151
152 // Initialise array for duplicate requests
153
154 loading[ url ] = [];
155
156 loading[ url ].push( {
157
158 onLoad: onLoad,
159 onProgress: onProgress,
160 onError: onError
161
162 } );
163
164 request = new XMLHttpRequest();
165
166 request.open( 'GET', url, true );
167
168 request.addEventListener( 'load', function ( event ) {
169
170 const response = this.response;
171
172 const callbacks = loading[ url ];
173
174 delete loading[ url ];
175
176 if ( this.status === 200 || this.status === 0 ) {
177
178 // Some browsers return HTTP Status 0 when using non-http protocol
179 // e.g. 'file://' or 'data://'. Handle as success.
180
181 if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
182
183 // Add to cache only on HTTP success, so that we do not cache
184 // error response bodies as proper responses to requests.
185 Cache.add( url, response );
186
187 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
188
189 const callback = callbacks[ i ];
190 if ( callback.onLoad ) callback.onLoad( response );
191
192 }
193
194 scope.manager.itemEnd( url );
195
196 } else {
197
198 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
199
200 const callback = callbacks[ i ];
201 if ( callback.onError ) callback.onError( event );
202
203 }
204
205 scope.manager.itemError( url );
206 scope.manager.itemEnd( url );
207
208 }
209
210 }, false );
211
212 request.addEventListener( 'progress', function ( event ) {
213
214 const callbacks = loading[ url ];
215
216 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
217
218 const callback = callbacks[ i ];
219 if ( callback.onProgress ) callback.onProgress( event );
220
221 }
222
223 }, false );
224
225 request.addEventListener( 'error', function ( event ) {
226
227 const callbacks = loading[ url ];
228
229 delete loading[ url ];
230
231 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
232
233 const callback = callbacks[ i ];
234 if ( callback.onError ) callback.onError( event );
235
236 }
237
238 scope.manager.itemError( url );
239 scope.manager.itemEnd( url );
240
241 }, false );
242
243 request.addEventListener( 'abort', function ( event ) {
244
245 const callbacks = loading[ url ];
246
247 delete loading[ url ];
248
249 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
250
251 const callback = callbacks[ i ];
252 if ( callback.onError ) callback.onError( event );
253
254 }
255
256 scope.manager.itemError( url );
257 scope.manager.itemEnd( url );
258
259 }, false );
260
261 if ( this.responseType !== undefined ) request.responseType = this.responseType;
262 if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
263
264 if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
265
266 for ( const header in this.requestHeader ) {
267
268 request.setRequestHeader( header, this.requestHeader[ header ] );
269
270 }
271
272 request.send( null );
273
274 }
275
276 scope.manager.itemStart( url );
277
278 return request;
279
280 },
281
282 setResponseType: function ( value ) {
283
284 this.responseType = value;
285 return this;
286
287 },
288
289 setMimeType: function ( value ) {
290
291 this.mimeType = value;
292 return this;
293
294 }
295
296} );
297
298
299export { FileLoader };