新しいフィールドタイプの作成

新しいフィールド タイプを作成する前に、もう一方のタイプを メソッド カスタマイズする方法もいくつかあります。アプリケーションで 既存の値の型に新しい UI を作成する場合は、 新しいフィールド タイプの作成が必要になる可能性があります。

新しいフィールドを作成する手順は次のとおりです。

  1. コンストラクタを実装する
  2. JSON キーを登録して fromJson を実装します
  3. ブロック上の UI とイベントの初期化を処理する 使用できます。
  4. イベント リスナーの破棄を処理(UI の破棄は ユーザー)。
  5. 値の処理を実装する
  6. ユーザー補助のために、フィールドの値のテキスト表現を追加する
  7. 次のような機能を追加します。 <ph type="x-smartling-placeholder">
  8. 次のようなフィールドの追加要素を設定します。 <ph type="x-smartling-placeholder">

このセクションは、 フィールド

カスタム フィールドの例については、カスタム フィールド デモ をタップします。

コンストラクタの実装

フィールドのコンストラクタは、フィールドの初期値を設定する役割を担います。 必要に応じて、ローカル バリデータ。カスタム フィールドのコンストラクタが呼び出されるのは、 ソースブロックが JSON と JavaScript のどちらで定義されているかを示す指標です。したがって、カスタム フィールドには、作成時にソースブロックへのアクセス権がありません。

次のコードサンプルでは、GenericField という名前のカスタム フィールドを作成します。

class GenericField extends Blockly.Field {
  constructor(value, validator) {
    super(value, validator);

    this.SERIALIZABLE = true;
  }
}

メソッドのシグネチャ

フィールド コンストラクタは通常、値とローカル バリデータを受け取ります。値は オプションです。また、値を渡さない場合(または、class に失敗する値を スーパークラスのデフォルト値が使用されます。対象: デフォルトの Field クラスの場合、値は null です。このデフォルトを使用しない場合は、 適切な値を渡すようにしてください。Validator パラメータは 編集可能なフィールドでは存在し、通常はオプションとしてマークされます。詳細 詳しくは、Validators、 ドキュメントをご覧ください。

構造

コンストラクタ内のロジックは、次のフローに従う必要があります。

  1. 継承されたスーパー コンストラクタを呼び出す(すべてのカスタム フィールドは Blockly.Field またはそのサブクラスのいずれか)を使用して、値を適切に初期化します。 フィールドにローカル検証ツールを設定します。
  2. フィールドがシリアル化可能である場合は、 コンストラクタがあります。編集可能なフィールドはシリアル化可能でなければならず、編集可能である必要がある ですからこのプロパティを true に設定することをおすすめします。 シリアル化可能であってはなりません。
  3. 省略可: 追加のカスタマイズを適用する(ラベルのフィールドなど) CSS クラスを渡し、それがテキストに適用されます)。

JSON と登録

JSON ブロック内 定義 フィールドは文字列(例: field_numberfield_textinput)で記述します。 Blockly は、これらの文字列からフィールド オブジェクトへのマップを維持し、 作成中に適切なオブジェクトに対する fromJson

Blockly.fieldRegistry.register を呼び出して、このマップにフィールド タイプを追加します。 2 番目の引数としてフィールド クラスを渡します。

Blockly.fieldRegistry.register('field_generic', GenericField);

また、fromJson 関数を定義する必要があります。実装では 最初に任意の文字列を逆参照 テーブル 参照: replaceMessageReferences, 次にその値をコンストラクタに渡します。

GenericField.fromJson = function(options) {
  const value = Blockly.utils.parsing.replaceMessageReferences(
      options['value']);
  return new CustomFields.GenericField(value);
};

初期化中

