Skip to content

Commit 0acbdca

Browse files
authored
allow block configs to override builtin blocks (microsoft#11082)
1 parent 2f769c6 commit 0acbdca

1 file changed

Lines changed: 44 additions & 25 deletions

File tree

‎webapp/src/blocks.tsx‎

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,6 +2176,7 @@ export class Editor extends toolboxeditor.ToolboxEditor {
21762176

21772177
protected showFlyoutBlocks(ns: string, color: string, blocks: toolbox.BlockDefinition[]) {
21782178
const filters = this.parent.state.editorState ? this.parent.state.editorState.filters : undefined;
2179+
let configBlocksShown = new Set<string>();
21792180
blocks.sort((f1, f2) => {
21802181
// Sort the blocks
21812182
return (f2.attributes.weight != undefined ? f2.attributes.weight : 50)
@@ -2186,6 +2187,19 @@ export class Editor extends toolboxeditor.ToolboxEditor {
21862187
blockXmlList = this.getButtonXml(block as toolbox.ButtonDefinition);
21872188
} else {
21882189
blockXmlList = this.getBlockXml(block as toolbox.BlockDefinition);
2190+
2191+
if (blockXmlList?.some(element => element?.getAttribute("data-isBlockConfigOverride") === "true")) {
2192+
// Some builtin blocks appear in the toolbox multiple times, for example the if/else
2193+
// and lists_create_with blocks. If one of those has its XML overridden by a block config,
2194+
// we need to make sure we only show it once since all of the snippets will have the same
2195+
// overridden XML.
2196+
if (configBlocksShown.has(block.attributes.blockId)) {
2197+
blockXmlList = undefined;
2198+
}
2199+
else {
2200+
configBlocksShown.add(block.attributes.blockId);
2201+
}
2202+
}
21892203
}
21902204
if (blockXmlList) this.flyoutXmlList = this.flyoutXmlList.concat(blockXmlList);
21912205
})
@@ -2268,12 +2282,29 @@ export class Editor extends toolboxeditor.ToolboxEditor {
22682282
private getBlockXml(block: toolbox.BlockDefinition, ignoregap?: boolean, shadow?: boolean): Element[] {
22692283
const that = this;
22702284
let blockXml: Element;
2285+
2286+
// Check for custom config in scope of the current tutorial step.
2287+
const currTutorialStep = this.parent.state.tutorialOptions?.tutorialStep;
2288+
const currTutorialStepInfo = currTutorialStep !== undefined ? this.parent.state.tutorialOptions.tutorialStepInfo[currTutorialStep] : undefined;
2289+
if (currTutorialStepInfo?.localBlockConfig?.blocks) {
2290+
blockXml = getBlockConfigXml(block, currTutorialStepInfo.localBlockConfig);
2291+
}
2292+
2293+
// Check for custom config in the tutorial's global scope.
2294+
if (!blockXml && this.parent.state.tutorialOptions?.globalBlockConfig?.blocks) {
2295+
blockXml = getBlockConfigXml(block, this.parent.state.tutorialOptions.globalBlockConfig);
2296+
}
2297+
2298+
if (blockXml) {
2299+
blockXml.setAttribute("data-isBlockConfigOverride", "true");
2300+
}
2301+
22712302
// Check if the block is built in, ignore it as it's already defined in snippets
22722303
if (block.attributes.blockBuiltin) {
22732304
pxt.log("ignoring built in block: " + block.attributes.blockId);
22742305
return undefined;
22752306
}
2276-
if (block.builtinBlock) {
2307+
if (block.builtinBlock && !blockXml) {
22772308
// function_return is conditionally added to the toolbox, so it needs a special case
22782309
if (block.attributes.blockId === "function_return") {
22792310
return [pxtblockly.mkReturnStatementBlock()];
@@ -2297,29 +2328,6 @@ export class Editor extends toolboxeditor.ToolboxEditor {
22972328
if (!shouldShowBlock(fn)) return undefined;
22982329
let comp = pxt.blocks.compileInfo(fn);
22992330

2300-
function getBlockConfigXml(blockConfig: pxt.tutorial.TutorialBlockConfig): Element | undefined {
2301-
const entry = blockConfig.blocks.find(entry => entry.blockId === block.attributes.blockId);
2302-
if (entry) {
2303-
const xml = Blockly.utils.xml.textToDom(entry.xml);
2304-
xml.setAttribute("gap", `${pxt.appTarget.appTheme
2305-
&& pxt.appTarget.appTheme.defaultBlockGap && pxt.appTarget.appTheme.defaultBlockGap.toString() || 8}`);
2306-
return xml;
2307-
}
2308-
return undefined;
2309-
}
2310-
2311-
// Check for custom config in scope of the current tutorial step.
2312-
const currTutorialStep = this.parent.state.tutorialOptions?.tutorialStep;
2313-
const currTutorialStepInfo = currTutorialStep !== undefined ? this.parent.state.tutorialOptions.tutorialStepInfo[currTutorialStep] : undefined;
2314-
if (currTutorialStepInfo?.localBlockConfig?.blocks) {
2315-
blockXml = getBlockConfigXml(currTutorialStepInfo.localBlockConfig);
2316-
}
2317-
2318-
// Check for custom config in the tutorial's global scope.
2319-
if (!blockXml && this.parent.state.tutorialOptions?.globalBlockConfig?.blocks) {
2320-
blockXml = getBlockConfigXml(this.parent.state.tutorialOptions.globalBlockConfig);
2321-
}
2322-
23232331
// Create the block XML from block definition.
23242332
if (!blockXml) {
23252333
blockXml = pxtblockly.createToolboxBlock(this.blockInfo, fn, comp, shadow);
@@ -2393,7 +2401,7 @@ export class Editor extends toolboxeditor.ToolboxEditor {
23932401
pxt.log("Couldn't find block for: " + block.attributes.blockId);
23942402
pxt.log(block);
23952403
}
2396-
} else {
2404+
} else if (!blockXml) {
23972405
blockXml = Blockly.utils.xml.textToDom(block.blockXml);
23982406
}
23992407
if (blockXml) {
@@ -2822,4 +2830,15 @@ function maybeCloneBlockForMove(workspace: Blockly.WorkspaceSvg) {
28222830

28232831
Blockly.getFocusManager().focusNode(clone as Blockly.BlockSvg);
28242832
}
2833+
}
2834+
2835+
function getBlockConfigXml(block: toolbox.BlockDefinition, blockConfig: pxt.tutorial.TutorialBlockConfig): Element | undefined {
2836+
const entry = blockConfig.blocks.find(entry => entry.blockId === block.attributes.blockId);
2837+
if (entry) {
2838+
const xml = Blockly.utils.xml.textToDom(entry.xml);
2839+
xml.setAttribute("gap", `${pxt.appTarget.appTheme
2840+
&& pxt.appTarget.appTheme.defaultBlockGap && pxt.appTarget.appTheme.defaultBlockGap.toString() || 8}`);
2841+
return xml;
2842+
}
2843+
return undefined;
28252844
}

0 commit comments

Comments
 (0)