Controlli di connessione

I controlli di connessione limitano le connessioni (e quindi i blocchi) che possono essere collegate tra loro.

I controlli di connessione sono utili per i tipi di definizione del modello. Ad esempio, i seguenti tre blocchi non hanno alcun motivo di essere collegati, perché rappresentano codice che restituisce tipi diversi:

Un blocco di elenco vuoto, collegato a un blocco di radice quadrata, collegato a un
blocco di lettere maiuscole

I controlli di connessione possono essere utilizzati per impedire la connessione di questi blocchi. In questo modo, gli utenti ricevono un feedback istantaneo e vengono evitati molti errori semplici.

Funzionamento

Ogni collegamento può essere associato a un "controllo connessione", che è un array di stringhe nullable.

Due connessioni possono essere collegate se:

  1. Si tratta di tipi compatibili (ad es. un output collegato a un input).
  2. Hanno almeno una stringa in comune nel controllo di connessione.

Ad esempio, le connessioni con i due controlli seguenti potrebbero essere collegate perché condividono la stringa 'apple':

['apple', 'ball', 'cat']
['apple', 'bear', 'caterpillar']

Tuttavia, i collegamenti con questi due controlli non sono stati possibili perché non condividono alcuna stringa:

['apple', 'ball', 'cat']
['ape', 'bear', 'caterpillar']

Esiste un altro caso speciale. Se uno degli array è null, anche le due connessioni possono essere collegate. In questo modo puoi definire connessioni che possono collegarsi a qualsiasi cosa.

null
['ape', 'bear', 'caterpillar]

Esempi

Per un elenco di esempi su come utilizzare i controlli di connessione, consulta il playbook per i controlli di connessione.

Controlli impostati

Per impostazione predefinita, tutte le connessioni hanno un controllo di connessione null, il che significa che possono collegarsi a qualsiasi cosa. I controlli di connessione devono essere assegnati manualmente.

Il modo in cui assegni i controlli di connessione alle connessioni è diverso a seconda che tu stia utilizzando definizioni di blocchi JSON o JavaScript.

JSON

Per le connessioni di primo livello, assegni il controllo direttamente alla proprietà che definisce la connessione. Il valore assegnato può essere null, una stringa (che diventa l'unica voce nel controllo di connessione) o un array di stringhe.

{
  'type': 'custom_value_block',

  'output': 'a connection check entry',
},
{
  'type': 'custom_statement_block',

  'nextStatement': null, // null check
  'previousStatement': ['four', 'connection', 'check', 'entries']
}

Per gli input, puoi assegnare il controllo a una proprietà check della definizione dell'input. Se la proprietà check non esiste, il controllo viene considerato null. Il valore assegnato può essere una stringa o un array di stringhe.

{
  'type': 'custom_block',
  'message0': '%1 %2',

  'args0': [
    {
      'type': 'input_value',
      'check': 'a connection check entry' // Accepts custom_value_block
    },
    {
      'type': 'input_statement',
      'check': ['two', 'entries'] // Accepts custom_statement_block
    }
  ]
}

JavaScript

Per le connessioni di primo livello, puoi passare il controllo direttamente al metodo che definisce la connessione. Se non specifichi un valore, il controllo viene considerato null. Il valore che passi può essere una stringa (che diventa l'unica voce nel controllo della connessione) o un array di stringhe.

Blockly.Blocks['custom_value_block'] = {
  init: function() {
    this.setOutput(true, 'a connection check entry');
  }
};
Blockly.Blocks['custom_statement_block'] = {
  init: function() {
    this.setNextStatement(true); // null check
    this.setPreviousStatement(true, ['four', 'connection', 'check', 'entries']);
  }
};

Per gli input, puoi passare il controllo al metodo setCheck dopo averli definiti. Se il metodo setCheck non viene chiamato, il controllo viene considerato null. Il valore che passi può essere una stringa o un array di stringhe.

Blockly.Blocks['custom_block'] = {
  init: function() {
    this.appendValueInput('NAME')
        .setCheck('a connection check entry'); // Accepts custom_value_block
    this.appendStatementInput('NAME')
        .setCheck(['two', 'entries']); // Accepts custom_statement_block
  }
};

Stringhe di controllo integrate

I blocchi integrati hanno controlli di connessione con i valori 'Array', 'Boolean', 'Colour', 'Number' e 'String'. Se vuoi che i tuoi blocchi interagiscano con i blocchi integrati, puoi utilizzare questi valori per renderli compatibili.

Limitazioni

Questo sistema è abbastanza solido e può risolvere molti casi d'uso, ma presenta alcune limitazioni.

Limitare il contesto più ampio

Questo sistema non supporta, da solo, la limitazione del "contesto più ampio" in cui è consentita una connessione. Ad esempio, non puoi dire che un blocco break può esistere solo all'interno di un blocco loop. Il sistema di controllo delle connessioni prende in considerazione solo le due connessioni immediate collegate.

Puoi supportare questa funzionalità utilizzando il sistema di eventi per ascoltare gli eventi di spostamento del blocco e verificare se il blocco è posizionato in modo errato.

Blockly.Blocks['custom_block'] = {
  init: function() { }

  onchange: function(e) {
    if (this.workspace.isDragging()) return;
    if (e.type !== Blockly.Events.BlockMove) return;
    if (!this.getSurroundLoop()) this.outputConnection.disconnect();
  }

  loopTypes: new Set(); // Your valid *block types* (not connection checks).

  getSurroundLoop: function () {
    let block = this.getSurroundParent();
    do {
      if (loopTypes.has(block.type)) return block;
      block = block.getSurroundParent();
    } while (block);
    return null;
  },
}

Tipi generici

Questo sistema non supporta, da solo, la definizione di tipi generici. Ad esempio, non puoi creare un blocco "Identità" che "restituisce" qualsiasi input.

Puoi in qualche modo supportare questa operazione modificando attivamente il controllo di connessione sull'output del blocco in modo che corrisponda all'input. Puoi farlo utilizzando il sistema di eventi per ascoltare gli eventi di spostamento dei blocchi.

Blockly.Blocks['custom_block'] = {
  init: function() { }

  onchange: function(e) {
    if (e.type !== Blockly.Events.BlockMove) return;
    this.setOutput(
        true, this.getInputTargetBlock()?.outputConnection.getCheck());
  }
}

Tuttavia, se il blocco collegato è anche generico, il blocco non funziona correttamente. Non esiste una buona soluzione alternativa per questo caso.

Strumenti di controllo della connessione

Se questo sistema non funziona per il tuo caso d'uso, puoi anche modificare il modo in cui vengono confrontati i controlli di connessione creando un controllo di connessione personalizzato.

Ad esempio, se vuoi creare un sistema più avanzato che gestisca alcune delle limitazioni di questo, puoi creare un controllo personalizzato delle connessioni.