工具箱

工具箱是使用者封鎖畫面的位置。通常會顯示在工作區的某一側。有時這裡有類別,有時則不會顯示。

本頁主要著重於如何指定工具箱的「結構」 (也就是所謂的類別,以及包含的區塊)。如要進一步瞭解如何變更工具箱的 UI,請參閱自訂 Blockly 工具箱程式碼研究室2021 Toolbox API 說明

格式

Blockly 可讓您使用幾種不同格式指定工具箱的結構。新建議格式採用 JSON,舊格式則使用 XML。

以下是指定上述工具箱的各種方式:

JSON

2020 年 9 月版本起,您可以使用 JSON 定義工具箱。

var toolbox = {
    "kind": "flyoutToolbox",
    "contents": [
      {
        "kind": "block",
        "type": "controls_if"
      },
      {
        "kind": "block",
        "type": "controls_whileUntil"
      }
    ]
  };
var workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});

XML

<xml id="toolbox" style="display: none">
  <block type="controls_if"></block>
  <block type="controls_whileUntil"></block>
</xml>
<script>
  var workspace = Blockly.inject('blocklyDiv',
      {toolbox: document.getElementById('toolbox')});
</script>

XML 字串

var toolbox = '<xml>' +
    '<block type="controls_if"></block>' +
    '<block type="controls_whileUntil"></block>' +
    '</xml>';
var workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});

類別

工具箱中的方塊可以依類別整理。

以下說明如何定義上述工具箱,工具箱包含兩個類別 (「Control」和「Logic」),且每個類別皆包含區塊:

JSON

{
  "kind": "categoryToolbox",
  "contents": [
    {
      "kind": "category",
      "name": "Control",
      "contents": [
        {
          "kind": "block",
          "type": "controls_if"
        },
      ]
    },
    {
      "kind": "category",
      "name": "Logic",
      "contents": [
        {
          "kind": "block",
          "type": "logic_compare"
        },
        {
          "kind": "block",
          "type": "logic_operation"
        },
        {
          "kind": "block",
          "type": "logic_boolean"
        }
      ]
    }
  ]
}

XML

<xml id="toolbox" style="display: none">
  <category name="Control">
    <block type="controls_if"></block>
  <category name="Logic">
    <block type="logic_compare"></block>
    <block type="logic_operation"></block>
    <block type="logic_boolean"></block>
  </category>
</xml>

巢狀類別

類別可在其他類別中建立巢狀結構。有兩個頂層類別 (「Core」和「自訂」),第二個類別包含兩個子類別,每個類別都包含區塊:

請注意,類別可能會同時包含子類別「和」區塊。在上述範例中,「Custom」有兩個子類別 (「Move」和「Turn」),以及自己的區塊 (「start」)。

JSON

{
  "kind": "categoryToolbox",
  "contents": [
    {
      "kind": "category",
      "name": "Core",
      "contents": [
        {
          "kind": "block",
          "type": "controls_if"
        },
        {
          "kind": "block",
          "type": "logic_compare"
        },
      ]
    },
    {
      "kind": "category",
      "name": "Custom",
      "contents": [
        {
          "kind": "block",
          "type": "start"
        },
        {
          "kind": "category",
          "name": "Move",
          "contents": [
            {
              "kind": "block",
              "type": "move_forward"
            }
          ]
        },
        {
          "kind": "category",
          "name": "Turn",
          "contents": [
            {
              "kind": "block",
              "type": "turn_left"
            }
          ]
        }
      ]
    }
  ]
}

XML

<xml id="toolbox" style="display: none">
  <category name="Core">
    <block type="controls_if"></block>
    <block type="logic_compare"></block>
  </category>
  <category name="Custom">
    <block type="start"></block>
    <category name="Move">
      <block type="move_forward"></block>
    </category>
    <category name="Turn">
      <block type="turn_left"></block>
    </category>
  </category>
</xml>

動態類別

動態類別是系統在每次開啟函式時,根據函式以動態方式填入的類別。

透過已註冊的字串鍵,將類別與函式建立關聯,藉此區塊支援此功能。此函式應傳回類別內容的定義 (包括區塊、按鈕、標籤等)。雖然建議使用 JSON,但內容可以指定為 JSON 或 XML。

另請注意,函式會提供目標工作區做為參數,因此動態類別中的區塊可以根據工作區的狀態。

JSON

自 2021 年 9 月起,您可以在不使用 'blockxml' 的情況下指定區塊狀態,

