定義區塊

區塊定義可說明區塊的外觀和行為,包括文字、顏色、形狀,以及區塊可以連接的其他區塊。

JSON 格式與 JavaScript API

Blockly 提供兩種定義區塊的方式:JSON 物件和 JavaScript 函式。JSON 格式旨在簡化本地化程序,為具有不同字詞順序的語言開發。定義區塊時建議使用 JSON 格式。

不過,JSON 格式無法直接定義進階功能,例如變動器或驗證工具。這些內容必須以 JavaScript 編寫,通常為擴充功能

使用 Blockly 原始 JavaScript 實作的應用程式也可以直接將區塊定義寫入較低層級的 Blockly API 函式呼叫,如下方各種 JavaScript 範例所示。

JSON

Blockly.defineBlocksWithJsonArray([{
  "type": "string_length",
  "message0": 'length of %1',
  "args0": [
    {
      "type": "input_value",
      "name": "VALUE",
      "check": "String"
    }
  ],
  "output": "Number",
  "colour": 160,
  "tooltip": "Returns number of letters in the provided text.",
  "helpUrl": "http://www.w3schools.com/jsref/jsref_length_string.asp"
}]);

JavaScript

Blockly.Blocks['string_length'] = {
  init: function() {
    this.appendValueInput('VALUE')
        .setCheck('String')
        .appendField('length of');
    this.setOutput(true, 'Number');
    this.setColour(160);
    this.setTooltip('Returns number of letters in the provided text.');
    this.setHelpUrl('http://www.w3schools.com/jsref/jsref_length_string.asp');
  }
};

init 函式會建立區塊的形狀。就這個函式的內容而言,關鍵字 this 是實際建立的區塊。

這兩個範例載入了相同的「string_length」區塊。

在網頁上,系統會使用 initJson 函式載入 JSON 格式。這也允許在 Blockly 網頁上混用這兩種格式。建議您盡可能使用 JSON 定義區塊,並針對 JSON 不支援的區塊定義部分使用 JavaScript。

以下範例中的區塊主要使用 JSON 定義,但透過 JavaScript API 進一步提供動態工具提示。

JavaScript

var mathChangeJson = {
  "message0": "change %1 by %2",
  "args0": [
    {"type": "field_variable", "name": "VAR", "variable": "item", "variableTypes": [""]},
    {"type": "input_value", "name": "DELTA", "check": "Number"}
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 230
};

Blockly.Blocks['math_change'] = {
  init: function() {
    this.jsonInit(mathChangeJson);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      return 'Add a number to variable "%1".'.replace('%1',
          thisBlock.getFieldValue('VAR'));
    });
  }
};

區塊顏色

區塊的主要顏色是由 JSON colour 屬性、block.setColour(..) 函式,或是使用主題及定義區塊樣式來定義。

JSON

{
  // ...,
  "colour": 160,
}

JavaScript

init: function() {
  // ...
  this.setColour(160);
}

詳情請參閱區塊顏色指南

陳述式連線

使用者可使用 nextStatementpreviousStatement 連接器建立區塊序列。在 Blockly 的標準版面配置中,這些連線位於頂端和底部,區塊會垂直堆疊。

具有上一個連接器的區塊不能有「輸出連接器」,反之亦然。「陳述式區塊」是指沒有值輸出的區塊。陳述式區塊通常會有先前的連線和下一個連線。

nextStatementpreviousStatement 連線可以類型,但標準區塊不使用此功能。

下一個連線

在區塊底部建立點,以便系統將其他陳述式堆疊在區塊下方。具有下一個連線但沒有先前連線的區塊通常代表事件,且可以設為使用帽子進行算繪。

JSON

未指定:

{
  ...,
  "nextStatement": null,
}

已輸入 (罕見):

{
  "nextStatement": "Action",
  ...
}

JavaScript

未指定:

this.setNextStatement(true);  // false implies no next connector, the default

已輸入 (罕見):

