Como atualizar um campo personalizado

Em julho de 2019 (versão 2.20190722), uma API de campos mais codificados foi adicionada. O objetivo é que ela seja o mais compatível com versões anteriores possível. Isso significa que, se você criou um campo personalizado antes de julho de 2019, ele provavelmente continuará funcionando. Antes de decidir se precisa fazer upgrade do campo personalizado, leia a seção Áreas perigosas e faça um teste completo.

Como não havia padronização entre os campos antes de julho de 2019, é difícil abordar todas as mudanças que um desenvolvedor precisava fazer. Este documento tenta abordar todas as mudanças prováveis. Porém, se ele não abordar algo do seu interesse, leia a seção sobre como receber assistência para upgrade.

Áreas perigosas

Áreas perigosas são lugares conhecidos em que a API foi alterada, e seu campo pode ser corrompido.

Blockly.Field.register

Os campos não estão mais registrados pelo Blockly.Field.register();. Agora há um namespace fieldRegistry que processa o registro.

Blockly.Field.register('my_field_name', myFieldClass);

O resultado é:

Blockly.fieldRegistry.register('my_field_name', myFieldClass);

setText

A função setText não é mais chamada pelo núcleo do Blockly. Portanto, se a função setText contiver lógica, ela precisará ser movida para o pacote de funções de processamento de valor, getText e funções de renderização, dependendo do que exatamente a função setText estiver fazendo.

CustomFields.UpgradeField.prototype.setText = function(newText) {
  // Do validation.
  if (typeof newText != 'string' || newText === this.text_) {
    return;
  }

  // Fire event.
  if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
    Blockly.events.fire(new Blockly.Events.BlockChange(
        this.sourceBlock_, 'field', this.name, this.text_, newText
    ));
  }

  // Update text value.
  this.text_ = 'prefix' + newText;

  // Rerender.
  this.size_.width = 0;
};

O resultado é:

CustomFields.UpgradeField.prototype.doClassValidation_ = function(newValue) {
  if (typeof newValue != 'string') {
    return null;
  }
  return newValue;
};

CustomFields.UpgradeField.prototype.getText = function() {
  return  'prefix' + this.value_;
}

O Blockly processa automaticamente:

  • Verificar se o novo valor é diferente do antigo.
  • Atualizando o valor.
  • Disparando eventos de mudança.
  • Nova renderização do campo.

Você vai precisar lidar com:

Upgrades recomendados são lugares em que a API de campo foi alterada, mas se você optar por não fazer alterações, seu campo provavelmente ainda funcionará.

SERIALIZÁVEL

Para mais informações sobre as propriedades EDITABLE e SERIALIZABLE, consulte Propriedades editáveis e serializáveis.

CustomFields.UpgradeField.prototype.SERIALIZABLE = true;

O aviso abaixo pode ser ignorado, mas você pode resolvê-lo definindo a propriedade SERIALIZABLE:

Detected an editable field that was not serializable. Please define
SERIALIZABLE property as true on all editable custom fields. Proceeding
with serialization.

O aviso acima significa que a Blockly acredita que você quer que o campo seja serializado (porque a propriedade EDITABLE é verdadeira), mas não pode ter certeza até que você defina a propriedade SERIALIZABLE. Se você não fizer isso, tudo funcionará corretamente e seu campo será serializado, mas você receberá avisos do console.

size_.width

this.size_.width = 0;

O resultado é:

this.isDirty_ = true;

O aviso abaixo pode ser ignorado, mas você pode resolvê-lo definindo a propriedade isDirty_ em vez da size_.width:

Deprecated use of setting size_.width to 0 to rerender a field. Set
field.isDirty_ to true instead.

O aviso acima significa que o Blockly detectou que você está usando um método antigo para renderizar um campo e quer que você use o novo método.

Para mais informações sobre a propriedade isDirty_, consulte isDirty_.

init

A função init foi transformada em uma função de modelo para reduzir o código duplicado em subclasses.