作成されるフィールドには、基本的に値のみが含まれます。 初期化は DOM の構築、モデルの構築(フィールドが イベントはバインドされます。

オンブロック ディスプレイ

初期化中は、必要なものをすべて作成する必要があります。 フィールドのオンブロックディスプレイに 入力します

デフォルト、背景、テキスト

デフォルトの initView 関数は、明るい色の rect 要素と text 要素。このフィールドに両方のフィールドを追加し、 追加する前に、スーパークラスの initView 関数を呼び出して DOM 要素。フィールドにどちらか一方のみを含める場合は、 createBorderRect_ 関数または createTextElement_ 関数を使用できます。

DOM 構築のカスタマイズ

フィールドが汎用テキスト フィールド(例: Text Input)、 DOM 構築は自動的に行われます。それ以外の場合は、値をオーバーライドする必要があります。 initView 関数を使用して、必要な DOM 要素を作成する 詳しく見ていきます。

たとえば、プルダウン フィールドには画像とテキストの両方を含めることができます。initView で は、1 つの画像要素と 1 つのテキスト要素を作成します。その後、render_ の期間中 アクティブな要素を表示し、もう一方を非表示にします。元の要素は、 選択します。

DOM 要素の作成は、 Blockly.utils.dom.createSvgElement メソッド、または従来の DOM 作成 あります。

フィールドのオンブロック表示の要件は次のとおりです。

  • すべての DOM 要素はフィールドの fieldGroup_ の子である必要があります。フィールド グループが自動的に作成されます。
  • すべての DOM 要素は、フィールドについてレポートされるディメンションの範囲内に収まる必要があります。

詳しくは、 レンダリング をご覧ください。

テキスト記号の追加

フィールドのテキストに記号( 角度 次フィールドの次数記号など)を使用する場合は、記号要素(通常は <tspan> など)をフィールドの textElement_ に直接渡すこともできます。

入力イベント

デフォルトでは、各フィールドはツールチップ イベントとマウスダウン イベント( 表示中 編集者など)。 他の種類のイベントをリッスンしたい場合(例: フィールドのドラッグなど)を行う場合は、そのフィールドの bindEvents_ 関数をオーバーライドする必要があります。

bindEvents_() {
  // Call the superclass function to preserve the default behavior as well.
  super.bindEvents_();

  // Then register your own additional event listeners.
  this.mouseDownWrapper_ =
  Blockly.browserEvents.conditionalBind(this.getClickTarget_(), 'mousedown', this,
      function(event) {
        this.originalMouseX_ = event.clientX;
        this.isMouseDown_ = true;
        this.originalValue_ = this.getValue();
        event.stopPropagation();
      }
  );
  this.mouseMoveWrapper_ =
    Blockly.browserEvents.conditionalBind(document, 'mousemove', this,
      function(event) {
        if (!this.isMouseDown_) {
          return;
        }
        var delta = event.clientX - this.originalMouseX_;
        this.setValue(this.originalValue_ + delta);
      }
  );
  this.mouseUpWrapper_ =
    Blockly.browserEvents.conditionalBind(document, 'mouseup', this,
      function(_event) {
        this.isMouseDown_ = false;
      }
  );
}

イベントにバインドするには、通常 Blockly.utils.browserEvents.conditionalBind 使用します。イベントをバインドするこの手法では、発生中の二次的な接触を ドラッグします。ドラッグの進行中でもハンドラを実行したい場合は、 こちらの Blockly.browserEvents.bind 使用します。

廃棄

フィールドの bindEvents_ 内にカスタム イベント リスナーを登録した場合 dispose 関数内で登録を解除する必要があります。

イベント ハンドラで ビュー (すべての DOM 要素を fieldGroup_ に追加)して、 フィールドの DOM は自動的に破棄されます。

価値の処理

→ フィールドの値とテキストの詳細については、フィールドの構造 フィールド

検証順序

バリデータの実行順序を示すフローチャート

クラス バリデータの実装

フィールドには特定の値のみを指定できます。たとえば数値フィールドでは 色フィールドには色などしか入力できません 地域社会で バリデータ。クラス ローカル バリデータと同じルールに従うが、ローカル バリデータも実行される の コンストラクタ source ブロックを参照しないようにする必要があります。

フィールドのクラス バリデータを実装するには、doClassValidation_ をオーバーライドします。 使用します。

doClassValidation_(newValue) {
  if (typeof newValue != 'string') {
    return null;
  }
  return newValue;
};

有効な値の処理

setValue のフィールドに渡される値が有効な場合は、 doValueUpdate_ コールバック。デフォルトでは、doValueUpdate_ 関数は次のように動作します。

  • value_ プロパティを newValue に設定します。
  • isDirty_ を設定します。 プロパティを true に設定します。

値の保存のみが必要で、カスタム処理を行いたくない場合は、 doValueUpdate_ をオーバーライドする必要はありません。

または、次のような操作を行います。

  • newValue のカスタム ストレージ。
  • newValue に基づいて他のプロパティを変更します。
  • 現在の値が有効かどうかを保存します。

doValueUpdate_ をオーバーライドする必要があります。

doValueUpdate_(newValue) {
  super.doValueUpdate_(newValue);
  this.displayValue_ = newValue;
  this.isValueValid_ = true;
}

無効な値の処理

setValue でフィールドに渡された値が無効な場合は、 doValueInvalid_ コールバック。デフォルトでは、doValueInvalid_ 関数は次の処理を行います。 ありません。つまり、デフォルトでは無効な値は表示されません。また、 は、フィールドが再レンダリングされないことを意味します。これは、 isDirty_ プロパティは設定されません。

無効な値を表示する場合は、doValueInvalid_ をオーバーライドする必要があります。 ほとんどの場合、displayValue_ プロパティを 無効な値、設定済み isDirty_ true に設定して、オーバーライドする render_ オンブロック ディスプレイを、displayValue_に基づいて value_

doValueInvalid_(newValue) {
  this.displayValue_ = newValue;
  this.isDirty_ = true;
  this.isValueValid_ = false;
}

マルチパート値

フィールドにマルチパート値(リスト、ベクトル、オブジェクトなど)が含まれる場合、 パーツを個別の値のように処理できます。

doClassValidation_(newValue) {
  if (FieldTurtle.PATTERNS.indexOf(newValue.pattern) == -1) {
    newValue.pattern = null;
  }

  if (FieldTurtle.HATS.indexOf(newValue.hat) == -1) {
    newValue.hat = null;
  }

  if (FieldTurtle.NAMES.indexOf(newValue.turtleName) == -1) {
    newValue.turtleName = null;
  }

  if (!newValue.pattern || !newValue.hat || !newValue.turtleName) {
    this.cachedValidatedValue_ = newValue;
    return null;
  }
  return newValue;
}

上記の例では、newValue の各プロパティが個別に検証されます。その後 doClassValidation_ 関数の最後にあります(個々のプロパティがある場合、 無効の場合、値はcacheValidatedValue_ null を返します(無効)。個別に検証されたオブジェクトをキャッシュに保存する プロパティを使用すると、 doValueInvalid_ 関数を使用して個別に処理します。これは、 各データを再検証する代わりに、!this.cacheValidatedValue_.property チェックを プロパティを個別に設定します。

マルチパート値を検証するこのパターンは、ローカル バリデータですが、 現在のところ、このパターンを適用する方法はありません。

isDirty_

isDirty_ は、Pod で使用するフラグです。 setValue フィールドの他の部分と一緒に使用して、フィールドを 再レンダリングされますフィールドの表示値が変更された場合、通常、isDirty_true に設定します。

テキスト

→ フィールドのテキストが使用される場所と相違点に関する情報 をご覧ください。詳しくは、フィールドの フィールド

フィールドのテキストがフィールドの値と異なる場合は、 オーバーライドする getText 関数 入力する必要があります。

getText() {
  let text = this.value_.turtleName + ' wearing a ' + this.value_.hat;
  if (this.value_.hat == 'Stovepipe' || this.value_.hat == 'Propeller') {
    text += ' hat';
  }
  return text;
}

エディタの作成

showEditor_ 関数を定義すると、Blockly は自動的に次のイベントをリッスンします。 クリックして showEditor_ を呼び出します。任意の HTML を表示可能 エディタで DropDownDiv という 2 つの特別な div のいずれかでラップして、 そして WidgetDiv はブロックリーの UI の上にフロート表示されます。

DropDownDiv は、接続されたボックス内にあるエディタを提供するために使用されます。 マッピングできます。自動的にフィールドの近くに来るように位置します 移動しますアングルピッカーやカラーピッカーは、 DropDownDiv

アングル選択ツールの画像

WidgetDiv は、以下の目的に使用されます。 エディタはボックス内には収まらない。数値フィールドでは HTML テキスト入力ボックスでフィールドを覆う WidgetDiv。DropDownDiv は 自動的に配置が処理されますが、WidgetDiv は処理しません。要素は次の条件を満たしている必要があります。 手動で配置します。座標系は、座標を基準とするピクセル座標です。 アクセスできます。テキスト入力エディタは WidgetDiv

テキスト入力エディタの画像

showEditor_() {
  // Create the widget HTML
  this.editor_ = this.dropdownCreate_();
  Blockly.DropDownDiv.getContentDiv().appendChild(this.editor_);

  // Set the dropdown's background colour.
  // This can be used to make it match the colour of the field.
  Blockly.DropDownDiv.setColour('white', 'silver');

  // Show it next to the field. Always pass a dispose function.
  Blockly.DropDownDiv.showPositionedByField(
      this, this.disposeWidget_.bind(this));
}

WidgetDiv のサンプルコード

showEditor_() {
  // Show the div. This automatically closes the dropdown if it is open.
  // Always pass a dispose function.
  Blockly.WidgetDiv.show(
    this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this));

  // Create the widget HTML.
  var widget = this.createWidget_();
  Blockly.WidgetDiv.getDiv().appendChild(widget);
}

クリーンアップ

DropDownDiv と WidgetDiv の両方がウィジェットの HTML を破棄する処理 ただし、既存のイベント リスナーは手動で破棄する必要があります。 自動的に適用されます。

widgetDispose_() {
  for (let i = this.editorListeners_.length, listener;
      listener = this.editorListeners_[i]; i--) {
    Blockly.browserEvents.unbind(listener);
    this.editorListeners_.pop();
  }
}

dispose 関数は、DropDownDivnull コンテキストで呼び出されます。オン WidgetDiv のコンテキストで呼び出されます。WidgetDivいずれの場合も 前のスライドの bind 上記の DropDownDiv に示すように、dispose 関数を渡すときにその関数を渡します。 と WidgetDiv の例。

→ 編集者の破棄に限らず、破棄については、以下をご覧ください。 破棄

オンブロック ディスプレイの更新

render_ 関数を使用して、フィールドのオンブロック ディスプレイを その内部値で識別されます。

一般的な例:

  • テキスト(プルダウン)を変更する
  • 色(色)を変更する
で確認できます。

デフォルト

デフォルトの render_ 関数は、表示テキストを getDisplayText_ 使用します。getDisplayText_ 関数は、フィールドの value_ プロパティを返します。 最大テキストに合わせて切り捨てられた後の文字列にキャストする あります。

デフォルトのブロック中表示とデフォルトのテキスト動作を使用している場合 適切に動作するため、render_ をオーバーライドする必要はありません。

デフォルトのテキスト動作がフィールドで機能しても、フィールドがオンブロックである場合 ディスプレイに追加の静的要素がある場合は、デフォルトの render_ ただし、このフィールドを更新するために、 あります。

デフォルトのテキスト動作がフィールドで動作しない場合や、 オンブロック ディスプレイに追加の動的要素があるため、カスタマイズ render_ 関数です

render_ をオーバーライドするかどうかを決定する方法を説明するフローチャート

レンダリングのカスタマイズ

デフォルトのレンダリング動作がフィールドで動作しない場合は、 カスタム レンダリングの動作を定義します。これにはカスタム設定や テキストの表示 画像要素の変更 背景色の更新など

DOM 属性の変更はすべて法的に認められています。覚えておくべきことは次の 2 点だけです。

  1. DOM の作成初期化、 その方が効率的です。
  2. 常に size_ を更新する必要があります。 プロパティを使用して、オンブロック ディスプレイのサイズと一致させます。
render_() {
  switch(this.value_.hat) {
    case 'Stovepipe':
      this.stovepipe_.style.display = '';
      break;
    case 'Crown':
      this.crown_.style.display = '';
      break;
    case 'Mask':
      this.mask_.style.display = '';
      break;
    case 'Propeller':
      this.propeller_.style.display = '';
      break;
    case 'Fedora':
      this.fedora_.style.display = '';
      break;
  }

  switch(this.value_.pattern) {
    case 'Dots':
      this.shellPattern_.setAttribute('fill', 'url(#polkadots)');
      break;
    case 'Stripes':
      this.shellPattern_.setAttribute('fill', 'url(#stripes)');
      break;
    case 'Hexagons':
      this.shellPattern_.setAttribute('fill', 'url(#hexagons)');
      break;
  }

  this.textContent_.nodeValue = this.value_.turtleName;

  this.updateSize_();
}

サイズを更新しています

フィールドの size_ プロパティの更新は、 フィールドの配置方法を指定できます。これを把握するのに最適な方法は 実際に試してみてはいかがでしょうか。size_

updateSize_() {
  const bbox = this.movableGroup_.getBBox();
  let width = bbox.width;
  let height = bbox.height;
  if (this.borderRect_) {
    width += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
    height += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
    this.borderRect_.setAttribute('width', width);
    this.borderRect_.setAttribute('height', height);
  }
  // Note how both the width and the height can be dynamic.
  this.size_.width = width;
  this.size_.height = height;
}

ブロックの色のマッチング

フィールドの要素をブロックの色に合わせるには、 applyColour メソッドをオーバーライドする必要があります。目標 ブロックの style プロパティを使用して、色にアクセスします。

applyColour() {
  const sourceBlock = this.sourceBlock_;
  if (sourceBlock.isShadow()) {
    this.arrow_.style.fill = sourceBlock.style.colourSecondary;
  } else {
    this.arrow_.style.fill = sourceBlock.style.colourPrimary;
  }
}

編集可能性を更新しています

updateEditable 関数を使用すると、フィールドの外観を変更できます。 編集できるかどうかによって異なります。デフォルトの関数では、 背景が編集可能な場合、または編集できない場合、カーソルを合わせるときのレスポンス(枠線)が表示されます。 オンブロック ディスプレイは編集の可否によってサイズが変わることはありませんが、 その他すべての変更は許可されます。

updateEditable() {
  if (!this.fieldGroup_) {
    // Not initialized yet.
    return;
  }
  super.updateEditable();

  const group = this.getClickTarget_();
  if (!this.isCurrentlyEditable()) {
    group.style.cursor = 'not-allowed';
  } else {
    group.style.cursor = this.CURSOR;
  }
}

シリアル化

シリアル化は、 後でワークスペースに再読み込みできるようにします。

ワークスペースの状態にはフィールドの値が常に含まれますが、 他の状態(フィールドの UI の状態など)を持たせることができます。たとえば、 ユーザーが国を選択できるズーム可能な地図でしたが、 ズームレベルをシリアル化します。

フィールドがシリアル化可能な場合は、SERIALIZABLE プロパティを次のように設定する必要があります。 true

Blockly には、フィールドのシリアル化フックのセットが 2 つあります。1 組のフック 他のペアは新しい JSON シリアル化システムで動作し、もう 1 つのペアは 古い XML シリアル化システムです。

saveStateloadState

saveStateloadState: 新しい JSON で動作するシリアル化フック 使用します。

デフォルトのロールはデフォルトのため、 確認しましょう。(1)フィールドが base の直接サブクラスの場合 Blockly.Field クラス。(2)値はシリアル化可能な JSON である。 タイプ、(3)必要なのは 値をシリアル化すると、デフォルトの実装で問題なく機能します。

それ以外の場合、saveState 関数はシリアル化可能な JSON を返す必要があります。 オブジェクト/値。フィールドの状態を表します。loadState 関数は、同じ JSON シリアル化可能なオブジェクト/値を受け取り、 表示されます。

saveState() {
  return {
    'country': this.getValue(),  // Value state
    'zoom': this.getZoomLevel(), // UI state
  };
}

loadState(state) {
  this.setValue(state['country']);
  this.setZoomLevel(state['zoom']);
}

完全なシリアル化とバッキング データ

saveState はオプションのパラメータ doFullSerialization も受け取ります。これは、 別の UDM イベントでシリアル化された状態を通常参照するフィールドで使用されます。 serializer(バッキング データモデルなど)を使用します。このパラメータは ブロックがシリアル化解除されたときに参照状態を利用できないため、 フィールドがすべてのシリアル化を行います。たとえばこれは ブロックをシリアライズするかブロックをコピーして貼り付けると、

一般的なユースケースは次の 2 つです。

  • バッキングデータが保存されるワークスペースに個々のブロックが モデルが存在しない場合、そのフィールドには、その状態を維持するのに十分な情報が 新しいデータモデルを作成します
  • ブロックをコピーして貼り付けると、フィールドによって常に新しいバッキングが作成される データモデルを使用します。

これを使用するフィールドの一つが、組み込み変数フィールドです。通常は 参照している変数の ID(ただし doFullSerialization が true の場合) すべての状態がシリアル化されます。

saveState(doFullSerialization) {
  const state = {'id': this.variable_.getId()};
  if (doFullSerialization) {
    state['name'] = this.variable_.name;
    state['type'] = this.variable_.type;
  }
  return state;
}

loadState(state) {
  const variable = Blockly.Variables.getOrCreateVariablePackage(
      this.getSourceBlock().workspace,
      state['id'],
      state['name'],   // May not exist.
      state['type']);  // May not exist.
  this.setValue(variable.getId());
}

変数フィールドは、ワークスペースに読み込まれたときに 変数が存在しない場合は、参照する新しい変数を作成できます。

toXmlfromXml

toXmlfromXml: 古い XML で動作するシリアル化フック 使用します。これらのフックは必要な場合にのみ使用してください(例: まだ移行されていない古いコードベースにインストールする)では、saveState を使用します。 loadState

toXml 関数は、状態を表す XML ノードを返す必要があります。 表示されます。そして、fromXml 関数は同じ XML ノードを受け入れ、 現場に持ち込むことができます

toXml(fieldElement) {
  fieldElement.textContent = this.getValue();
  fieldElement.setAttribute('zoom', this.getZoomLevel());
  return fieldElement;
}

fromXml(fieldElement) {
  this.setValue(fieldElement.textContent);
  this.setZoomLevel(fieldElement.getAttribute('zoom'));
}

編集可能でシリアル化可能なプロパティ

EDITABLE プロパティは、それを示す UI をフィールドに表示するかどうかを決定します 操作できるようになります。デフォルトでは true に設定されます。

SERIALIZABLE プロパティは、フィールドをシリアル化するかどうかを決定します。これは、 デフォルトは false です。このプロパティが true の場合、値の指定が必要になることがあります。 シリアル化および逆シリアル化関数 シリアル化)。

カーソルをカスタマイズする

CURSOR プロパティにより、ユーザーがカーソルを合わせたときに表示されるカーソルが決まります 指定します。有効な CSS カーソル文字列を指定する必要があります。デフォルトはカーソルです。 .blocklyDraggable(グラブカーソル)で定義されます。