// Returns an array of objects.
var coloursFlyoutCallback = function(workspace) {
  // Returns an array of hex colours, e.g. ['#4286f4', '#ef0447']
  var colourList = getPalette();
  var blockList = [];
  for (var i = 0; i < colourList.length; i++) {
    blockList.push({
      'kind': 'block',
      'type': 'colour_picker',
      'fields': {
        'COLOUR': colourList[i]
      }
    });
  }
  return blockList;
};

// Associates the function with the string 'COLOUR_PALETTE'
myWorkspace.registerToolboxCategoryCallback(
    'COLOUR_PALETTE', coloursFlyoutCallback);

舊版 JSON

在 2021 年 9 月推出之前,您必須使用 'blockxml' 屬性指定區塊狀態。

// Returns an array of objects.
var coloursFlyoutCallback = function(workspace) {
  // Returns an array of hex colours, e.g. ['#4286f4', '#ef0447']
  var colourList = getPalette();
  var blockList = [];
  for (var i = 0; i < colourList.length; i++) {
    blockList.push({
      'kind': 'block',
      'type': 'colour_picker', // Type is optional if you provide blockxml
      'blockxml': '<block type="colour_picker">' +
          '<field name="COLOUR">' + colourList[i] + '</field>' +
          '</block>'
    });
  }
  return blockList;
};

// Associates the function with the string 'COLOUR_PALETTE'
myWorkspace.registerToolboxCategoryCallback(
    'COLOUR_PALETTE', coloursFlyoutCallback);

XML

// Returns an arry of XML nodes.
var coloursFlyoutCallback = function(workspace) {
  // Returns an array of hex colours, e.g. ['#4286f4', '#ef0447']
  var colourList = getPalette();
  var blockList = [];
  for (var i = 0; i < colourList.length; i++) {
    var block = document.createElement('block');
    block.setAttribute('type', 'colour_picker');
    var field = document.createElement('field');
    field.setAttribute('name', 'COLOUR');
    field.innerText = colourList[i];
    block.appendChild(field);
    blockList.push(block);
  }
  return blockList;
};

// Associates the function with the string 'COLOUR_PALETTE'
myWorkspace.registerToolboxCategoryCallback(
    'COLOUR_PALETTE', coloursFlyoutCallback);

動態類別函式與字串鍵 (即已註冊) 建立關聯後,您可以將這個字串鍵指派給類別定義中的 custom 屬性,讓類別成為動態類別。

JSON

{
  "kind": "category",
  "name": "Colours",
  "custom": "COLOUR_PALETTE"
}

XML

<category name="Colours" custom="COLOUR_PALETTE"></category>

內建動態類別

Blockly 提供三個內建的動態類別。

  • 'VARIABLE' 會為「未類型」變數建立類別。
  • 'VARIABLE_DYNAMIC' 會為「類型」變數建立類別。內含建立字串、數字和顏色的按鈕
  • 'PROCEDURE' 會建立函式區塊的類別。

JSON

{
  "kind": "category",
  "name": "Variables",
  "custom": "VARIABLE"
},
{
  "kind": "category",
  "name": "Variables",
  "custom": "VARIABLE_DYNAMIC"
},
{
  "kind": "category",
  "name": "Functions",
  "custom": "PROCEDURE"
}

XML

<category name="Variables" custom="VARIABLE"></category>
<category name="Variables" custom="VARIABLE_DYNAMIC"></category>
<category name="Functions" custom="PROCEDURE"></category>

注意:「程序」這個詞在整個 Blockly 程式碼集中都使用,但學生已經可以理解「函式」一詞。很抱歉造成你的不便。

停用中

停用的類別不允許使用者開啟該類別,而會在鍵盤瀏覽期間略過該類別。

var category = toolbox.getToolboxItems()[0];
category.setDisabled('true');

停用類別時,系統會將 'disabled' 屬性新增至 DOM 元素,讓您控制已停用類別的外觀。

.blocklyToolboxCategory[disabled="true"] {
  opacity: .5;
}

正在隱藏

隱藏的類別不會顯示在工具方塊中。隱藏的類別之後可透過 JavaScript 顯示。

JSON

{
  "kind": "category",
  "name": "...",
  "hidden": "true"
}

XML

<category name="..." hidden="true"></category>

JavaScript

var category = toolbox.getToolboxItems()[0];
category.hide();
// etc...
category.show();

展開中

