ツールボックス

ツールボックスは、ユーザーがブロックを受ける場所です。通常はワークスペースの 片側に表示されますカテゴリがある場合とない場合があります。

このページでは、ツールボックスの構造(ツールボックスに含まれるカテゴリと含まれているブロック)を指定する方法を中心に説明します。ツールボックスの UI を変更する方法の詳細については、Blockly ツールボックスをカスタマイズする Codelab2021 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});

Categories

ツールボックスのブロックはカテゴリ別に整理できます。

上記のツールボックスを定義する方法は次のとおりです。このツールボックスには 2 つのカテゴリ(「制御」と「ロジック」)があり、それぞれにブロックが含まれています。

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>

ネストされたカテゴリ

カテゴリを他のカテゴリ内にネストすることもできます。ここには 2 つのトップレベル カテゴリ(「コア」と「カスタム」)があり、2 番目のサブカテゴリには 2 つのサブカテゴリがあり、それぞれにブロックが含まれています。

1 つのカテゴリに、サブカテゴリとブロックの両方が存在する場合があります。上記の例では、「カスタム」に 2 つのサブカテゴリ(「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>

動的カテゴリ

動的カテゴリとは、開くたびに関数に基づいて動的に再入力されるカテゴリです。

Blockly では、登録済みの文字列キーを介してカテゴリを関数に関連付けることで、これをサポートします。この関数は、カテゴリのコンテンツ(ブロック、ボタン、ラベルなど)の定義を返します。コンテンツは JSON または XML として指定できますが、JSON をおすすめします。

また、この関数ではターゲット ワークスペースがパラメータとして提供されます。動的カテゴリのブロックは、ワークスペースの状態に基づいて設定できます。

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 には、組み込みの動的カテゴリが 3 つ用意されています。

  • '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 ツールボックスのカスタマイズに関する Codelab2021 年の Toolbox API に関する説明をご覧ください。

テーマ

テーマを使用すると、カテゴリの色を含め、ワークスペースのすべての色を一度に指定できます。

カスタム レイアウトを使用するには、カテゴリを特定のカテゴリ スタイルに関連付ける必要があります。

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 です。
  • row - カテゴリのラベルとアイコンを含む div のクラス。デフォルトは blocklyTreeRow です。
  • icon - カテゴリ アイコンのクラス。デフォルトは blocklyTreeIcon です。
  • label - カテゴリラベルのクラス。デフォルトは blocklyTreeLabel です。
  • selected - 選択されたときにカテゴリに追加されるクラス。デフォルトは blocklyTreeSelected です。
  • openicon - カテゴリにネストされたカテゴリがあり、カテゴリが開いているときにアイコンに追加されるクラス。デフォルトは blocklyTreeIconOpen です。
  • closedicon - カテゴリにネストされたカテゴリがあり、閉じられた場合にアイコンに追加されるクラス。デフォルトは blocklyTreeIconClosed です。

そして、どちらかの形式を使用してクラスを指定する方法を以下に示します。

JSON

cssConfig プロパティを使用して、特定の要素タイプの CSS クラスを設定します。

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

XML

特定の要素タイプの CSS クラスを、先頭に「css-」を付けて設定します。

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

アクセス

プログラムでカテゴリにアクセスする方法は 2 つあります。インデックスでアクセスすることもできます(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>

プリセット ブロック

ツールボックス定義には、フィールドがデフォルト値に設定されているブロックや、すでに互いに接続されているブロックが含まれている場合があります。

4 つのブロックがあります。

  1. プリセット値のない単純な logic_boolean ブロック:
  2. デフォルトの 0 ではなく数字 42 を表示するよう変更された math_number ブロック:
  3. 3 つの math_number ブロックが接続された controls_for ブロック:
  4. 2 つの math_number シャドウ ブロックが接続された math_arithmetic ブロック:

これら 4 つのブロックを含むツールボックス定義を以下に示します。

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"
        }
      }
    }
  ]
}

区切り文字

2 つのカテゴリの間に区切り記号を追加すると、2 つのカテゴリの間に行とスペースが追加されます。

区切り文字のクラスは JSON または XML ツールボックス定義で変更できます。

JSON

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

XML

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

2 つのブロックの間にセパレータを追加すると、ブロック間に空白が生じます。 デフォルトでは、すべてのブロックは下位の近傍から 24 ピクセル分分離されます。 この分離は「gap」属性を使用して変更できます。この属性により、デフォルトのギャップが置き換えられます。

これにより、ツールボックスでブロックの論理グループを作成できます。

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 クラス名を指定できます。上記の例では、最初のラベルでカスタム スタイルを使用し、2 番目のラベルでデフォルトのスタイルを使用します。

ボタンにはコールバック関数が必要です。ラベルには使用しないでください。特定のボタンクリックに対するコールバックを 設定するには

yourWorkspace.registerButtonCallback(yourCallbackKey, yourFunction).

関数は、クリックされたボタンを引数として受け入れる必要があります。変数カテゴリの [Create variable...] ボタンは、コールバック付きのボタンの一例です。

ツールボックスの変更

アプリケーションは、1 回の関数呼び出しでいつでもツールボックスの使用可能なブロックを変更できます。

workspace.updateToolbox(newTree);

初期構成の場合と同様に、newTree はノードのツリー、文字列表現、JSON オブジェクトのいずれかになります。唯一の制限は、モードを変更できないことです。つまり、最初に定義されたツールボックスにカテゴリがあった場合、新しいツールボックスもカテゴリを持つ必要があります(カテゴリは変更される可能性があります)。同様に、最初に定義したツールボックスにカテゴリがない場合、新しいツールボックスにカテゴリが存在しないことがあります。

1 つのカテゴリのコンテンツは次の方法で更新できます。

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

ここで、flyoutContents は、JSON を使用して定義されたブロックのリスト、ノードのツリー、または文字列表現です。

現時点では、ツールボックスを更新すると UI が多少リセットされることに注意してください。

  • カテゴリのないツールボックスで、ユーザーが変更したフィールド(プルダウンなど)はデフォルトに戻ります。

カテゴリとブロック グループのツリーのライブデモをご覧ください。