Strumenti

La toolbox è il punto in cui gli utenti ricevono blocchi. Di solito è visualizzata su un lato dello spazio di lavoro. A volte ci sono categorie, altre no.

Questa pagina si concentra principalmente su come specificare la struttura dei tuoi strumenti (ovvero quali categorie include e quali blocchi contengono). Se vuoi maggiori dettagli su come modificare l'UI dei tuoi strumenti, consulta il codelab per la personalizzazione di un strumento Blockly e la guida sulle API degli strumenti Blockly del 2021.

Formati

Blockly ti consente di specificare la struttura della toolbox utilizzando alcuni formati diversi. Il nuovo formato consigliato utilizza JSON, mentre il vecchio formato XML.

Ecco i diversi modi in cui puoi specificare gli strumenti indicati sopra:

JSON

A partire dalla release di settembre 2020, gli strumenti possono essere definiti utilizzando 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>

Stringa XML

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

Categorie

I blocchi del riquadro degli strumenti possono essere organizzati in categorie.

Ecco i modi in cui puoi definire la casella degli strumenti riportata sopra, che ha due categorie ("Controllo" e "Logica"), ciascuna delle quali contiene blocchi:

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>

Categorie nidificate

Le categorie possono essere nidificate all'interno di altre categorie. Di seguito sono riportate due categorie di primo livello, "Principale" e "Personalizzata", la seconda contiene due sottocategorie, ognuna delle quali contiene blocchi:

Tieni presente che una categoria può contenere sia sottocategorie sia blocchi. Nell'esempio precedente, la categoria "Personalizzato" presenta due sottocategorie ("Sposta" e "Giro") e un blocco separato ("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>

Categorie dinamiche

Le categorie dinamiche sono categorie che vengono ricompilate dinamicamente in base a una funzione ogni volta che vengono aperte.

Blockly supporta questa operazione consentendo di associare una categoria a una funzione tramite una chiave di stringa registrata. La funzione deve restituire una definizione dei contenuti di una categoria (inclusi blocchi, pulsanti, etichette e così via). I contenuti possono essere specificati come JSON o XML, anche se si consiglia JSON.

Inoltre, tieni presente che alla funzione viene fornita come parametro l'area di lavoro di destinazione, in modo che i blocchi nella categoria dinamica possano essere basati sullo stato dell'area di lavoro.

JSON

A partire dalla release di settembre 2021, puoi specificare lo stato dei blocchi senza utilizzare '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 precedente

Prima della release di settembre 2021, dovevi utilizzare la proprietà 'blockxml' per specificare lo stato dei blocchi.

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

Dopo aver associato le funzioni di categoria dinamica a una chiave stringa (nota anche come registrata), puoi assegnare questa chiave alla proprietà custom della definizione della tua categoria per renderla dinamica.

JSON

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

XML

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

Categorie dinamiche integrate

Blockly fornisce tre categorie dinamiche integrate.

  • 'VARIABLE' crea una categoria per le variabili non digitate.
  • 'VARIABLE_DYNAMIC' crea una categoria per le variabili tipizzate. Ha pulsanti per creare stringhe, numeri e colori.
  • 'PROCEDURE' crea una categoria per i blocchi funzione.

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>

Nota: il termine "procedura" viene utilizzato in tutto il codebase di Blockly, ma il termine "funzione" è risultato essere più comprensibile per gli studenti. Ci scusiamo per l'inconveniente.

Disabilitazione in corso…

Una categoria disattivata non consente a un utente di aprirla e verrà saltata durante la navigazione da tastiera.

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

Quando una categoria viene disattivata, viene aggiunta una proprietà 'disabled' all'elemento DOM, per consentirti di controllare l'aspetto di una categoria disattivata.

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

Impostazione come nascosto in corso…

Una categoria nascosta non verrà visualizzata come parte della toolbox. Le categorie nascoste possono essere mostrate in un secondo momento tramite JavaScript.

JSON

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

XML

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

JavaScript

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

Espansione in corso

