From 914fa842d6e11e36346451f1ae30a77814c9b3ae Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Sat, 26 Aug 2017 02:01:23 -0700 Subject: [PATCH 1/7] dont open costumes in a new window --- gui.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gui.js b/gui.js index 512ef3b5..32bfe321 100644 --- a/gui.js +++ b/gui.js @@ -885,7 +885,7 @@ IDE_Morph.prototype.createControlBar = function () { } this.refreshResumeSymbol(); }; - + this.controlBar.refreshResumeSymbol = function () { var pauseSymbols; if (Process.prototype.enableSingleStepping && @@ -4227,7 +4227,7 @@ IDE_Morph.prototype.saveFileAs = function ( IDE_Morph.prototype.saveCanvasAs = function (canvas, fileName, newWindow) { // Export a Canvas object as a PNG image // Note: This commented out due to poor browser support. - // cavas.toBlob() is currently supported in Firefox, IE, Chrome but + // cavas.toBlob() is currently supported in Firefox, IE, Chrome but // browsers prevent easily saving the generated files. // Do not re-enable without revisiting issue #1191 // if (canvas.toBlob) { @@ -4237,7 +4237,7 @@ IDE_Morph.prototype.saveCanvasAs = function (canvas, fileName, newWindow) { // }); // return; // } - + this.saveFileAs(canvas.toDataURL(), 'image/png', fileName, newWindow); }; @@ -5644,7 +5644,7 @@ ProjectDialogMorph.prototype.buildFilterField = function () { this.filterField.reactToKeystroke = function (evt) { var text = this.getValue(); - myself.listField.elements = + myself.listField.elements = myself.projectList.filter(function (aProject) { var name, notes; @@ -6272,7 +6272,7 @@ ProjectDialogMorph.prototype.fixLayout = function () { // LibraryImportDialogMorph /////////////////////////////////////////// // I am preview dialog shown before importing a library. -// I inherit from a DialogMorph but look similar to +// I inherit from a DialogMorph but look similar to // ProjectDialogMorph, and BlockImportDialogMorph LibraryImportDialogMorph.prototype = new DialogBoxMorph(); @@ -6507,7 +6507,7 @@ LibraryImportDialogMorph.prototype.fixLayout = function () { Morph.prototype.trackChanges = oldFlag; this.changed(); }; - + // Library Cache Utilities. LibraryImportDialogMorph.prototype.hasCached = function (key) { return this.libraryCache.hasOwnProperty(key); @@ -7237,7 +7237,7 @@ CostumeIconMorph.prototype.exportCostume = function () { // don't show SVG costumes in a new tab (shows text) ide.saveFileAs(this.object.contents.src, 'text/svg', this.object.name); } else { // rasterized Costume - ide.saveCanvasAs(this.object.contents, this.object.name, true); + ide.saveCanvasAs(this.object.contents, this.object.name); } }; @@ -8211,7 +8211,7 @@ PaletteHandleMorph.prototype.mouseEnter PaletteHandleMorph.prototype.mouseLeave = StageHandleMorph.prototype.mouseLeave; - + PaletteHandleMorph.prototype.mouseDoubleClick = function () { this.target.parentThatIsA(IDE_Morph).setPaletteWidth(200); }; From 63598c3994383050e28c09dba9092c7e80068341 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Sat, 26 Aug 2017 02:33:41 -0700 Subject: [PATCH 2/7] more fixes to prevent opening in new windows - remove some project XMLs - remove a few from exporting sprite and stage pics - remove the false parameter (since it is the default) ' --- gui.js | 3 +-- objects.js | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/gui.js b/gui.js index 32bfe321..0615a0f6 100644 --- a/gui.js +++ b/gui.js @@ -3916,8 +3916,7 @@ IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) { this.saveFileAs( '' + html.toString(), 'text/html;charset=utf-8', - pname, - false // request opening a new window. + pname ); }; diff --git a/objects.js b/objects.js index b9e456d6..d54673b1 100644 --- a/objects.js +++ b/objects.js @@ -9306,8 +9306,7 @@ WatcherMorph.prototype.userMenu = function () { inp.click(); } ); - if (this.currentValue && - (isString(this.currentValue) || !isNaN(+this.currentValue))) { + if (isString(this.currentValue) || !isNaN(+this.currentValue)) { menu.addItem( 'export...', function () { @@ -9315,8 +9314,7 @@ WatcherMorph.prototype.userMenu = function () { ide.saveFileAs( myself.currentValue.toString(), 'text/plain;charset=utf-8', - myself.getter, // variable name - true + myself.getter // variable name ); } ); From 8ce6333d123daf93026e81864469a327e30a2d86 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Sat, 26 Aug 2017 18:01:35 -0700 Subject: [PATCH 3/7] Remove code for opening exported things in a new window we can add it back later, but for now its useless. --- gui.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/gui.js b/gui.js index 0615a0f6..832fd0f7 100644 --- a/gui.js +++ b/gui.js @@ -2861,8 +2861,7 @@ IDE_Morph.prototype.projectMenu = function () { } 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); + myself.exportProject(name, false); }, null, 'exportProject'); } }, @@ -3500,7 +3499,7 @@ IDE_Morph.prototype.rawSaveProject = function (name) { }; -IDE_Morph.prototype.exportProject = function (name, plain, newWindow) { +IDE_Morph.prototype.exportProject = function (name, plain) { // Export project XML, saving a file to disk // newWindow requests displaying the project in a new tab. var menu, str, dataPrefix; @@ -3512,7 +3511,7 @@ IDE_Morph.prototype.exportProject = function (name, plain, newWindow) { menu = this.showMessage('Exporting'); str = this.serializer.serialize(this.stage); this.setURL('#open:' + dataPrefix + encodeURIComponent(str)); - this.saveXMLAs(str, name, newWindow); + this.saveXMLAs(str, name); menu.destroy(); this.showMessage('Exported!', 1); } catch (err) { @@ -3636,7 +3635,7 @@ IDE_Morph.prototype.exportScriptsPicture = function () { y += padding; y += each.height; }); - this.saveCanvasAs(pic, this.projectName || localize('Untitled'), true); + this.saveCanvasAs(pic, this.projectName || localize('Untitled')); }; IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) { @@ -4223,7 +4222,7 @@ IDE_Morph.prototype.saveFileAs = function ( } }; -IDE_Morph.prototype.saveCanvasAs = function (canvas, fileName, newWindow) { +IDE_Morph.prototype.saveCanvasAs = function (canvas, fileName) { // Export a Canvas object as a PNG image // Note: This commented out due to poor browser support. // cavas.toBlob() is currently supported in Firefox, IE, Chrome but @@ -4232,17 +4231,17 @@ IDE_Morph.prototype.saveCanvasAs = function (canvas, fileName, newWindow) { // if (canvas.toBlob) { // var myself = this; // canvas.toBlob(function (blob) { - // myself.saveFileAs(blob, 'image/png', fileName, newWindow); + // myself.saveFileAs(blob, 'image/png', fileName); // }); // return; // } - this.saveFileAs(canvas.toDataURL(), 'image/png', fileName, newWindow); + this.saveFileAs(canvas.toDataURL(), 'image/png', fileName); }; -IDE_Morph.prototype.saveXMLAs = function(xml, fileName, newWindow) { +IDE_Morph.prototype.saveXMLAs = function(xml, fileName) { // wrapper to saving XML files with a proper type tag. - this.saveFileAs(xml, 'text/xml;chartset=utf-8', fileName, newWindow); + this.saveFileAs(xml, 'text/xml;chartset=utf-8', fileName); }; IDE_Morph.prototype.switchToUserMode = function () { @@ -6833,8 +6832,7 @@ SpriteIconMorph.prototype.userMenu = function () { var ide = myself.parentThatIsA(IDE_Morph); ide.saveCanvasAs( myself.object.fullImageClassic(), - this.object.name, - true + this.object.name ); }, 'open a new window\nwith a picture of the stage' From d4c3709d4ae9649ae61eac5795210e27547b145b Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Sat, 26 Aug 2017 18:02:33 -0700 Subject: [PATCH 4/7] Update filesaver.js to lastest version -- mostly minor tweaks --- FileSaver.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FileSaver.min.js b/FileSaver.min.js index 8bbbf769..9a1e397f 100644 --- a/FileSaver.min.js +++ b/FileSaver.min.js @@ -1,2 +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})} \ No newline at end of file +var saveAs=saveAs||function(e){"use strict";if(typeof e==="undefined"||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"),o="download"in r,a=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},i=/constructor/i.test(e.HTMLElement)||e.safari,f=/CriOS\/[\d]+/.test(navigator.userAgent),u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",d=1e3*40,c=function(e){var t=function(){if(typeof e==="string"){n().revokeObjectURL(e)}else{e.remove()}};setTimeout(t,d)},l=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var o=e["on"+t[r]];if(typeof o==="function"){try{o.call(e,n||e)}catch(a){u(a)}}}},p=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob([String.fromCharCode(65279),e],{type:e.type})}return e},v=function(t,u,d){if(!d){t=p(t)}var v=this,w=t.type,m=w===s,y,h=function(){l(v,"writestart progress write writeend".split(" "))},S=function(){if((f||m&&i)&&e.FileReader){var r=new FileReader;r.onloadend=function(){var t=f?r.result:r.result.replace(/^data:[^;]*;/,"data:attachment/file;");var n=e.open(t,"_blank");if(!n)e.location.href=t;t=undefined;v.readyState=v.DONE;h()};r.readAsDataURL(t);v.readyState=v.INIT;return}if(!y){y=n().createObjectURL(t)}if(m){e.location.href=y}else{var o=e.open(y,"_blank");if(!o){e.location.href=y}}v.readyState=v.DONE;h();c(y)};v.readyState=v.INIT;if(o){y=n().createObjectURL(t);setTimeout(function(){r.href=y;r.download=u;a(r);h();c(y);v.readyState=v.DONE});return}S()},w=v.prototype,m=function(e,t,n){return new v(e,t||e.name||"download",n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){t=t||e.name||"download";if(!n){e=p(e)}return navigator.msSaveOrOpenBlob(e,t)}}w.abort=function(){};w.readyState=w.INIT=0;w.WRITING=1;w.DONE=2;w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null;return m}(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("FileSaver.js",function(){return saveAs})} From e8c03857194c4e6b3c6439b09a0d1d44e4de7df2 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Sat, 26 Aug 2017 18:05:37 -0700 Subject: [PATCH 5/7] Remove remaing code for opening exports in a new window --- blocks.js | 18 +++++++----------- byob.js | 3 +-- gui.js | 43 +++---------------------------------------- objects.js | 3 +-- 4 files changed, 12 insertions(+), 55 deletions(-) diff --git a/blocks.js b/blocks.js index 58baead1..9706e665 100644 --- a/blocks.js +++ b/blocks.js @@ -65,7 +65,7 @@ BoxMorph* CommentMorph ScriptFocusMorph - + * from morphic.js @@ -1972,8 +1972,7 @@ SyntaxElementMorph.prototype.exportPictureWithResult = function (aBubble) { // request to open pic in new window. ide.saveCanvasAs( pic, - ide.projetName || localize('Untitled') + ' ' + localize('script pic'), - false + ide.projetName || localize('Untitled') + ' ' + localize('script pic') ); }; @@ -2552,8 +2551,7 @@ BlockMorph.prototype.userMenu = function () { ide.saveCanvasAs( myself.topBlock().scriptPic(), ide.projetName || localize('Untitled') + ' ' + - localize('script pic'), - false // request new window + localize('script pic') ); }, 'open a new window\nwith a picture of this script' @@ -3315,7 +3313,7 @@ BlockMorph.prototype.doRefactorSpriteVar = function ( newName, justTheTemplate ) { - var receiver = this.scriptTarget(), + var receiver = this.scriptTarget(), ide = receiver.parentThatIsA(IDE_Morph), oldWatcher = receiver.findVariableWatcher(oldName), oldValue, newWatcher; @@ -3364,7 +3362,7 @@ BlockMorph.prototype.doRefactorGlobalVar = function ( newName, justTheTemplate ) { - var receiver = this.scriptTarget(), + var receiver = this.scriptTarget(), ide = receiver.parentThatIsA(IDE_Morph), stage = ide ? ide.stage : null, oldWatcher = receiver.findVariableWatcher(oldName), @@ -6307,8 +6305,7 @@ ScriptsMorph.prototype.exportScriptsPicture = function () { ide.saveCanvasAs( pic, ide.projetName || localize('Untitled') + ' ' + - localize('script pic'), - false // request new window + localize('script pic') ); } }; @@ -11656,8 +11653,7 @@ CommentMorph.prototype.userMenu = function () { ide.saveCanvasAs( myself.fullImageClassic(), ide.projetName || localize('Untitled') + ' ' + - localize('comment pic'), - false // request new window + localize('comment pic') ); }, 'open a new window\nwith a picture of this comment' diff --git a/byob.js b/byob.js index 123aeb5d..a50f1b7f 100644 --- a/byob.js +++ b/byob.js @@ -931,8 +931,7 @@ CustomCommandBlockMorph.prototype.userMenu = function () { ide.saveCanvasAs( this.topBlock().scriptPic(), ide.projectName || localize('Untitled') + ' ' + - localize('script pic'), - true // request opening a new window + localize('script pic') ); }, 'open a new window\nwith a picture of this script' diff --git a/gui.js b/gui.js index 832fd0f7..4b7f2a7e 100644 --- a/gui.js +++ b/gui.js @@ -4129,15 +4129,11 @@ IDE_Morph.prototype.setURL = function (str) { IDE_Morph.prototype.saveFileAs = function ( contents, fileType, - fileName, - newWindow // (optional) defaults to false. + fileName ) { - /** Allow for downloading a file to a disk or open in a new tab. + /** Allow for downloading a file to a disk. 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(), @@ -4149,13 +4145,6 @@ IDE_Morph.prototype.saveFileAs = function ( // 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, @@ -4173,37 +4162,11 @@ IDE_Morph.prototype.saveFileAs = function ( 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 (blobIsSupported) { if (!(contents instanceof Blob)) { contents = dataURItoBlob(contents, fileType); } diff --git a/objects.js b/objects.js index d54673b1..de8bcb70 100644 --- a/objects.js +++ b/objects.js @@ -7235,8 +7235,7 @@ StageMorph.prototype.userMenu = function () { function () { ide.saveCanvasAs( myself.fullImageClassic(), - myself.name, - true // open as new window + myself.name ); }, 'open a new window\nwith a picture of the stage' From 072ae4aaa7fd517ed3d9d9383caa14173664ce15 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Fri, 1 Sep 2017 16:08:01 -0700 Subject: [PATCH 6/7] sigh..fix conflicts --- gui.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gui.js b/gui.js index e6c2f183..e331c84b 100644 --- a/gui.js +++ b/gui.js @@ -7199,11 +7199,7 @@ CostumeIconMorph.prototype.exportCostume = function () { // don't show SVG costumes in a new tab (shows text) ide.saveFileAs(this.object.contents.src, 'text/svg', this.object.name); } else { // rasterized Costume -<<<<<<< HEAD ide.saveCanvasAs(this.object.contents, this.object.name); -======= - ide.saveCanvasAs(this.object.contents, this.object.name, false); ->>>>>>> master } }; From 7c570dbd28a37b522b40dd613064eb3b4c8c5126 Mon Sep 17 00:00:00 2001 From: Florrie Date: Sat, 9 Sep 2017 17:01:29 -0300 Subject: [PATCH 7/7] Fix 'untitled script pic' (meant to be [project name] script pic) --- blocks.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/blocks.js b/blocks.js index 8a307d8e..1b07e98a 100644 --- a/blocks.js +++ b/blocks.js @@ -1973,7 +1973,7 @@ SyntaxElementMorph.prototype.exportPictureWithResult = function (aBubble) { // request to open pic in new window. ide.saveCanvasAs( pic, - (ide.projetName || localize('untitled')) + ' ' + localize('script pic') + (ide.projectName || localize('untitled')) + ' ' + localize('script pic') ); }; @@ -2551,7 +2551,7 @@ BlockMorph.prototype.userMenu = function () { ); ide.saveCanvasAs( myself.topBlock().scriptPic(), - (ide.projetName || localize('untitled')) + ' ' + + (ide.projectName || localize('untitled')) + ' ' + localize('script pic') ); }, @@ -6305,7 +6305,7 @@ ScriptsMorph.prototype.exportScriptsPicture = function () { if (pic) { ide.saveCanvasAs( pic, - (ide.projetName || localize('untitled')) + ' ' + + (ide.projectName || localize('untitled')) + ' ' + localize('script pic') ); } @@ -11656,7 +11656,7 @@ CommentMorph.prototype.userMenu = function () { var ide = myself.parentThatIsA(IDE_Morph); ide.saveCanvasAs( myself.fullImageClassic(), - (ide.projetName || localize('untitled')) + ' ' + + (ide.projectName || localize('untitled')) + ' ' + localize('comment pic') ); },