diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js index 4f129c17..1c02c2ae 100644 --- a/src/serialization/sb3.js +++ b/src/serialization/sb3.js @@ -446,15 +446,25 @@ const serializeTarget = function (target) { /** * Serializes the specified VM runtime. - * @param {!Runtime} runtime VM runtime instance to be serialized. + * @param {!Runtime} runtime VM runtime instance to be serialized. + * @param {string=} targetId Optional target id if serializing only a single target * @return {object} Serialized runtime instance. */ -const serialize = function (runtime) { +const serialize = function (runtime, targetId) { // Fetch targets const obj = Object.create(null); - const flattenedOriginalTargets = JSON.parse(JSON.stringify( + const flattenedOriginalTargets = JSON.parse(JSON.stringify(targetId ? + [runtime.getTargetById(targetId)] : runtime.targets.filter(target => target.isOriginal))); - obj.targets = flattenedOriginalTargets.map(t => serializeTarget(t, runtime)); + + const serializedTargets = flattenedOriginalTargets.map(t => serializeTarget(t, runtime)); + + if (targetId) { + return serializedTargets[0]; + } + + obj.targets = serializedTargets; + // TODO Serialize monitors diff --git a/src/serialization/serialize-assets.js b/src/serialization/serialize-assets.js index 9dc7bf0d..ac444f11 100644 --- a/src/serialization/serialize-assets.js +++ b/src/serialization/serialize-assets.js @@ -5,10 +5,11 @@ * to be written and the contents of the file, the serialized asset. * @param {Runtime} runtime The runtime with the assets to be serialized * @param {string} assetType The type of assets to be serialized: 'sounds' | 'costumes' + * @param {string=} optTargetId Optional target id to serialize assets for * @returns {Array} An array of file descriptors for each asset */ -const serializeAssets = function (runtime, assetType) { - const targets = runtime.targets; +const serializeAssets = function (runtime, assetType, optTargetId) { + const targets = optTargetId ? [runtime.getTargetById(optTargetId)] : runtime.targets; const assetDescs = []; for (let i = 0; i < targets.length; i++) { const currTarget = targets[i]; @@ -27,14 +28,16 @@ const serializeAssets = function (runtime, assetType) { }; /** - * Serialize all the sounds in the provided runtime into an array of file - * descriptors. A file descriptor is an object containing the name of the file + * Serialize all the sounds in the provided runtime or, if a target id is provided, + * in the specified target into an array of file descriptors. + * A file descriptor is an object containing the name of the file * to be written and the contents of the file, the serialized sound. * @param {Runtime} runtime The runtime with the sounds to be serialized + * @param {string=} optTargetId Optional targetid for serializing sounds of a single target * @returns {Array} An array of file descriptors for each sound */ -const serializeSounds = function (runtime) { - return serializeAssets(runtime, 'sounds'); +const serializeSounds = function (runtime, optTargetId) { + return serializeAssets(runtime, 'sounds', optTargetId); }; /** @@ -42,10 +45,11 @@ const serializeSounds = function (runtime) { * descriptors. A file descriptor is an object containing the name of the file * to be written and the contents of the file, the serialized costume. * @param {Runtime} runtime The runtime with the costumes to be serialized + * @param {string} optTargetId Optional targetid for serializing costumes of a single target * @returns {Array} An array of file descriptors for each costume */ -const serializeCostumes = function (runtime) { - return serializeAssets(runtime, 'costumes'); +const serializeCostumes = function (runtime, optTargetId) { + return serializeAssets(runtime, 'costumes', optTargetId); }; module.exports = { diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 4ff368fa..378f9021 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -263,14 +263,7 @@ class VirtualMachine extends EventEmitter { // Put everything in a zip file zip.file('project.json', projectJson); - for (let i = 0; i < soundDescs.length; i++) { - const currSound = soundDescs[i]; - zip.file(currSound.fileName, currSound.fileContent); - } - for (let i = 0; i < costumeDescs.length; i++) { - const currCostume = costumeDescs[i]; - zip.file(currCostume.fileName, currCostume.fileContent); - } + this._addFileDescsToZip(soundDescs.concat(costumeDescs), zip); return zip.generateAsync({ type: 'blob', @@ -281,6 +274,31 @@ class VirtualMachine extends EventEmitter { }); } + _addFileDescsToZip (fileDescs, zip) { + for (let i = 0; i < fileDescs.length; i++) { + const currFileDesc = fileDescs[i]; + zip.file(currFileDesc.fileName, currFileDesc.fileContent); + } + } + + exportSprite (targetId) { + const soundDescs = serializeSounds(this.runtime, targetId); + const costumeDescs = serializeCostumes(this.runtime, targetId); + const spriteJson = JSON.stringify(sb3.serialize(this.runtime, targetId)); + + const zip = new JSZip(); + zip.file('sprite.json', spriteJson); + this._addFileDescsToZip(soundDescs.concat(costumeDescs), zip); + + return zip.generateAsync({ + type: 'blob', + compression: 'DEFLATE', + compressionOptions: { + level: 6 + } + }); + } + /** * Export project as a Scratch 3.0 JSON representation. * @return {string} Serialized state of the runtime.