工具箱

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

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

格式

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

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

JSONXMLXML 字串

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

類別

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

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

JSONXML
{
 
"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 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」)。

JSONXML
{
 
"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 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舊版 JSONXML

自 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);

在 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);
// 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 屬性,讓類別成為動態類別。

JSONXML
{
 
"kind": "category",
 
"name": "Colours",
 
"custom": "COLOUR_PALETTE"
}
<category name="Colours" custom="COLOUR_PALETTE"></category>

內建動態類別

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

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

JSONXML
{
 
"kind": "category",
 
"name": "Variables",
 
"custom": "VARIABLE"
},
{
 
"kind": "category",
 
"name": "Variables",
 
"custom": "VARIABLE_DYNAMIC"
},
{
 
"kind": "category",
 
"name": "Functions",
 
"custom": "PROCEDURE"
}
<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 顯示。

JSONXMLJavaScript
{
 
"kind": "category",
 
"name": "...",
 
"hidden": "true"
}
<category name="..." hidden="true"></category>
var category = toolbox.getToolboxItems()[0];
category
.hide();
// etc...
category
.show();

展開中

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

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

JSONXML
{
 
"kind": "category",
 
"name": "...",
 
"expanded": "true"
}
<category name="..." expanded="true"></sep>

樣式

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

主題

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

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

JSONXML
{
 
"kind": "category",
 
"name": "Logic",
 
"categorystyle": "logic_category"
}
<category name="Logic" categorystyle="logic_category"></category>

色款

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

JSONXML
{
 
"contents": [
   
{
     
"kind": "category",
     
"name": "Logic",
     
"colour": "210"
   
},
   
{
     
"kind": "category",
     
"name": "Loops",
     
"colour": "120"
   
}
 
]
}
<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

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

JSONXML

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

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

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

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

存取

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

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

或依 ID:

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

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

JSONXML
{
 
"kind": "category",
 
"name": "...",
 
"toolboxitemid": "categoryId"
}
<category name="..." toolboxitemid="categoryId"></category>

預設模塊

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

有四個區塊:

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

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

JSON舊版 JSONXML

自 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
           
}
         
}
       
}
     
}
   
},
 
]
}

在 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 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>

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

JSONXML
console.log(Blockly.serialization.workspaces.save(Blockly.getMainWorkspace()));
console.log(Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()));

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

陰影設定方塊

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

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

停用的封鎖條件

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

JSONXML
{
 
"kind": "flyoutToolbox",
 
"contents": [
   
{
     
"kind": "block",
     
"type":"math_number"
   
},
   
{
     
"kind": "block",
     
"type": "math_arithmetic"
   
},
   
{
     
"kind": "block",
     
"type": "math_single",
     
"disabled": "true"
   
}
 
]
}
<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 工具箱定義中變更分隔符的類別。

JSONXML
{
 
"kind": "sep",
 
"cssConfig": {
   
"container": "yourClassName"
 
}
}
<sep css-container="yourClassName"></sep>

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

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

JSONXML
{
 
"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 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>

按鈕和標籤

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

JSONXML
{
 
"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 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 重設:

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

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