this.setNextStatement(true, 'Action');

上一個連線

在區塊頂端建立凹口,以便以陳述式堆疊的形式連結。

先前已連線的區塊不能有輸出連線。

JSON

未指定:

{
  ...,
  "previousStatement": null,
}

已輸入 (罕見):

{
  "previousStatement": "Action",
  ...
}

JavaScript

未指定:

this.setPreviousStatement(true);  // false implies no previous connector, the default

已輸入 (罕見):

this.setPreviousStatement(true, 'Action');

區塊輸出

區塊可能含有單一輸出,以在領先邊緣上的男性 Jigsaw 連接器表示。輸出內容會連結至值輸入。有輸出的區塊通常稱為「值區塊」

JSON

未指定:

{
  // ...,
  "output": null,
}

輸入:

{
  // ...,
  "output": "Number",
}

JavaScript

未指定:

init: function() {
  // ...
  this.setOutput(true);
}

輸入:

init: function() {
  // ...
  this.setOutput(true, 'Number');
}

含有輸出連接器的區塊不得也包含先前的陳述式凹槽。

封鎖輸入內容

區塊具有一或多個輸入,其中每個輸入都有一系列的欄位,且可能會結束連線。內建輸入有多種類型。

  • 值輸入:連線至值區塊輸出連線math_arithmetic 區塊 (加減法) 是輸入兩個值的區塊範例。
  • 陳述式輸入:連線至陳述式區塊先前的連線。雖然時迴圈的巢狀區段是陳述式輸入的範例,
  • 虛擬輸入:沒有區塊連線。在將區塊設定為使用外部值輸入內容時,以換行的方式執行。
  • 結尾資料列輸入:沒有區塊連線,而且一律類似換行。

您也可以建立自訂輸入內容來支援自訂算繪

JSON 格式和 JavaScript API 在描述輸入內容時使用的模型稍有不同。

JSON 格式的輸入和欄位

JSON 定義的區塊是以一系列內插訊息字串 ( message0message1、...) 的結構表示,其中每個內插權杖 (%1%2、...) 都是欄位或輸入結尾 (也就是輸入連接器轉譯到相符 JSON argsN 陣列中的輸入端)。此格式旨在簡化國際化。

JSON

{
  "message0": "set %1 to %2",
  "args0": [
    {
      "type": "field_variable",
      "name": "VAR",
      "variable": "item",
      "variableTypes": [""]
    },
    {
      "type": "input_value",
      "name": "VALUE"
    }
  ]
}

內插符記必須完全與 args0 陣列相符:沒有重複項目,也沒有遺漏。符記可按任何順序顯示,以便不同語言變更區塊的版面配置。

內插符記兩側的文字都會使用空格截斷。使用 % 字元的文字 (例如在參照百分比時) 應使用 %%,以免將其解讀為內插權杖。

引數和引數類型的順序會定義區塊的形狀。變更其中一個字串可能會完全變更區塊的版面配置。在字詞順序與英文不同的語言中,這一點尤其重要。假設這個假設語言必須反轉 "set %1 to %2" (如上例中的用法) 必須反轉為 "put %2 in %1"。變更這個字串 (而不更動 JSON 的其餘部分) 會導致以下區塊:

封鎖自動變更欄位順序、建立虛擬輸入,並從外部切換為內部輸入。

也會自動以結尾列輸入內容取代訊息字串中的任何換行字元 (\n)。

JSON

{
  "message0": "set %1\nto %2",
  "args0": [
    {
      "type": "field_variable",
      "name": "VAR",
      "variable": "item",
      "variableTypes": [""]
    },
    {
      "type": "input_value",
      "name": "VALUE"
    }
  ]
}

Args

每個訊息字串都會與相同數字的 args 陣列配對。例如,message0 搭配 args0。內插權杖 (%1%2、...) 是指 args 陣列的項目。每個物件都有 type 字串。其餘的參數會因類型而有所不同:

