scratchfoundation / scratchfoundation/scratch-blocks

Open mutator dialog will cause part of the toolbox not visible

Open
#3,366 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
2.8k
Forks
1.6k
Avg merge
4h 51m
Merged PRs (30d)
12

Description

Expected Behavior

When open a mutator dialog, toolbox remains visible.

Actual Behavior

When open the if else mutator dialog, part of the toolbox not visible like bellow:
Image

when close the mutator dialog, tool box back to normal

Image
Steps to Reproduce

Steps to reproduce the behavior:

  1. create a if else block
import * as Blockly from 'scratch-blocks'

import { BlockInterface } from '@/components/ir-program/program-blockly/blockly-lib/blocks/interface'
import { i18n } from '@/i18n'

/**
 * 代表逻辑 if-else 的 Block
 */
const logicalIfElseBlock: BlockInterface = {
  init() {
    this.jsonInit({
      type: 'logical_if',
      message0: i18n.tc('blockly.block.ifDo'),
      args0: [
        {
          type: 'input_value',
          name: 'IF0',
          check: 'Boolean'
        }
      ],
      message1: '%1',
      args1: [
        {
          type: 'input_statement',
          name: 'DO0'
        }
      ],
      mutator: 'controls_if_mutator',
      category: Blockly.Categories.control,
      extensions: ['colours_control', 'shape_statement']
    })
  },
  gbtInfo() {
    const info = {
      tagName: 'logical',
      type: 'if'
    }
    return info
  }
}

/**
 * 代表 logical_if 变量中 else-if 语句的代码块。
 */
const mutatorElseIfBlock: BlockInterface = {
  init() {
    this.jsonInit({
      type: 'mutator_if_elseif',
      message0: i18n.tc('blockly.block.elseIf'),
      category: Blockly.Categories.control,
      extensions: ['colours_control', 'shape_statement']
    })
  },
  gbtInfo() {
    const info = {
      tagName: 'vice_logical',
      type: 'elif'
    }
    return info
  }
}

/**
 * 代表 logical_if 变量中 else 语句的代码块。
 */
const mutatorElseBlock: BlockInterface = {
  init() {
    this.jsonInit({
      type: 'mutator_if_else',
      message0: i18n.tc('blockly.block.else'),
      category: Blockly.Categories.control,
      extensions: ['colours_control', 'shape_end']
    })
  },
  gbtInfo() {
    const info = {
      tagName: 'logical',
      type: 'else'
    }
    return info
  }
}

/**
 * 代表 logical_if 变量中 if 语句的代码块。
 */
const mutatorIfContainerBlock: BlockInterface = {
  init() {
    this.jsonInit({
      type: 'mutator_if_if',
      message0: i18n.tc('blockly.block.if'),
      nextStatement: false,
      category: Blockly.Categories.control,
      extensions: ['colours_control', 'shape_hat']
    })
  },
  gbtInfo() {
    const info = {
      tagName: 'logical_title',
      type: 'if_title'
    }
    return info
  }
}

/**
 * Mutator 方法
 */