Questo vale solo per le categorie che contengono altre categorie nidificate.

Una categoria espansa mostra le relative categorie secondarie. Per impostazione predefinita, le categorie nidificate sono compresse e devono essere selezionate per essere espanse.

JSON

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

XML

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

Stili

Blockly fornisce un'interfaccia utente predefinita per le categorie, insieme ad alcune opzioni di base per lo stile. Se vuoi informazioni su come eseguire stili/configurazioni più avanzate dell'interfaccia utente, consulta il codelab per la personalizzazione di uno degli strumenti Blockly e la sezione relativa alle API degli strumenti Blockly 2021.

Temi

I temi ti consentono di specificare tutti i colori della tua area di lavoro contemporaneamente, compresi quelli delle nostre categorie.

Per utilizzarle, devi associare la tua categoria a uno specifico stile di categoria:

JSON

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

XML

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

Colori

Puoi anche specificare direttamente il colore, ma ciò non è consigliato. Il colore è un numero stringato (0-360) che specifica la tonalità. Nota l'ortografia britannica.

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>

Tieni presente che supportiamo anche l'utilizzo di riferimenti sui colori localizzabili.

CSS categoria

Se vuoi una personalizzazione più efficace, Blockly ti consente anche di specificare le classi CSS per i diversi elementi dell'interfaccia utente predefinita. Puoi quindi utilizzare CSS per definire uno stile.

Ai seguenti tipi di elementi possono essere applicate classi CSS:

  • container - La classe dell'elemento div principale della categoria. Valore predefinito blocklyToolboxCategory.
  • riga . La classe del div contenente l'icona e l'etichetta della categoria. Valore predefinito blocklyTreeRow.
  • icon - Il corso per l'icona della categoria. Valore predefinito: blocklyTreeIcon.
  • label - La classe dell'etichetta della categoria. Valore predefinito: blocklyTreeLabel.
  • selected - Il corso che viene aggiunto alla categoria quando viene selezionata. Valore predefinito blocklyTreeSelected.
  • openicon - Il corso aggiunto a un'icona quando la categoria ha categorie nidificate ed è aperta. Valore predefinito: blocklyTreeIconOpen.
  • closedicon - Il corso aggiunto a un'icona quando la categoria contiene categorie nidificate ed è chiusa. Valore predefinito: blocklyTreeIconClosed.

Ecco come specificare le classi utilizzando uno dei due formati:

JSON

Imposta la classe CSS di un determinato tipo di elemento utilizzando la proprietà cssConfig.

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

XML

Imposta la classe CSS di un determinato tipo di elemento anteponendovi "css-".

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

Accesso in corso...

Esistono due modi per accedere a una categoria in modo programmatico. Puoi accedervi tramite l'indice (dove 0 è la categoria principale):

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

Oppure per ID:

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

Dove l'ID è specificato nella definizione della casella degli strumenti:

JSON

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

XML

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

Blocchi preimpostati

La definizione della casella degli strumenti può contenere blocchi con campi impostati su un valore predefinito o blocchi già collegati tra loro.

Ecco quattro blocchi:

  1. Un semplice blocco logic_boolean senza valori preimpostati:
  2. Un blocco math_number che è stato modificato per visualizzare il numero 42 anziché il valore predefinito 0:
  3. Un blocco controls_for a cui sono collegati tre blocchi math_number:
  4. Un blocco math_arithmetic a cui sono collegati due blocchi ombra math_number:

Di seguito è riportata una definizione di toolbox contenente questi quattro blocchi:

JSON

A partire dalla release di settembre 2021, puoi specificare lo stato dei blocchi senza utilizzare '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 precedente

Prima della release di settembre 2021, dovevi utilizzare la proprietà 'blockxml' per specificare lo stato dei blocchi.

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

Scrivere queste definizioni manualmente può essere... un po' complicato. Puoi invece caricare i blocchi in un'area di lavoro e quindi eseguire il codice seguente per ottenere le definizioni. Queste chiamate funzionano perché il toolbox utilizza per i blocchi lo stesso formato del sistema di serializzazione.

