Özel prosedür blokları oluşturma

Özel prosedür blokları oluşturmak için aşağıdakileri yapmanız gerekir:

  1. Prosedürleri kullanma sayfasında açıklandığı şekilde @blockly/block-shareable-procedures eklentisini yükleyin.
  2. Genel bakış sayfasında açıklandığı gibi JSON serileştirme sistemini kullanın.

Çalışma alanına veri modelleri ekleme

Hem prosedür tanımı hem de prosedür çağrısı blokları, prosedürün imzasını (ad, parametreler ve dönüş) tanımlayan bir yedek veri modeline referans verir. Bu, uygulamanızı tasarlarken daha fazla esneklik sağlar (ör. prosedürlerin bir çalışma alanında tanımlanmasına ve başka bir çalışma alanında referans verilmesine izin verebilirsiniz).

Bu, bloklarınızın çalışması için prosedür veri modellerini çalışma alanına eklemeniz gerektiği anlamına gelir. Bunu yapmanın birçok yolu vardır (ör. özel kullanıcı arayüzleri).

@blockly/block-shareable-procedur, bunu çalışma alanında somutlaştırıldığında prosedür tanımı bloklarının destek verisi modellerini dinamik olarak oluşturarak yapar. Bunu kendiniz uygulamak için modeli init içinde oluşturup destroy ürününde silmeniz gerekir.

import {ObservableProcedureModel} from '@blockly/block-shareable-procedures';

Blockly.Blocks['my_procedure_def'] = {
  init: function() {
    this.model = new ObservableProcedureModel('default name');
    this.workspace.getProcedureMap().add(model);
    // etc...
  }

  destroy: function() {
    // Optionally:
    // Destroy the model when the definition block is deleted.
    this.workpace.getProcedureMap().delete(model.getId());
  }
}

Engellemelerle ilgili bilgileri döndür

Prosedür tanımı ve prosedür çağrı bloklarınızın getProcedureModel, isProcedureDef ve getVarModels yöntemlerini uygulaması gerekir. Bunlar, Blockly kodunun prosedür bloklarınız hakkında bilgi almak için kullandığı kancalardır.

Blockly.Blocks['my_procedure_def'] = {
  getProcedureModel() {
    return this.model;
  },

  isProcedureDef() {
    return true;
  },

  getVarModels() {
    // If your procedure references variables
    // then you should return those models here.
    return [];
  },
};

Blockly.Blocks['my_procedure_call'] = {
  getProcedureModel() {
    return this.model;
  },

  isProcedureDef() {
    return false;
  },

  getVarModels() {
    // If your procedure references variables
    // then you should return those models here.
    return [];
  },
};

Güncellemelerde yeniden oluşturmayı tetikle

Prosedür tanımı ve prosedür çağrı bloklarınızın, doProcedureUpdate yöntemini uygulaması gerekir. Bu, prosedür bloklarınıza kendilerini yeniden oluşturmalarını söylemek için veri modellerinin çağırdığı kancadır.