您也可以定義自己的自訂欄位自訂輸入內容,並將其做為引數傳遞。

每個物件也可能都有 alt 欄位。如果 Blockly 無法辨識物件的 type,則會使用 alt 物件。例如,如果在 Blockly 中新增名為 field_time 的新欄位,使用這個欄位封鎖時,可以使用 alt 為舊版 Blockly 定義 field_input 備用項:

JSON

{
  "message0": "sound alarm at %1",
  "args0": [
    {
      "type": "field_time",
      "name": "TEMPO",
      "hour": 9,
      "minutes": 0,
      "alt":
        {
          "type": "field_input",
          "name": "TEMPOTEXT",
          "text": "9:00"
        }
    }
  ]
}

alt 物件可能有自己的 alt 物件,因此可以鏈結。最後,如果 Blockly 無法在嘗試任何 alt 物件後於 args0 陣列中建立物件,系統就會略過該物件。

如果 message 字串的結尾是並非輸入內容的文字或欄位,系統就會在區塊結尾自動加入虛擬輸入內容。因此,如果區塊的最後一個輸入內容是虛擬的輸入內容,系統可能會從 args 陣列中省略該輸入內容,而且不需要在 message 中插入內插值。自動新增尾隨虛擬輸入可讓譯者變更 message,無需修改 JSON 的其餘部分。請參閱本頁前半部的 "set %1 to %2" (無虛擬輸入) 和 "put %2 in %1" (虛擬輸入) 範例。

implicitAlign0

在極少數情況下,自動建立的結尾虛擬輸入內容必須與 "RIGHT""CENTRE" 對齊。如果未指定,則預設值為 "LEFT"

以下範例中的 message0"send email to %1 subject %2 secure %3",且 Blockly 會自動為第三列新增虛擬輸入內容。將 implicitAlign0 設為 "RIGHT" 可強制將此資料列靠右對齊。這項對齊方式適用於未在 JSON 區塊定義中明確定義的所有輸入,包括在訊息中取代換行字元 ('\n') 的結尾資料列輸入。此外,已淘汰的屬性 lastDummyAlign0 的行為與 implicitAlign0 相同。

設計 RTL (阿拉伯文和希伯來文) 區塊時,左右相反方向。 因此,"RIGHT" 會向左對齊欄位。

message1args1implicitAlign1

部分區塊可自然分為兩個以上的獨立部分。這個重複區塊有兩個資料列:

如果這個區塊是以單一訊息描述,message0 屬性會是 "repeat %1 times %2 do %3"。這個字串對翻譯人員來說不太清楚,因此很難說明 %2 取代的意義。在部分語言中,甚至可能不需要 %2 虛擬輸入。此外,可能有多個區塊想分享第二列的文字。更理想的做法是讓 JSON 使用多則訊息和引數屬性:

JSON

