kopia lustrzana https://github.com/backface/turtlestitch
Improve saveAs refactoring (WIP across all Snap!)
- added TODO comments to all functions that need updating (byob, blocks) - separate out the code into 3 new functions for readability: - `saveFileAs` is a generic method - `saveCanvasAs` and `saveXMLAs` are wrappers which aid in exporting images and all XML files which together cover almost all export cases. - In other cases, you can call `saveFileAs` directly with some additional input. - `saveCanvasAs` in particular uses a new `Canvas.toBlob()` option when it is available (FF and IE currently) that should greatly reduce memory. (Chrome and Safari both have open bugs and may at somepoint implement this function.) - I have added in code to detect bugs in chrome, including when a new window is being opened. If a new window cannot be opened, the a (to be written) warning message will appear. - a few functions (namely those in morphic.js) have not touched. However, these are functions which should only occur in a small subset of cases and are behind hidden features.dev
rodzic
35c1826be3
commit
e47dcb0ebf
|
@ -1853,6 +1853,7 @@ SyntaxElementMorph.prototype.exportPictureWithResult = function (aBubble) {
|
|||
ctx = pic.getContext('2d');
|
||||
ctx.drawImage(scr, 0, pic.height - scr.height);
|
||||
ctx.drawImage(bub, scr.width + 2, 0);
|
||||
// TODO: modify this call!
|
||||
window.open(pic.toDataURL());
|
||||
};
|
||||
|
||||
|
@ -2312,6 +2313,7 @@ BlockMorph.prototype.userMenu = function () {
|
|||
);
|
||||
menu.addItem(
|
||||
"script pic...",
|
||||
// TODO: modify this function to use saveAs
|
||||
function () {
|
||||
window.open(myself.topBlock().scriptPic().toDataURL());
|
||||
},
|
||||
|
@ -5376,6 +5378,7 @@ ScriptsMorph.prototype.cleanUp = function () {
|
|||
ScriptsMorph.prototype.exportScriptsPicture = function () {
|
||||
var pic = this.scriptsPicture();
|
||||
if (pic) {
|
||||
// TODO: modify this to use a saveAs
|
||||
window.open(pic.toDataURL());
|
||||
}
|
||||
};
|
||||
|
@ -11039,6 +11042,7 @@ CommentMorph.prototype.userMenu = function () {
|
|||
menu.addItem("delete", 'destroy');
|
||||
menu.addItem(
|
||||
"comment pic...",
|
||||
// TODO: modify this to use save as
|
||||
function () {
|
||||
window.open(myself.fullImageClassic().toDataURL());
|
||||
},
|
||||
|
|
3
byob.js
3
byob.js
|
@ -762,6 +762,7 @@ CustomCommandBlockMorph.prototype.userMenu = function () {
|
|||
menu = new MenuMorph(this);
|
||||
menu.addItem(
|
||||
"script pic...",
|
||||
// TODO: modify this to use saveAs
|
||||
function () {
|
||||
window.open(this.topBlock().fullImage().toDataURL());
|
||||
},
|
||||
|
@ -784,6 +785,7 @@ CustomCommandBlockMorph.prototype.userMenu = function () {
|
|||
|
||||
CustomCommandBlockMorph.prototype.exportBlockDefinition = function () {
|
||||
var xml = new SnapSerializer().serialize(this.definition);
|
||||
// TODO: modify this to use saveAs
|
||||
window.open('data:text/xml,' + encodeURIComponent(xml));
|
||||
};
|
||||
|
||||
|
@ -3326,6 +3328,7 @@ BlockExportDialogMorph.prototype.selectNone = function () {
|
|||
// BlockExportDialogMorph ops
|
||||
|
||||
BlockExportDialogMorph.prototype.exportBlocks = function () {
|
||||
// TODO: modify this code to use saveAs
|
||||
var str = encodeURIComponent(
|
||||
this.serializer.serialize(this.blocks)
|
||||
);
|
||||
|
|
74
gui.js
74
gui.js
|
@ -67,7 +67,7 @@ BlockImportDialogMorph, SnapTranslator, localize, List, InputSlotMorph,
|
|||
SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512,
|
||||
sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio,
|
||||
SpeechBubbleMorph, ScriptFocusMorph, XML_Element, WatcherMorph,
|
||||
BlockRemovalDialogMorph*/
|
||||
BlockRemovalDialogMorph, saveAs*/
|
||||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -3647,56 +3647,48 @@ IDE_Morph.prototype.setURL = function (str) {
|
|||
};
|
||||
|
||||
// Allow for downloading a file to a disk or open in a new tab.
|
||||
// This function relies the FileSaver.js library which exports saveAs()
|
||||
// https://github.com/eligrey/FileSaver.js
|
||||
// This function is the primary way to get any data (image or text) out of Snap!
|
||||
IDE_Morph.prototype.saveFileAs = function (contents, fileName, newWindow) {
|
||||
// This relies the FileSaver.js library which exports saveAs()
|
||||
// See: https://github.com/eligrey/FileSaver.js
|
||||
// There are two utility methods saveImageAs and saveXMLAs that should be used
|
||||
// over this method, if appropriate.
|
||||
IDE_Morph.prototype.saveFileAs = function (contents, type, fileName, newWindow) {
|
||||
// TODO: handle Process.isCatchingErrors easily?
|
||||
// TODO: Add confirmations
|
||||
// TODO: Properly handle extensions.
|
||||
// TODO: Check for URI encoding?
|
||||
var isFileSaverSupported,
|
||||
blobData, fileType, fileExt,
|
||||
var isFileSaverSupported = false,
|
||||
fileExt,
|
||||
encodedData, world, dlg, errorMessage;
|
||||
|
||||
// File type for blobs, text for XML, image/png for images.
|
||||
fileType = 'text/xml;charset=utf-8';
|
||||
fileExt = '.xml'; // .txt, when?
|
||||
// type is a <kind>/<ext>;<meta> format.
|
||||
fileExt = '.' + type.split('/')[1].split(';')[0]
|
||||
// Error Message Handling
|
||||
world = this.world();
|
||||
errorMessage = 'Longer Message is coming soon!';
|
||||
|
||||
// This is a workaround for a known Chrome crash with large URLs
|
||||
function exhibitsChomeBug(contents) {
|
||||
var MAX_LENGTH = 2e6;
|
||||
var MAX_LENGTH = 2e6,
|
||||
isChrome = navigator.userAgent.indexOf('Chrome') !== -1,
|
||||
isTooLong = contents.length > MAX_LENGTH;
|
||||
|
||||
return false;
|
||||
return isChrome && isTooLong
|
||||
};
|
||||
|
||||
function dataURLFormat (text) {
|
||||
return 'data:' + fileType + ',' + text;
|
||||
}
|
||||
|
||||
try {
|
||||
isFileSaverSupported = !!new Blob;
|
||||
} catch (e) {}
|
||||
|
||||
// Handle rendering Cavas elements
|
||||
if (contents instanceof HTMLCanvasElement) {
|
||||
if (contents.toBlob && isFileSaverSupported) {
|
||||
contents.toBlob(function(blob) {
|
||||
saveAs(blobData, fileName, false);
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
contents = contents.toDataURL();
|
||||
fileType = 'image/png';
|
||||
fileExt = '.png';
|
||||
}
|
||||
}
|
||||
|
||||
// Force open in a new window, or use as a fallback.
|
||||
if (!isFileSaverSupported || newWindow) {
|
||||
// Prevent crashing errors in Chrome
|
||||
encodedData = encodeURIComponent(contents);
|
||||
if (!exhibitsChomeBug(encodedData)) {
|
||||
window.open('data:' + fileType + ',' + encodedData, '_blank');
|
||||
window.open(dataURLFormat(encodedData), '_blank');
|
||||
} else {
|
||||
dlg = new DialogBoxMorph();
|
||||
dlg.inform('Uh oh!', errorMessage, world);
|
||||
|
@ -3704,11 +3696,29 @@ IDE_Morph.prototype.saveFileAs = function (contents, fileName, newWindow) {
|
|||
dlg.fixLayout();
|
||||
dlg.drawNew();
|
||||
}
|
||||
} else {
|
||||
console.log('FILENAME: ', fileName);
|
||||
blobData = new Blob([contents], {type: fileType});
|
||||
saveAs(blobData, fileName + fileExt, false);
|
||||
} else if (!(contents instanceof Blob)){
|
||||
contents = new Blob([contents], {type: type });
|
||||
}
|
||||
|
||||
saveAs(contents, fileName + fileExt, false);
|
||||
}
|
||||
|
||||
// This helps exporting a canvas as an image
|
||||
// cavas.toBlob() is only supported in Firefox and IE, but is faster.
|
||||
IDE_Morph.prototype.saveCanvasAs = function (canvas, fileName, newWindow) {
|
||||
var myself = this;
|
||||
if (canvas.toBlob) {
|
||||
canvas.toBlob(function(blob) {
|
||||
this.saveFileAs(blob, 'image/png', fileName, newWindow);
|
||||
});
|
||||
} else {
|
||||
this.saveFileAs(canvas.toDataURL(), 'image/png', fileName, newWindow);
|
||||
}
|
||||
}
|
||||
|
||||
IDE_Morph.prototype.saveXMLAs = function(text, fileName, newWindow) {
|
||||
var typeTag = 'text/xml;chartset=utf-8';
|
||||
this.saveFileAs(text, typeTag, fileName, newWindow);
|
||||
}
|
||||
|
||||
IDE_Morph.prototype.switchToUserMode = function () {
|
||||
|
@ -5908,6 +5918,7 @@ SpriteIconMorph.prototype.fixLayout = function () {
|
|||
|
||||
// SpriteIconMorph menu
|
||||
|
||||
// TODO: fix this function
|
||||
SpriteIconMorph.prototype.userMenu = function () {
|
||||
var menu = new MenuMorph(this),
|
||||
myself = this;
|
||||
|
@ -6270,6 +6281,7 @@ CostumeIconMorph.prototype.removeCostume = function () {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO: Modify and fix this
|
||||
CostumeIconMorph.prototype.exportCostume = function () {
|
||||
if (this.object instanceof SVG_Costume) {
|
||||
window.open(this.object.contents.src);
|
||||
|
|
17
objects.js
17
objects.js
|
@ -583,7 +583,7 @@ SpriteMorph.prototype.initBlocks = function () {
|
|||
},
|
||||
|
||||
/* migrated to a newer block version:
|
||||
|
||||
|
||||
receiveClick: {
|
||||
type: 'hat',
|
||||
category: 'control',
|
||||
|
@ -5735,8 +5735,13 @@ StageMorph.prototype.userMenu = function () {
|
|||
menu.addItem("show all", 'showAll');
|
||||
menu.addItem(
|
||||
"pic...",
|
||||
<<<<<<< Local Changes
|
||||
// TODO: replace this function.
|
||||
=======
|
||||
>>>>>>> External Changes
|
||||
function () {
|
||||
window.open(myself.fullImageClassic().toDataURL());
|
||||
// pass a canvas to be opened as a new window.
|
||||
ide.saveCanvasAs(myself.fullImageClassic(), 'stage', true);
|
||||
},
|
||||
'open a new window\nwith a picture of the stage'
|
||||
);
|
||||
|
@ -7614,9 +7619,11 @@ WatcherMorph.prototype.userMenu = function () {
|
|||
menu.addItem(
|
||||
'export...',
|
||||
function () {
|
||||
window.open(
|
||||
'data:text/plain;charset=utf-8,' +
|
||||
encodeURIComponent(this.currentValue.toString())
|
||||
ide.saveFileAs(
|
||||
this.currentValue.toString(),
|
||||
'text/plain;charset=utf-8',
|
||||
'variable',
|
||||
false
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
Ładowanie…
Reference in New Issue