Added buffer to file. Added installation and better usage instructions.

master 0.0.2
Qvazar 2015-09-14 18:34:34 +02:00
rodzic b2edee96ad
commit 487a977047
8 zmienionych plików z 387 dodań i 39 usunięć

1
.gitignore vendored
Wyświetl plik

@ -1,2 +1 @@
build
node_modules node_modules

Wyświetl plik

@ -11,38 +11,40 @@ Useful when packing all your application images/sound/json/etc. data in a standa
As of September 2015 this includes Chrome>=20, Firefox>=13, IE>=10, Opera>=12.10 and Safari>=8. As of September 2015 this includes Chrome>=20, Firefox>=13, IE>=10, Opera>=12.10 and Safari>=8.
[Web Worker transferable objects](https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage) are used when available, increasing speed greatly. This is supported in Chrome>=21, Firefox>=18, Opera>=15 and Safari. [Web Worker transferable objects](https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage) are used when available, increasing speed greatly. This is supported in Chrome>=21, Firefox>=18, Opera>=15 and Safari.
## Installation
bower install --save js-untar
## Documentation ## Documentation
Load the module with RequireJS or similar. The module is a function that returns a modified Promise with a progress callback. Supports AMD, CommonJS or simply load with a script tag, which will provide a global untar function.
The module is a function that returns a modified Promise with a progress callback.
This callback is executed every time a file is extracted. This callback is executed every time a file is extracted.
The standard Promise.then method is also called when extraction is done, with all extracted files as argument. The standard Promise.then method is also called when extraction is done, with all extracted files as argument.
The extraction is done in a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) to allow the main UI thread to continue. The extraction is done in a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) to allow the main UI thread to continue.
### Example: ### Example:
define(["untar"], function(untar) { // Load the source ArrayBuffer from a XMLHttpRequest (or any other way you may need).
// Load the source ArrayBuffer from a XMLHttpRequest (or any other way you may need). var sourceBuffer = [...];
var sourceBuffer = [...];
untar(sourceBuffer)
untar(sourceBuffer) .progress(function(extractedFile) {
.progress(function(extractedFile) { ... // Do something with a single extracted file.
... })
}) .then(function(extractedFiles) {
.then(function(extractedFiles) { ... // Do something with all extracted files.
...
});
// or
untar(sourceBuffer).then(
function(extractedFiles) { // onSuccess
...
},
function(err) { // onError
...
},
function(extractedFile) { // onProgress
...
}
);
}); });
// or
untar(sourceBuffer).then(
function(extractedFiles) { // onSuccess
... // Do something with all extracted files.
},
function(err) { // onError
... // Handle the error.
},
function(extractedFile) { // onProgress
... // Do something with a single extracted file.
}
);
### File object ### File object
The returned file object(s) has the following properties. Most of these are explained in the [Tar wikipedia entry](https://en.wikipedia.org/wiki/Tar_(computing)#File_format). The returned file object(s) has the following properties. Most of these are explained in the [Tar wikipedia entry](https://en.wikipedia.org/wiki/Tar_(computing)#File_format).
@ -57,7 +59,8 @@ The returned file object(s) has the following properties. Most of these are expl
* type * type
* linkname * linkname
* ustarFormat * ustarFormat
* blob A [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) object with the contens of the file. * buffer An ArrayBuffer with the contents of the file.
* blob A [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) object with the contents of the file.
* getObjectUrl() * getObjectUrl()
A unique [ObjectUrl](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL) to the data can be retrieved with this method for easy usage of extracted data in <img> tags etc. A unique [ObjectUrl](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL) to the data can be retrieved with this method for easy usage of extracted data in <img> tags etc.
document.getElementById("targetImageElement").src = file.getObjectUrl(); document.getElementById("targetImageElement").src = file.getObjectUrl();

Wyświetl plik

@ -0,0 +1,65 @@
;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.ProgressivePromise = factory();
}
}(this, function() {
"use strict";
/* globals window: false, Promise: false */
/**
Returns a Promise decorated with a progress() event.
*/
function ProgressivePromise(fn) {
if (typeof Promise !== "function") {
throw new Error("Promise implementation not available in this environment.");
}
var progressCallbacks = [];
var progressHistory = [];
function doProgress(value) {
for (var i = 0, l = progressCallbacks.length; i < l; ++i) {
progressCallbacks[i](value);
}
progressHistory.push(value);
}
var promise = new Promise(function(resolve, reject) {
fn(resolve, reject, doProgress);
});
promise.progress = function(cb) {
if (typeof cb !== "function") {
throw new Error("cb is not a function.");
}
// Report the previous progress history
for (var i = 0, l = progressHistory.length; i < l; ++i) {
cb(progressHistory[i]);
}
progressCallbacks.push(cb);
return promise;
};
var origThen = promise.then;
promise.then = function(onSuccess, onFail, onProgress) {
origThen.call(promise, onSuccess, onFail);
if (onProgress !== undefined) {
promise.progress(onProgress);
}
return promise;
};
return promise;
}
return ProgressivePromise;
}));

