From 95b6becced531bcfd0b08fdbd2fac5717e61f5f9 Mon Sep 17 00:00:00 2001 From: divyanshu_Kumar <154233802+d1vyanshu-kumar@users.noreply.github.com> Date: Fri, 24 Jan 2025 03:36:31 +0530 Subject: [PATCH] Fix #3335: Detect and handle unavailable extensions in dragged PNGs --- .../blocklyeditor/src/exportBlocksImage.js | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/appinventor/blocklyeditor/src/exportBlocksImage.js b/appinventor/blocklyeditor/src/exportBlocksImage.js index 8e379bb3e0d..b8d470b761d 100644 --- a/appinventor/blocklyeditor/src/exportBlocksImage.js +++ b/appinventor/blocklyeditor/src/exportBlocksImage.js @@ -517,6 +517,75 @@ Blockly.exportBlockAsPng = function(block) { }); }; +/** + * Extracts the block types from the given XML. + * @param {Document} xml - The XML document containing blocks. + * @returns {Array} An array of block types. + */ +function extractBlockTypes(xml) { + var blockTypes = []; + var blocks = xml.getElementsByTagName('block'); + for (var i = 0; i < blocks.length; i++) { + var mutation = blocks[i].getElementsByTagName('mutation')[0]; + if (mutation) { + var componentType = mutation.getAttribute('component_type'); + if (componentType) { + blockTypes.push(componentType); + } + } + } + return blockTypes; +} + +/** + * Validates the block types against the component database in the workspace. + * @param {Array} blockTypes - The block types to validate. + * @param {Blockly.WorkspaceSvg} workspace - The workspace containing the component database. + * @returns {Array} An array of missing component types. + */ +function validateBlockTypes(blockTypes, workspace) { + if (!blockTypes || blockTypes.length === 0) { + console.warn('No block types provided for validation.'); + return []; + } + + var componentDb = workspace.getComponentDatabase(); + if (!componentDb) { + console.error('Component database is not available.'); + return []; + } + + var missingExtensions = []; + for (var i = 0; i < blockTypes.length; i++) { + var typeDescriptor = componentDb.getType(blockTypes[i]); + if (!typeDescriptor || !typeDescriptor.componentInfo || typeDescriptor.componentInfo.name !== blockTypes[i]) { + missingExtensions.push(blockTypes[i]); + } + } + + if (missingExtensions.length > 0) { + console.warn('Missing component types:', missingExtensions.join(', ')); + } + return missingExtensions; +} + +/** + * Displays a dialog showing the missing extensions. + * @param {Array} missingExtensions - The missing component types. + */ +function showMissingExtensionDialog(missingExtensions) { + // Filter out undefined or null values + missingExtensions = missingExtensions.filter(function(extension) { + return extension !== undefined && extension !== null; + }); + + if (missingExtensions.length > 0) { + var message = 'This image references the following blocks which require extensions that are not present in the project:\n\n'; + message += missingExtensions.join('\n'); + alert(message); + } +} + /** * Imports a block from a PNG file if the code chunk is present. * @param {!Blockly.WorkspaceSvg} workspace the target workspace for the block @@ -529,6 +598,18 @@ Blockly.importPngAsBlock = function(workspace, xy, png) { if (xmlChunk) { var xmlText = new TextDecoder().decode(xmlChunk.data); var xml = /** @type {!Element} */ (Blockly.utils.xml.textToDom(xmlText)); + if (!xml) { + console.error('Failed to parse XML from PNG.'); + return; + } + var blockTypes = extractBlockTypes(xml); + + var missingExtensions = validateBlockTypes(blockTypes, workspace); + if (missingExtensions.length > 0) { + showMissingExtensionDialog(missingExtensions); + return; + } + xml = xml.firstElementChild; var block = /** @type {Blockly.BlockSvg} */ (Blockly.Xml.domToBlock(xml, workspace)); block.moveBy(xy.x, xy.y);