JSON

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

XML

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

Puoi anche rimuovere le proprietà x, y e id perché sono ignorate dagli strumenti.

Blocchi di ombra

I blocchi di ombra sono blocchi segnaposto che svolgono diverse funzioni:

  • Indicano i valori predefiniti per il blocco principale.
  • Consentono agli utenti di digitare i valori direttamente senza dover recuperare un blocco di numeri o stringhe.
  • A differenza di un blocco normale, vengono sostituiti se l'utente vi sposta sopra un blocco.
  • Comunicano all'utente il tipo di valore previsto.

Blocchi disattivati

I blocchi disattivati non possono essere trascinati dalla casella degli strumenti. I blocchi possono essere disabilitati singolarmente utilizzando la proprietà facoltativa 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>

Puoi anche disattivare o attivare un blocco in modo programmatico utilizzando setEnabled.

Campi variabili

Potrebbe essere necessario specificare i campi variabili in modo diverso quando sono inseriti in una serie di strumenti rispetto a quando sono semplicemente serializzati.

In particolare, quando i campi variabili sono normalmente serializzati in JSON, contengono solo l'ID della variabile che rappresentano, poiché il nome e il tipo di variabile sono serializzati separatamente. Tuttavia, le toolbox non contengono queste informazioni, quindi devono essere incluse direttamente nel campo della variabile.

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

Separatori

L'aggiunta di un separatore tra due categorie qualsiasi creerà una riga e uno spazio in più tra le due categorie.

Puoi modificare la classe del separatore nella definizione della casella degli strumenti JSON o XML.

JSON

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

XML

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

L'aggiunta di un separatore tra due blocchi qualsiasi creerà uno spazio tra i blocchi. Per impostazione predefinita, ogni blocco è separato dal suo vicino inferiore di 24 pixel. Questa separazione può essere modificata utilizzando l'attributo "gap", che sostituirà il divario predefinito.

In questo modo puoi creare gruppi logici di blocchi.

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>

Pulsanti ed etichette

Puoi inserire un pulsante o un'etichetta ovunque sia possibile inserire un blocco nella casella degli strumenti.

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>

Puoi specificare un nome di classe CSS da applicare al pulsante o all'etichetta. Nell'esempio precedente, la prima etichetta utilizza uno stile personalizzato, mentre la seconda utilizza lo stile predefinito.

I pulsanti devono avere funzioni di callback, ma non le etichette. Per impostare il callback per un determinato clic su un pulsante,

yourWorkspace.registerButtonCallback(yourCallbackKey, yourFunction).

La funzione deve accettare come argomento il pulsante su cui è stato fatto clic. Il pulsante "Crea variabile..." nella categoria di variabili è un buon esempio di pulsante con callback.

Cambiare gli strumenti

L'applicazione può modificare i blocchi disponibili nella toolbox in qualsiasi momento con una singola chiamata di funzione:

workspace.updateToolbox(newTree);

Come nel caso della configurazione iniziale, newTree può essere una struttura di nodi, una rappresentazione stringa o un oggetto JSON. L'unica limitazione è che la modalità non può essere modificata; ovvero, se nel toolbox inizialmente definito esistevano categorie, anche il nuovo toolbox deve contenere categorie (sebbene le categorie possano cambiare). Analogamente, se lo strumento definito inizialmente non aveva categorie, la nuova Casella degli strumenti potrebbe non contenere alcuna categoria.

I contenuti di una singola categoria possono essere aggiornati nei seguenti modi:

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

dove flyoutContents può essere un elenco di blocchi definiti utilizzando JSON, una struttura di nodi o una rappresentazione di stringa.

Tieni presente che al momento l'aggiornamento del riquadro degli strumenti causa alcune reimpostazioni di minore entità dell'interfaccia utente:

  • In una casella degli strumenti senza categorie, per i campi modificati dall'utente (ad esempio un menu a discesa) verranno ripristinati i valori predefiniti.

Ecco una demo dal vivo di un albero con categorie e gruppi di blocchi.