Wyświetl plik

@ -0,0 +1,189 @@
"use strict";
/* globals postMessage: false, DataView: false, self: false, window: false, ArrayBuffer: false, Uint8Array: false */
function UntarWorker() {
}
UntarWorker.prototype = {
onmessage: function(msg) {
try {
if (msg.data.type === "extract") {
this.untarBuffer(msg.data.buffer);
} else {
throw new Error("Unknown message type: " + msg.data.type);
}
} catch (err) {
this.postError(err);
}
},
postError: function(err) {
//console.info("postError(" + err.message + ")" + " " + JSON.stringify(err));
this.postMessage({ type: "error", data: { message: err.message } });
},
postLog: function(level, msg) {
console.info("postLog");
this.postMessage({ type: "log", data: { level: level, msg: msg }});
},
untarBuffer: function(arrayBuffer) {
try {
var tarFileStream = new UntarFileStream(arrayBuffer);
while (tarFileStream.hasNext()) {
var file = tarFileStream.next();
this.postMessage({ type: "extract", data: file }, [file.buffer]);
}
this.postMessage({ type: "complete" });
} catch (err) {
this.postError(err);
}
},
postMessage: function(msg, transfers) {
console.info("postMessage(" + msg + ", " + JSON.stringify(transfers) + ")");
self.postMessage(msg, transfers);
}
};
if (typeof self !== "undefined") {
// We're running in a worker thread
var worker = new UntarWorker();
self.onmessage = function(msg) { worker.onmessage(msg); };
}
function TarFile() {
}
function UntarStream(arrayBuffer) {
this._bufferView = new DataView(arrayBuffer);
this._position = 0;
}
UntarStream.prototype = {
readString: function(charCount) {
//console.log("readString: position " + this.position() + ", " + charCount + " chars");
var charSize = 1;
var byteCount = charCount * charSize;
var charCodes = [];
for (var i = 0; i < charCount; ++i) {
var charCode = this._bufferView.getUint8(this.position() + (i * charSize), true);
if (charCode !== 0) {
charCodes.push(charCode);
} else {
break;
}
}
this.seek(byteCount);
return String.fromCharCode.apply(null, charCodes);
},
readBuffer: function(byteCount) {
var buf;
if (typeof ArrayBuffer.prototype.slice === "function") {
buf = this._bufferView.buffer.slice(this.position(), this.position() + byteCount);
} else {
buf = new ArrayBuffer(byteCount);
var target = new Uint8Array(buf);
var src = new Uint8Array(this._bufferView.buffer, this.position(), byteCount);
target.set(src);
}
this.seek(byteCount);
return buf;
},
seek: function(byteCount) {
this._position += byteCount;
},
peekUint32: function() {
return this._bufferView.getUint32(this.position(), true);
},
position: function(newpos) {
if (newpos === undefined) {
return this._position;
} else {
this._position = newpos;
}
},
size: function() {
return this._bufferView.byteLength;
}
};
function UntarFileStream(arrayBuffer) {
this._stream = new UntarStream(arrayBuffer);
}
UntarFileStream.prototype = {
hasNext: function() {
// A tar file ends with 4 zero bytes
return this._stream.position() + 4 < this._stream.size() && this._stream.peekUint32() !== 0;
},
next: function() {
var stream = this._stream;
var file = new TarFile();
var headerBeginPos = stream.position();
var dataBeginPos = headerBeginPos + 512;
// Read header
file.name = stream.readString(100);
file.mode = stream.readString(8);
file.uid = stream.readString(8);
file.gid = stream.readString(8);
file.size = parseInt(stream.readString(12), 8);
file.modificationTime = parseInt(stream.readString(12), 8);
file.checksum = stream.readString(8);
file.type = stream.readString(1);
file.linkname = stream.readString(1);
file.ustarFormat = stream.readString(6);
if (file.ustarFormat === "ustar") {
file.version = stream.readString(2);
file.uname = stream.readString(32);
file.gname = stream.readString(32);
file.devmajor = stream.readString(8);
file.devminor = stream.readString(8);
file.namePrefix = stream.readString(155);
if (file.namePrefix.length > 0) {
file.name = file.namePrefix + file.name;
}
}
stream.position(dataBeginPos);
// Normal file is either "\0" or 0.
if (file.type === "0" || file.type === "\0") {
file.buffer = stream.readBuffer(file.size);
} else if (file.type == 5) {
// Directory - should we do anything with this? Nope!
} else {
// We only care about real files, not symlinks.
}
if (file.buffer === undefined) {
file.buffer = new ArrayBuffer(0);
}
// File data is padded to reach a 512 byte boundary; skip the padded bytes.
var dataEndPos = dataBeginPos + (file.size > 0 ? file.size + (512 - file.size % 512) : 0);
stream.position(dataEndPos);
return file;
}
};