{
  "type": "controls_repeat_ext",
  "message0": "repeat %1 times",
  "args0": [
    {"type": "input_value", "name": "TIMES", "check": "Number"}
  ],
  "message1": "do %1",
  "args1": [
    {"type": "input_statement", "name": "DO"}
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 120
}

任何數量的 messageargsimplicitAlign 屬性都可以用 JSON 格式定義,從 0 開始,並依序遞增。請注意,Block Factory 無法將訊息分割成多個部分,但手動執行這項作業相當簡單。

JavaScript 中的輸入和欄位

JavaScript API 包含每種輸入類型的 append 方法:

JavaScript

this.appendEndRowInput()
    .appendField('for each')
    .appendField('item')
    .appendField(new Blockly.FieldVariable());
this.appendValueInput('LIST')
    .setCheck('Array')
    .setAlign(Blockly.inputs.Align.RIGHT)
    .appendField('in list');
this.appendStatementInput('DO')
    .appendField('do');
this.appendDummyInput()
    .appendField('end');

每個附加方法可以使用 ID 字串,程式碼產生器會使用這個 ID 字串。虛擬和結束資料列輸入內容很少需要參照,且 ID 通常處於未設定狀態。

JavaScript API 也包含用於附加自訂輸入內容的一般 appendInput 方法。請注意,在這種情況下,ID 應直接傳遞至自訂輸入的建構函式。

JavaScript

this.appendInput(new MyCustomInput('INPUT_NAME'))
    .appendField('an example label')

所有 appendInput 方法 (一般和非一般) 都會傳回輸入物件,以便透過方法鏈結進一步設定。有三種內建方法可用於設定輸入。

setCheck

JavaScript

input.setCheck('Number');

這個選用函式可用於檢查已連結輸入的類型。如果將引數設為 null,則預設值,則這個輸入可能會連線至任何區塊。詳情請參閱「類型檢查」。

setAlign

JavaScript

input.setAlign(Blockly.inputs.Align.RIGHT);

這個選用函式可用來對齊欄位 (請見下方說明)。以下三個自我描述性值可當做引數傳遞給這個函式:Blockly.inputs.Align.LEFTBlockly.inputs.Align.RIGHTBlockly.inputs.Align.CENTER

設計 RTL (阿拉伯文和希伯來文) 區塊時,左右相反方向。 因此,Blockly.inputs.Align.RIGHT 會向左對齊欄位。

appendField

建立輸入內容並附加至含有 appendInput 的區塊後,可以選擇在輸入內容中附加任意數量的欄位。這些欄位通常會用做標籤,說明每個輸入內容的用途。

JavaScript

input.appendField('hello');

最簡單的欄位元素是文字。Blockly 慣例是使用小寫文字,但專有名稱除外 (例如 Google、SQL)。

輸入列可包含任意數量的欄位元素。多個 appendField 呼叫可以鏈結在一起,有效率地將多個欄位新增至同一個輸入資料列。

JavaScript

input.appendField('hello')
     .appendField(new Blockly.FieldLabel('Neil', 'person'));

appendField('hello') 呼叫實際上是使用明確 FieldLabel 建構函式 appendField(new Blockly.FieldLabel('hello')) 的捷徑。唯一想使用建構函式的時機,就是指定類別名稱,以便使用 CSS 規則設定文字樣式。

內嵌或外部

區塊輸入可以做為外部或內部轉譯。

區塊定義可以指定選用的布林值,以控制輸入內容是否內嵌。如果設為 false,則任何輸入值都會是外部 (例如左側區塊)。如果設為 true,則所有輸入值都會內嵌 (例如上方的右側區塊)。

JSON

{
  // ...,
  "inputsInline": true
}

JavaScript

init: function() {
  // ...
  this.setInputsInline(true);
}

如未定義, Blockly 會使用一些經驗法則推測最適合的模式。假設 Blockly 做出正確選擇,建議您不要定義這個欄位,因為不同的語言翻譯會自動有不同的模式。請參閱本頁前述的 "set %1 to %2" (外部輸入內容) 和 "put %2 in %1" (內嵌輸入內容) JSON 範例。

如果區塊可能含有小幅輸入內容 (例如數字),請使用內嵌輸入。如果啟用 collapse 設定,使用者可以透過內容選單切換這個選項 (如果工具箱具有類別,則預設為 true)。

欄位

欄位可定義區塊中的大部分 UI 元素,包括字串標籤、圖片和常值資料 (例如字串和數字) 的輸入內容。最簡單的範例為 math_number 區塊,該區塊使用 field_input 讓使用者輸入數字。

使用 appendField 將欄位附加至區塊。

Blockly 提供許多內建欄位,包括文字輸入、顏色挑選器和圖片。您也可以自行建立欄位。

→ 進一步瞭解內建欄位

→ 進一步瞭解建立自訂欄位

圖示

圖示用於定義區塊中的 UI 元素,該區塊會顯示區塊的「中繼」資訊。

使用 addIcon 將圖示附加至區塊。

Blockly 提供多個內建圖示,包括註解圖示和警告圖示。您也可以自行建立圖示。

→ 進一步瞭解如何建立自訂圖示

工具提示

使用者將滑鼠遊標懸停在區塊上時,工具提示會提供即時說明。如果文字過長,系統會自動換行。

JSON

{
  // ...,
  "tooltip": "Tooltip text."
}

JavaScript

init: function() {
  this.setTooltip("Tooltip text.");
}

在 JavaScript API 中,工具提示也可以定義為函式,而非靜態字串。如此便可執行動態說明。請參閱 math_arithmetic 的說明,瞭解可根據使用者選擇的下拉式選單選項變更的工具提示。

JavaScript

Blockly.Blocks['math_arithmetic'] = {
  init: function() {
    // ...

    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      var mode = thisBlock.getFieldValue('OP');
      var TOOLTIPS = {
        'ADD': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
        'MINUS': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
        'MULTIPLY': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
        'DIVIDE': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
        'POWER': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER
      };
      return TOOLTIPS[mode];
    });
  }
};

