From 624afeee94ee257b44bf2284bc57810f6460160a Mon Sep 17 00:00:00 2001 From: Andrew n marshall Date: Thu, 26 Jan 2017 15:12:32 -0800 Subject: [PATCH] Blockly.Extensions.buildTooltipForDropdown(..): Deferred validation. (#870) Defer tooltip message string check until after load, when all Blockly.Msg should be loaded. Avoids validation in headless mode, due to lack of document.readyState. --- core/extensions.js | 16 ++++++++++++---- core/utils.js | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/core/extensions.js b/core/extensions.js index 10eaac032..c13e7c867 100644 --- a/core/extensions.js +++ b/core/extensions.js @@ -88,16 +88,23 @@ Blockly.Extensions.buildTooltipForDropdown = function(dropdownName, lookupTable) // List of block types already validated, to minimize duplicate warnings. var blockTypesChecked = []; - // Validate message strings early. - for (var key in lookupTable) { - Blockly.utils.checkMessageReferences(lookupTable[key]); + // Check the tooltip string messages for invalid references. + // Wait for load, in case Blockly.Msg is not yet populated. + // runAfterPageLoad() does not run in a Node.js environment due to lack of + // document object, in which case skip the validation. + if (document) { // Relies on document.readyState + Blockly.utils.runAfterPageLoad(function() { + for (var key in lookupTable) { + Blockly.utils.checkMessageReferences(lookupTable[key]); + } + }); } /** * The actual extension. * @this {Blockly.Block} */ - return function() { + var extensionFn = function() { var thisBlock = this; if (this.type && !blockTypesChecked.includes(this.type)) { @@ -125,6 +132,7 @@ Blockly.Extensions.buildTooltipForDropdown = function(dropdownName, lookupTable) return tooltip; }); }; + return extensionFn; }; /** diff --git a/core/utils.js b/core/utils.js index 2bf60d014..ff00c22b6 100644 --- a/core/utils.js +++ b/core/utils.js @@ -834,3 +834,25 @@ Blockly.utils.insertAfter_ = function(newNode, refNode) { parentNode.appendChild(newNode); } }; + +/** + * Calls a function after the page has loaded, possibly immediately. + * @param {function()} fn Function to run. + * @throws Error Will throw if no global document can be found (e.g., Node.js). + */ +Blockly.utils.runAfterPageLoad = function(fn) { + if (!document) { + throw new Error('Blockly.utils.runAfterPageLoad() requires browser document.'); + } + if (document.readyState === 'complete') { + fn(); // Page has already loaded. Call immediately. + } else { + // Poll readyState. + var readyStateCheckInterval = setInterval(function() { + if (document.readyState === 'complete') { + clearInterval(readyStateCheckInterval); + fn(); + } + }, 10); + } +};