91
build/dev/untar.js 100644
Wyświetl plik

@ -0,0 +1,91 @@
;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(['ProgressivePromise'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('ProgressivePromise'));
} else {
root.untar = factory(root.ProgressivePromise);
}
}(this, function(ProgressivePromise) {
"use strict";
/* globals window: false, Blob: false, Promise: false, console: false, Worker: false, ProgressivePromise: false */
var workerScriptUri; // Included at compile time
var URL = window.URL || window.webkitURL;
/**
Returns a ProgressivePromise.
*/
function untar(arrayBuffer) {
if (!(arrayBuffer instanceof ArrayBuffer)) {
throw new TypeError("arrayBuffer is not an instance of ArrayBuffer.");
}
if (!window.Worker) {
throw new Error("Worker implementation not available in this environment.");
}
return new ProgressivePromise(function(resolve, reject, progress) {
var worker = new Worker(workerScriptUri);
var files = [];
worker.onerror = function(err) {
reject(err);
};
worker.onmessage = function(message) {
message = message.data;
switch (message.type) {
case "log":
console[message.data.level]("Worker: " + message.data.msg);
break;
case "extract":
var file = decorateExtractedFile(message.data);
files.push(file);
progress(file);
break;
case "complete":
resolve(files);
break;
case "error":
//console.log("error message");
reject(new Error(message.data.message));
break;
default:
reject(new Error("Unknown message from worker: " + message.type));
break;
}
};
//console.info("Sending arraybuffer to worker for extraction.");
worker.postMessage({ type: "extract", buffer: arrayBuffer }, [arrayBuffer]);
});
}
function decorateExtractedFile(file) {
var blob;
var blobUrl;
Object.defineProperties(file, {
blob: {
get: function() {
return blob || (blob = new Blob([this.buffer]));
}
},
getObjectUrl: {
value: function() {
return blobUrl || (blubUrl = URL.createObjectURL(blob));
}
}
});
return file;
}
workerScriptUri = '/base/build/dev/untar-worker.js';
return untar;
}));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlcyI6WyJ1bnRhci5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBnbG9iYWxzIHdpbmRvdzogZmFsc2UsIEJsb2I6IGZhbHNlLCBQcm9taXNlOiBmYWxzZSwgY29uc29sZTogZmFsc2UsIFdvcmtlcjogZmFsc2UsIFByb2dyZXNzaXZlUHJvbWlzZTogZmFsc2UgKi9cblxudmFyIHdvcmtlclNjcmlwdFVyaTsgLy8gSW5jbHVkZWQgYXQgY29tcGlsZSB0aW1lXG5cbnZhciBVUkwgPSB3aW5kb3cuVVJMIHx8IHdpbmRvdy53ZWJraXRVUkw7XG5cbi8qKlxuUmV0dXJucyBhIFByb2dyZXNzaXZlUHJvbWlzZS5cbiovXG5mdW5jdGlvbiB1bnRhcihhcnJheUJ1ZmZlcikge1xuXHRpZiAoIShhcnJheUJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSkge1xuXHRcdHRocm93IG5ldyBUeXBlRXJyb3IoXCJhcnJheUJ1ZmZlciBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgQXJyYXlCdWZmZXIuXCIpO1xuXHR9XG5cblx0aWYgKCF3aW5kb3cuV29ya2VyKSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKFwiV29ya2VyIGltcGxlbWVudGF0aW9uIG5vdCBhdmFpbGFibGUgaW4gdGhpcyBlbnZpcm9ubWVudC5cIik7XG5cdH1cblxuXHRyZXR1cm4gbmV3IFByb2dyZXNzaXZlUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QsIHByb2dyZXNzKSB7XG5cdFx0dmFyIHdvcmtlciA9IG5ldyBXb3JrZXIod29ya2VyU2NyaXB0VXJpKTtcblxuXHRcdHZhciBmaWxlcyA9IFtdO1xuXG5cdFx0d29ya2VyLm9uZXJyb3IgPSBmdW5jdGlvbihlcnIpIHtcblx0XHRcdHJlamVjdChlcnIpO1xuXHRcdH07XG5cblx0XHR3b3JrZXIub25tZXNzYWdlID0gZnVuY3Rpb24obWVzc2FnZSkge1xuXHRcdFx0bWVzc2FnZSA9IG1lc3NhZ2UuZGF0YTtcblxuXHRcdFx0c3dpdGNoIChtZXNzYWdlLnR5cGUpIHtcblx0XHRcdFx0Y2FzZSBcImxvZ1wiOlxuXHRcdFx0XHRcdGNvbnNvbGVbbWVzc2FnZS5kYXRhLmxldmVsXShcIldvcmtlcjogXCIgKyBtZXNzYWdlLmRhdGEubXNnKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBcImV4dHJhY3RcIjpcblx0XHRcdFx0XHR2YXIgZmlsZSA9IGRlY29yYXRlRXh0cmFjdGVkRmlsZShtZXNzYWdlLmRhdGEpO1xuXHRcdFx0XHRcdGZpbGVzLnB1c2goZmlsZSk7XG5cdFx0XHRcdFx0cHJvZ3Jlc3MoZmlsZSk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgXCJjb21wbGV0ZVwiOlxuXHRcdFx0XHRcdHJlc29sdmUoZmlsZXMpO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIFwiZXJyb3JcIjpcblx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKFwiZXJyb3IgbWVzc2FnZVwiKTtcblx0XHRcdFx0XHRyZWplY3QobmV3IEVycm9yKG1lc3NhZ2UuZGF0YS5tZXNzYWdlKSk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0cmVqZWN0KG5ldyBFcnJvcihcIlVua25vd24gbWVzc2FnZSBmcm9tIHdvcmtlcjogXCIgKyBtZXNzYWdlLnR5cGUpKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0Ly9jb25zb2xlLmluZm8oXCJTZW5kaW5nIGFycmF5YnVmZmVyIHRvIHdvcmtlciBmb3IgZXh0cmFjdGlvbi5cIik7XG5cdFx0d29ya2VyLnBvc3RNZXNzYWdlKHsgdHlwZTogXCJleHRyYWN0XCIsIGJ1ZmZlcjogYXJyYXlCdWZmZXIgfSwgW2FycmF5QnVmZmVyXSk7XG5cdH0pO1xufVxuXG5mdW5jdGlvbiBkZWNvcmF0ZUV4dHJhY3RlZEZpbGUoZmlsZSkge1xuXHR2YXIgYmxvYjtcblx0dmFyIGJsb2JVcmw7XG5cdE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKGZpbGUsIHtcblx0XHRibG9iOiB7XG5cdFx0XHRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gYmxvYiB8fCAoYmxvYiA9IG5ldyBCbG9iKFt0aGlzLmJ1ZmZlcl0pKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdGdldE9iamVjdFVybDoge1xuXHRcdFx0dmFsdWU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gYmxvYlVybCB8fCAoYmx1YlVybCA9IFVSTC5jcmVhdGVPYmplY3RVUkwoYmxvYikpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSk7XG5cblx0cmV0dXJuIGZpbGU7XG59XG4iXSwiZmlsZSI6InVudGFyLmpzIiwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0=