使用 JavaScript API 時,區塊可以指定函式,而非傳回工具提示字串的靜態字串。這樣一來,您就可以使用動態工具提示。 如需範例,請參閱 math_arithmetic

自訂

您也可以提供自訂算繪函式,藉此自訂工具提示的外觀。建立可接受兩個參數的函式:

  • 第一個,您要在當中轉譯內容的 <div> 元素
  • 第二,實際要將滑鼠遊標懸停在哪些元素上 就會顯示工具提示

您可以在函式主體中,將任何內容轉譯成 div。如要取得將滑鼠移到區塊上定義的工具提示字串,您可以呼叫 Blockly.Tooltip.getTooltipOfObject(element);,其中 element 是上述第二個參數。

最後,註冊這個函式,以便 Blockly 於適當時機呼叫該函式:

Blockly.Tooltip.setCustomTooltip(yourFnHere);

如需範例說明,請參閱自訂工具提示示範

說明網址

您可以為封鎖設定提供相關聯的說明頁面。方法是在 Blockly for Web 的使用者上按一下滑鼠右鍵,然後在內容選單中選取「Help」(說明)。如果這個值為 null,選單會顯示為灰色。

JSON

{
  // ...,
  "helpUrl": "https://en.wikipedia.org/wiki/For_loop"
}

JavaScript

init: function() {
  // ...
  this.setHelpUrl('https://en.wikipedia.org/wiki/For_loop');
}

使用 JavaScript API 時,區塊可以指定函式,而非傳回網址字串的靜態字串,藉此提供動態說明。

變更事件監聽器和驗證工具

區塊可包含變更監聽器函式,系統會在任何工作區變更時呼叫這些函式 (包括與區塊無關的函式)。這些屬性主要是用來設定區塊的警告文字,或設定工作區以外的類似使用者通知。

這個函式是透過函式呼叫 setOnChange 的方式,可在初始化期間或透過 JSON 擴充功能完成 (如果您打算在所有平台上使用)。

JSON

{
  // ...,
  "extensions":["warning_on_change"],
}

Blockly.Extensions.register('warning_on_change', function() {
  // Example validation upon block change:
  this.setOnChange(function(changeEvent) {
    if (this.getInput('NUM').connection.targetBlock()) {
      this.setWarningText(null);
    } else {
      this.setWarningText('Must have an input block.');
    }
  });
});

JavaScript

Blockly.Blocks['block_type'] = {
  init: function() {
    // Example validation upon block change:
    this.setOnChange(function(changeEvent) {
      if (this.getInput('NUM').connection.targetBlock()) {
        this.setWarningText(null);
      } else {
        this.setWarningText('Must have an input block.');
      }
    });
  }
}

系統會呼叫函式並傳入變更事件。在函式中,this 是指區塊執行個體。

由於函式會在任何變更上呼叫,因此如果使用這個函式,開發人員應確保事件監聽器能快速執行。如果工作區有所變更,且可能會收合或循環回事件監聽器,也請特別留意。