這僅適用於包含其他巢狀類別的類別。

展開的類別會顯示子類別。根據預設,巢狀類別會處於收合狀態,需要按一下才能展開。

JSON

{
  "kind": "category",
  "name": "...",
  "expanded": "true"
}

XML

<category name="..." expanded="true"></sep>

樣式

Blockly 提供預設類別 UI,以及一些基本樣式選項。如要瞭解如何執行 UI 的進階樣式/設定,請參閱自訂 Blockly 工具箱程式碼研究室,以及 2021 Toolbox API 簡介

主題

「Themes」可讓您一次指定工作區的所有顏色,包括類別的顏色。

如要使用這些參數,您必須將類別與特定的類別樣式建立關聯:

JSON

{
  "kind": "category",
  "name": "Logic",
  "categorystyle": "logic_category"
}

XML

<category name="Logic" categorystyle="logic_category"></category>

色款

您也可以直接指定顏色,但我們不建議這麼做。顏色是指定色調的字串數字 (0-360)。請注意英國的拼字。

JSON

{
  "contents": [
    {
      "kind": "category",
      "name": "Logic",
      "colour": "210"
    },
    {
      "kind": "category",
      "name": "Loops",
      "colour": "120"
    }
  ]
}

XML

<xml id="toolbox" style="display: none">
  <category name="Logic" colour="210">...</category>
  <category name="Loops" colour="120">...</category>
  <category name="Math" colour="230">...</category>
  <category name="Colour" colour="20">...</category>
  <category name="Variables" colour="330" custom="VARIABLE"></category>
  <category name="Functions" colour="290" custom="PROCEDURE"></category>
</xml>

請注意,我們也支援使用可本地化的色彩參照

類別 CSS

如需更強大的自訂功能,Blockly 也可讓您為預設 UI 的不同元素指定 CSS 類別。然後,您可以使用 CSS 設定樣式

下列元素類型可套用 CSS 類別:

  • container - 類別的父項 div 類別。預設的 blocklyToolboxCategory
  • bar - 包含類別標籤和圖示的 div 類別。預設的 blocklyTreeRow
  • icon - 類別圖示的類別。預設 blocklyTreeIcon
  • label - 類別標籤的類別。預設 blocklyTreeLabel
  • selected - 會在選取類別時新增至類別。預設的 blocklyTreeSelected
  • openicon - 當類別有巢狀類別且已開啟時,在圖示中新增類別。預設 blocklyTreeIconOpen
  • 關閉圖示 - 當類別包含巢狀類別且已關閉時,在圖示中新增類別。預設 blocklyTreeIconClosed

以下說明使用任一格式指定類別的方式:

JSON

使用 cssConfig 屬性設定特定元素類型的 CSS 類別。

{
  "kind": "category",
  "name": "...",
  "cssConfig": {
    "container": "yourClassName"
  }
}

XML

如要設定特定元素類型的 CSS 類別,請在該元素類型的前面加上「css」值。

<category name="..." css-container="yourClassName"></category>

存取

有兩種方式可以透過程式輔助方式存取類別。您可以依索引進行存取 (其中 0 是頂層類別):

var category = toolbox.getToolboxItems()[0];

或依 ID:

var category = toolbox.getToolboxItemById('categoryId');

此工具方塊定義中會指定 ID 的位置:

JSON

{
  "kind": "category",
  "name": "...",
  "toolboxitemid": "categoryId"
}

XML

<category name="..." toolboxitemid="categoryId"></category>

預設模塊

工具箱定義可能包含的區塊,可能將欄位設為預設值,或是有已連接的區塊。

有四個區塊:

  1. 沒有預設值的簡單 logic_boolean 區塊:
  2. math_number 區塊經過修改,顯示數字 42,而非預設的 0:
  3. controls_for 區塊包含三個 math_number 區塊:
  4. math_arithmetic 區塊連結了兩個 math_number 陰影區塊

以下是包含這四個區塊的工具箱定義:

JSON

