diff --git a/packages/scratch-gui/src/lib/make-toolbox-xml.js b/packages/scratch-gui/src/lib/make-toolbox-xml.js
index 90346b8b03..ed86d2cc6e 100644
--- a/packages/scratch-gui/src/lib/make-toolbox-xml.js
+++ b/packages/scratch-gui/src/lib/make-toolbox-xml.js
@@ -5,7 +5,7 @@ const categorySeparator = '';
const blockSeparator = ''; // At default scale, about 28px
-
+
const motion = function (isInitialSetup, isStage, targetId, colors) {
const stageSelected = ScratchBlocks.ScratchMsgs.translate(
'MOTION_STAGE_SELECTED',
@@ -513,6 +513,7 @@ const sensing = function (isInitialSetup, isStage, targetId, colors) {
${blockSeparator}
+
${categorySeparator}
@@ -736,7 +737,7 @@ const myBlocks = function (isInitialSetup, isStage, targetId, colors) {
`;
};
-
+
const xmlOpen = '';
const xmlClose = '';
diff --git a/packages/scratch-gui/src/lib/opcode-labels.js b/packages/scratch-gui/src/lib/opcode-labels.js
index 22bff608af..9fd9f2240f 100644
--- a/packages/scratch-gui/src/lib/opcode-labels.js
+++ b/packages/scratch-gui/src/lib/opcode-labels.js
@@ -68,6 +68,11 @@ const messages = defineMessages({
description: 'Label for the loudness monitor when shown on the stage',
id: 'gui.opcodeLabels.loudness'
},
+ sensing_online: {
+ defaultMessage: 'online',
+ description: 'Label for the online status monitor when shown on the stage',
+ id: 'gui.opcodeLabels.online'
+ },
sensing_username: {
defaultMessage: 'username',
description: 'Label for the username monitor when shown on the stage',
@@ -152,6 +157,7 @@ class OpcodeLabels {
// Sensing
sensing_answer: {category: 'sensing'},
sensing_loudness: {category: 'sensing'},
+ sensing_online: {category: 'sensing'},
sensing_username: {category: 'sensing'},
sensing_current: {category: 'sensing'},
sensing_timer: {category: 'sensing'}
@@ -208,6 +214,7 @@ class OpcodeLabels {
// Sensing
this._opcodeMap.sensing_answer.labelFn = () => this._translator(messages.sensing_answer);
this._opcodeMap.sensing_loudness.labelFn = () => this._translator(messages.sensing_loudness);
+ this._opcodeMap.sensing_online.labelFn = () => this._translator(messages.sensing_online);
this._opcodeMap.sensing_username.labelFn = () => this._translator(messages.sensing_username);
this._opcodeMap.sensing_current.labelFn = params => {
switch (params.CURRENTMENU.toLowerCase()) {
diff --git a/packages/scratch-vm/src/blocks/scratch3_sensing.js b/packages/scratch-vm/src/blocks/scratch3_sensing.js
index 3d1ddbf4dd..cddf3ce4f5 100644
--- a/packages/scratch-vm/src/blocks/scratch3_sensing.js
+++ b/packages/scratch-vm/src/blocks/scratch3_sensing.js
@@ -71,6 +71,7 @@ class Scratch3SensingBlocks {
sensing_loud: this.isLoud,
sensing_askandwait: this.askAndWait,
sensing_answer: this.getAnswer,
+ sensing_online: this.getOnline,
sensing_username: this.getUsername,
sensing_userid: () => {} // legacy no-op block
};
@@ -84,6 +85,9 @@ class Scratch3SensingBlocks {
sensing_loudness: {
getId: () => 'loudness'
},
+ sensing_online: {
+ getId: () => 'online'
+ },
sensing_timer: {
getId: () => 'timer'
},
@@ -328,6 +332,16 @@ class Scratch3SensingBlocks {
return 0;
}
+ getOnline (args, util) {
+ const status = window.navigator.onLine;
+ if (typeof status === 'boolean') {
+ return status;
+ }
+ // an empty string will evaluate as false in a Boolean context,
+ // but it allows distinguishing between "false" and "unknown" if needed
+ return '';
+ }
+
getUsername (args, util) {
return util.ioQuery('userData', 'getUsername');
}