diff --git a/HISTORY.md b/HISTORY.md
index 8fac2bc6..5707e090 100755
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -4,7 +4,7 @@
* **New Features:**
* support dragging blocks, costumes and sounds out from result bubbles, and from speech balloons and variable watchers when in edit mode
- * support exporting costumes and sounds from result bubbles
+ * support exporting costumes and sounds from result bubbles, and from speech balloons in edit mode
* support deleting and inserting individual variadic slots, script vars & ring params
* **Notable Changes:**
* **Notable Fixes:**
@@ -19,6 +19,7 @@
* tables: support dragging costumes and sounds out from table views
* blocks: support exporting costumes from result bubbles
* blocks: support exporting sounds from result bubbles
+* objects: support exporting sounds and costumes from speech balloons in edit mode
### 2022-01-27
* blocks, gui: support dragging costumes and sounds out from result bubbles
diff --git a/snap.html b/snap.html
index 41d5f813..59af8172 100755
--- a/snap.html
+++ b/snap.html
@@ -18,7 +18,7 @@
-
+
diff --git a/src/blocks.js b/src/blocks.js
index f62b7d12..35efa98c 100644
--- a/src/blocks.js
+++ b/src/blocks.js
@@ -2276,7 +2276,7 @@ SyntaxElementMorph.prototype.showBubble = function (value, exportPic, target) {
return icon;
};
- // support exporting costumes directly from result bubbles
+ // support exporting costumes directly from result bubbles:
morphToShow.userMenu = function () {
var menu = new MenuMorph(this);
menu.addItem(
@@ -2324,7 +2324,7 @@ SyntaxElementMorph.prototype.showBubble = function (value, exportPic, target) {
return icon;
};
- // support exporting sounds directly from result bubbles
+ // support exporting sounds directly from result bubbles:
morphToShow.userMenu = function () {
var menu = new MenuMorph(this);
menu.addItem(
diff --git a/src/objects.js b/src/objects.js
index 187a5cf2..9d857a63 100644
--- a/src/objects.js
+++ b/src/objects.js
@@ -87,7 +87,7 @@ BlockVisibilityDialogMorph, CostumeIconMorph, SoundIconMorph*/
/*jshint esversion: 6*/
-modules.objects = '2022-January-27';
+modules.objects = '2022-January-28';
var SpriteMorph;
var StageMorph;
@@ -10043,6 +10043,32 @@ SpriteBubbleMorph.prototype.dataAsMorph = function (data) {
icon.setCenter(this.center());
return icon;
};
+
+ // support exporting costumes directly from speech balloons:
+ contents.userMenu = function () {
+ var menu = new MenuMorph(this),
+ ide = this.parentThatIsA(IDE_Morph)||
+ this.world().childThatIsA(IDE_Morph);
+
+ if (ide.isAppMode) {return; }
+ menu.addItem(
+ 'export',
+ () => {
+ if (data instanceof SVG_Costume) {
+ // don't show SVG costumes in a new tab (shows text)
+ ide.saveFileAs(
+ data.contents.src,
+ 'text/svg',
+ data.name
+ );
+ } else { // rasterized Costume
+ ide.saveCanvasAs(data.contents, data.name);
+ }
+ }
+ );
+ return menu;
+ };
+
} else if (data instanceof Sound) {
contents = new SymbolMorph('notes', 30);
@@ -10072,6 +10098,21 @@ SpriteBubbleMorph.prototype.dataAsMorph = function (data) {
icon.setCenter(this.center());
return icon;
};
+
+ // support exporting sounds directly from speech balloons:
+ contents.userMenu = function () {
+ var menu = new MenuMorph(this),
+ ide = this.parentThatIsA(IDE_Morph)||
+ this.world().childThatIsA(IDE_Morph);
+
+ if (ide.isAppMode) {return; }
+ menu.addItem(
+ 'export',
+ () => ide.saveAudioAs(data.audio, data.name)
+ );
+ return menu;
+ };
+
} else if (data instanceof HTMLCanvasElement) {
img = data;
contents = new Morph();