気ままなタンス*プログラミングなどのノートブック

プログラミングやRPGツクール、DTM等について、学んだことや備忘録をアウトプットとして残し、情報を必要としている誰かにとって「かゆいところに手が届く」ブログとなることを願いながら記事を書いています。

【intra-mart】[IM-FormaDesigner] デプロイ無しでセレクトボックスの制限値を変更する

スポンサーリンク

こんにちは。

今回は、intra-martに関する記事です。

intra-martアドベントカレンダー2020の24日目です。(まだ誰も参加してなかったので、こっそり参加しました) qiita.com

TL;DR

  • product_80_selectbox(2017Summer以降のバージョンで利用可能)
  • warファイルを差し替えなくとも、IM-FormaDesigner上だけのコーディングで、セレクトボックスの制限値の変更が可能な暫定対応
  • システム停止調整業務が面倒な場合に利用すると良いかも

目次

概要

intra-martのIM-FormaDesignerのセレクトボックスを利用する際、 システムの初期設定では30項目までしか表示されません。 31項目以降は切り捨てられて非表示になってしまいます。 f:id:rinne_grid2_1:20201225210548p:plain

これは、WEB-INF/conf/forma-config.xmlのselectbox-item-limitで設定されている値であり、 対象値を変更することで対応ができるようです。 しかしこれは同時に、設定ファイルを書き換えるといったサーバー上ファイルの変更やwarファイルの差し替えが必要になるということを表します。

こんな場合、きっと下記のような問題にぶち当たり、即時反映ができないかもしれません。

  • 本番環境への直接のファイル適用はNGである(ほとんどそうだと思われます)
  • intra-martテナントの利用規模が大きく、システム停止及び移送調整に時間がかかる、あるいは定例停止日まで対応できない
  • でもユーザは急いで対応してほしいと言う

解決策

IM-FormaDesigner上のカスタムスクリプトで対応する。

FormaDesigner -> アクション設定 -> 初期表示イベントのカスタムスクリプトとして、下記のソースコードを指定します

f:id:rinne_grid2_1:20201225211503p:plain

ポイント

  • セレクトボックスのフィールド識別IDをRNGD_CONST.FIELD_ID_SELECTBOX_ITEM変数に指定します
    • サンプルではselectbox1
  • セレクトボックスに表示したい件数をRNGD_CONST.APPLY_LIST_LIMIT_COUNT変数に指定します
    • サンプルでは10000
