Rozszerzenia i mutatory

Rozszerzenia to funkcje, które działają w każdym bloku danego typu, gdy blok jest Utworzono. Często powodują one dodanie do bloku niestandardowej konfiguracji lub zachowania.

Mutator to szczególnego rodzaju rozszerzenie, które dodaje niestandardową serializację. lub innym.

Rozszerzenia

Rozszerzenia to funkcje, które działają w każdym bloku danego typu, gdy blok jest Utworzono. Może dodać konfigurację niestandardową (np. ustawić etykietkę bloku) lub zachowanie niestandardowe (np. dodanie do bloku detektora zdarzeń).

// This extension sets the block's tooltip to be a function which displays
// the parent block's tooltip (if it exists).
Blockly.Extensions.register(
    'parent_tooltip_extension',
    function() { // this refers to the block that the extension is being run on
      var thisBlock = this;
      this.setTooltip(function() {
        var parent = thisBlock.getParent();
        return (parent && parent.getInputsInline() && parent.tooltip) ||
            Blockly.Msg.MATH_NUMBER_TOOLTIP;
      });
    });

Rozszerzenia muszą być „zarejestrowane” aby można je było powiązać z ciągiem . Następnie możesz przypisać ten klucz ciągu do właściwości extensions na Twojej JSON dla typu bloku definicji, aby zastosować z blokiem.

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

Możesz też dodać wiele rozszerzeń jednocześnie. Pamiętaj, że w polu extensions musi być tablicą, nawet jeśli stosujesz tylko jedno rozszerzenie.

{
  //...,
  "extensions": ["parent_tooltip_extension", "break_warning_extension"],
}

Składanki

Blockly to także wygodna metoda w sytuacjach, w których chcesz dodawać właściwości/funkcje pomocnicze w danym bloku, ale nie uruchamiają ich od razu. Ten działa, umożliwiając zarejestrowanie składniki , który zawiera wszystkie dodatkowe właściwości/metody. Obiekt wymieszania jest następnie opakowana w funkcji, która stosuje mieszankę za każdym razem, gdy wystąpienie podany typ blokady.