Blockly.Blocks['my_procedure_def'] = {
  doProcedureUpdate() {
    this.setFieldValue('NAME', this.model.getName());
    this.setFieldValue(
        'PARAMS',
        this.model.getParameters()
            .map((p) => p.getName())
            .join(','));
    this.setFieldValue(
        'RETURN', this.model.getReturnTypes().join(',');
  }
};

Blockly.Blocks['my_procedure_call'] = {
  doProcedureUpdate() {
    // Similar to the def block above...
  }
};

Özel serileştirme ekleyin

Prosedür blokları için serileştirme işlemi iki ayrı şey yapmalıdır.

  1. Bloklar ve modeller ayrı olarak serileştirildiğinden, JSON'den yükleme yaparken bloklarınızın destek veri modeline bir referans alması gerekir.
  2. Bir prosedür bloğunu kopyalayıp yapıştırırken, blokun kopyalanıp kopyalanabilmesi için işlem modelinin tüm durumunu serileştirmesi gerekir.

Bu işlemlerin ikisi de saveExtraState ve loadExtraState aracılığıyla işlenir. Özel prosedür bloklarının yalnızca JSON serileştirme sistemi kullanılırken desteklendiğini unutmayın. Bu nedenle, yalnızca JSON serileştirme kancalarını tanımlamamız gerekir.

import {
    ObservableProcedureModel,
    ObservableParameterModel,
    isProcedureBlock
} from '@blockly/block-shareable-procedures';

Blockly.Blocks['my_procedure_def'] = {
  saveExtraState() {
    return {
      'procedureId': this.model.getId(),

      // These properties are only necessary for pasting.
      'name': this.model.getName(),
      'parameters': this.model.getParameters().map((p) => {
        return {name: p.getName(), p.getId()};
      }),
      'returnTypes': this.model.getReturnTypes(),
    };
  },

  loadExtraState(state) {
    const id = state['procedureId']
    const map = this.workspace.getProcedureMap();

    // Grab a reference to the existing procedure model.
    if (this.model.getId() != id && map.has(id) &&
        (this.isInsertionMarker || this.noBlockHasClaimedModel_(id))) {
      // Delete the existing model (created in init).
      this.workspace.getProcedureMap().delete(model.getId());
      // Grab a reference to the new model.
      this.model = this.workspace.getProcedureMap()
          .get(state['procedureId']);
      this.doProcedureUpdate();
      return;
    }

    // There is no existing procedure model (we are likely pasting), so
    // generate it from JSON.
    this.model
        .setName(state['name'])
        .setReturnTypes(state['returnTypes']);
    for (const [i, param] of state['parameters'].entries()) {
      this.model.insertParameter(
          i,
          new ObservableParameterModel(
              this.workspace, param['name'], param['id']));
    }
  },

  // We don't want to reference a model that some other procedure definition
  // is already referencing.
  noBlockHasClaimedModel_(procedureId) {
    const model =
      this.workspace.getProcedureMap().get(procedureId);
    return this.workspace.getAllBlocks(false).every(
      (block) =>
        !isProcedureBlock(block) ||
        !block.isProcedureDef() ||
        block.getProcedureModel() !== model);
  },
};

Blockly.Blocks['my_procedure_call'] = {
  saveExtraState() {
    return {
      'procedureId': this.model.getId(),
    };
  },

  loadExtraState(state) {
    // Delete our existing model (created in init).
    this.workspace.getProcedureMap().delete(model.getId());
    // Grab a reference to the new model.
    this.model = this.workspace.getProcedureMap()
        .get(state['procedureId']);
    if (this.model) this.doProcedureUpdate();
  },

  // Handle pasting after the procedure definition has been deleted.
  onchange(event) {
    if (event.type === Blockly.Events.BLOCK_CREATE &&
        event.blockId === this.id) {
      if(!this.model) { // Our procedure definition doesn't exist =(
        this.dispose();
      }
    }
  }
};

İsteğe bağlı olarak prosedür modelini/imzayı değiştirin

Ayrıca, kullanıcılara prosedür modelini/imzayı değiştirme olanağı da ekleyebilirsiniz. insertParameter, deleteParameter veya setReturnTypes yöntemleri çağrıldığında engellemelerinizin yeniden oluşturulması (doProcedureUpdate aracılığıyla) otomatik olarak tetiklenir.

Prosedür modelini değiştirmek için kullanıcı arayüzü oluşturma seçenekleri arasında mutatörler (yerleşik prosedür bloklarının kullandığı), tıklama işleyicileri olan resim alanları, Blockly'nin tamamen dışında olan bir şey kullanma vb. yer alır.

Araç kutusuna bloklar ekleyin

Blockly'nin yerleşik dinamik prosedür kategorisi, Blockly'nin yerleşik prosedür bloklarına özeldir. Bloklarınıza erişebilmek için kendi özel dinamik kategorinizi tanımlamanız ve bunu araç kutunuza eklemeniz gerekir.

const proceduresFlyoutCallback = function(workspace) {
  const blockList = [];
  blockList.push({
    'kind': 'block',
    'type': 'my_procedure_def',
  });
  for (const model of
        workspace.getProcedureMap().getProcedures()) {
    blockList.push({
      'kind': 'block',
      'type': 'my_procedure_call',
      'extraState': {
        'procedureId': model.getId(),
      },
    });
  }
  return blockList;
};

myWorkspace.registerToolboxCategoryCallback(
    'MY_PROCEDURES', proceduresFlyoutCallback);