const CONTROLS_IF_MUTATOR_MIXIN = {
  elseifCount_: 0,
  elseCount_: 0,

  /**
   * 创建 XML 来表示 else-if 和 else 输入的数量。
   */
  mutationToDom(this): Element | null {
    if (!this.elseifCount_ && !this.elseCount_) {
      return null
    }
    const container = document.createElement('mutation')
    if (this.elseifCount_) {
      container.setAttribute('elseif', String(this.elseifCount_))
    }
    if (this.elseCount_) {
      container.setAttribute('else', '1')
    }
    return container
  },
  /**
   * 解析 XML 以恢复 else-if 和 else 输入。
   */
  domToMutation(this, xmlElement: Element) {
    this.elseifCount_ = parseInt(xmlElement.getAttribute('elseif') ?? '0', 10)
    this.elseCount_ = parseInt(xmlElement.getAttribute('else') ?? '0', 10)
    this.updateShape_()
  },
  /**
   * 用该程序块的组件填充变形器对话框。
   *
   * @param workspace MutatorIcon 的工作区。
   * @returns Root block in mutator.
   */
  decompose(this, workspace: any) {
    const containerBlock = workspace.newBlock('mutator_if_if')
    containerBlock.initSvg()
    let connection = containerBlock.nextConnection
    for (let i = 1; i <= this.elseifCount_; i++) {
      const elseifBlock = workspace.newBlock('mutator_if_elseif')
      elseifBlock.initSvg()
      connection.connect(elseifBlock.previousConnection)
      connection = elseifBlock.nextConnection
    }
    if (this.elseCount_) {
      const elseBlock = workspace.newBlock('mutator_if_else')
      elseBlock.initSvg()
      connection.connect(elseBlock.previousConnection)
    }
    return containerBlock
  },
  /**
   * 根据变形器对话框的组件重新配置。
   *
   * @param containerBlock Root block in mutator.
   */
  compose(this, containerBlock: any) {
    let clauseBlock = containerBlock.nextConnection?.targetBlock()
    // 计算组件数量.
    this.elseifCount_ = 0
    this.elseCount_ = 0
    while (clauseBlock) {
      // 判断是否为插入标记区块
      if (clauseBlock.isInsertionMarker()) {
        clauseBlock = clauseBlock.getNextBlock()
        continue
      }
      switch (clauseBlock.type) {
        case 'mutator_if_elseif':
          this.elseifCount_++
          break
        case 'mutator_if_else':
          this.elseCount_++
          break
        default:
          throw TypeError(`Unknown block type: ${clauseBlock.type}`)
      }
      clauseBlock = clauseBlock.getNextBlock()
    }
    this.updateShape_()
  },
  /**
   * 存储指向任何相连子块的指针。
   *
   * @param containerBlock Root block in mutator.
   */
  saveConnections(this: any, containerBlock: any) {
    let clauseBlock = containerBlock.nextConnection?.targetBlock()
    let i = 1
    while (clauseBlock) {
      if (clauseBlock.isInsertionMarker()) {
        clauseBlock = clauseBlock.getNextBlock()
        continue
      }
      switch (clauseBlock.type) {
        case 'mutator_if_elseif': {
          const inputIf = this.getInput(`IF${i}`)
          const inputDo = this.getInput(`DO${i}`)
          clauseBlock.valueConnection_ = inputIf && inputIf.connection.targetConnection
          clauseBlock.statementConnection_ = inputDo && inputDo.connection.targetConnection
          i++
          break
        }
        case 'mutator_if_else': {
          const inputDo = this.getInput('ELSE')
          clauseBlock.statementConnection_ = inputDo && inputDo.connection.targetConnection
          break
        }
        default:
          throw TypeError(`Unknown block type: ${clauseBlock.type}`)
      }
      clauseBlock = clauseBlock.getNextBlock()
    }
  },
  /**
   * 更新程序块,以获得正确的输入数。
   */
  updateShape_(this: any) {
    // Delete everything.
    while (this.getInput('DummyDo')) {
      this.removeInput('DummyDo')
    }
    if (this.getInput('ELSE')) {
      this.removeInput('ELSE')
      this.removeInput('DummyElse')
    }
    for (let i = 1; this.getInput(`IF${i}`); i++) {
      this.removeInput(`IF${i}`)
      this.removeInput(`DO${i}`)
    }
    // 重塑
    for (let i = 1; i <= this.elseifCount_; i++) {
      this.appendValueInput(`IF${i}`).setCheck('Boolean').appendField(i18n.tc('blockly.block.elseIf'))
      this.appendDummyInput('DummyDo').appendField(i18n.tc('blockly.block.do'))
      this.appendStatementInput(`DO${i}`)
    }
    if (this.elseCount_) {
      this.appendDummyInput('DummyElse').appendField(i18n.tc('blockly.block.else'))
      this.appendStatementInput('ELSE')
    }
  }
}

/**
 * 注册变形器
 */
Blockly.Extensions.registerMutator('controls_if_mutator', CONTROLS_IF_MUTATOR_MIXIN, null, [
  'mutator_if_elseif',
  'mutator_if_else'
])

/**
 * 注册 logical_if blocks
 */
const registerBlocks = () => {
  Blockly.Blocks.logical_if = logicalIfElseBlock
  Blockly.Blocks.mutator_if_else = mutatorElseBlock
  Blockly.Blocks.mutator_if_elseif = mutatorElseIfBlock
  Blockly.Blocks.mutator_if_if = mutatorIfContainerBlock
}

export default registerBlocks
  1. Click on 'mutator icon'
  2. Check the toolbox
System Details

Windows 10 Chrome 126.0.6478.115

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the issue with the supplied logical_if block registration, then inspect the mutator icon, mutator dialog, and toolbox layout behavior in scratch-blocks. Compare the toolbox before and after opening the dialog in Chrome on Windows. Done means the complete toolbox remains visible while the mutator dialog is open.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
frontend, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.