Merge pull request #983 from cycomachead/blob-api

Use Blob API to Save Files (to Disk)
dev
Jens Mönig 2015-12-15 12:56:52 +01:00
commit 99784ca436
7 zmienionych plików z 270 dodań i 194 usunięć

2
FileSaver.min.js vendored 100644
Wyświetl plik

@ -0,0 +1,2 @@
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
var saveAs=saveAs||function(e){"use strict";if(typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=t.createElementNS("http://www.w3.org/1999/xhtml","a"),i="download"in r,o=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},a=/Version\/[\d\.]+.*Safari/.test(navigator.userAgent),f=e.webkitRequestFileSystem,u=e.requestFileSystem||f||e.mozRequestFileSystem,s=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},c="application/octet-stream",d=0,l=500,w=function(t){var r=function(){if(typeof t==="string"){n().revokeObjectURL(t)}else{t.remove()}};if(e.chrome){r()}else{setTimeout(r,l)}},p=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var i=e["on"+t[r]];if(typeof i==="function"){try{i.call(e,n||e)}catch(o){s(o)}}}},v=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob(["\ufeff",e],{type:e.type})}return e},y=function(t,s,l){if(!l){t=v(t)}var y=this,m=t.type,S=false,h,R,O=function(){p(y,"writestart progress write writeend".split(" "))},g=function(){if(R&&a&&typeof FileReader!=="undefined"){var r=new FileReader;r.onloadend=function(){var e=r.result;R.location.href="data:attachment/file"+e.slice(e.search(/[,;]/));y.readyState=y.DONE;O()};r.readAsDataURL(t);y.readyState=y.INIT;return}if(S||!h){h=n().createObjectURL(t)}if(R){R.location.href=h}else{var i=e.open(h,"_blank");if(i==undefined&&a){e.location.href=h}}y.readyState=y.DONE;O();w(h)},b=function(e){return function(){if(y.readyState!==y.DONE){return e.apply(this,arguments)}}},E={create:true,exclusive:false},N;y.readyState=y.INIT;if(!s){s="download"}if(i){h=n().createObjectURL(t);r.href=h;r.download=s;setTimeout(function(){o(r);O();w(h);y.readyState=y.DONE});return}if(e.chrome&&m&&m!==c){N=t.slice||t.webkitSlice;t=N.call(t,0,t.size,c);S=true}if(f&&s!=="download"){s+=".download"}if(m===c||f){R=e}if(!u){g();return}d+=t.size;u(e.TEMPORARY,d,b(function(e){e.root.getDirectory("saved",E,b(function(e){var n=function(){e.getFile(s,E,b(function(e){e.createWriter(b(function(n){n.onwriteend=function(t){R.location.href=e.toURL();y.readyState=y.DONE;p(y,"writeend",t);w(e)};n.onerror=function(){var e=n.error;if(e.code!==e.ABORT_ERR){g()}};"writestart progress write abort".split(" ").forEach(function(e){n["on"+e]=y["on"+e]});n.write(t);y.abort=function(){n.abort();y.readyState=y.DONE};y.readyState=y.WRITING}),g)}),g)};e.getFile(s,{create:false},b(function(e){e.remove();n()}),b(function(e){if(e.code===e.NOT_FOUND_ERR){n()}else{g()}}))}),g)}),g)},m=y.prototype,S=function(e,t,n){return new y(e,t,n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){if(!n){e=v(e)}return navigator.msSaveOrOpenBlob(e,t||"download")}}m.abort=function(){var e=this;e.readyState=e.DONE;p(e,"abort")};m.readyState=m.INIT=0;m.WRITING=1;m.DONE=2;m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null;return S}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!=null){define([],function(){return saveAs})}

Wyświetl plik