1
build/dist/untar.js vendored 100644
Wyświetl plik

@ -0,0 +1 @@
!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?module.exports=t():e.untar=t()}(this,function(){"use strict";function e(e){function t(e){for(var t=0,i=r.length;i>t;++t)r[t](e);n.push(e)}if("function"!=typeof Promise)throw new Error("Promise implementation not available in this environment.");var r=[],n=[],i=new Promise(function(r,n){e(r,n,t)});i.progress=function(e){if("function"!=typeof e)throw new Error("cb is not a function.");for(var t=0,o=n.length;o>t;++t)e(n[t]);return r.push(e),i};var o=i.then;return i.then=function(e,t,r){return o.call(i,e,t),void 0!==r&&i.progress(r),i},i}function t(t){if(!(t instanceof ArrayBuffer))throw new TypeError("arrayBuffer is not an instance of ArrayBuffer.");if(!window.Worker)throw new Error("Worker implementation not available in this environment.");return new e(function(e,i,o){var a=new Worker(n),s=[];a.onerror=function(e){i(e)},a.onmessage=function(t){switch(t=t.data,t.type){case"log":console[t.data.level]("Worker: "+t.data.msg);break;case"extract":var n=r(t.data);s.push(n),o(n);break;case"complete":e(s);break;case"error":i(new Error(t.data.message));break;default:i(new Error("Unknown message from worker: "+t.type))}},a.postMessage({type:"extract",buffer:t},[t])})}function r(e){var t,r;return Object.defineProperties(e,{blob:{get:function(){return t||(t=new Blob([this.buffer]))}},getObjectUrl:{value:function(){return r||(blubUrl=i.createObjectURL(t))}}}),e}var n,i=window.URL||window.webkitURL;return n=i.createObjectURL(new Blob(['"use strict";function UntarWorker(){}function TarFile(){}function UntarStream(e){this._bufferView=new DataView(e),this._position=0}function UntarFileStream(e){this._stream=new UntarStream(e)}if(UntarWorker.prototype={onmessage:function(e){try{if("extract"!==e.data.type)throw new Error("Unknown message type: "+e.data.type);this.untarBuffer(e.data.buffer)}catch(t){this.postError(t)}},postError:function(e){this.postMessage({type:"error",data:{message:e.message}})},postLog:function(e,t){console.info("postLog"),this.postMessage({type:"log",data:{level:e,msg:t}})},untarBuffer:function(e){try{for(var t=new UntarFileStream(e);t.hasNext();){var r=t.next();this.postMessage({type:"extract",data:r},[r.buffer])}this.postMessage({type:"complete"})}catch(i){this.postError(i)}},postMessage:function(e,t){console.info("postMessage("+e+", "+JSON.stringify(t)+")"),self.postMessage(e,t)}},"undefined"!=typeof self){var worker=new UntarWorker;self.onmessage=function(e){worker.onmessage(e)}}UntarStream.prototype={readString:function(e){for(var t=1,r=e*t,i=[],n=0;e>n;++n){var s=this._bufferView.getUint8(this.position()+n*t,!0);if(0===s)break;i.push(s)}return this.seek(r),String.fromCharCode.apply(null,i)},readBuffer:function(e){var t;if("function"==typeof ArrayBuffer.prototype.slice)t=this._bufferView.buffer.slice(this.position(),this.position()+e);else{t=new ArrayBuffer(e);var r=new Uint8Array(t),i=new Uint8Array(this._bufferView.buffer,this.position(),e);r.set(i)}return this.seek(e),t},seek:function(e){this._position+=e},peekUint32:function(){return this._bufferView.getUint32(this.position(),!0)},position:function(e){return void 0===e?this._position:void(this._position=e)},size:function(){return this._bufferView.byteLength}},UntarFileStream.prototype={hasNext:function(){return this._stream.position()+4<this._stream.size()&&0!==this._stream.peekUint32()},next:function(){var e=this._stream,t=new TarFile,r=e.position(),i=r+512;t.name=e.readString(100),t.mode=e.readString(8),t.uid=e.readString(8),t.gid=e.readString(8),t.size=parseInt(e.readString(12),8),t.modificationTime=parseInt(e.readString(12),8),t.checksum=e.readString(8),t.type=e.readString(1),t.linkname=e.readString(1),t.ustarFormat=e.readString(6),"ustar"===t.ustarFormat&&(t.version=e.readString(2),t.uname=e.readString(32),t.gname=e.readString(32),t.devmajor=e.readString(8),t.devminor=e.readString(8),t.namePrefix=e.readString(155),t.namePrefix.length>0&&(t.name=t.namePrefix+t.name)),e.position(i),"0"===t.type||"\x00"===t.type?t.buffer=e.readBuffer(t.size):5==t.type,void 0===t.buffer&&(t.buffer=new ArrayBuffer(0));var n=i+(t.size>0?t.size+(512-t.size%512):0);return e.position(n),t}};'])),t});

