この時点で、まともなコンポーネントができました。ただし、他の人(特に非開発者)と共有したい場合、その有用性は制限されます。リンゴと梨のどちらかしか選択できません。これは最初の顧客(おそらくフルーツケーキ工場)には最適でしたが、次に取り組んでいる自動車会社は、休憩室で従業員が果物を選ぶのを助けるために拡張現実を使用することはおそらくないでしょう。今こそ、コンポーネントの再利用性と構成性を高める時です。

コンポーネントの構成方法は既にわかっています。ワークフローフローチャートでコンポーネントを選択すると、ワークフローフローチャートの右側にコンポーネント設定パネルがポップアップ表示され、設定オプションが表示されます。

コンポーネントの構成は、ユーザーが構成できる内容の定義と、選択した値の処理の 2 つの部分で構成されます。

構成オプションの定義

提供する構成オプションは、JSON 形式で定義されます。ユーザーは、単純なテキスト入力、チェックボックス入力、ファイルアップロード入力など、さまざまな入力タイプから選択できます。

次に設定例を示します。

{
  "tab1": {
        "title_text": {
            "title": "タイトル",  
            "inputType": "textinput",
            "value": "選択してください"
        }
  },
  "tab2": {
        "options": {
            "title": "オプション",
            "inputType": "map-input",
            "placeholder": {
                "key": "オプションキー",
                "value": "オプションのタイトル"
            },
            "value": [
                {
                    "key": "オプション1",
                    "value": "オプション1"
                },
                {
                    "key": "オプション2",
                    "value": "オプション2"
                },
                {
                    "key": "オプション3",
                    "value": "オプション3"
                }
            ]
        },
         "use_all": {
             "title": "最後のオプションを提供する",
             "inputType": "checkbox-input",
             "value": "true"
         }
  }

JSON ファイルのルート レベルにあるオブジェクトは、構成パネルのタブです (そのキーはタブのタイトルとして表示されます)。各入力フィールドオブジェクトには、少なくとも 3 つの属性があります。

  • a title は、設定パネルの入力フィールドの上に表示される見出しです。
  • inputTypeこれは、表示する入力フィールドのタイプです
  • a value: ユーザーが入力フィールドに入力した内容 (またはデフォルト値)

また、ツールチップとしてレンダリングされ、入力フィールドの目的をより詳細に説明するために使用できる属性を追加するinfoこともできます。

さらに、使用する入力タイプに応じて、多くの特定の属性が可能です。

構成パネルのUIを改善できる高度な手法が利用可能です。たとえば、複数の入力フィールドを繰り返し折りたたむことができるコンテナにグループ化したり、特定の入力フィールドを条件付きで表示したりできます。これらを次の例で示します。

選択した値の処理

構成を定義したら、構成値をコンポーネントに埋め込みます。設定ファイルの値には、 を使用して§{ ... }§アクセスできます。角かっこ内では、ドット表記を使用して構成オブジェクトにアクセスできます。これらのプレースホルダーは、プリコンパイル手順で構成された値に置き換えられます。

たとえば、上記の例で定義した「タイトル」値をステップレイアウトに含めるマッピングを次のように作成できます。

<mapping>
    <ui_element name="Topic"><
        param name="content">§{ tab1.title_text.value }§</param>
    </ui_element>
</mapping>

ヒントとコツ: 設定にアクセスするときの典型的な間違いは、終了の ".value" を忘れることです。

ヘルパー関数を使用して構成を実装することもできます。これらの関数は、次のような多くのことを行うのに役立ちます。

  • 構成に基づいて条件付きでのみワークフローに追加されるルールを実装する
  • 設定された値をループし、ルール/アクション/...各値に対して
  • 追加処理のために設定された値を操作します

ヘルパーの使用例も見てみましょう。

§{#each tab2.options.value}§
    §{#unless @last}§
    <rule id="opt_§{key}§">
        <expression><![CDATA[ #{event:command} == '§{value}§' ]]></expression>
        <actions>
            <action ref="set_command"/>
        </actions><
    /rule>
    §{/unless}§

    §{#if @last}§
    §{#if (and tab2.use_all.value (compare (collection tab2.options.value "size") ">" 1))}§
        <rule id="special_opt_§{key}§">
            <expression><![CDATA[ #{event:command} == '§{value}§' ]]></expression>
            <actions>
                <action ref="special_action"/>
            </actions><
        /rule>    
    §{/if}§
    §{/if}§
§§{/each}§

ここで注意すべき重要な点がいくつかあります。

  • ヘルパー関数の前にある は#必須であり、コード ブロックを囲んで参照することを通知します。
  • ヘルパー関数を入れ子にすると、内側から外側に評価されます。この例では、ヘルパーはcollectionサイズ 3 を返し、d compareを 1 にして true を返します。この結果とチェックボックス入力の値に「論理積」を適用すると、if-helper-functionの最終的なブール値が得られます。
  • いくつかのブロックヘルパー内には、データの配列/マップ内の位置を管理するのに役立ついくつかの自動的に設定される変数があります。@firstこれらは、 @last@index @key

上記の設定例でプリコンパイルすると、次のようになります。

    <ルールid="opt_option1">
        <expression><![CDATA[ #{event:command} == 'オプション 1' ]]></expression><
        actions>
            <action ref="set_command"/>
        </actions><
    /rule>

    <rule id="opt_option2">
        <expression><![CDATA[ #{event:command} == 'オプション 2' ]]></expression><
        actions><
            action ref="set_command"/>
        </actions><
    /rule>

    <rule id="special_opt_option3">
        <expression><![CDATA[ #{event:command} == 'オプション 3' ]]></expression>
        <actions><
            action ref="special_action"/>
        </actions><
    /rule>  

次の 2 つの例は、コンポーネント構成を理解しやすくするための高度な方法を示しています。

入力フィールドのグループ化

inputType "container" を使用して、複数の入力フィールドをグループ化できます。これにより、視覚的にわかりやすくなり、要素のグループの複製などの機能も有効になります。

ここでは、具体的な属性とその説明について説明します。

  • コンテナー グループ: さまざまな種類のグループを区別します。これは、ワークフロー マークアップ内のコンテナーを調べるために使用できます。
  • repeatable: ユーザーがグループのコピーを作成できるようにします。これらは個別に変更できるため、繰り返し可能な要素の実装が可能になります。
  • collapsible: グループを最小化し、タイトルのみを表示します。
  • deletable: 構成からコンテナーを削除します。これは、コピーされたコンテナに対して自動的に設定され、基本コンテナには使用しないでください。
  • editable: ユーザーがコンテナのタイトルを変更できるようにします。
"base_sensor": {
            "title": "センサー 1",
            "inputType": "container",
            "containerGroup": "sensors",
            "repeatable": true,
            "collapsible": true,
            "deleteable": false,
            "editable": true,
            "value": {
                "sensor_shown": {
                    "title": "値の表示",
                    "inputType": "checkbox-input",
                    "value": false,
                    "showIfComputed": true
                },
                "sensor_type": {
                    "inputType": "file-upload",
                    "title": "アイコン",
                    "accept": "image/png",
                    "multiple": false,
                    "value": "",
                    "showIfComputed": true
                },
                "sensor_unit": {
                    "title": "ユニット"、
                    "inputType": "textinput"、
                    "value": "rpm"、
                    "showIfComputed": true
                }、
                "sensor_json_path": {
                    "title": "JSON パス"、
                    "inputType": "textinput"、
                    "value": "rpm"、
                    "showIfComputed": true
                }
            }、
            "showIfComputed": true、
            "container_editing": false、
            "container_opened":true
        }

入力フィールドの条件付き表示

「showif」属性を使用して、入力フィールドを表示または非表示にする条件を定義できます。たとえば、コンポーネントに詳細に構成できるオプション機能があるとします。この機能がまったく使用されていない場合は、詳細な構成パラメーターを表示したくありません。

例を見てみましょう。

{
  "camera":{
    "use_camera":{
      "title": "デバイスカメラを使用",
      "inputType": "checkbox-input",
      "value": "false"
    },
    "zoom_level":{
      "title": "ズームレベル",
      "inputType": "dropdown-input",
      "showIf": "root.Camera.use_camera.value",
      "value": { "name": 1 },
      "elements": [
        {
          "name": 1
        },
        {
          "name": 2
        },
        {
          "name": 3
        }
      ]
    },
    "show_zoom_level": {
      "title": "ズームレベルを表示",
        "inputType": "チェックボックス入力",
        "showIf": "ルート。Camera.use_camera.value & root.Camera.zoom_level.value.name > 1",
        "value": "false"
    },
    "timeout":{
      "title": "カメラのタイムアウト (ミリ秒)",
      "showIf": "root.Camera.use_camera.value",
      "inputType": "textinput",
      "value": 5000
    }
  }
}

以下に、予想される出力を示します。

チェックボックスが false に設定されているため、他のすべての入力フィールドは表示されません。true の場合、ズーム レベルが 1 より高い場合にのみ表示されるため、[ズーム レベルを表示] チェックボックス以外のすべてが表示されます。

📌割り当て

  • タイトルの設定フィールドと、2 つのボタンの画像とテキストを追加します。
  • 両方のボタンに画像が存在する場合にのみ画像を表示します。画像が構成されているボタンが 1 つだけの場合は、テキストのみを表示します。

 コンポーネントのダウンロード(事前割り当て)

ヘルプ& リソース

レイアウトファイル内の構成へのアクセス:

レイアウトタグの属性内では、通常どおり設定にアクセスできます。

<ボタン名="§{ ... }§" .../>

ただし、ブロックヘルパー関数の場合は、次のようなもの <Script> を使用する必要があります。

<スクリプト>§{#if ...}§</Script>
<Button .../>
<Script>§{/if}§</Script>

また、他のすべてのタグ内でタグ <Script> を使用することはできないことに注意することも重要です。以下は 無効な 例です。

<Button>
<Script>§{#...}§</スクリプト>
...
<スクリプト>§{/...}§</Script>
</Button>

最後に、条件の結果が構文エラー Duplicate unique valueになる場合、要素名は 2 回存在するが、プリコンパイル後に一度に 1 つしか存在しないことがわかっているため、構文エラーを無視できます。

解決

以下は、レイアウトの模範的なソリューションです。

<LayoutModel Name="ChoiceScreen" Page="DefaultMaster" Orientation="Vertical">
  <Content PlaceHolder="Content" weight="1" Orientation="Horizontal">
    <Script>§{#if (and (compare configuration.leftImage.value.image.value "!=" "") (compare configuration.rightImage.value.image.value "!=" ""))}§</Script>
    <ボタン名="§{configuration.leftImage.value.text.value}§" FocusOrder="0" Weight="0.5" style="ImageButtonStyle">
      <Image name="LEFT_IMAGE" weight="0.8" margin="0,0,0,0" content="§{configuration.leftImage.value.image.value}§" ScaleType="CenterCrop"/>
      <Text Name="LEFT_TEXT" Style="FooterButtonTextStyle" Weight=".2" MaxSize="30" Content="§{configuration.leftImage.value.text.value}§"/>
      <Events/>
    </Button><
    Script>§{else}§</Script><
    Button Name="§{configuration.leftImage.value.text.value}§" FocusOrder="0" weight="0.5" style="ImageButtonStyle">
      <Text Name="LEFT_TEXT" Style="FooterButtonTextStyle" Weight="1" MaxSize="30" Content="§{configuration.leftImage.value.text.value}§"/>
      <Events/>
    </Button>
    <Script>§{/if}§</Script><

    Script>§{#if (and (compare configuration.leftImage.value.image.value "!=" "") (comp; configuration.rightImage.value.image.value "!=" ""))}§</Script>
    <Button Name="§{configuration.rightImage.value.text.value}§" FocusOrder="1" weight="0.5" style="ImageButtonStyle">
      <Image name="RIGHT_IMAGE" weight="0.8" margin="0,0,0,0" content="§{configuration.rightImage.value.image.value}§" ScaleType="CenterCrop"/>
      <Text Name="RIGHT_TEXT" Style="FooterButtonTextStyle" Weight=".2" MaxSize="30" Content="§{configuration.rightImage.value.text.value}§"/>
      <Events/>
    </Button><
    Script>§{else}§</Script>
    <Button Name="§{configuration.rightImage.value.text.value}§" FocusOrder="1" weight="0.5" style="ImageButtonStyle">
      <Text Name="RIGHT_TEXT" Style="FooterButtonTextStyle" Weight="1" MaxSize="30" Content="§{configuration.rightImage.value.text.value}§"/>
      <Events/>
    </Button>
    <Script>§{/if}§</Script><

  /Content><
/LayoutModel>

 コンポーネントのダウンロード(課題後)

このようなレイアウト ファイル内から構成にアクセスするのは面倒な場合があります。 同様の状況に再び遭遇した場合は、ワイルドカードウィジェットのUI要素を確認する 価値があるかもしれません。この要素は、実行時に動的に編集できます。

ワイルドカードウィジェットを使用したソリューションは、次のようになります。

まず、2 つのボタンのバリアントで 2 つの PartTemplates を作成します。

<PartTemplate Name="OptionButtonsWithImage" orientation="horizontal">
  <button name="§{configuration.rightImage.value.text.value}§" FocusOrder="0" weight="0.5" style="ImageButtonStyle">
    <Image name="RIGHT_IMAGE" weight="0.8" margin="0,0,0,0" content="§{configuration.rightImage.value.image.value}§" ScaleType="CenterCrop"/>
    <Text Name="RIGHT_TEXT" Style="FooterButtonTextStyle" Weight=".2" MaxSize="30" Content="§{configuration.rightImage.value.text.value}§"/>
    <Events/>
  </Button><
  Button Name="§{configuration.leftImage.value.text.value}§" FocusOrder="1" weight="0.5" style="ImageButtonStyle">
    <Image Name="LEFT_IMAGE" Weight="0.8" Margin="0,0,0,0" Content="§{configuration.leftImage.value.image.value}§" ScaleType="CenterCrop"/>
    <Text Name="LEFT_TEXT" Style="FooterButtonTextStyle" Weight=".2" MaxSize="30" Content="§{configuration.leftImage.value.text.value}§"/>
    <Events/>
  </Button><
/PartTemplate>
<PartTemplate Name="OptionButtonsText" Orientation="Horizontal">
  <Button Name="§{configuration.leftImage.value.text.value}§" FocusOrder="0" Weight="0.5" Style="ImageButtonStyle">
    <Text Name="LEFT_TEXT" Style="FooterButtonTextStyle" Weight="1" MaxSize="30" Content="§{configuration.leftImage.value.text.value}§"/>
    <events/>
  </button>
  <button name="§{configuration.rightImage.value.text.value}§" FocusOrder="1" weight="0.5" style="ImageButtonStyle">
    <Text Name="RIGHT_TEXT" style="FooterButtonTextStyle" weight="1" MaxSize="30" Content="§{configuration.rightImage.value.text.value}§"/>
    <Events/>
  </Button><
/PartTemplateです>

「 LayoutModel WildcardWidget」が含まれているだけです。

<LayoutModel Name="ChoiceScreen" Page="DefaultMaster" Orientation="Vertical">
  <Content PlaceHolder="Content" Weight="1" Orientation="Horizontal"><
    WildcardWidget Name="Options" PartTemplateName="OptionButtonWithImage" Weight="1"/>
  </Content><
/LayoutModel>

最後に、ワークフローで、構成に基づいて使用する PartTemplate を設定します。

<mapping><ui_element
    name="Options">
        <param name="parttemplatename">§{#if (and (compare configuration.leftImage.value.image.value "!=" "") (compare configuration.rightImage.value.image.value "!=" ""))}§OptionButtonsWithImage§{else}§OptionButtonsText§{/if}§</param><
    /ui_element>
</mapping>

これにより、レイアウト ファイル内から構成にアクセスするときの構文エラーや特殊なケースを回避できます。

 ワイルドカードウィジェットを使用したコンポーネントのダウンロード(割り当て後)