diff --git a/CHANGES.md b/CHANGES.md index fbcb7afa..25fe632d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,7 +3,6 @@ title: Changelog layout: default section: main --- - ### v2.3.0 2014-06-18 - don't generate subfolders (see [#130](https://github.com/Stuk/jszip/issues/130)). - add comment support (see [#134](https://github.com/Stuk/jszip/issues/134)). diff --git a/component.json b/component.json index 34e28c87..294984e6 100644 --- a/component.json +++ b/component.json @@ -13,4 +13,4 @@ "scripts": [ "dist/jszip.js" ] -} \ No newline at end of file +} diff --git a/documentation/api_jszip/file_data.md b/documentation/api_jszip/file_data.md index 3ae0b7ce..41f11a99 100644 --- a/documentation/api_jszip/file_data.md +++ b/documentation/api_jszip/file_data.md @@ -23,7 +23,8 @@ binary | boolean | `false` | set to `true` if the data should be treated as date | date | the current date | the last modification date. compression | string | null | If set, specifies compression method to use for this specific file. If not, the default file compression will be used, see [generate(options)]({{site.baseurl}}/documentation/api_jszip/generate.html). comment | string | null | The comment for this file. -optimizedBinaryString | boolean | `false` | Set it to true if (and only if) the input is a "binary string" and has already been prepared with a 0xFF mask. +optimizedBinaryString | boolean | `false` | Set to true if (and only if) the input is a "binary string" and has already been prepared with a 0xFF mask. +createSubFolders | boolean | `false` | Set to true if folders in the file path should be automatically created, otherwise there will only be virtual folders that represent the path to the file. You shouldn't update the data given to this method : it is kept as it so any update will impact the stored data. @@ -58,6 +59,12 @@ zip.file("animals.txt", "dog,platypus\n").file("people.txt", "james,sebastian\n" // result : Hello.txt, smile.gif, Xmas.txt, animals.txt, people.txt, // folder/, folder/file.txt +// In the above case, the "folder" folder will not have a 'D'irectory attribute or Method property. The +// folder only exists as part of the path to "file.txt". + +zip.file("folder/file.txt", "file in folder", {createSubFolders: true}); +// In this case, the "folder" folder WILL have a 'D'irectory attribute and a Method property of "store". +// It will exist whether or not "file.txt" is present. ``` diff --git a/documentation/api_jszip/load.md b/documentation/api_jszip/load.md index 82c95262..1721754f 100644 --- a/documentation/api_jszip/load.md +++ b/documentation/api_jszip/load.md @@ -22,6 +22,7 @@ name | type | default | description options.base64 | boolean | false | set to `true` if the data is base64 encoded, `false` for binary. options.checkCRC32 | boolean | false | set to `true` if the read data should be checked against its CRC32. options.optimizedBinaryString | boolean | false | set to true if (and only if) the input is a string and has already been prepared with a 0xFF mask. +options.createSubFolders | boolean | false | set to true to create folders in the file path automatically. Leaving it false will result in only virtual folders (i.e. folders that merely represent part of the file path) being created. You shouldn't update the data given to this method : it is kept as it so any update will impact the stored data. diff --git a/documentation/api_zipobject.md b/documentation/api_zipobject.md index 4c175f0a..0078be54 100644 --- a/documentation/api_zipobject.md +++ b/documentation/api_zipobject.md @@ -10,18 +10,18 @@ will be automatically decompressed/converted first. ### Attributes -attribute name | type | description ----------------------|-------------|------------- -`name` | string | the absolute path of the file -`dir` | boolean | true if this is a directory -`date` | date | the last modification date -`comment` | string | the comment for this file -`options` | object | the options of the file. The available options are : -`options.base64` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) -`options.binary` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) -`options.dir` | boolean | **Deprecated**, use `dir`. True if this is a directory -`options.date` | date | **Deprecated**, use `date`. See [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) -`options.compression`| compression | see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) +attribute name | type | description +----------------------------|-------------|------------- +`name` | string | the absolute path of the file +`dir` | boolean | true if this is a directory +`date` | date | the last modification date +`comment` | string | the comment for this file +`options` | object | the options of the file. The available options are : +`options.base64` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) +`options.binary` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) +`options.dir` | boolean | **Deprecated**, use `dir`. True if this is a directory +`options.date` | date | **Deprecated**, use `date`. See [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) +`options.compression` | compression | see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html) ### Getters diff --git a/lib/defaults.js b/lib/defaults.js index b979fdab..0ede494e 100644 --- a/lib/defaults.js +++ b/lib/defaults.js @@ -2,6 +2,7 @@ exports.base64 = false; exports.binary = false; exports.dir = false; +exports.createSubFolders = false; exports.date = null; exports.compression = null; exports.comment = null; diff --git a/lib/load.js b/lib/load.js index 655686e9..23d2cc51 100644 --- a/lib/load.js +++ b/lib/load.js @@ -17,7 +17,8 @@ module.exports = function(data, options) { optimizedBinaryString: true, date: input.date, dir: input.dir, - comment : input.fileComment.length ? input.fileComment : null + comment : input.fileComment.length ? input.fileComment : null, + createSubFolders: options.createSubFolders }); } if (zipEntries.zipComment.length) { diff --git a/lib/object.js b/lib/object.js index 7415f45a..c2e443ff 100644 --- a/lib/object.js +++ b/lib/object.js @@ -226,10 +226,15 @@ var prepareFileAttrs = function(o) { */ var fileAdd = function(name, data, o) { // be sure sub folders exist - var dataType = utils.getTypeOf(data); + var dataType = utils.getTypeOf(data), + parent; o = prepareFileAttrs(o); + if (o.createSubFolders && (parent = parentFolder(name))) { + folderAdd.call(this, parent, true); + } + if (o.dir || data === null || typeof data === "undefined") { o.base64 = false; o.binary = false; @@ -264,22 +269,41 @@ var fileAdd = function(name, data, o) { return object; }; +/** + * Find the parent folder of the path. + * @private + * @param {string} path the path to use + * @return {string} the parent folder, or "" + */ +var parentFolder = function (path) { + if (path.slice(-1) == '/') { + path = path.substring(0, path.length - 1); + } + var lastSlash = path.lastIndexOf('/'); + return (lastSlash > 0) ? path.substring(0, lastSlash) : ""; +}; + /** * Add a (sub) folder in the current folder. * @private * @param {string} name the folder's name + * @param {boolean=} [createSubFolders] If true, automatically create sub + * folders. Defaults to false. * @return {Object} the new folder. */ -var folderAdd = function(name) { +var folderAdd = function(name, createSubFolders) { // Check the name ends with a / if (name.slice(-1) != "/") { name += "/"; // IE doesn't like substr(-1) } + createSubFolders = (typeof createSubFolders !== 'undefined') ? createSubFolders : false; + // Does this folder already exist? if (!this.files[name]) { fileAdd.call(this, name, null, { - dir: true + dir: true, + createSubFolders: createSubFolders }); } return this.files[name]; diff --git a/test/test.js b/test/test.js index 63eeffed..82fe5048 100644 --- a/test/test.js +++ b/test/test.js @@ -1233,6 +1233,14 @@ if (QUnit.urlParams.complexfiles) { ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.ms-package.xps-fixeddocument+xml") !== -1, "the zip was correctly read."); }); + // Same test as above, but with createSubFolders option set to true + testZipFile("Outlook2007_Calendar.xps", "ref/complex_files/Outlook2007_Calendar.xps", function(file) { + var zip = new JSZip(file, {createSubFolders: true}); + // the zip file contains 15 entries, but we get 23 when creating all the sub-folders. + equal(zip.filter(function(){return true;}).length, 23, "the zip contains the good number of elements."); + ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.ms-package.xps-fixeddocument+xml") !== -1, "the zip was correctly read."); + }); + // an example file in http://cheeso.members.winisp.net/srcview.aspx?dir=js-unzip // the data come from http://www.antarctica.ac.uk/met/READER/upper_air/ testZipFile("AntarcticaTemps.xlsx", "ref/complex_files/AntarcticaTemps.xlsx", function(file) { @@ -1242,12 +1250,28 @@ if (QUnit.urlParams.complexfiles) { ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml") !== -1, "the zip was correctly read."); }); + // Same test as above, but with createSubFolders option set to true + testZipFile("AntarcticaTemps.xlsx", "ref/complex_files/AntarcticaTemps.xlsx", function(file) { + var zip = new JSZip(file, {createSubFolders: true}); + // the zip file contains 16 entries, but we get 27 when creating all the sub-folders. + equal(zip.filter(function(){return true;}).length, 27, "the zip contains the good number of elements."); + ok(zip.file("[Content_Types].xml").asText().indexOf("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml") !== -1, "the zip was correctly read."); + }); + + // same as two up, but in the Open Document format + testZipFile("AntarcticaTemps.ods", "ref/complex_files/AntarcticaTemps.ods", function (file) { + var zip = new JSZip(file); + // the zip file contains 20 entries. + equal(zip.filter(function () {return true;}).length, 20, "the zip contains the good number of elements."); + ok(zip.file("META-INF/manifest.xml").asText().indexOf("application/vnd.oasis.opendocument.spreadsheet") !== -1, "the zip was correctly read."); + }); + // same as above, but in the Open Document format - testZipFile("AntarcticaTemps.ods", "ref/complex_files/AntarcticaTemps.ods", function(file) { - var zip = new JSZip(file); - // the zip file contains 20 entries. - equal(zip.filter(function(){return true;}).length, 20, "the zip contains the good number of elements."); - ok(zip.file("META-INF/manifest.xml").asText().indexOf("application/vnd.oasis.opendocument.spreadsheet") !== -1, "the zip was correctly read."); + testZipFile("AntarcticaTemps.ods", "ref/complex_files/AntarcticaTemps.ods", function (file) { + var zip = new JSZip(file, {createSubFolders: true}); + // the zip file contains 19 entries, but we get 27 when creating all the sub-folders. + equal(zip.filter(function () {return true;}).length, 27, "the zip contains the good number of elements."); + ok(zip.file("META-INF/manifest.xml").asText().indexOf("application/vnd.oasis.opendocument.spreadsheet") !== -1, "the zip was correctly read."); }); } // }}} Load complex files