diff --git a/HISTORY.md b/HISTORY.md
index 6be264a5..5a935313 100755
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -6,6 +6,7 @@
* export pen trails as SVG
* access pen trails as SVG_Costume: new "pen vectors" reporter variant of "pen trails"
* new Snap! API: programmatically broadcast messages and optionally wait from outside Snap!
+ * new Snap! API: programmatically add message listeners to get notified and react to broadcasts from outside Snap!
* new Snap! API: programmatically get and set global variables from outside Snap!
* **Notable Changes:**
* when creating a costume from pen trails (raster or vector) make its rotation center the position of the sprite
@@ -18,6 +19,7 @@
### 2019-12-15
* gui, threads: new Snap! API: programmatically broadcast messages and optionally wait from outside Snap!
* gui: added global variable access methods to the new Snap! API
+* gui, objects: added ability to add message listeners to broadcasts
### 2019-12-13
* added direct relabelling option to pen trails blocks' context menus
diff --git a/snap.html b/snap.html
index 75668b5a..547e3ae9 100755
--- a/snap.html
+++ b/snap.html
@@ -8,7 +8,7 @@
-
+
diff --git a/src/gui.js b/src/gui.js
index 43dc021a..cf7b2804 100644
--- a/src/gui.js
+++ b/src/gui.js
@@ -6061,6 +6061,8 @@ IDE_Morph.prototype.isIE = function () {
// IDE_Morph external communication API - experimental
/*
programmatically trigger scripts from outside of Snap!
+ add message listeners to Snap! broadcasts and access
+ global variables
*/
IDE_Morph.prototype.broadcast = function(message, callback) {
@@ -6069,7 +6071,7 @@ IDE_Morph.prototype.broadcast = function(message, callback) {
// if a callback is supplied wait for all processes to terminate
// then call the callback, same as using the "broadcast and wait" block
- var rcvrs = this.stage.children.concat(this.stage),
+ var rcvrs = this.sprites.contents.concat(this.stage),
myself = this,
procs = [];
@@ -6100,6 +6102,26 @@ IDE_Morph.prototype.broadcast = function(message, callback) {
));
});
});
+ (this.stage.messageCallbacks[message] || []).forEach(function (callback) {
+ callback();
+ });
+};
+
+IDE_Morph.prototype.addMessageListener = function (message, callback) {
+ // associate a callback function with a broadcast message,
+ // whenever the message is broadcast, the callback is executed,
+ // you can add multiple callbacks to a message, they will be
+ // executed in the order you added them
+ var funcs;
+ if (!isString(message)) {
+ throw new Error('message must be a String');
+ }
+ funcs = this.stage.messageCallbacks[message];
+ if (funcs instanceof Array) {
+ funcs.push(callback);
+ } else {
+ this.stage.messageCallbacks[message] = [callback];
+ }
};
IDE_Morph.prototype.getVarNames = function () {
diff --git a/src/objects.js b/src/objects.js
index 4a7dfbd0..dcbeb9e3 100644
--- a/src/objects.js
+++ b/src/objects.js
@@ -84,7 +84,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, BooleanSlotMorph,
localize, TableMorph, TableFrameMorph, normalizeCanvas, VectorPaintEditorMorph,
HandleMorph, AlignmentMorph, Process, XML_Element, WorldMap, copyCanvas*/
-modules.objects = '2019-December-13';
+modules.objects = '2019-December-15';
var SpriteMorph;
var StageMorph;
@@ -7486,6 +7486,9 @@ StageMorph.prototype.init = function (globals) {
// world map client - experimental, transient
this.worldMap = new WorldMap();
+ // Snap! API event listeners - experimental, transient
+ this.messageCallbacks = {}; // name : [functions]
+
StageMorph.uber.init.call(this);
this.cachedHSV = this.color.hsv();
diff --git a/src/threads.js b/src/threads.js
index cf753327..1a4496d9 100644
--- a/src/threads.js
+++ b/src/threads.js
@@ -3180,6 +3180,9 @@ Process.prototype.doBroadcast = function (message) {
});
}
});
+ (stage.messageCallbacks[msg] || []).forEach(function (callback) {
+ callback();
+ });
}
return procs;
};