@ -1855,7 +1855,8 @@ SyntaxElementMorph.prototype.showBubble = function (value, exportPic) {
}; };
SyntaxElementMorph.prototype.exportPictureWithResult = function (aBubble) { SyntaxElementMorph.prototype.exportPictureWithResult = function (aBubble) {
var scr = this.fullImage(), var ide = this.parentThatIsA(IDE_Morph),
scr = this.fullImage(),
bub = aBubble.fullImageClassic(), bub = aBubble.fullImageClassic(),
taller = Math.max(0, bub.height - scr.height), taller = Math.max(0, bub.height - scr.height),
pic = newCanvas(new Point( pic = newCanvas(new Point(
@ -1865,7 +1866,12 @@ SyntaxElementMorph.prototype.exportPictureWithResult = function (aBubble) {
ctx = pic.getContext('2d'); ctx = pic.getContext('2d');
ctx.drawImage(scr, 0, pic.height - scr.height); ctx.drawImage(scr, 0, pic.height - scr.height);
ctx.drawImage(bub, scr.width + 2, 0); ctx.drawImage(bub, scr.width + 2, 0);
window.open(pic.toDataURL()); // request to open pic in new window.
ide.saveCanvasAs(
pic,
ide.projetName || localize('Untitled') + ' ' + localize('script pic'),
true
);
}; };
// SyntaxElementMorph code mapping // SyntaxElementMorph code mapping
@ -2332,7 +2338,13 @@ BlockMorph.prototype.userMenu = function () {
menu.addItem( menu.addItem(
"script pic...", "script pic...",
function () { function () {
window.open(myself.topBlock().scriptPic().toDataURL()); var ide = myself.parentThatIsA(IDE_Morph);
ide.saveCanvasAs(
myself.topBlock().scriptPic(),
ide.projetName || localize('Untitled') + ' ' +
localize('script pic'),
true // request new window
);
}, },
'open a new window\nwith a picture of this script' 'open a new window\nwith a picture of this script'
); );
@ -5489,9 +5501,15 @@ ScriptsMorph.prototype.cleanUp = function () {
}; };
ScriptsMorph.prototype.exportScriptsPicture = function () { ScriptsMorph.prototype.exportScriptsPicture = function () {
var pic = this.scriptsPicture(); var pic = this.scriptsPicture(),
ide = this.world().children[0];
if (pic) { if (pic) {
window.open(pic.toDataURL()); ide.saveCanvasAs(
pic,
ide.projetName || localize('Untitled') + ' ' +
localize('script pic'),
true // request new window
);
} }
}; };
@ -11166,7 +11184,13 @@ CommentMorph.prototype.userMenu = function () {
menu.addItem( menu.addItem(
"comment pic...", "comment pic...",
function () { function () {
window.open(myself.fullImageClassic().toDataURL()); var ide = myself.parentThatIsA(IDE_Morph);
ide.saveCanvasAs(
myself.fullImageClassic(),
ide.projetName || localize('Untitled') + ' ' +
localize('comment pic'),
true // request new window
);
}, },
'open a new window\nwith a picture of this comment' 'open a new window\nwith a picture of this comment'
); );

28
byob.js
Wyświetl plik

@ -821,7 +821,13 @@ CustomCommandBlockMorph.prototype.userMenu = function () {
menu.addItem( menu.addItem(
"script pic...", "script pic...",
function () { function () {
window.open(this.topBlock().scriptPic().toDataURL()); var ide = this.world().children[0];
ide.saveCanvasAs(
this.topBlock().scriptPic(),
ide.projectName || localize('Untitled') + ' ' +
localize('script pic'),
true // request opening a new window
);
}, },
'open a new window\nwith a picture of this script' 'open a new window\nwith a picture of this script'
); );
@ -862,8 +868,10 @@ CustomCommandBlockMorph.prototype.userMenu = function () {
}; };
CustomCommandBlockMorph.prototype.exportBlockDefinition = function () { CustomCommandBlockMorph.prototype.exportBlockDefinition = function () {
var xml = new SnapSerializer().serialize(this.definition); var xml = new SnapSerializer().serialize(this.definition),
window.open('data:text/xml,' + encodeURIComponent(xml)); ide = this.parentThatIsA(IDE_Morph);
ide.saveXMLAs(xml, this.spec);
}; };
CustomCommandBlockMorph.prototype.deleteBlockDefinition = function () { CustomCommandBlockMorph.prototype.deleteBlockDefinition = function () {
@ -3497,17 +3505,21 @@ BlockExportDialogMorph.prototype.selectNone = function () {
// BlockExportDialogMorph ops // BlockExportDialogMorph ops
BlockExportDialogMorph.prototype.exportBlocks = function () { BlockExportDialogMorph.prototype.exportBlocks = function () {
var str = encodeURIComponent( var str = this.serializer.serialize(this.blocks),
this.serializer.serialize(this.blocks) ide = this.world().children[0];
);
if (this.blocks.length > 0) { if (this.blocks.length > 0) {
window.open('data:text/xml,<blocks app="' str = '<blocks app="'
+ this.serializer.app + this.serializer.app
+ '" version="' + '" version="'
+ this.serializer.version + this.serializer.version
+ '">' + '">'
+ str + str
+ '</blocks>'); + '</blocks>';
ide.saveXMLAs(
str,
ide.projectName || localize('Untitled') + ' ' + localize('blocks')
);
} else { } else {
new DialogBoxMorph().inform( new DialogBoxMorph().inform(
'Export blocks', 'Export blocks',

371
gui.js
Wyświetl plik

@ -67,7 +67,7 @@ BlockImportDialogMorph, SnapTranslator, localize, List, InputSlotMorph,
SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512, SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512,
sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio, sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio,
SpeechBubbleMorph, ScriptFocusMorph, XML_Element, WatcherMorph, SpeechBubbleMorph, ScriptFocusMorph, XML_Element, WatcherMorph,
BlockRemovalDialogMorph*/ BlockRemovalDialogMorph, saveAs*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
@ -85,7 +85,6 @@ var SoundIconMorph;
var JukeboxMorph; var JukeboxMorph;
var StageHandleMorph; var StageHandleMorph;
// IDE_Morph /////////////////////////////////////////////////////////// // IDE_Morph ///////////////////////////////////////////////////////////
// I am SNAP's top-level frame, the Editor window // I am SNAP's top-level frame, the Editor window
@ -2519,15 +2518,6 @@ IDE_Morph.prototype.projectMenu = function () {
menu.addItem('New', 'createNewProject'); menu.addItem('New', 'createNewProject');
menu.addItem('Open...', 'openProjectsBrowser'); menu.addItem('Open...', 'openProjectsBrowser');
menu.addItem('Save', "save"); menu.addItem('Save', "save");
if (shiftClicked) {
menu.addItem(
'Save to disk',
'saveProjectToDisk',
'store this project\nin the downloads folder\n'
+ '(in supporting browsers)',
new Color(100, 0, 0)
);
}
menu.addItem('Save As...', 'saveProjectsBrowser'); menu.addItem('Save As...', 'saveProjectsBrowser');
menu.addLine(); menu.addLine();
menu.addItem( menu.addItem(
@ -2564,6 +2554,24 @@ IDE_Morph.prototype.projectMenu = function () {
'file menu import hint' // looks up the actual text in the translator 'file menu import hint' // looks up the actual text in the translator
); );
if (shiftClicked) {
menu.addItem(
localize('Export project...') + ' ' + localize('(in a new window)'),
function () {
if (myself.projectName) {
myself.exportProject(myself.projectName, shiftClicked);
} else {
myself.prompt('Export Project As...', function (name) {
// false - override the shiftClick setting to use XML
// true - open XML in a new tab
myself.exportProject(name, false, true);
}, null, 'exportProject');
}
},
'show project data as XML\nin a new browser window',
new Color(100, 0, 0)
);
}
menu.addItem( menu.addItem(
shiftClicked ? shiftClicked ?
'Export project as plain text...' : 'Export project...', 'Export project as plain text...' : 'Export project...',
@ -2572,11 +2580,11 @@ IDE_Morph.prototype.projectMenu = function () {
myself.exportProject(myself.projectName, shiftClicked); myself.exportProject(myself.projectName, shiftClicked);
} else { } else {
myself.prompt('Export Project As...', function (name) { myself.prompt('Export Project As...', function (name) {
myself.exportProject(name); myself.exportProject(name, shiftClicked);
}, null, 'exportProject'); }, null, 'exportProject');
} }
}, },
'show project data as XML\nin a new browser window', 'save project data as XML\nto your downloads folder',
shiftClicked ? new Color(100, 0, 0) : null shiftClicked ? new Color(100, 0, 0) : null
); );
@ -2606,7 +2614,7 @@ IDE_Morph.prototype.projectMenu = function () {
'Export summary with drop-shadows...', 'Export summary with drop-shadows...',
function () {myself.exportProjectSummary(true); }, function () {myself.exportProjectSummary(true); },
'open a new browser browser window' + 'open a new browser browser window' +
'\n with a summary of this project' + '\nwith a summary of this project' +
'\nwith drop-shadows on all pictures.' + '\nwith drop-shadows on all pictures.' +
'\nnot supported by all browsers', '\nnot supported by all browsers',
new Color(100, 0, 0) new Color(100, 0, 0)
@ -2984,7 +2992,6 @@ IDE_Morph.prototype.save = function () {
} }
}; };
IDE_Morph.prototype.saveProject = function (name) { IDE_Morph.prototype.saveProject = function (name) {
var myself = this; var myself = this;
this.nextSteps([ this.nextSteps([
@ -2997,6 +3004,7 @@ IDE_Morph.prototype.saveProject = function (name) {
]); ]);
}; };
// Serialize a project and save to the browser.
IDE_Morph.prototype.rawSaveProject = function (name) { IDE_Morph.prototype.rawSaveProject = function (name) {
var str; var str;
if (name) { if (name) {
@ -3019,104 +3027,28 @@ IDE_Morph.prototype.rawSaveProject = function (name) {
} }
}; };
IDE_Morph.prototype.saveProjectToDisk = function () {
var data,
link = document.createElement('a');
if (Process.prototype.isCatchingErrors) { IDE_Morph.prototype.exportProject = function (name, plain, newWindow) {
try { // Export project XML, saving a file to disk
data = this.serializer.serialize(this.stage); // newWindow requests displaying the project in a new tab.
link.setAttribute('href', 'data:text/xml,' + data); var menu, str, dataPrefix;
link.setAttribute('download', this.projectName + '.xml');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (err) {
this.showMessage('Saving failed: ' + err);
}
} else {
data = this.serializer.serialize(this.stage);
link.setAttribute('href', 'data:text/xml,' + data);
link.setAttribute('download', this.projectName + '.xml');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
};
/* alternative download mechanism, commented out in favor of blob-uris
IDE_Morph.prototype.saveProjectToDisk = function () {
var data;
if (Process.prototype.isCatchingErrors) {
try {
data = this.serializer.serialize(this.stage);
} catch (err) {
this.showMessage('Serialization failed: ' + err);
}
} else {
data = this.serializer.serialize(this.stage);
}
this.download(data, this.projectName);
};
IDE_Morph.prototype.download = function (data, fileName, mime, suffix) {
var link = document.createElement('a'),
myself = this;
mime = mime || 'data:text/xml';
fileName = fileName || 'download';
suffix = suffix || 'xml';
function saveToDisk() {
var msg = myself.showMessage('Downloading to disk...');
link.setAttribute('href', mime + ',' + data);
link.setAttribute('download', fileName + '.' + suffix);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
msg.destroy();
}
if (Process.prototype.isCatchingErrors) {
try {
saveToDisk();
} catch (err) {
this.showMessage('Saving failed: ' + err);
}
} else {
saveToDisk();
}
};
*/
IDE_Morph.prototype.exportProject = function (name, plain) {
var menu, str;
if (name) { if (name) {
this.setProjectName(name); this.setProjectName(name);
if (Process.prototype.isCatchingErrors) { dataPrefix = 'data:text/' + plain ? 'plain,' : 'xml,';
try { try {
menu = this.showMessage('Exporting');
str = encodeURIComponent(
this.serializer.serialize(this.stage)
);
this.setURL('#open:' + str);
window.open('data:text/'
+ (plain ? 'plain,' + str : 'xml,' + str));
menu.destroy();
this.showMessage('Exported!', 1);
} catch (err) {
this.showMessage('Export failed: ' + err);
}
} else {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = encodeURIComponent( str = this.serializer.serialize(this.stage)
this.serializer.serialize(this.stage) this.setURL('#open:' + dataPrefix + encodeURIComponent(str));
); this.saveXMLAs(str, name, newWindow);
this.setURL('#open:' + str);
window.open('data:text/'
+ (plain ? 'plain,' + str : 'xml,' + str));
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} catch (err) {
if (Process.prototype.isCatchingErrors) {
this.showMessage('Export failed: ' + err);
} else {
throw err;
}
} }
} }
}; };
@ -3175,16 +3107,15 @@ IDE_Morph.prototype.removeUnusedBlocks = function () {
}; };
IDE_Morph.prototype.exportSprite = function (sprite) { IDE_Morph.prototype.exportSprite = function (sprite) {
var str = encodeURIComponent( var str = this.serializer.serialize(sprite.allParts());
this.serializer.serialize(sprite.allParts()) str = '<sprites app="'
);
window.open('data:text/xml,<sprites app="'
+ this.serializer.app + this.serializer.app
+ '" version="' + '" version="'
+ this.serializer.version + this.serializer.version
+ '">' + '">'
+ str + str
+ '</sprites>'); + '</sprites>';
this.saveXMLAs(str, sprite.name);
}; };
IDE_Morph.prototype.exportScriptsPicture = function () { IDE_Morph.prototype.exportScriptsPicture = function () {
@ -3233,8 +3164,7 @@ IDE_Morph.prototype.exportScriptsPicture = function () {
y += padding; y += padding;
y += each.height; y += each.height;
}); });
this.saveCanvasAs(pic, this.projectName || localize('Untitled'), true);
window.open(pic.toDataURL());
}; };
IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) { IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) {
@ -3511,9 +3441,12 @@ IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) {
addBlocks(stage.globalBlocks); addBlocks(stage.globalBlocks);
} }
window.open('data:text/html;charset=utf-8,' + encodeURIComponent( this.saveFileAs(
'<!DOCTYPE html>' + html.toString() '<!DOCTYPE html>' + html.toString(),
)); 'text/html;charset=utf-8,',
pname,
true // request opening a new window.
);
}; };
IDE_Morph.prototype.openProjectString = function (str) { IDE_Morph.prototype.openProjectString = function (str) {
@ -3713,11 +3646,126 @@ IDE_Morph.prototype.openProject = function (name) {
}; };
IDE_Morph.prototype.setURL = function (str) { IDE_Morph.prototype.setURL = function (str) {
// Set the URL to a project's XML contents
if (this.projectsInURLs) { if (this.projectsInURLs) {
location.hash = str; location.hash = str;
} }
}; };
IDE_Morph.prototype.saveFileAs = function (
contents,
fileType,
fileName,
newWindow // (optional) defaults to false.
) {
/** Allow for downloading a file to a disk or open in a new tab.
This relies the FileSaver.js library which exports saveAs()
Two utility methods saveImageAs and saveXMLAs should be used first.
1. Opening a new window uses standard URI encoding.
2. downloading a file uses Blobs.
- every other combo is unsupposed.
*/
var blobIsSupported = false,
world = this.world(),
fileExt,
dataURI, dialog;
// fileType is a <kind>/<ext>;<charset> format.
fileExt = fileType.split('/')[1].split(';')[0];
// handle text/plain as a .txt file
fileExt = '.' + (fileExt === 'plain' ? 'txt' : fileExt);
// This is a workaround for a known Chrome crash with large URLs
function exhibitsChomeBug(contents) {
var MAX_LENGTH = 2e6,
isChrome = navigator.userAgent.indexOf('Chrome') !== -1;
return isChrome && contents.length > MAX_LENGTH;
}
function dataURItoBlob(text, mimeType) {
var i,
data = text,
components = text.split(','),
hasTypeStr = text.indexOf('data:') === 0;
// Convert to binary data, in format Blob() can use.
if (hasTypeStr && components[0].indexOf('base64') > -1) {
text = atob(components[1]);
data = new Uint8Array(text.length),
i = text.length;
while (i--) {
data[i] = text.charCodeAt(i);
}
}
return new Blob([data], {type: mimeType });
}
function dataURLFormat(text) {
var hasTypeStr = text.indexOf('data:') === 0;
if (hasTypeStr) {return text; }
return 'data:' + fileType + ',' + encodeURIComponent(text);
}
try {
blobIsSupported = !!new Blob;
} catch (e) {}
if (newWindow) {
// Blob URIs need a custom URL to be displayed in a new window
if (contents instanceof Blob) {
dataURI = URL.createObjectURL(contents);
} else {
dataURI = dataURLFormat(contents);
}
// Detect crashing errors - fallback to downloading if necessary
if (!exhibitsChomeBug(dataURI)) {
window.open(dataURI, fileName);
// Blob URIs should be "cleaned up" to reduce memory.
if (contents instanceof Blob) {
URL.revokeObjectURL(dataURI);
}
} else {
// (recursively) call this defauling newWindow to false
this.showMessage('download to disk text');
this.saveFileAs(contents, fileType, fileName);
}
} else if (blobIsSupported) {
if (!(contents instanceof Blob)) {
contents = dataURItoBlob(contents, fileType);
}
// download a file and delegate to FileSaver
// false: Do not preprend a BOM to the file.
saveAs(contents, fileName + fileExt, false);
} else {
dialog = new DialogBoxMorph();
dialog.inform(
localize('Could not export') + ' ' + fileName,
'unable to export text',
world
);
dialog.fixLayout();
dialog.drawNew();
}
}
IDE_Morph.prototype.saveCanvasAs = function (canvas, fileName, newWindow) {
// Export a Canvas object as a PNG image
// cavas.toBlob() is currently only supported in Firefox and IE
var myself = this;
if (canvas.toBlob) {
canvas.toBlob(function (blob) {
myself.saveFileAs(blob, 'image/png', fileName, newWindow);
});
} else {
this.saveFileAs(canvas.toDataURL(), 'image/png', fileName, newWindow);
}
}
IDE_Morph.prototype.saveXMLAs = function(xml, fileName, newWindow) {
// wrapper to saving XML files with a proper type tag.
this.saveFileAs(xml, 'text/xml;chartset=utf-8', fileName, newWindow);
}
IDE_Morph.prototype.switchToUserMode = function () { IDE_Morph.prototype.switchToUserMode = function () {
var world = this.world(); var world = this.world();
@ -4487,33 +4535,19 @@ IDE_Morph.prototype.exportProjectMedia = function (name) {
this.serializer.isCollectingMedia = true; this.serializer.isCollectingMedia = true;
if (name) { if (name) {
this.setProjectName(name); this.setProjectName(name);
if (Process.prototype.isCatchingErrors) { try {
try {
menu = this.showMessage('Exporting');
encodeURIComponent(
this.serializer.serialize(this.stage)
);
media = encodeURIComponent(
this.serializer.mediaXML(name)
);
window.open('data:text/xml,' + media);
menu.destroy();
this.showMessage('Exported!', 1);
} catch (err) {
this.serializer.isCollectingMedia = false;
this.showMessage('Export failed: ' + err);
}
} else {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
encodeURIComponent( media = this.serializer.mediaXML(name);
this.serializer.serialize(this.stage) this.saveXMLAs(media, this.projectName + ' media');
);
media = encodeURIComponent(
this.serializer.mediaXML()
);
window.open('data:text/xml,' + media);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} catch (err) {
if (Process.prototype.isCatchingErrors) {
this.serializer.isCollectingMedia = false;
this.showMessage('Export failed: ' + err);
} else {
throw err;
}
} }
} }
this.serializer.isCollectingMedia = false; this.serializer.isCollectingMedia = false;
@ -4529,10 +4563,8 @@ IDE_Morph.prototype.exportProjectNoMedia = function (name) {
if (Process.prototype.isCatchingErrors) { if (Process.prototype.isCatchingErrors) {
try { try {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = encodeURIComponent( str = this.serializer.serialize(this.stage);
this.serializer.serialize(this.stage) this.saveXMLAs(str, this.projectName);
);
window.open('data:text/xml,' + str);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} catch (err) { } catch (err) {
@ -4541,10 +4573,8 @@ IDE_Morph.prototype.exportProjectNoMedia = function (name) {
} }
} else { } else {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = encodeURIComponent( str = this.serializer.serialize(this.stage);
this.serializer.serialize(this.stage) this.saveXMLAs(str, this.projectName);
);
window.open('data:text/xml,' + str);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} }
@ -4561,17 +4591,10 @@ IDE_Morph.prototype.exportProjectAsCloudData = function (name) {
if (Process.prototype.isCatchingErrors) { if (Process.prototype.isCatchingErrors) {
try { try {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = encodeURIComponent( str = this.serializer.serialize(this.stage);
this.serializer.serialize(this.stage) media = this.serializer.mediaXML(name);
); dta = '<snapdata>' + str + media + '</snapdata>';
media = encodeURIComponent( this.saveXMLAs(str, this.projectName);
this.serializer.mediaXML(name)
);
dta = encodeURIComponent('<snapdata>')
+ str
+ media
+ encodeURIComponent('</snapdata>');
window.open('data:text/xml,' + dta);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} catch (err) { } catch (err) {
@ -4580,17 +4603,10 @@ IDE_Morph.prototype.exportProjectAsCloudData = function (name) {
} }
} else { } else {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = encodeURIComponent( str = this.serializer.serialize(this.stage);
this.serializer.serialize(this.stage) media = this.serializer.mediaXML(name);
); dta = '<snapdata>' + str + media + '</snapdata>';
media = encodeURIComponent( this.saveXMLAs(str, this.projectName);
this.serializer.mediaXML()
);
dta = encodeURIComponent('<snapdata>')
+ str
+ media
+ encodeURIComponent('</snapdata>');
window.open('data:text/xml,' + dta);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} }
@ -5908,7 +5924,12 @@ SpriteIconMorph.prototype.userMenu = function () {
menu.addItem( menu.addItem(
'pic...', 'pic...',
function () { function () {
window.open(myself.object.fullImageClassic().toDataURL()); var ide = myself.parentThatIsA(IDE_Morph);
ide.saveCanvasAs(
myself.object.fullImageClassic(),
this.object.name,
true
);
}, },
'open a new window\nwith a picture of the stage' 'open a new window\nwith a picture of the stage'
); );
@ -6269,10 +6290,12 @@ CostumeIconMorph.prototype.removeCostume = function () {
}; };
CostumeIconMorph.prototype.exportCostume = function () { CostumeIconMorph.prototype.exportCostume = function () {
var ide = this.parentThatIsA(IDE_Morph);
if (this.object instanceof SVG_Costume) { if (this.object instanceof SVG_Costume) {
window.open(this.object.contents.src); // don't show SVG costumes in a new tab (shows text)
} else { // rastered Costume ide.saveFileAs(this.object.contents.src, 'text/svg', this.object.name);
window.open(this.object.contents.toDataURL()); } else { // rasterized Costume
ide.saveCanvasAs(this.object.object.contents, this.object.name, true);
} }
}; };

Wyświetl plik

@ -141,7 +141,15 @@ SnapTranslator.dict.en = {
+ 'a file on your computer by dropping it here\n', + 'a file on your computer by dropping it here\n',
'block deletion dialog text': 'block deletion dialog text':
'Are you sure you want to delete this\n' 'Are you sure you want to delete this\n'
+ 'custom block and all its instances?' + 'custom block and all its instances?',
'download to disk text':
'This item could not be opened in a new tab.\n' +
'It has been saved to your browser\'s downloads folder.',
'unable to export text':
'This item could not be exported from Snap!.\n' +
'It\'s likely that your project may contain a lot of media ' +
'(sounds and images) or that you are using an older browser.' +
'Please try using a recent version of Chrome, Firefox, or Safari.'
}; };
SnapTranslator.dict.de = { SnapTranslator.dict.de = {

Wyświetl plik

@ -589,7 +589,7 @@ SpriteMorph.prototype.initBlocks = function () {
}, },
/* migrated to a newer block version: /* migrated to a newer block version:
receiveClick: { receiveClick: {
type: 'hat', type: 'hat',
category: 'control', category: 'control',
@ -5839,7 +5839,11 @@ StageMorph.prototype.userMenu = function () {
menu.addItem( menu.addItem(
"pic...", "pic...",
function () { function () {
window.open(myself.fullImageClassic().toDataURL()); ide.saveCanvasAs(
myself.fullImageClassic(),
myself.name,
true // open as new window
);
}, },
'open a new window\nwith a picture of the stage' 'open a new window\nwith a picture of the stage'
); );
@ -7729,9 +7733,11 @@ WatcherMorph.prototype.userMenu = function () {
menu.addItem( menu.addItem(
'export...', 'export...',
function () { function () {
window.open( var ide = myself.parentThatIsA(IDE_Morph);
'data:text/plain;charset=utf-8,' + ide.saveFileAs(
encodeURIComponent(this.currentValue.toString()) myself.currentValue.toString(),
'text/plain;charset=utf-8',
myself.getter // variable name
); );
} }
); );

Wyświetl plik

@ -18,6 +18,7 @@
<script type="text/javascript" src="locale.js"></script> <script type="text/javascript" src="locale.js"></script>
<script type="text/javascript" src="cloud.js"></script> <script type="text/javascript" src="cloud.js"></script>
<script type="text/javascript" src="sha512.js"></script> <script type="text/javascript" src="sha512.js"></script>
<script type="text/javascript" src="FileSaver.min.js"></script>
<script type="text/javascript"> <script type="text/javascript">
var world; var world;
window.onload = function () { window.onload = function () {