( function( $ ){
  var RNGD_CONST = {};
  RNGD_CONST.FIELD_ID_SELECTBOX_ITEM = "selectbox1"; // ここにセレクトボックスのフィールド識別IDを指定します
  RNGD_CONST.APPLY_LIST_LIMIT_COUNT = 10000; // ここにセレクトボックスに表示したい件数を指定します

  // PC版かどうかを判断する
  function isPc() {
    return forma.funcs.getDisplayClientType() === "pc";
  }

  var responseType = $("#imfr_response_type").val();
  switch(responseType) {
    case "REGISTRATION":
    case "EDIT":
      if (isPc()) {
        var listId = $("#" + RNGD_CONST.FIELD_ID_SELECTBOX_ITEM).find("select")[0].id;

        if (!window.formaItems) {
          window.formaItems = {};
        }
        if (!window.formaItems.product_80_selectbox) {
          window.formaItems.product_80_selectbox = {};
        }
        // エラー表示
        if (!window.formaItems.product_80_selectbox.AcceptError) {
          window.formaItems.product_80_selectbox.AcceptError = function (event) {
            if ($('span#' + event.inputId).parent().find('span.forma-icon-exclamation-red').size() == 0) {
              $('span#' + event.inputId).find('input:text').addClass('imfr_item_input_error_check').css('outline', 'none')
                .parent().append('<span class="forma-icon-exclamation-red"></span>');
            }
          }
        }
        // エラー表示クリア
        if (!window.formaItems.product_80_selectbox.ClearError) {
          window.formaItems.product_80_selectbox.ClearError = function (event) {
            $('span#' + event.inputId).find('input:text').removeClass('imfr_item_input_error_check').parent().find('span.forma-icon-exclamation-red').remove();
          }
        }

        $(document).ready(function () {
          var fieldSize = '500';
          var item_id = $("#" + RNGD_CONST.FIELD_ID_SELECTBOX_ITEM).parent().attr("id");
          var input_id = RNGD_CONST.FIELD_ID_SELECTBOX_ITEM;

          $('#' + listId).children('option').each(function (index) {
            $(this).text($(this).text().split('').join(String.fromCharCode(8203)));
          });
          reflectStyle();

          if (!window.formaItems.product_80_selectbox.eventSettingInfo) {
            window.formaItems.product_80_selectbox.eventSettingInfo = {};
          }
          if (!window.formaItems.product_80_selectbox.getItemData) {
            window.formaItems.product_80_selectbox.getItemData = {};
          }
          if (!window.formaItems.product_80_selectbox.setItemData) {
            window.formaItems.product_80_selectbox.setItemData = {};
          }

          window.formaItems.product_80_selectbox.eventSettingInfo[item_id] = function (eventType) {
            var selectTag = $('[name="' + RNGD_CONST.FIELD_ID_SELECTBOX_ITEM + '"]');
            var selectorObj = selectTag;
            return selectorObj.selector;
          };

          //外部連携データ収集
          window.formaItems.product_80_selectbox.getItemData[input_id] = function () {
            var selector = $('#' + listId);
            var castsData = forma.cooperation.castsData('0', selector.val());
            return castsData;
          };

          // 外部連携データ反映
          window.formaItems.product_80_selectbox.setItemData[input_id] = function (selectboxInputs) {
            var fieldSize = '500';
            var tabindex = '1';
            var limit = RNGD_CONST.APPLY_LIST_LIMIT_COUNT;
            var displayLimit = '-1';
            var input_id = RNGD_CONST.FIELD_ID_SELECTBOX_ITEM;

            if ((selectboxInputs.master !== undefined) &&
              (selectboxInputs.master[input_id] !== undefined) &&
              (selectboxInputs.master[input_id].length !== 0) &&
              (selectboxInputs.master[input_id][0]['value_' + input_id] !== undefined)) {
              // 取得データを元にタグを生成
              var inputId = RNGD_CONST.FIELD_ID_SELECTBOX_ITEM;
              var thisList = $('#' + inputId);
              var selectedKey = $('[name="escape_' + input_id + '"]').val();
              var strHtml = [];
              var checkValueArray = [];
              var check = false;
              var option = {};
              var select = {};
              var selectTag = $('[name="' + RNGD_CONST.FIELD_ID_SELECTBOX_ITEM + '"]');

              // 初期表示時selectタグを生成
              if (selectboxInputs && !selectTag.attr('id')) {
                selectTag.attr('id', listId);
              }
              // option要素をクリア
              selectTag.children('option').remove();
              // 入力値のクリア
              var input_ = $('#' + listId).next('input');
              selectTag.val('');
              input_.val('');

              if (selectboxInputs.master[input_id].length > 0) {
                // option要素の作成

                // 空白行
                option = new Option('', '');
                select = document.getElementById(listId);
                select.options[select.options.length] = option;


                selectedKey = (selectboxInputs.data[input_id] !== undefined) ? selectboxInputs.data[input_id] : selectedKey;
                var dataNumber = (displayLimit > 0 || selectboxInputs.master[input_id].length < limit) ? selectboxInputs.master[input_id].length : limit;
                for (var i = 0; i < dataNumber; i++) {
                  check = false;
                  // 選択値を反映
                  var optionKey = (selectboxInputs.master[input_id][i]['key_' + input_id] === undefined) ? selectboxInputs.master[input_id][i]['value_' + input_id] : selectboxInputs.master[input_id][i]['key_' + input_id];
                  if (selectedKey === selectboxInputs.master[input_id][i]['value_' + input_id]) {
                    check = true;
                  }
                  option = new Option(String(optionKey).split('').join(String.fromCharCode(8203)), selectboxInputs.master[input_id][i]['value_' + input_id], '', check);
                  select = document.getElementById(listId);
                  select.options[select.options.length] = option;
                }
                /*
                          //ie7,8NG
                          selectTag.append( $( '<option>' ).val( args.data[i][sTargetIdKey] )
                                        .text( args.escapedData[i][sTargetId] )
                                        .attr( 'selected', check ) );
                */

              }
              // 表示値セット
              input_.val(selectTag.children(':selected').text());
              selectTag.change();
            } else {
              if (selectboxInputs.data[input_id] !== undefined) {
                var options = document.getElementById(listId).getElementsByTagName('option');
                var displayValue;
                for (var i = 0; i < options.length; i++) {
                  if (options[i].value == selectboxInputs.data[input_id]) {
                    displayValue = options[i].text;
                  }
                }
                $('#' + listId).val(selectboxInputs.data[input_id]).change();
                $('#' + listId).frSelectbox({ 'menuSize': -1 }).nextAll('input:first').val(displayValue);
              }
            }
          };

          // イベントアクション用関数
          if (!window.formaItems.product_80_selectbox.changeInputMode) {
            window.formaItems.product_80_selectbox.changeInputMode = function (controlSetting) {
              var editableFlg = (controlSetting.mode === 'valid') ? true : false;

              if (editableFlg) {
                $('select[name="' + controlSetting.inputId + '"]').nextAll('input,button').removeAttr('disabled readonly').not('input').css('cursor', '');
              } else {
                $('select[name="' + controlSetting.inputId + '"]').nextAll('input,button').attr({ 'disabled': 'disabled', 'readonly': true }).not('input').css('cursor', 'default');
              }
            }
          }

          function reflectStyle() {
            if (isFinite(fieldSize)) {
              $('[name="' + RNGD_CONST.FIELD_ID_SELECTBOX_ITEM + '"]').width(fieldSize + 'px');
            }

            // create時に空にしても自動でtitleに半角が入るのを制御
            $('#' + listId).frSelectbox({ 'menuSize': -1 }).nextAll('button:first').attr('title', '').end()
              .nextAll('input:first').attr('tabindex', '1');

            $('#' + listId).frSelectbox({ 'menuSize': -1 }).nextAll('input:first')
              .css('background-color', '')
              .css('color', '')
              .css('border-color', '')



              .css('font-family', '')
              .css('font-weight', 'normal')
              .css('font-style', 'normal')
              .css('text-decoration', 'none')
              .addClass(' imfr_input_shadows');
          }
        });
      } else {
        $("#" + RNGD_CONST.FIELD_ID_SELECTBOX_ITEM + "_properties").attr("data-imfr-limit", RNGD_CONST.APPLY_LIST_LIMIT_COUNT);
      }      
      break;
    case "POSTSCRIPT":
    case "REFERENCE":
      if (isPc()) {
        var itemId = $("[name=" + RNGD_CONST.FIELD_ID_SELECTBOX_ITEM + "]").parent().parent().attr("id");
        var targetId = $("#" + itemId + "").find("input")[0].name;
        console.log(targetId);
        if (!window.formaItems) {
          window.formaItems = {};
        }

        $(document).ready(function () {
          var input_id = RNGD_CONST.FIELD_ID_SELECTBOX_ITEM;
          if (!window.formaItems.product_80_selectbox) {
            window.formaItems.product_80_selectbox = {};
          }
          if (!window.formaItems.product_80_selectbox.getItemData) {
            window.formaItems.product_80_selectbox.getItemData = {};
          }
          if (!window.formaItems.product_80_selectbox.setItemData) {
            window.formaItems.product_80_selectbox.setItemData = {};
          }
          // 外部連携データ収集
          window.formaItems.product_80_selectbox.getItemData[input_id] = function () {
            var selector = $('input[name="' + input_id + '"]');
            var castsData = forma.cooperation.castsData('0', selector.val());
            return castsData;
          };
          // 外部連携データ反映
          window.formaItems.product_80_selectbox.setItemData[input_id] = function (selectboxInputs) {
            var fieldSize = '500';
            var limit = RNGD_CONST.APPLY_LIST_LIMIT_COUNT;
            if ((selectboxInputs.master !== undefined) &&
              (selectboxInputs.master[input_id] !== undefined) &&
              (selectboxInputs.master[input_id].length !== 0) &&
              (selectboxInputs.master[input_id][0]['value_' + input_id] !== undefined)) {
              // 取得データを元にタグを生成
              var inputId = RNGD_CONST.FIELD_ID_SELECTBOX_ITEM;
              var thisList = $('#' + inputId);
              var selectedKey = $('[name="escape_' + input_id + '"]').val();
              var value = '';
              var optionLocale = $('input[name="' + input_id + '_locale"]').val();
              var masterData = [];
              selectedKey = (selectboxInputs.data[input_id] !== undefined) ? selectboxInputs.data[input_id] : selectedKey;
              var dataNumber = (selectboxInputs.master[input_id].length < limit) ? selectboxInputs.master[input_id].length : limit;
              for (var i = 0; i < dataNumber; i++) {
                // 選択値を反映
                if (selectedKey === selectboxInputs.master[input_id][i]['value_' + input_id]) {
                  value = (selectboxInputs.master[input_id][i]['key_' + input_id] === undefined) ? selectboxInputs.master[input_id][i]['value_' + input_id] : selectboxInputs.master[input_id][i]['key_' + input_id];
                }
                masterData[i] = {};
                masterData[i].display_names = {};
                masterData[i].display_names[optionLocale] = selectboxInputs.master[input_id][i]['key_' + input_id];
                masterData[i].send_value = selectboxInputs.master[input_id][i]['value_' + input_id];
              }
              $('input[name=' + targetId + ']').val(value);
              $('input[name=' + targetId + ']').attr("title", value);
              $('input[name="' + input_id + '_listData"]').val(ImJson.toJSONString(masterData));
            } else {
              if (selectboxInputs.data[input_id] !== undefined) {
                var locale = RNGD_CONST.FIELD_ID_SELECTBOX_ITEM + '_locale';
                var propertyListData = ImJson.parseJSON($('input[name="' + input_id + '_listData"]').val());
                var value = '';
                var hiddenValue = '';
                for (var i = 0; i < propertyListData.length; i++) {
                  if (propertyListData[i].send_value == selectboxInputs.data[input_id]) {
                    value = propertyListData[i].display_names[$('[name=' + locale + ']').val()];
                    hiddenValue = propertyListData[i].send_value;
                    break;
                  }
                }
                $('input[name=' + targetId + ']').val(value);
                $('input[name=' + targetId + ']').attr("title", value);
                $('input[name="' + input_id + '"]').val(hiddenValue);
              }
            }
          };
        });

      } else {
        $("#" + RNGD_CONST.FIELD_ID_SELECTBOX_ITEM + "_properties").attr("data-imfr-limit", RNGD_CONST.APPLY_LIST_LIMIT_COUNT);
      }

      break;
  }
  
} )( jQuery );

これで、FormaDesignerの画面を開いて見ると、セレクトボックスの制限値が変わり、31個以上の項目が表示されてることがわかります。

f:id:rinne_grid2_1:20201225211848p:plain

やっていること

どうやらproduct_80_selectboxは、forma-config.xmlのselectbox-item-limitの値を取得し、 セレクトボックス部品を生成・表示する際に動的にその値を埋め込みJavaScriptを生成しているようです。

そこで、埋め込まれたJavaScriptを抽出しselectbox-item-limitに該当する値を書き換えつつ、 それを初期処理タイミングで、再実行し、元々埋め込まれたセレクトボックスのアイテムの挙動の差し替えを行っているイメージです。

サンプル定義はこちら

IM-FormaDesigner定義

rngd_sample_rewrite_sbox_limit.zip

データソース定義

datasource_for_rngd_sample_rewrite_sbox_limit.zip

最後に注意点

本件はあくまでもサーバー上のforma-config.xml内容の設定変更が困難な状況であるという場合への暫定対策であり、パフォーマンス等を考慮すると妥当な手順とは言えません。 本当にこの内容で暫定対応を実施すべきかどうかを熟考した上で適用するべきと考えます。 この対応によって発生した障害等について、一切責任を負いません。