如需範例,請參閱 controls_flow_statementslogic_compareprocedures_ifreturn 區塊。

請注意,可編輯的欄位有專屬的用於輸入驗證的事件監聽器,並造成副作用。

更動後

更動子可讓進階區塊變更形狀,最明顯的是,使用者開啟對話方塊以新增、移除或重新排列元件時。您可以使用 mutator 鍵透過 JSON 新增變動器。

JSON

{
  // ...,
  "mutator":"if_else_mutator"
}

個別區塊設定

區塊執行個體有許多屬性,可以設定如何對使用者的行為。這些引數可用於限制工作區以反映網域的特定屬性 (例如,只有一個「start」事件),或聚焦於使用者的努力 (例如教學課程)。

可刪除狀態

block.setDeletable(false);

如果設為 False,使用者就無法刪除封鎖。封鎖功能預設為在可編輯的工作區中刪除。

任何區塊 (甚至是可刪除的封鎖) 可以透過程式輔助方式刪除:

block.dispose();

可編輯狀態

block.setEditable(false);

如果設為 false,使用者就無法變更區塊的欄位 (例如下拉式選單和文字輸入內容)。封鎖設定預設為在可編輯的工作區中編輯。

可移動狀態

block.setMovable(false);

如果設為 false,使用者就無法直接移動區塊。一個是另一個區塊的不可移除區塊,可能不會與該區塊取消連結,不過在父項移動時,它會隨其父項移動。封鎖設定預設為在可編輯的工作區上移動。

將區塊 (甚至是不可移動的區塊) 放入工作區後,即可以程式輔助方式移動任何區塊。

block.moveBy(dx, dy)

工作區上區塊的起始位置預設為 (0, 0)。

封鎖資料

this.data = '16dcb3a4-bd39-11e4-8dfc-aa07a5b093db';

資料是選用且附加至區塊的任意字串。當區塊序列化資料字串時,就會使用該字串進行序列化。這包括複製或複製區塊。

通常用於將區塊與外部資源建立關聯。

序列化為 JSON 時,資料會以區塊中的頂層屬性的形式儲存:

{
  "type": "my_block",
  "data": "16dcb3a4-bd39-11e4-8dfc-aa07a5b093db",
  // etc..
}

序列化為 XML (舊版冰箱序列化系統) 時,資料字串會儲存在區塊的 <data></data> 標記內:

<block type="my_block">
  <data>16dcb3a4-bd39-11e4-8dfc-aa07a5b093db</data>
  <!-- etc... -->
</block>

破壞

區塊有 destroy 掛鉤,系統會在從工作區刪除這些區塊時呼叫該掛鉤。這可用來刪除與區塊相關聯的任何備份資料模型/外部資源,不再需要這些資源。

JSON

{
  // ...,
  "extensions":["destroy"],
}

Blockly.Extensions.registerMixin('destroy', {
  destroy: function() {
    this.myResource.dispose();
  }
});

JavaScript

Blockly.Blocks['block_type'] = {
  destroy: function() {
    this.myResource.dispose();
  }
}

系統會在區塊的父項已被捨棄,但在子項或欄位棄置之前,呼叫 destroy 方法。

內容選單

根據預設,區塊的內容選單可以按一下滑鼠右鍵,讓使用者執行新增註解或複製區塊等動作。

如要停用個別區塊的內容選單,請按照下列步驟操作:

block.contextMenu = false;

您也可以自訂選單中顯示的選項。如要自訂所有區塊的選單,請參閱內容選單說明文件。如要自訂個別區塊的選單,可以實作 customContextMenu。這個函式會採用選單選項陣列,並視情況修改選單選項,也就是說,您可以新增或移除項目。

每個選單選項都是包含三個屬性的物件:

  • text 是顯示文字。
  • enabled 為布林值。停用後,這個選項會顯示為灰色,但會顯示灰色。
  • callback 是點選選項時要呼叫的函式。