自 2021 年 9 月起,您可以使用 'blockxml' 指定區塊清除狀態。

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type": "logic_boolean"
    },
    {
      "kind": "block",
      "type": "math_number",
      "fields": {
        "NUM": 42
      }
    },
    {
      "kind": "block",
      "type": "controls_for",
      "inputs": {
        "FROM": {
          "block": {
            "type": "math_number",
            "fields": {
              "NUM": 1
            }
          }
        },
        "TO": {
          "block": {
            "type": "math_number",
            "fields": {
              "NUM": 10
            }
          }
        },
        "BY": {
          "block": {
            "type": "math_number",
            "fields": {
              "NUM": 1
            }
          }
        },
      }
    },
    {
      "kind": "block",
      "type": "math_arithmetic",
      "fields": {
        "OP": "ADD"
      },
      "inputs": {
        "A": {
          "shadow": {
            "type": "math_number",
            "fields": {
              "NUM": 1
            }
          }
        },
        "B": {
          "shadow": {
            "type": "math_number",
            "fields": {
              "NUM": 1
            }
          }
        }
      }
    },
  ]
}

舊版 JSON

在 2021 年 9 月推出之前,您必須使用 'blockxml' 屬性指定區塊狀態。

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type": "logic_boolean"
    },
    {
      "kind": "block",
      "blockxml":
          '<block type="math_number">' +
          '<field name="NUM">42</field>' +
          '</block>'
    },
    {
      "kind": "block",
      "blockxml":
          '<block type="controls_for">' +
            '<value name="FROM">' +
              '<block type="math_number">' +
                '<field name="NUM">1</field>' +
              '</block>' +
            '</value>' +
            '<value name="TO">' +
              '<block type="math_number">' +
                '<field name="NUM">10</field>' +
              '</block>' +
            '</value>' +
            '<value name="BY">' +
              '<block type="math_number">' +
                '<field name="NUM">1</field>' +
              '</block>' +
            '</value>' +
          '</block>'
    },
    {
      "kind": "block",
      "blockxml":
          '<block type="math_arithmetic">' +
            '<field name="OP">ADD</field>' +
            '<value name="A">' +
              '<shadow type="math_number">' +
                '<field name="NUM">1</field>' +
              '</shadow>' +
            '</value>' +
            '<value name="B">' +
              '<shadow type="math_number">' +
                '<field name="NUM">1</field>' +
              '</shadow>' +
            '</value>' +
          '</block>'
    },
  ]
}

XML

<xml id="toolbox" style="display: none">
  <block type="logic_boolean"></block>

  <block type="math_number">
    <field name="NUM">42</field>
  </block>

  <block type="controls_for">
    <value name="FROM">
      <block type="math_number">
        <field name="NUM">1</field>
      </block>
    </value>
    <value name="TO">
      <block type="math_number">
        <field name="NUM">10</field>
      </block>
    </value>
    <value name="BY">
      <block type="math_number">
        <field name="NUM">1</field>
      </block>
    </value>
  </block>

  <block type="math_arithmetic">
    <field name="OP">ADD</field>
    <value name="A">
      <shadow type="math_number">
        <field name="NUM">1</field>
      </shadow>
    </value>
    <value name="B">
      <shadow type="math_number">
        <field name="NUM">1</field>
      </shadow>
    </value>
  </block>
</xml>

用手寫出這些定義可能會...有些痛苦。您可以改為將區塊載入工作區,然後執行下列程式碼取得定義。這些呼叫之所以有效,是因為工具箱對區塊採用與序列化系統相同的格式。

JSON

console.log(Blockly.serialization.workspaces.save(Blockly.getMainWorkspace()));

XML

console.log(Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()));

您也可以移除 xyid 屬性,因為工具箱會忽略這些屬性。

陰影設定方塊

陰影區塊是可執行多項函式的預留位置區塊:

  • 它們會指出上層區塊的預設值。
  • 可讓使用者直接輸入值,而不必擷取數字或字串區塊。
  • 這與一般區塊不同,如果使用者在上方拖曳區塊,即可取代這些區塊。
  • 可告知使用者預期的值類型。

停用的封鎖條件

您無法從工具箱拖曳已停用的封鎖程式。您可以使用選用的 disabled 屬性個別停用封鎖功能。

JSON

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type":"math_number"
    },
    {
      "kind": "block",
      "type": "math_arithmetic"
    },
    {
      "kind": "block",
      "type": "math_single",
      "disabled": "true"
    }
  ]
}

XML

<xml id="toolbox" style="display: none">
  <block type="math_number"></block>
  <block type="math_arithmetic"></block>
  <block type="math_single" disabled="true"></block>
</xml>

您也可以透過程式輔助方式,使用 setEnabled 停用或啟用區塊。

變數欄位

變數欄位位於工具箱和單純序列化時,可能需要以不同的方式指定。