Blockly.Extensions.registerMixin('my_mixin', {
  someProperty: 'a cool value',

  someMethod: function() {
    // Do something cool!
  }
))`

Do kluczy łańcuchowych powiązanych z kombinacjami można się odwoływać w formacie JSON tak jak do każdego innego .

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

Mutatory

Mutator to specjalny typ rozszerzenia, który dodaje serializację (dodatkowe który jest zapisywany i wczytywany) do bloku. Dotyczy to na przykład wbudowanego Bloki controls_if i list_create_with wymagają dodatkowej serializacji, mogą zapisać liczbę podanych danych wejściowych.

Pamiętaj, że zmiana kształtu bryły nie musi oznaczać konieczności to dodatkowa serializacja. Na przykład blok math_number_property zmienia się kształtu, ale robi to na podstawie pola rozwijanego, którego wartość jest zserializowany. W ten sposób można użyć po prostu pola, walidatorowi i nie potrzebujesz mutatora.

Zapoznaj się z artykułem o serializacji strony w przypadku o tym, kiedy potrzebujesz mutatora, a kiedy nie.

Mutatory mają też wbudowany interfejs użytkownika, za pomocą którego użytkownik może zmieniać kształt brył, możesz udostępnić kilka metod opcjonalnych.

Punkty zaczepienia serializacji

Mutatory mają dwie pary punktów zaczepienia serializacji, z którymi współpracują. 1 para haczyków działa z nowym systemem serializacji JSON, a druga para działa z starego systemu serializacji XML. Musisz podać co najmniej jedną z tych par.

SaveExtraState i loadExtraState

saveExtraState i loadExtraState to punkty zaczepienia serializacji, które współpracują z parametrami nowego systemu serializacji JSON. saveExtraState zwraca serializowalny kod JSON wartość, która reprezentuje dodatkowy stan bloku, oraz loadExtraState akceptuje tę samą serializowalną wartość JSON i stosuje ją do bloku.

// These are the serialization hooks for the lists_create_with block.
saveExtraState: function() {
  return {
    'itemCount': this.itemCount_,
  };
},

loadExtraState: function(state) {
  this.itemCount_ = state['itemCount'];
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

Wynikowy kod JSON będzie wyglądał tak:

{
  "type": "lists_create_with",
  "extraState": {
    "itemCount": 3 // or whatever the count is
  }
}
Brak stanu

Jeśli podczas serializacji blok jest w stanie domyślnym, Metoda saveExtraState może zwracać wartość null, aby to zaznaczyć. Jeśli Metoda saveExtraState zwraca wartość null, następnie do argumentu nie dodano żadnej właściwości extraState w formacie JSON. Dzięki temu rozmiar zapisywanego pliku będzie niewielki.

Pełna serializacja i dane kopii zapasowej

Funkcja saveExtraState otrzymuje też opcjonalny parametr doFullSerialization. Ten jest używany przez bloki, które odwołują się do stanu zserializowanego przez inny serializer (np. zapasowe modele danych). Parametr ten informuje, wskazany stan nie będzie dostępny, gdy blok zostanie deserializowany, więc powinien zserializować cały stan kopii zapasowej. Na przykład jest to true (prawda), gdy pojedynczy blok jest zserializowany lub gdy blok jest skopiowany i wklejony.

Są to 2 częste przypadki użycia:

  • Gdy pojedynczy blok jest wczytywany do obszaru roboczego, w którym dane zapasowe model nie istnieje, ale ma w swoim stanie wystarczająco dużo informacji, w celu utworzenia nowego modelu danych.
  • Kopiowanie i wklejanie bloku zawsze powoduje utworzenie nowej kopii zapasowej model danych zamiast odwoływania się do istniejącego.

Niektóre bloki, które z niego korzystają, to blokady @blockly/block-shareable-procedures. Normalnie zserializują odwołanie do bazowego modelu danych, w którym znajduje się ich stan. Jeśli jednak parametr doFullSerialization ma wartość prawda, zserializowane są wszystkie wartości ze swojego stanu. Korzystają z niej blokady procedury udostępniania, aby mieć pewność, że są kopiowane i wklejane, co pozwala utworzyć nowy bazowy model danych, zamiast odwoływać się istniejącego modelu.

mutationToDom i domToMutation

mutationToDom i domToMutation to punkty zaczepienia serializacji, które współpracują z parametrami starego systemu serializacji XML. Używaj tych haczyków tylko wtedy, gdy jest to konieczne (np. na starej bazie kodu, która nie została jeszcze przeniesiona), w przeciwnym razie użyj saveExtraState i loadExtraState.

mutationToDom zwraca węzeł XML, który reprezentuje dodatkowy stan funkcji blok, a domToMutation akceptuje ten sam węzeł XML i stosuje stan do do blokowania bloków.

// These are the old XML serialization hooks for the lists_create_with block.
mutationToDom: function() {
  // You *must* create a <mutation></mutation> element.
  // This element can have children.
  var container = Blockly.utils.xml.createElement('mutation');
  container.setAttribute('items', this.itemCount_);
  return container;
},

domToMutation: function(xmlElement) {
  this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

Powstały kod XML będzie wyglądał tak:

<block type="lists_create_with">
  <mutation items="3"></mutation>
</block>

Jeśli funkcja mutationToDom zwraca wartość null, żaden dodatkowy element nie będzie dodany do pliku XML.

Elementy przykuwające UI

Jeśli podasz określone funkcje jako część mutatora, Blockly doda tag domyślny „mutator” Interfejs użytkownika do bloku.

Nie musisz używać tego interfejsu, jeśli chcesz dodać dodatkową serializację. Możesz użyć niestandardowego interfejsu, takiego jak blocks-plus-minus wtyczka lub nie chcesz w ogóle korzystać z interfejsu.

tworzenie i rozkładanie

Domyślny interfejs użytkownika korzysta z funkcji compose i decompose.

decompose – wybuch na mniejsze bloki podrzędne, które można przesuwać oraz dodawać i usuwać. Ta funkcja powinna zwrócić „górny blok” czyli blok główny w obszarze roboczym mutatora, z którym łączą się bloki podrzędne.

compose następnie interpretuje konfigurację podbloków i używa ich do i zmodyfikować blok główny. Ta funkcja powinna akceptować „górny blok” co było zwracanych przez funkcję decompose jako parametr.

Zwróć uwagę, że te funkcje są „mieszane” do „mutowanego” bloku więc this można powołać się na tę blokadę.

// These are the decompose and compose functions for the lists_create_with block.
decompose: function(workspace) {
  // This is a special sub-block that only gets created in the mutator UI.
  // It acts as our "top block"
  var topBlock = workspace.newBlock('lists_create_with_container');
  topBlock.initSvg();

  // Then we add one sub-block for each item in the list.
  var connection = topBlock.getInput('STACK').connection;
  for (var i = 0; i < this.itemCount_; i++) {
    var itemBlock = workspace.newBlock('lists_create_with_item');
    itemBlock.initSvg();
    connection.connect(itemBlock.previousConnection);
    connection = itemBlock.nextConnection;
  }

  // And finally we have to return the top-block.
  return topBlock;
},

// The container block is the top-block returned by decompose.
compose: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we collect up all of the connections of on our main block that are
  // referenced by our sub-blocks.
  // This relates to the saveConnections hook (explained below).
  var connections = [];
  while (itemBlock && !itemBlock.isInsertionMarker()) {  // Ignore insertion markers!
    connections.push(itemBlock.valueConnection_);
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }

  // Then we disconnect any children where the sub-block associated with that
  // child has been deleted/removed from the stack.
  for (var i = 0; i < this.itemCount_; i++) {
    var connection = this.getInput('ADD' + i).connection.targetConnection;
    if (connection && connections.indexOf(connection) == -1) {
      connection.disconnect();
    }
  }

  // Then we update the shape of our block (removing or adding iputs as necessary).
  // `this` refers to the main block.
  this.itemCount_ = connections.length;
  this.updateShape_();

  // And finally we reconnect any child blocks.
  for (var i = 0; i < this.itemCount_; i++) {
    connections[i].reconnect(this, 'ADD' + i);
  }
},

saveConnections

Opcjonalnie możesz również zdefiniować funkcję saveConnections, która działa z do domyślnego interfejsu. Ta funkcja umożliwia powiązanie elementów podrzędnych blok główny (istniejący w głównym obszarze roboczym) z blokami podrzędnymi występującymi w obszaru roboczego mutatora. Możesz potem użyć tych danych, aby sprawdzić, czy Twoje urządzenie compose prawidłowo ponownie łączy elementy podrzędne bloku głównego, gdy a bloki podrzędne zostają uporządkowane.

saveConnections powinien zaakceptować „górny blok” zwrócone przez: decompose jako parametru. Jeśli zdefiniowano funkcję saveConnections, Blockly Zadzwoni przed zadzwonieniem pod numer compose.

saveConnections: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we go through and assign references to connections on our main block
  // (input.connection.targetConnection) to properties on our sub blocks
  // (itemBlock.valueConnection_).
  var i = 0;
  while (itemBlock) {
    // `this` refers to the main block (which is being "mutated").
    var input = this.getInput('ADD' + i);
    // This is the important line of this function!
    itemBlock.valueConnection_ = input && input.connection.targetConnection;
    i++;
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }
},

Rejestruję…

Mutatory to specjalny rodzaj rozszerzeń, więc muszą , zanim będzie można ich używać w JSON typu bloku .

// Function signature.
Blockly.Extensions.registerMutator(name, mixinObj, opt_helperFn, opt_blockList);

// Example call.
Blockly.Extensions.registerMutator(
    'controls_if_mutator',
    { /* mutator methods */ },
    undefined,
    ['controls_if_elseif', 'controls_if_else']);
  • name: ciąg znaków do powiązania z mutatorem, aby można było go użyć w formacie JSON.
  • mixinObj: obiekt zawierający różne metody mutacji. Na przykład: saveExtraState i loadExtraState.
  • opt_helperFn: opcjonalna funkcja pomocnicza, która będzie po wymieszaniu mieszanin.
  • opt_blockList: opcjonalna tablica typów bloków (w formie ciągów znaków), która zostanie jest dodawana do menu rozwijanego w domyślnym interfejsie mutatora, jeśli metody interfejsu zdefiniowano jego definicję.

Pamiętaj, że w przeciwieństwie do rozszerzeń każdy typ bloku może mieć tylko jeden mutator.

{
  //...
  "mutator": "controls_if_mutator"
}

Funkcja pomocnicza

Wraz z mikserem mutator może zarejestrować funkcję pomocniczą. Ta funkcja jest po utworzeniu każdego bloku danego typu, a miksinObj ma – dodano. Można jej użyć do dodania do mutacji dodatkowych wyzwalaczy lub efektów.

Możesz na przykład dodać do bloku listy funkcji pomocniczej, która ustawia początkowa liczba elementów:

var helper = function() {
  this.itemCount_ = 5;
  this.updateShape();
}