CustomFields.UpgradeField.prototype.init = function() {
  if (this.fieldGroup_) {
    // Already initialized once.
    return;
  }

  // Call superclass.
  CustomFields.UpgradeField.superClass_.init.call(this);

  // Create DOM elements.
  this.extraDom_ = Blockly.utils.dom.createSvgElement('image',
      {
        'height': '10px',
        'width': '10px'
      });
  this.extraDom_.setAttributeNS('http://www.w3.org/1999/xlink',
      'xlink:href', 'image.svg');
  this.extraDom_.style.cursor = 'pointer';
  this.fieldGroup_.appendChild(this.extraDom_);

  // Bind events.
  this.mouseOverWrapper_ =
    Blockly.browserEvents.bind(
        this.getClickTarget_(), 'mouseover', this, this.onMouseOver_);
  this.mouseOutWrapper_ =
    Blockly.browserEvents.bind(
        this.getClickTarget_(), 'mouseout', this, this.onMouseOut_);

  // Render.
  this.setValue(this.getValue());
};

O resultado é:

CustomFields.UpgradeField.prototype.initView = function() {
  CustomFields.UpgradeField.superClass_.initView.call(this);

  this.extraDom_ = Blockly.utils.dom.createSvgElement('image',
      {
        'height': '10px',
        'width': '10px'
      });
  this.extraDom_.setAttributeNS('http://www.w3.org/1999/xlink',
      'xlink:href', 'image.svg');
  this.extraDom_.style.cursor = 'pointer';
  this.fieldGroup_.appendChild(this.extraDom_);
};

CustomFields.UpgradeField.prototype.bindEvents_ = function() {
  CustomFields.UpgradeField.superClass_.bindEvents_.call(this);

  this.mouseOverWrapper_ =
    Blockly.bindEvent_(
        this.getClickTarget_(), 'mouseover', this, this.onMouseOver_);
  this.mouseOutWrapper_ =
    Blockly.bindEvent_(
        this.getClickTarget_(), 'mouseout', this, this.onMouseOut_);
};

Isso significa que o blockly agora processa automaticamente o seguinte:

  • Verificar se o campo já está inicializado.
  • Criando o fieldGroup_.
  • Renderização do campo.
  • Vincular dica e mostrar eventos do editor.

Você vai precisar lidar com:

onMouseDown_

CustomFields.UpgradeField.prototype.onMouseDown_ = function(e) {
  // ...
};

O resultado é:

CustomFields.UpgradeField.prototype.showEditor_ = function() {
  // ...
}

Recomendamos que você substitua a função showEditor_ para processar cliques do mouse em vez da função onMouseDown_, já que ela permite que a entrada seja transmitida pelo sistema de gestos.

Para mais informações, consulte Editores.

setValue

A função setValue agora é uma função de modelo para reduzir o código duplicado em subclasses. Se a função setValue tiver lógica, refatore-a para se ajustar aos caminhos de processamento de valor descritos em Processamento de valor.

text_

Recomendamos que você nunca acesse ou atualize a propriedade text_ do campo diretamente. Em vez disso, use a função getText para acessar o texto legível pelo usuário do campo e a função setValue para atualizar o valor armazenado do campo.

Para saber mais sobre o valor de um campo em comparação com o texto dele, consulte Anatomia de um campo.

Como receber assistência para upgrade

O que fornecer

Ao pedir ajuda, é melhor fazer perguntas específicas:

Não recomendado: "O que há de errado com este campo?"

Também não recomendado: "Preciso de ajuda para fazer upgrade deste campo".

Recomendado: "O texto do campo não está sendo atualizado corretamente."

Também é necessário fornecer recursos para as pessoas que estão ajudando você. Esses arquivos precisam ser fáceis de usar.

Não recomendado:

  • Imagens de código.
  • Código incompleto.

Recomendado:

  • Preencha o código do campo em formato de texto.
  • Imagens de GIFs de mau comportamento no campo.
  • Etapas para reproduzir o mau comportamento do campo.
  • A versão do blockly a partir da qual você está fazendo upgrade.

Onde postar

Perguntas após o upgrade no fórum de desenvolvedores do Blockly

Se você tiver certeza de que o problema é com o núcleo em blocos, também é possível postar um problema no GitHub com blocos. Se você decidir postar um problema, preencha todas as informações solicitadas.