Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 42 additions & 32 deletions core/blockly.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ goog.require('Blockly.common');
goog.require('Blockly.ComponentManager');
goog.require('Blockly.connectionTypes');
goog.require('Blockly.constants');
goog.require('Blockly.dialog');
goog.require('Blockly.DropDownDiv');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
Expand Down Expand Up @@ -255,41 +256,50 @@ Blockly.hideChaff = function(opt_onlyClosePopups) {
*/
Blockly.getMainWorkspace = Blockly.common.getMainWorkspace;

/**
* Wrapper to window.alert() that app developers may override to
* provide alternatives to the modal browser window.
* @param {string} message The message to display to the user.
* @param {function()=} opt_callback The callback when the alert is dismissed.
*/
Blockly.alert = function(message, opt_callback) {
alert(message);
if (opt_callback) {
opt_callback();
// Add a getter and setter pair for Blockly.alert, for legacy reasons.
Object.defineProperty(Blockly, 'alert', {
set: function(newAlert) {
Blockly.utils.deprecation.warn(
'Blockly.alert', 'September 2021', 'September 2022');
Blockly.dialog.setAlert(newAlert);
},
get: function() {
Blockly.utils.deprecation.warn(
'Blockly.alert', 'September 2021', 'September 2022',
'Blockly.dialog.alert()');
return Blockly.dialog.alert;
}
};
});

/**
* Wrapper to window.confirm() that app developers may override to
* provide alternatives to the modal browser window.
* @param {string} message The message to display to the user.
* @param {!function(boolean)} callback The callback for handling user response.
*/
Blockly.confirm = function(message, callback) {
callback(confirm(message));
};
// Add a getter and setter pair for Blockly.confirm, for legacy reasons.
Object.defineProperty(Blockly, 'confirm', {
set: function(newConfirm) {
Blockly.utils.deprecation.warn(
'Blockly.confirm', 'September 2021', 'September 2022');
Blockly.dialog.setConfirm(newConfirm);
},
get: function() {
Blockly.utils.deprecation.warn(
'Blockly.confirm', 'September 2021', 'September 2022',
'Blockly.dialog.confirm()');
return Blockly.dialog.confirm;
}
});

/**
* Wrapper to window.prompt() that app developers may override to provide
* alternatives to the modal browser window. Built-in browser prompts are
* often used for better text input experience on mobile device. We strongly
* recommend testing mobile when overriding this.
* @param {string} message The message to display to the user.
* @param {string} defaultValue The value to initialize the prompt with.
* @param {!function(?string)} callback The callback for handling user response.
*/
Blockly.prompt = function(message, defaultValue, callback) {
callback(prompt(message, defaultValue));
};
// Add a getter and setter pair for Blockly.prompt, for legacy reasons.
Object.defineProperty(Blockly, 'prompt', {
set: function(newPrompt) {
Blockly.utils.deprecation.warn(
'Blockly.prompt', 'September 2021', 'September 2022');
Blockly.dialog.setPrompt(newPrompt);
},
get: function() {
Blockly.utils.deprecation.warn(
'Blockly.prompt', 'September 2021', 'September 2022',
'Blockly.dialog.prompt()');
return Blockly.dialog.prompt;
}
});

/**
* Helper function for defining a block from JSON. The resulting function has
Expand Down
3 changes: 2 additions & 1 deletion core/contextmenu_items.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const Msg = goog.require('Blockly.Msg');
/* eslint-disable-next-line no-unused-vars */
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
const clipboard = goog.require('Blockly.clipboard');
const dialog = goog.require('Blockly.dialog');
const idGenerator = goog.require('Blockly.utils.idGenerator');
const inputTypes = goog.require('Blockly.inputTypes');
const userAgent = goog.require('Blockly.utils.userAgent');
Expand Down Expand Up @@ -292,7 +293,7 @@ const registerDeleteAll = function() {
if (deletableBlocks.length < 2) {
deleteNext_(deletableBlocks, eventGroup);
} else {
Blockly.confirm(
dialog.confirm(
Msg['DELETE_ALL_BLOCKS'].replace('%1', deletableBlocks.length),
function(ok) {
if (ok) {
Expand Down
98 changes: 98 additions & 0 deletions core/dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @fileoverview Wrapper functions around JS functions for showing
* alert/confirmation dialogs.
*/

'use strict';

goog.module('Blockly.dialog');
goog.module.declareLegacyNamespace();

let alertImplementation = function(message, opt_callback) {
window.alert(message);
if (opt_callback) {
opt_callback();
}
};

let confirmImplementation = function(message, callback) {
callback(window.confirm(message));
};

let promptImplementation = function(message, defaultValue, callback) {
callback(window.prompt(message, defaultValue));
};

/**
* Wrapper to window.alert() that app developers may override via setAlert to
* provide alternatives to the modal browser window.
* @param {string} message The message to display to the user.
* @param {function()=} opt_callback The callback when the alert is dismissed.
*/
const alert = function(message, opt_callback) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why create a wrapper here, instead of just doing exports.alert = alertImplementation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because that exports the initial value of alertImplementation, so even if alertImplementation gets modified via the setter, the initial/default implementation will continue to be used.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, that makes sense.

The comment is no longer correct (for this and the others) because to override you would call setAlert rather than overriding alert.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the JSDoc to clarify, thanks!

alertImplementation(message, opt_callback);
};
exports.alert = alert;

/**
* Sets the function to be run when Blockly.dialog.alert() is called.
* @param {!function(string, function()=)} alertFunction The function to be run.
* @see Blockly.dialog.alert
*/
const setAlert = function(alertFunction) {
alertImplementation = alertFunction;
};
exports.setAlert = setAlert;

/**
* Wrapper to window.confirm() that app developers may override via setConfirm
* to provide alternatives to the modal browser window.
* @param {string} message The message to display to the user.
* @param {!function(boolean)} callback The callback for handling user response.
*/
const confirm = function(message, callback) {
confirmImplementation(message, callback);
};
exports.confirm = confirm;

/**
* Sets the function to be run when Blockly.dialog.confirm() is called.
* @param {!function(string, !function(boolean))} confirmFunction The function
* to be run.
* @see Blockly.dialog.confirm
*/
const setConfirm = function(confirmFunction) {
confirmImplementation = confirmFunction;
};
exports.setConfirm = setConfirm;

/**
* Wrapper to window.prompt() that app developers may override via setPrompt to
* provide alternatives to the modal browser window. Built-in browser prompts
* are often used for better text input experience on mobile device. We strongly
* recommend testing mobile when overriding this.
* @param {string} message The message to display to the user.
* @param {string} defaultValue The value to initialize the prompt with.
* @param {!function(?string)} callback The callback for handling user response.
*/
const prompt = function(message, defaultValue, callback) {
promptImplementation(message, defaultValue, callback);
};
exports.prompt = prompt;

/**
* Sets the function to be run when Blockly.dialog.prompt() is called.
* @param {!function(string, string, !function(?string))} promptFunction The
* function to be run.
* @see Blockly.dialog.prompt
*/
const setPrompt = function(promptFunction) {
promptImplementation = promptFunction;
};
exports.setPrompt = setPrompt;
4 changes: 2 additions & 2 deletions core/field_textinput.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
goog.module('Blockly.FieldTextInput');
goog.module.declareLegacyNamespace();

const Blockly = goog.require('Blockly');
/* eslint-disable-next-line no-unused-vars */
const BlockSvg = goog.requireType('Blockly.BlockSvg');
const Coordinate = goog.require('Blockly.utils.Coordinate');
Expand All @@ -27,6 +26,7 @@ const WidgetDiv = goog.require('Blockly.WidgetDiv');
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
const aria = goog.require('Blockly.utils.aria');
const browserEvents = goog.require('Blockly.browserEvents');
const dialog = goog.require('Blockly.dialog');
const dom = goog.require('Blockly.utils.dom');
const fieldRegistry = goog.require('Blockly.fieldRegistry');
const object = goog.require('Blockly.utils.object');
Expand Down Expand Up @@ -312,7 +312,7 @@ FieldTextInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
* @private
*/
FieldTextInput.prototype.showPromptEditor_ = function() {
Blockly.prompt(Msg['CHANGE_VALUE_TITLE'], this.getText(), function(text) {
dialog.prompt(Msg['CHANGE_VALUE_TITLE'], this.getText(), function(text) {
this.setValue(this.getValueFromEditorText_(text));
}.bind(this));
};
Expand Down
5 changes: 3 additions & 2 deletions core/variable_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const Names = goog.require('Blockly.Names');
const VariableModel = goog.require('Blockly.VariableModel');
/* eslint-disable-next-line no-unused-vars */
const Workspace = goog.requireType('Blockly.Workspace');
const dialog = goog.require('Blockly.dialog');
const idGenerator = goog.require('Blockly.utils.idGenerator');
const object = goog.require('Blockly.utils.object');
/** @suppress {extraRequire} */
Expand Down Expand Up @@ -233,7 +234,7 @@ VariableMap.prototype.deleteVariableById = function(id) {
const deleteText = Msg['CANNOT_DELETE_VARIABLE_PROCEDURE']
.replace('%1', variableName)
.replace('%2', procedureName);
Blockly.alert(deleteText);
dialog.alert(deleteText);
return;
}
}
Expand All @@ -244,7 +245,7 @@ VariableMap.prototype.deleteVariableById = function(id) {
const confirmText = Msg['DELETE_VARIABLE_CONFIRMATION']
.replace('%1', String(uses.length))
.replace('%2', variableName);
Blockly.confirm(confirmText, function(ok) {
dialog.confirm(confirmText, function(ok) {
if (ok && variable) {
map.deleteVariableInternal(variable, uses);
}
Expand Down
7 changes: 4 additions & 3 deletions core/variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const VariableModel = goog.require('Blockly.VariableModel');
/* eslint-disable-next-line no-unused-vars */
const Workspace = goog.requireType('Blockly.Workspace');
const Xml = goog.require('Blockly.Xml');
const dialog = goog.require('Blockly.dialog');
const utilsXml = goog.require('Blockly.utils.xml');


Expand Down Expand Up @@ -267,7 +268,7 @@ const createVariableButtonHandler = function(
msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE'];
msg = msg.replace('%1', existing.name).replace('%2', existing.type);
}
Blockly.alert(msg, function() {
dialog.alert(msg, function() {
promptAndCheckWithAlert(text); // Recurse
});
} else {
Expand Down Expand Up @@ -313,7 +314,7 @@ const renameVariable = function(workspace, variable, opt_callback) {
const msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE']
.replace('%1', existing.name)
.replace('%2', existing.type);
Blockly.alert(msg, function() {
dialog.alert(msg, function() {
promptAndCheckWithAlert(newName); // Recurse
});
} else {
Expand Down Expand Up @@ -342,7 +343,7 @@ exports.renameVariable = renameVariable;
* variable name, or null if the user picked something illegal.
*/
const promptName = function(promptText, defaultText, callback) {
Blockly.prompt(promptText, defaultText, function(newVar) {
dialog.prompt(promptText, defaultText, function(newVar) {
// Merge runs of whitespace. Strip leading and trailing whitespace.
// Beyond this, all names are legal.
if (newVar) {
Expand Down
2 changes: 1 addition & 1 deletion demos/code/code.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ Code.checkAllGeneratorFunctionsDefined = function(generator) {
if (!valid) {
var msg = 'The generator code for the following blocks not specified for ' +
generator.name_ + ':\n - ' + missingBlockGenerators.join('\n - ');
Blockly.alert(msg); // Assuming synchronous. No callback.
Blockly.dialog.alert(msg); // Assuming synchronous. No callback.
}
return valid;
};
Expand Down
18 changes: 9 additions & 9 deletions demos/custom-dialogs/custom-dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
*/
CustomDialog = {};

/** Override Blockly.alert() with custom implementation. */
Blockly.alert = function(message, callback) {
/** Override Blockly.dialog.alert() with custom implementation. */
Blockly.dialog.setAlert(function(message, callback) {
console.log('Alert: ' + message);
CustomDialog.show('Alert', message, {
onCancel: callback
});
};
});

/** Override Blockly.confirm() with custom implementation. */
Blockly.confirm = function(message, callback) {
/** Override Blockly.dialog.confirm() with custom implementation. */
Blockly.dialog.setConfirm(function(message, callback) {
console.log('Confirm: ' + message);
CustomDialog.show('Confirm', message, {
showOkay: true,
Expand All @@ -34,10 +34,10 @@ Blockly.confirm = function(message, callback) {
callback(false);
}
});
};
});

/** Override Blockly.prompt() with custom implementation. */
Blockly.prompt = function(message, defaultValue, callback) {
/** Override Blockly.dialog.prompt() with custom implementation. */
Blockly.dialog.setPrompt(function(message, defaultValue, callback) {
console.log('Prompt: ' + message);
CustomDialog.show('Prompt', message, {
showInput: true,
Expand All @@ -51,7 +51,7 @@ Blockly.prompt = function(message, defaultValue, callback) {
}
});
CustomDialog.inputField.value = defaultValue;
};
});

/** Hides any currently visible dialog. */
CustomDialog.hide = function() {
Expand Down
2 changes: 1 addition & 1 deletion demos/custom-fields/pitch/field_pitch.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ CustomFields.FieldPitch.prototype.showEditor_ = function() {

var div = Blockly.WidgetDiv.getDiv();
if (!div.firstChild) {
// Mobile interface uses Blockly.prompt.
// Mobile interface uses Blockly.dialog.prompt.
return;
}
// Build the DOM.
Expand Down
Loading