Wyświetl plik

@ -26,7 +26,6 @@
}, },
"homepage": "https://github.com/Qvazar/js-untar", "homepage": "https://github.com/Qvazar/js-untar",
"devDependencies": { "devDependencies": {
"es6-promise": "^3.0.2",
"gulp": "^3.9.0", "gulp": "^3.9.0",
"gulp-add-src": "^0.2.0", "gulp-add-src": "^0.2.0",
"gulp-concat": "^2.6.0", "gulp-concat": "^2.6.0",
@ -42,9 +41,7 @@
"karma-firefox-launcher": "^0.1.6", "karma-firefox-launcher": "^0.1.6",
"karma-ie-launcher": "^0.2.0", "karma-ie-launcher": "^0.2.0",
"karma-jasmine": "^0.3.6", "karma-jasmine": "^0.3.6",
"karma-phantomjs-launcher": "^0.2.1",
"karma-requirejs": "^0.2.2", "karma-requirejs": "^0.2.2",
"phantomjs": "^1.9.18",
"requirejs": "^2.1.20" "requirejs": "^2.1.20"
} }
} }

Wyświetl plik

@ -56,17 +56,20 @@ function untar(arrayBuffer) {
} }
function decorateExtractedFile(file) { function decorateExtractedFile(file) {
file.blob = new Blob([file.buffer]); var blob;
delete file.buffer;
var blobUrl; var blobUrl;
file.getObjectUrl = function() { Object.defineProperties(file, {
if (!blobUrl) { blob: {
blobUrl = URL.createObjectURL(file.blob); get: function() {
return blob || (blob = new Blob([this.buffer]));
}
},
getObjectUrl: {
value: function() {
return blobUrl || (blubUrl = URL.createObjectURL(blob));
}
} }
});
return blobUrl;
};
return file; return file;
} }