特別是當變數欄位通常序列化為 JSON 時,只會包含其所代表變數的 ID,因為變數的名稱和類型會分開序列化。然而,工具箱並不包含這類資訊,因此您必須直接加入變數欄位。

{
  "kind": "flyoutToolbox",
  "content": [
    {
      "type": "controls_for",
      "fields": {
        "VAR": {
          "name": "index",
          "type": "Number"
        }
      }
    }
  ]
}

分隔符

在任兩個類別之間加入分隔符,即可在兩個類別之間建立行和額外空間。

您可以在 JSON 或 XML 工具箱定義中變更分隔符的類別。

JSON

{
  "kind": "sep",
  "cssConfig": {
    "container": "yourClassName"
  }
}

XML

<sep css-container="yourClassName"></sep>

在任兩個區塊之間加入分隔符,即可形成區塊之間的間距。根據預設,每個區塊的鄰近區域都會與鄰近區域間隔 24 像素。您可以使用「間隔」屬性變更這項分隔,這將取代預設的差距。

這可讓您在工具箱中建立區塊的邏輯群組。

JSON

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type":"math_number"
    },
    {
      "kind": "sep",
      "gap": "32"
    },
    {
      "kind": "block",
      "blockxml": "<block type='math_arithmetic'><field name='OP'>ADD</field></block>"
    },
    {
      "kind": "sep",
      "gap": "8"
    },
    {
      "kind": "block",
      "blockxml": "<block type='math_arithmetic'><field name='OP'>MINUS</field></block>"
    }
  ]
}

XML

<xml id="toolbox" style="display: none">
  <block type="math_number"></block>
  <sep gap="32"></sep>
  <block type="math_arithmetic">
    <field name="OP">ADD</field>
  </block>
  <sep gap="8"></sep>
  <block type="math_arithmetic">
    <field name="OP">MINUS</field>
  </block>
</xml>

按鈕和標籤

你可以將按鈕或標籤放在可以加入工具箱中的任何位置。

JSON

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type":"logic_operation"
    },
    {
      "kind": "label",
      "text": "A label",
      "web-class": "myLabelStyle"
    },
    {
      "kind": "label",
      "text": "Another label"
    },
    {
      "kind": "block",
      "type": "logic_negate"
    },
    {
      "kind": "button",
      "text": "A button",
      "callbackKey": "myFirstButtonPressed"
    },
    {
      "kind": "block",
      "type": "logic_boolean"
    }
  ]
}

XML

<xml id="toolbox" style="display: none">
  <block type="logic_operation"></block>
  <label text="A label" web-class="myLabelStyle"></label>
  <label text="Another label"></label>
  <block type="logic_negate"></block>
  <button text="A button" callbackKey="myFirstButtonPressed"></button>
  <block type="logic_boolean"></block>
</xml>
    <style>
    .myLabelStyle>.blocklyFlyoutLabelText {
      font-style: italic;
      fill: green;
    }
    </style>

您可以指定要套用至按鈕或標籤的 CSS 類別名稱。在上述範例中,第一個標籤使用自訂樣式,第二個標籤則使用預設樣式。

按鈕應有回呼函式,標籤不應。如要為特定按鈕點擊設定回呼,請使用

yourWorkspace.registerButtonCallback(yourCallbackKey, yourFunction).

您的函式應接受使用者點選按鈕的引數。變數類別中的「建立變數...」按鈕是包含回呼按鈕的絕佳範例。

變更工具箱

應用程式可以透過單一函式呼叫,隨時變更工具箱中可用的區塊:

workspace.updateToolbox(newTree);

如同初始設定期間的情況,newTree 可以是節點的樹狀結構、字串表示法或 JSON 物件。唯一的限制是模式無法變更;也就是說,如果初始定義的工具箱中有類別,新的工具箱也必須有類別 (但類別可能會變更)。同樣地,如果初始定義的工具箱沒有任何類別,新的工具箱可能就不會有任何類別。

你可以透過以下方式更新單一類別的內容:

var category = workspace.getToolbox().getToolboxItems()[0];
category.updateFlyoutContents(flyoutContents);

其中 flyoutContents 可以是使用 JSON 定義的區塊清單、節點樹狀結構或字串表示法。

請注意,目前更新工具箱會導致部分小幅 UI 重設:

  • 在沒有類別的工具方塊中,使用者變更的任何欄位 (例如下拉式選單) 都會還原為預設值。

這裡的現場示範包含類別和區塊群組的樹木。