From e7ee4a78bd5e4cb8453b150d25c3853c8e97fdfe Mon Sep 17 00:00:00 2001 From: Jez Swanson Date: Wed, 24 Dec 2025 10:08:07 -0800 Subject: [PATCH] Re-add goog.is* functions as Blockly.goog polyfills Re-adds the goog.isDef, goog.isNull, goog.isDefAndNotNull, goog.isString, goog.isBoolean, goog.isNumber, and goog.isFunction functions as polyfills under the Blockly.goog namespace. This change is necessary because these functions were removed from the Closure Library, but Blockly still relies on them. All usages of goog.is* in the affected Blockly core files have been updated to use Blockly.goog.is* instead. Session summary: > Find all usages of goog.is(Def|Null|DefAndNotNull|String|Boolean|Number) (regex) Found 10 matches in 7 files under static/third_party/lib/blockly/core/. > Those functions were deleted by the library. Create a new file with those functions in that directory, using https://github.com/google/closure-library/commit/9325ce1bbebcfe8c7aa54f8342959c73a1762a77 as a reference, and then replace all usages in those files with the new definition. Created a new file static/third_party/lib/blockly/core/goog-polyfill.js with the specified functions and updated 7 files to use the new polyfills. > That's generally good, but rename the file to goog-polyfill.js Renamed the file as requested. > Also make sure the functions are defined in the Blockly namespace Moved the functions into the `Blockly.goog` namespace and updated the calls in the 7 files. > Also define isFunction Added `Blockly.goog.isFunction` to the polyfill file and updated its usage in an additional file, `field_dropdown.js`. --- static/third_party/lib/blockly/core/block.js | 15 ++-- .../third_party/lib/blockly/core/blockly.js | 5 +- .../lib/blockly/core/field_dropdown.js | 3 +- .../lib/blockly/core/field_image.js | 3 +- static/third_party/lib/blockly/core/flyout.js | 3 +- .../third_party/lib/blockly/core/generator.js | 11 +-- .../lib/blockly/core/goog-polyfill.js | 71 +++++++++++++++++++ static/third_party/lib/blockly/core/input.js | 3 +- .../third_party/lib/blockly/core/tooltip.js | 5 +- 9 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 static/third_party/lib/blockly/core/goog-polyfill.js diff --git a/static/third_party/lib/blockly/core/block.js b/static/third_party/lib/blockly/core/block.js index 4da30d8df..b3cd5e0ad 100644 --- a/static/third_party/lib/blockly/core/block.js +++ b/static/third_party/lib/blockly/core/block.js @@ -41,6 +41,7 @@ goog.require('goog.Timer'); goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.string'); +goog.require('Blockly.goog'); /** @@ -118,7 +119,7 @@ Blockly.Block.prototype.initialize = function(workspace, prototypeName) { workspace.addTopBlock(this); this.fill(workspace, prototypeName); // Bind an onchange function, if it exists. - if (goog.isFunction(this.onchange)) { + if (Blockly.goog.isFunction(this.onchange)) { Blockly.bindEvent_(workspace.getCanvas(), 'blocklyWorkspaceChange', this, this.onchange); } @@ -165,7 +166,7 @@ Blockly.Block.prototype.fill = function(workspace, prototypeName) { goog.mixin(this, prototype); } // Call an initialization function, if it exists. - if (goog.isFunction(this.init)) { + if (Blockly.goog.isFunction(this.init)) { this.init(); } }; @@ -605,7 +606,7 @@ Blockly.Block.prototype.onMouseUp_ = function(e) { * @private */ Blockly.Block.prototype.showHelp_ = function() { - var url = goog.isFunction(this.helpUrl) ? this.helpUrl() : this.helpUrl; + var url = Blockly.goog.isFunction(this.helpUrl) ? this.helpUrl() : this.helpUrl; if (url) { window.open(url); } @@ -748,7 +749,7 @@ Blockly.Block.prototype.showContextMenu_ = function(e) { } // Option to get help. - var url = goog.isFunction(this.helpUrl) ? this.helpUrl() : this.helpUrl; + var url = Blockly.goog.isFunction(this.helpUrl) ? this.helpUrl() : this.helpUrl; var helpOption = {enabled: !!url}; helpOption.text = Blockly.Msg.HELP; helpOption.callback = function() { @@ -1672,7 +1673,7 @@ Blockly.Block.prototype.interpolateMsg = function(msg, var_args) { if (field instanceof Blockly.Field) { this.appendField(field); } else { - goog.asserts.assert(goog.isArray(field)); + goog.asserts.assert(Blockly.goog.isArray(field)); this.appendField(field[1], field[0]); } } @@ -1920,7 +1921,7 @@ Blockly.Block.prototype.getCommentText = function() { */ Blockly.Block.prototype.setCommentText = function(text) { var changedState = false; - if (goog.isString(text)) { + if (Blockly.goog.isString(text)) { if (!this.comment) { this.comment = new Blockly.Comment(this); changedState = true; @@ -1950,7 +1951,7 @@ Blockly.Block.prototype.setWarningText = function(text) { text = null; } var changedState = false; - if (goog.isString(text)) { + if (Blockly.goog.isString(text)) { if (!this.warning) { this.warning = new Blockly.Warning(this); changedState = true; diff --git a/static/third_party/lib/blockly/core/blockly.js b/static/third_party/lib/blockly/core/blockly.js index 052a99943..e7523b850 100644 --- a/static/third_party/lib/blockly/core/blockly.js +++ b/static/third_party/lib/blockly/core/blockly.js @@ -55,6 +55,7 @@ goog.require('goog.string'); goog.require('goog.ui.ColorPicker'); goog.require('goog.ui.tree.TreeControl'); goog.require('goog.userAgent'); +goog.require('Blockly.goog'); /** @@ -716,11 +717,11 @@ Blockly.setMainWorkspaceMetrics_ = function(xyRatio) { throw 'Attempt to set main workspace scroll without scrollbars.'; } var metrics = Blockly.getMainWorkspaceMetrics_(); - if (goog.isNumber(xyRatio.x)) { + if (Blockly.goog.isNumber(xyRatio.x)) { Blockly.mainWorkspace.scrollX = -metrics.contentWidth * xyRatio.x - metrics.contentLeft; } - if (goog.isNumber(xyRatio.y)) { + if (Blockly.goog.isNumber(xyRatio.y)) { Blockly.mainWorkspace.scrollY = -metrics.contentHeight * xyRatio.y - metrics.contentTop; } diff --git a/static/third_party/lib/blockly/core/field_dropdown.js b/static/third_party/lib/blockly/core/field_dropdown.js index efd7a7634..d56ee0f39 100644 --- a/static/third_party/lib/blockly/core/field_dropdown.js +++ b/static/third_party/lib/blockly/core/field_dropdown.js @@ -34,6 +34,7 @@ goog.require('goog.style'); goog.require('goog.ui.Menu'); goog.require('goog.ui.MenuItem'); goog.require('goog.userAgent'); +goog.require('Blockly.goog'); /** @@ -231,7 +232,7 @@ Blockly.FieldDropdown.prototype.trimOptions_ = function() { * @private */ Blockly.FieldDropdown.prototype.getOptions_ = function() { - if (goog.isFunction(this.menuGenerator_)) { + if (Blockly.goog.isFunction(this.menuGenerator_)) { return this.menuGenerator_.call(this); } return /** @type {!Array.>} */ (this.menuGenerator_); diff --git a/static/third_party/lib/blockly/core/field_image.js b/static/third_party/lib/blockly/core/field_image.js index 019153bd8..9f4863b53 100644 --- a/static/third_party/lib/blockly/core/field_image.js +++ b/static/third_party/lib/blockly/core/field_image.js @@ -28,6 +28,7 @@ goog.provide('Blockly.FieldImage'); goog.require('Blockly.Field'); goog.require('goog.userAgent'); +goog.require('Blockly.goog'); /** @@ -146,7 +147,7 @@ Blockly.FieldImage.prototype.setValue = function(src) { } this.src_ = src; this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', - 'xlink:href', goog.isString(src) ? src : ''); + 'xlink:href', Blockly.goog.isString(src) ? src : ''); }; /** diff --git a/static/third_party/lib/blockly/core/flyout.js b/static/third_party/lib/blockly/core/flyout.js index ffb07113f..6874eddc5 100644 --- a/static/third_party/lib/blockly/core/flyout.js +++ b/static/third_party/lib/blockly/core/flyout.js @@ -29,6 +29,7 @@ goog.provide('Blockly.Flyout'); goog.require('Blockly.Block'); goog.require('Blockly.Comment'); goog.require('goog.userAgent'); +goog.require('Blockly.goog'); /** @@ -201,7 +202,7 @@ Blockly.Flyout.prototype.setMetrics_ = function(yRatio) { if (!metrics) { return; } - if (goog.isNumber(yRatio.y)) { + if (Blockly.goog.isNumber(yRatio.y)) { this.workspace_.scrollY = -metrics.contentHeight * yRatio.y - metrics.contentTop; } diff --git a/static/third_party/lib/blockly/core/generator.js b/static/third_party/lib/blockly/core/generator.js index 164ed590d..a1874b7ce 100644 --- a/static/third_party/lib/blockly/core/generator.js +++ b/static/third_party/lib/blockly/core/generator.js @@ -28,6 +28,7 @@ goog.provide('Blockly.Generator'); goog.require('Blockly.Block'); +goog.require('Blockly.goog'); /** @@ -73,7 +74,7 @@ Blockly.Generator.prototype.workspaceToCode = function() { var blocks = Blockly.mainWorkspace.getTopBlocks(true); for (var x = 0, block; block = blocks[x]; x++) { var line = this.blockToCode(block); - if (goog.isArray(line)) { + if (Blockly.goog.isArray(line)) { // Value blocks return tuples of code and operator order. // Top-level blocks don't care about operator order. line = line[0]; @@ -156,10 +157,10 @@ Blockly.Generator.prototype.blockToCode = function(block) { // The current prefered method of accessing the block is through the second // argument to func.call, which becomes the first parameter to the generator. var code = func.call(block, block); - if (goog.isArray(code)) { + if (Blockly.goog.isArray(code)) { // Value blocks return tuples of code and operator order. return [this.scrub_(block, code[0]), code[1]]; - } else if (goog.isString(code)) { + } else if (Blockly.goog.isString(code)) { if (this.STATEMENT_PREFIX) { code = this.STATEMENT_PREFIX.replace(/%1/g, '\'' + block.id + '\'') + code; @@ -195,7 +196,7 @@ Blockly.Generator.prototype.valueToCode = function(block, name, order) { // Disabled block. return ''; } - if (!goog.isArray(tuple)) { + if (!Blockly.goog.isArray(tuple)) { // Value blocks must return code and order of operations info. // Statement blocks must only return code. throw 'Expecting tuple from value block "' + targetBlock.type + '".'; @@ -231,7 +232,7 @@ Blockly.Generator.prototype.valueToCode = function(block, name, order) { Blockly.Generator.prototype.statementToCode = function(block, name) { var targetBlock = block.getInputTargetBlock(name); var code = this.blockToCode(targetBlock); - if (!goog.isString(code)) { + if (!Blockly.goog.isString(code)) { // Value blocks must return code and order of operations info. // Statement blocks must only return code. throw 'Expecting code from statement block "' + targetBlock.type + '".'; diff --git a/static/third_party/lib/blockly/core/goog-polyfill.js b/static/third_party/lib/blockly/core/goog-polyfill.js new file mode 100644 index 000000000..cd5c9d1f8 --- /dev/null +++ b/static/third_party/lib/blockly/core/goog-polyfill.js @@ -0,0 +1,71 @@ +'use strict'; + +goog.provide('Blockly.goog'); + +/** + * Re-adds functions that were deleted from goog. + * These are polyfills for Closure Library's goog.is* functions. + */ + +/** + * Returns true if the specified value is not undefined. + * @param {?} val Variable to test. + * @return {boolean} Whether variable is defined. + */ +Blockly.goog.isDef = function(val) { + return val !== void 0; +}; + +/** + * Returns true if the specified value is `null`. + * @param {?} val Variable to test. + * @return {boolean} Whether variable is null. + */ +Blockly.goog.isNull = function(val) { + return val === null; +}; + +/** + * Returns true if the specified value is defined and not null. + * @param {?} val Variable to test. + * @return {boolean} Whether variable is defined and not null. + */ +Blockly.goog.isDefAndNotNull = function(val) { + return val != null; +}; + +/** + * Returns true if the specified value is a string. + * @param {?} val Variable to test. + * @return {boolean} Whether variable is a string. + */ +Blockly.goog.isString = function(val) { + return typeof val == 'string'; +}; + +/** + * Returns true if the specified value is a boolean. + * @param {?} val Variable to test. + * @return {boolean} Whether variable is a boolean. + */ +Blockly.goog.isBoolean = function(val) { + return typeof val == 'boolean'; +}; + +/** + * Returns true if the specified value is a number. + * @param {?} val Variable to test. + * @return {boolean} Whether variable is a number. + */ +Blockly.goog.isNumber = function(val) { + return typeof val == 'number'; +}; + +/** + * Returns true if the specified value is a function. + * @param {?} val Variable to test. + * @return {boolean} Whether variable is a function. + */ +Blockly.goog.isFunction = function(val) { + return typeof val == 'function'; +}; \ No newline at end of file diff --git a/static/third_party/lib/blockly/core/input.js b/static/third_party/lib/blockly/core/input.js index 1a03090a6..4da21cf19 100644 --- a/static/third_party/lib/blockly/core/input.js +++ b/static/third_party/lib/blockly/core/input.js @@ -31,6 +31,7 @@ goog.provide('Blockly.Input'); goog.require('Blockly.Connection'); goog.require('Blockly.FieldLabel'); goog.require('goog.asserts'); +goog.require('Blockly.goog'); /** @@ -66,7 +67,7 @@ Blockly.Input.prototype.appendField = function(field, opt_name) { return this; } // Generate a FieldLabel when given a plain text field. - if (goog.isString(field)) { + if (Blockly.goog.isString(field)) { field = new Blockly.FieldLabel(/** @type {string} */ (field)); } if (this.sourceBlock_.svg_) { diff --git a/static/third_party/lib/blockly/core/tooltip.js b/static/third_party/lib/blockly/core/tooltip.js index 876d20cf9..9a6f97dd5 100644 --- a/static/third_party/lib/blockly/core/tooltip.js +++ b/static/third_party/lib/blockly/core/tooltip.js @@ -30,6 +30,7 @@ 'use strict'; goog.provide('Blockly.Tooltip'); +goog.require('Blockly.goog'); /** @@ -173,7 +174,7 @@ Blockly.Tooltip.onMouseOver_ = function(e) { // If the tooltip is an object, treat it as a pointer to the next object in // the chain to look at. Terminate when a string or function is found. var element = e.target; - while (!goog.isString(element.tooltip) && !goog.isFunction(element.tooltip)) { + while (!Blockly.goog.isString(element.tooltip) && !Blockly.goog.isFunction(element.tooltip)) { element = element.tooltip; } if (Blockly.Tooltip.element_ != element) { @@ -267,7 +268,7 @@ Blockly.Tooltip.show_ = function() { /** @type {!Element} */ (Blockly.Tooltip.svgText_)); // Get the new text. var tip = Blockly.Tooltip.element_.tooltip; - if (goog.isFunction(tip)) { + if (Blockly.goog.isFunction(tip)) { tip = tip(); } tip = Blockly.Tooltip.wrap_(tip, Blockly.Tooltip.LIMIT);